jlog.cpp 84 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587
  1. /*##############################################################################
  2. Copyright (C) 2011 HPCC Systems.
  3. All rights reserved. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ############################################################################## */
  14. #include "platform.h"
  15. #include <algorithm>
  16. #include "stdio.h"
  17. #include "jlog.hpp"
  18. #include "jlog.ipp"
  19. #include "jmutex.hpp"
  20. #include "jarray.hpp"
  21. #include "jsocket.hpp"
  22. #include "jmisc.hpp"
  23. #define MSGCOMP_NUMBER 1000
  24. #define FILE_LOG_ENABLES_QUEUEUING
  25. #ifndef _WIN32
  26. #define AUDIT_DATA_LOG_TEMPLATE "/var/log/seisint/log_data_XXXXXX"
  27. #endif
  28. // Time, in nanoseconds, after which the clock field loops --- 3600000000000ns = 1hr
  29. #define CLOCK_LOOP_NANOSECONDS I64C(3600000000000)
  30. // LogMsgSysInfo
  31. static FILE *getNullHandle()
  32. {
  33. #ifdef _WIN32
  34. return fopen("nul","w");
  35. #else
  36. return fopen("/dev/null","w");
  37. #endif
  38. }
  39. LogMsgSysInfo::LogMsgSysInfo(LogMsgId _id, unsigned port, LogMsgSessionId session)
  40. {
  41. id = _id;
  42. time(&timeStarted);
  43. processID = GetCurrentProcessId();
  44. threadID = threadLogID();
  45. sessionID = session;
  46. node.setLocalHost(port);
  47. #ifdef JLOG_PROVIDES_CLOCK
  48. nanoTime = cycle_to_nanosec(get_cycles_now()) % CLOCK_LOOP_NANOSECONDS;
  49. #endif
  50. }
  51. void LogMsgSysInfo::serialize(MemoryBuffer & out) const
  52. {
  53. out.append(id).append((unsigned)timeStarted).append(processID).append(threadID).append(sessionID); node.serialize(out);
  54. }
  55. void LogMsgSysInfo::deserialize(MemoryBuffer & in)
  56. {
  57. unsigned t;
  58. in.read(id).read(t).read(processID).read(threadID).read(sessionID); node.deserialize(in);
  59. timeStarted = t;
  60. }
  61. // LogMsg
  62. StringBuffer & LogMsg::toStringPlain(StringBuffer & out, unsigned fields) const
  63. {
  64. out.ensureCapacity(LOG_MSG_FORMAT_BUFFER_LENGTH);
  65. if(fields & MSGFIELD_audience)
  66. out.append("aud=").append(LogMsgAudienceToVarString(category.queryAudience())).append(' ');
  67. if(fields & MSGFIELD_class)
  68. out.append("cls=").append(LogMsgClassToVarString(category.queryClass())).append(' ');
  69. if(fields & MSGFIELD_detail)
  70. out.appendf("det=%d ", category.queryDetail());
  71. if(fields & MSGFIELD_msgID)
  72. out.appendf("id=%X ", sysInfo.queryMsgID());
  73. if(fields & MSGFIELD_timeDate)
  74. {
  75. time_t timeNum = sysInfo.queryTime();
  76. char timeString[12];
  77. struct tm timeStruct;
  78. localtime_r(&timeNum, &timeStruct);
  79. if(fields & MSGFIELD_date)
  80. {
  81. strftime(timeString, 12, "%Y-%m-%d ", &timeStruct);
  82. out.append(timeString);
  83. }
  84. if(fields & MSGFIELD_time)
  85. {
  86. strftime(timeString, 12, "%H:%M:%S ", &timeStruct);
  87. out.append(timeString);
  88. }
  89. }
  90. if(fields & MSGFIELD_process)
  91. out.appendf("pid=%d ",sysInfo.queryProcessID());
  92. if(fields & MSGFIELD_thread)
  93. out.appendf("tid=%d ",sysInfo.queryThreadID());
  94. if(fields & MSGFIELD_session)
  95. if(sysInfo.querySessionID() == UnknownSession)
  96. out.append("sid=unknown ");
  97. else
  98. out.appendf("sid=%"I64F"u ", sysInfo.querySessionID());
  99. if(fields & MSGFIELD_node)
  100. {
  101. size32_t len = out.length();
  102. sysInfo.queryNode()->getUrlStr(out);
  103. out.append(" ");
  104. }
  105. #ifdef JLOG_PROVIDES_CLOCK
  106. if(fields & MSGFIELD_nanoTime)
  107. out.appendf("%"I64F"dns ", sysInfo.queryClock());
  108. else if(fields & MSGFIELD_microTime)
  109. out.appendf("%"I64F"dus ", sysInfo.queryClock()/1000);
  110. else if(fields & MSGFIELD_milliTime)
  111. out.appendf("%"I64F"dms ", sysInfo.queryClock()/1000000);
  112. #endif
  113. if(fields & MSGFIELD_job)
  114. if(jobInfo.queryJobID() == UnknownJob)
  115. out.append("job=unknown ");
  116. else
  117. out.appendf("job=%"I64F"u ", jobInfo.queryJobID());
  118. if(fields & MSGFIELD_user)
  119. if(jobInfo.queryUserID() == UnknownUser)
  120. out.append("usr=unknown ");
  121. else
  122. out.appendf("usr=%"I64F"u ", jobInfo.queryUserID());
  123. if(fields & MSGFIELD_component)
  124. out.appendf("cmp=%u ", component);
  125. if (fields & MSGFIELD_quote)
  126. out.append('"');
  127. if (fields & MSGFIELD_prefix)
  128. out.append(msgPrefix(category.queryClass()));
  129. if((fields & MSGFIELD_code) && (msgCode != NoLogMsgCode))
  130. out.append(msgCode).append(": ").append(text.str());
  131. else
  132. out.append(text.str());
  133. if (fields & MSGFIELD_quote)
  134. out.append('"');
  135. return out;
  136. }
  137. StringBuffer & LogMsg::toStringXML(StringBuffer & out, unsigned fields) const
  138. {
  139. out.ensureCapacity(LOG_MSG_FORMAT_BUFFER_LENGTH);
  140. out.append("<msg ");
  141. if(fields & MSGFIELD_audience)
  142. out.append("Audience=\"").append(LogMsgAudienceToVarString(category.queryAudience())).append("\" ");
  143. if(fields & MSGFIELD_class)
  144. out.append("Class=\"").append(LogMsgClassToVarString(category.queryClass())).append("\" ");
  145. if(fields & MSGFIELD_detail)
  146. out.append("Detail=\"").append(category.queryDetail()).append("\" ");
  147. #ifdef LOG_MSG_NEWLINE
  148. if(fields & MSGFIELD_allCategory) out.append("\n ");
  149. #endif
  150. if(fields & MSGFIELD_msgID)
  151. out.append("MessageID=\"").append(sysInfo.queryMsgID()).append("\" ");
  152. if(fields & MSGFIELD_timeDate)
  153. {
  154. time_t timeNum = sysInfo.queryTime();
  155. char timeString[20];
  156. struct tm timeStruct;
  157. localtime_r(&timeNum, &timeStruct);
  158. if(fields & MSGFIELD_date)
  159. {
  160. strftime(timeString, 20, "date=\"%Y-%m-%d\" ", &timeStruct);
  161. out.append(timeString);
  162. }
  163. if(fields & MSGFIELD_time)
  164. {
  165. strftime(timeString, 20, "time=\"%H:%M:%S\" ", &timeStruct);
  166. out.append(timeString);
  167. }
  168. }
  169. if(fields & MSGFIELD_process)
  170. out.append("PID=\"").append(sysInfo.queryProcessID()).append("\" ");
  171. if(fields & MSGFIELD_thread)
  172. out.append("TID=\"").append(sysInfo.queryThreadID()).append("\" ");
  173. if(fields & MSGFIELD_session)
  174. if(sysInfo.querySessionID() == UnknownSession)
  175. out.append("SessionID=\"unknown\" ");
  176. else
  177. out.append("SessionID=\"").append(sysInfo.querySessionID()).append("\" ");
  178. if(fields & MSGFIELD_node)
  179. {
  180. out.append("Node=\"");
  181. sysInfo.queryNode()->getUrlStr(out);
  182. out.append("\" ");
  183. }
  184. #ifdef JLOG_PROVIDES_CLOCK
  185. if(fields & MSGFIELD_nanoTime)
  186. out.append("Clock=\"").append(sysInfo.queryClock()).append("ns\" ");
  187. else if(fields & MSGFIELD_microTime)
  188. out.append("Clock=\"").append(sysInfo.queryClock()/1000).append("us\" ");
  189. else if(fields & MSGFIELD_milliTime)
  190. out.append("Clock=\"").append(sysInfo.queryClock()/1000000).append("ms\" ");
  191. #endif
  192. #ifdef LOG_MSG_NEWLINE
  193. if(fields & MSGFIELD_allSysInfo) out.append("\n ");
  194. #endif
  195. if(fields & MSGFIELD_job)
  196. if(jobInfo.queryJobID() == UnknownJob)
  197. out.append("JobID=\"unknown\" ");
  198. else
  199. out.append("JobID=\"").append(jobInfo.queryJobID()).append("\" ");
  200. if(fields & MSGFIELD_user)
  201. if(jobInfo.queryUserID() == UnknownUser)
  202. out.append("UserID=\"unknown\" ");
  203. else
  204. out.append("UserID=\"").append(jobInfo.queryUserID()).append("\" ");
  205. #ifdef LOG_MSG_NEWLINE
  206. if(fields & MSGFIELD_allJobInfo) out.append("\n ");
  207. #endif
  208. if(fields & MSGFIELD_component) out.append("Component=\"").append(component).append("\" ");
  209. if((fields & MSGFIELD_code) && (msgCode != NoLogMsgCode))
  210. out.append("code=\"").append(msgCode).append("\" ");
  211. out.append("text=\"").append(text.str()).append("\" />\n");
  212. return out;
  213. }
  214. StringBuffer & LogMsg::toStringTable(StringBuffer & out, unsigned fields) const
  215. {
  216. out.ensureCapacity(LOG_MSG_FORMAT_BUFFER_LENGTH);
  217. if(fields & MSGFIELD_audience)
  218. out.append(LogMsgAudienceToFixString(category.queryAudience()));
  219. if(fields & MSGFIELD_class)
  220. out.append(LogMsgClassToFixString(category.queryClass()));
  221. if(fields & MSGFIELD_detail)
  222. out.appendf("%10d ", category.queryDetail());
  223. if(fields & MSGFIELD_msgID)
  224. out.appendf("%8X ", sysInfo.queryMsgID());
  225. if(fields & MSGFIELD_timeDate)
  226. {
  227. time_t timeNum = sysInfo.queryTime();
  228. char timeString[12];
  229. struct tm timeStruct;
  230. localtime_r(&timeNum, &timeStruct);
  231. if(fields & MSGFIELD_date)
  232. {
  233. strftime(timeString, 12, "%Y-%m-%d ", &timeStruct);
  234. out.append(timeString);
  235. }
  236. if(fields & MSGFIELD_time)
  237. {
  238. strftime(timeString, 12, "%H:%M:%S ", &timeStruct);
  239. out.append(timeString);
  240. }
  241. }
  242. if(fields & MSGFIELD_process)
  243. out.appendf("%5d ",sysInfo.queryProcessID());
  244. if(fields & MSGFIELD_thread)
  245. out.appendf("%5d ",sysInfo.queryThreadID());
  246. if(fields & MSGFIELD_session)
  247. if(sysInfo.querySessionID() == UnknownSession)
  248. out.append(" unknown ");
  249. else
  250. out.appendf("%20"I64F"u ", sysInfo.querySessionID());
  251. if(fields & MSGFIELD_node)
  252. {
  253. size32_t len = out.length();
  254. sysInfo.queryNode()->getUrlStr(out);
  255. out.appendN(20 + len - out.length(), ' ');
  256. }
  257. #ifdef JLOG_PROVIDES_CLOCK
  258. if(fields & MSGFIELD_nanoTime)
  259. out.appendf("%13"I64F"d ", sysInfo.queryClock());
  260. else if(fields & MSGFIELD_microTime)
  261. out.appendf("%10"I64F"d ", sysInfo.queryClock()/1000);
  262. else if(fields & MSGFIELD_milliTime)
  263. out.appendf("%7"I64F"d ", sysInfo.queryClock()/1000000);
  264. #endif
  265. if(fields & MSGFIELD_job)
  266. if(jobInfo.queryJobID() == UnknownJob)
  267. out.append("unknown ");
  268. else
  269. out.appendf("%7"I64F"u ", jobInfo.queryJobID());
  270. if(fields & MSGFIELD_user)
  271. if(jobInfo.queryUserID() == UnknownUser)
  272. out.append("unknown ");
  273. else
  274. out.appendf("%7"I64F"u ", jobInfo.queryUserID());
  275. if(fields & MSGFIELD_component)
  276. out.appendf("%6u ", component);
  277. if (fields & MSGFIELD_quote)
  278. out.append('"');
  279. if (fields & MSGFIELD_prefix)
  280. out.append(msgPrefix(category.queryClass()));
  281. if((fields & MSGFIELD_code) && (msgCode != NoLogMsgCode))
  282. out.append(msgCode).append(": ").append(text.str());
  283. else
  284. out.append(text.str());
  285. if (fields & MSGFIELD_quote)
  286. out.append('"');
  287. out.append('\n');
  288. return out;
  289. }
  290. StringBuffer & LogMsg::toStringTableHead(StringBuffer & out, unsigned fields)
  291. {
  292. if(fields & MSGFIELD_audience)
  293. out.append("Audience ");
  294. if(fields & MSGFIELD_class)
  295. out.append("Class ");
  296. if(fields & MSGFIELD_detail)
  297. out.append(" Detail ");
  298. if(fields & MSGFIELD_msgID)
  299. out.append(" MsgID ");
  300. if(fields & MSGFIELD_date)
  301. out.append(" Date ");
  302. if(fields & MSGFIELD_time)
  303. out.append(" Time ");
  304. if(fields & MSGFIELD_process)
  305. out.append(" PID ");
  306. if(fields & MSGFIELD_thread)
  307. out.append(" TID ");
  308. if(fields & MSGFIELD_session)
  309. out.append(" SessionID ");
  310. if(fields & MSGFIELD_node)
  311. out.append(" Node ");
  312. #ifdef JLOG_PROVIDES_CLOCK
  313. if(fields & MSGFIELD_nanoTime)
  314. out.append(" Clock/ns ");
  315. else if(fields & MSGFIELD_microTime)
  316. out.append(" Clock/us ");
  317. else if(fields & MSGFIELD_milliTime)
  318. out.append("Clock/ms ");
  319. #endif
  320. if(fields & MSGFIELD_job)
  321. out.append(" JobID ");
  322. if(fields & MSGFIELD_user)
  323. out.append(" UserID ");
  324. if(fields & MSGFIELD_component)
  325. out.append(" Compo ");
  326. out.append("\n\n");
  327. return out;
  328. }
  329. void LogMsg::fprintPlain(FILE * handle, unsigned fields) const
  330. {
  331. if(fields & MSGFIELD_audience)
  332. fprintf(handle, "aud=%s", LogMsgAudienceToVarString(category.queryAudience()));
  333. if(fields & MSGFIELD_class)
  334. fprintf(handle, "cls=%s", LogMsgClassToVarString(category.queryClass()));
  335. if(fields & MSGFIELD_detail)
  336. fprintf(handle, "det=%d ", category.queryDetail());
  337. if(fields & MSGFIELD_msgID)
  338. fprintf(handle, "id=%X ", sysInfo.queryMsgID());
  339. if(fields & MSGFIELD_timeDate)
  340. {
  341. time_t timeNum = sysInfo.queryTime();
  342. char timeString[12];
  343. struct tm timeStruct;
  344. localtime_r(&timeNum, &timeStruct);
  345. if(fields & MSGFIELD_date)
  346. {
  347. strftime(timeString, 12, "%Y-%m-%d ", &timeStruct);
  348. fputs(timeString, handle);
  349. }
  350. if(fields & MSGFIELD_time)
  351. {
  352. strftime(timeString, 12, "%H:%M:%S ", &timeStruct);
  353. fputs(timeString, handle);
  354. }
  355. }
  356. if(fields & MSGFIELD_process)
  357. fprintf(handle, "pid=%d ",sysInfo.queryProcessID());
  358. if(fields & MSGFIELD_thread)
  359. fprintf(handle, "tid=%d ",sysInfo.queryThreadID());
  360. if(fields & MSGFIELD_session)
  361. if(sysInfo.querySessionID() == UnknownSession)
  362. fprintf(handle, "sid=unknown ");
  363. else
  364. fprintf(handle, "sid=%"I64F"u ", sysInfo.querySessionID());
  365. if(fields & MSGFIELD_node)
  366. {
  367. StringBuffer buff;
  368. sysInfo.queryNode()->getUrlStr(buff);
  369. fprintf(handle, "%s ", buff.str());
  370. }
  371. #ifdef JLOG_PROVIDES_CLOCK
  372. if(fields & MSGFIELD_nanoTime)
  373. fprintf(handle, "%"I64F"dns ", sysInfo.queryClock());
  374. else if(fields & MSGFIELD_microTime)
  375. fprintf(handle, "%"I64F"dus ", sysInfo.queryClock()/1000);
  376. else if(fields & MSGFIELD_milliTime)
  377. fprintf(handle, "%"I64F"dms ", sysInfo.queryClock()/1000000);
  378. #endif
  379. if(fields & MSGFIELD_job)
  380. if(jobInfo.queryJobID() == UnknownJob)
  381. fprintf(handle, "job=unknown ");
  382. else
  383. fprintf(handle, "job=%"I64F"u ", jobInfo.queryJobID());
  384. if(fields & MSGFIELD_user)
  385. if(jobInfo.queryUserID() == UnknownUser)
  386. fprintf(handle, "usr=unknown ");
  387. else
  388. fprintf(handle, "usr=%"I64F"u ", jobInfo.queryUserID());
  389. if(fields & MSGFIELD_component)
  390. fprintf(handle, "cmp=%u ", component);
  391. const char * quote = (fields & MSGFIELD_quote) ? "\"" : "";
  392. const char * prefix = (fields & MSGFIELD_prefix) ? msgPrefix(category.queryClass()) : "";
  393. if((fields & MSGFIELD_code) && (msgCode != NoLogMsgCode))
  394. fprintf(handle, "%s%s%d: %s%s", quote, prefix, msgCode, text.str(), quote);
  395. else
  396. fprintf(handle, "%s%s%s%s", quote, prefix, text.str(), quote);
  397. }
  398. void LogMsg::fprintXML(FILE * handle, unsigned fields) const
  399. {
  400. fprintf(handle, "<msg ");
  401. if(fields & MSGFIELD_audience)
  402. fprintf(handle, "Audience=\"%s\" ", LogMsgAudienceToVarString(category.queryAudience()));
  403. if(fields & MSGFIELD_class)
  404. fprintf(handle, "Class=\"%s\" ", LogMsgClassToVarString(category.queryClass()));
  405. if(fields & MSGFIELD_detail)
  406. fprintf(handle, "Detail=\"%d\" ", category.queryDetail());
  407. #ifdef LOG_MSG_NEWLINE
  408. if(fields & MSGFIELD_allCategory) fprintf(handle, "\n ");
  409. #endif
  410. if(fields & MSGFIELD_msgID)
  411. fprintf(handle, "MessageID=\"%d\" ",sysInfo.queryMsgID());
  412. if(fields & MSGFIELD_timeDate)
  413. {
  414. time_t timeNum = sysInfo.queryTime();
  415. char timeString[20];
  416. struct tm timeStruct;
  417. localtime_r(&timeNum, &timeStruct);
  418. if(fields & MSGFIELD_date)
  419. {
  420. strftime(timeString, 20, "date=\"%Y-%m-%d\" ", &timeStruct);
  421. fputs(timeString, handle);
  422. }
  423. if(fields & MSGFIELD_time)
  424. {
  425. strftime(timeString, 20, "time=\"%H:%M:%S\" ", &timeStruct);
  426. fputs(timeString, handle);
  427. }
  428. }
  429. if(fields & MSGFIELD_process)
  430. fprintf(handle, "PID=\"%d\" ", sysInfo.queryProcessID());
  431. if(fields & MSGFIELD_thread)
  432. fprintf(handle, "TID=\"%d\" ", sysInfo.queryThreadID());
  433. if(fields & MSGFIELD_session)
  434. if(sysInfo.querySessionID() == UnknownSession)
  435. fprintf(handle, "SessionID=\"unknown\" ");
  436. else
  437. fprintf(handle, "SessionID=\"%"I64F"u\" ", sysInfo.querySessionID());
  438. if(fields & MSGFIELD_node)
  439. {
  440. StringBuffer buff;
  441. sysInfo.queryNode()->getUrlStr(buff);
  442. fprintf(handle, "Node=\"%s\" ", buff.str());
  443. }
  444. #ifdef JLOG_PROVIDES_CLOCK
  445. if(fields & MSGFIELD_nanoTime)
  446. fprintf(handle, "Clock=\"%"I64F"d ns\" ", sysInfo.queryClock());
  447. else if(fields & MSGFIELD_nanoTime)
  448. fprintf(handle, "Clock=\"%"I64F"d us\" ", sysInfo.queryClock()/1000);
  449. else if(fields & MSGFIELD_nanoTime)
  450. fprintf(handle, "Clock=\"%"I64F"d ms\" ", sysInfo.queryClock()/1000000);
  451. #endif
  452. #ifdef LOG_MSG_NEWLINE
  453. if(fields & MSGFIELD_allSysInfo) fprintf(handle, "\n ");
  454. #endif
  455. if(fields & MSGFIELD_job)
  456. if(jobInfo.queryJobID() == UnknownJob)
  457. fprintf(handle, "JobID=\"unknown\" ");
  458. else
  459. fprintf(handle, "JobID=\"%"I64F"u\" ", jobInfo.queryJobID());
  460. if(fields & MSGFIELD_user)
  461. if(jobInfo.queryUserID() == UnknownUser)
  462. fprintf(handle, "UserID=\"unknown\" ");
  463. else
  464. fprintf(handle, "UserID=\"%"I64F"u\" ", jobInfo.queryUserID());
  465. if(fields & MSGFIELD_component)
  466. fprintf(handle, "Component=\"%6u\" ", component);
  467. #ifdef LOG_MSG_NEWLINE
  468. if(fields & MSGFIELD_allJobInfo) fprintf(handle, "\n ");
  469. #endif
  470. if((fields & MSGFIELD_code) && (msgCode != NoLogMsgCode))
  471. fprintf(handle, "code=\"%d\" ", msgCode);
  472. fprintf(handle, "text=\"%s\" />\n", text.str());
  473. }
  474. void LogMsg::fprintTable(FILE * handle, unsigned fields) const
  475. {
  476. if(fields & MSGFIELD_audience)
  477. fputs(LogMsgAudienceToFixString(category.queryAudience()), handle);
  478. if(fields & MSGFIELD_class)
  479. fputs(LogMsgClassToFixString(category.queryClass()), handle);
  480. if(fields & MSGFIELD_detail)
  481. fprintf(handle, "%10d ", category.queryDetail());
  482. if(fields & MSGFIELD_msgID)
  483. fprintf(handle, "%08X ", sysInfo.queryMsgID());
  484. if(fields & MSGFIELD_timeDate)
  485. {
  486. time_t timeNum = sysInfo.queryTime();
  487. char timeString[12];
  488. struct tm timeStruct;
  489. localtime_r(&timeNum, &timeStruct);
  490. if(fields & MSGFIELD_date)
  491. {
  492. strftime(timeString, 12, "%Y-%m-%d ", &timeStruct);
  493. fputs(timeString, handle);
  494. }
  495. if(fields & MSGFIELD_time)
  496. {
  497. strftime(timeString, 12, "%H:%M:%S ", &timeStruct);
  498. fputs(timeString, handle);
  499. }
  500. }
  501. if(fields & MSGFIELD_process)
  502. fprintf(handle, "%5d ",sysInfo.queryProcessID());
  503. if(fields & MSGFIELD_thread)
  504. fprintf(handle, "%5d ",sysInfo.queryThreadID());
  505. if(fields & MSGFIELD_session)
  506. if(sysInfo.querySessionID() == UnknownSession)
  507. fprintf(handle, " unknown ");
  508. else
  509. fprintf(handle, "%20"I64F"u ", sysInfo.querySessionID());
  510. if(fields & MSGFIELD_node)
  511. {
  512. StringBuffer buff;
  513. static const char * twenty_spaces = " ";
  514. sysInfo.queryNode()->getUrlStr(buff);
  515. fprintf(handle, "%s%s", buff.str(), (buff.length()<=20) ? twenty_spaces+buff.length() : "");
  516. }
  517. #ifdef JLOG_PROVIDES_CLOCK
  518. if(fields & MSGFIELD_nanoTime)
  519. fprintf(handle, "%13"I64F"d ", sysInfo.queryClock());
  520. else if(fields & MSGFIELD_microTime)
  521. fprintf(handle, "%10"I64F"d ", sysInfo.queryClock()/1000);
  522. else if(fields & MSGFIELD_milliTime)
  523. fprintf(handle, "%7"I64F"d ", sysInfo.queryClock()/1000000);
  524. #endif
  525. if(fields & MSGFIELD_job)
  526. if(jobInfo.queryJobID() == UnknownJob)
  527. fprintf(handle, "unknown ");
  528. else
  529. fprintf(handle, "%7"I64F"u ", jobInfo.queryJobID());
  530. if(fields & MSGFIELD_user)
  531. if(jobInfo.queryUserID() == UnknownUser)
  532. fprintf(handle, "unknown ");
  533. else
  534. fprintf(handle, "%7"I64F"u ", jobInfo.queryUserID());
  535. if(fields & MSGFIELD_component)
  536. fprintf(handle, "%6u ", component);
  537. const char * quote = (fields & MSGFIELD_quote) ? "\"" : "";
  538. const char * prefix = (fields & MSGFIELD_prefix) ? msgPrefix(category.queryClass()) : "";
  539. if((fields & MSGFIELD_code) && (msgCode != NoLogMsgCode))
  540. fprintf(handle, "%s%s%d: %s%s\n", quote, prefix, msgCode, text.str(), quote);
  541. else
  542. fprintf(handle, "%s%s%s%s\n", quote, prefix, text.str(), quote);
  543. }
  544. void LogMsg::fprintTableHead(FILE * handle, unsigned fields)
  545. {
  546. if(fields & MSGFIELD_audience)
  547. fprintf(handle, "Audience ");
  548. if(fields & MSGFIELD_class)
  549. fprintf(handle, "Class ");
  550. if(fields & MSGFIELD_detail)
  551. fprintf(handle, " Detail ");
  552. if(fields & MSGFIELD_msgID)
  553. fprintf(handle, " MsgID ");
  554. if(fields & MSGFIELD_date)
  555. fprintf(handle, " Date ");
  556. if(fields & MSGFIELD_time)
  557. fprintf(handle, " Time ");
  558. if(fields & MSGFIELD_process)
  559. fprintf(handle, " PID ");
  560. if(fields & MSGFIELD_thread)
  561. fprintf(handle, " TID ");
  562. if(fields & MSGFIELD_session)
  563. fprintf(handle, " SessionID ");
  564. if(fields & MSGFIELD_node)
  565. fprintf(handle, " Node ");
  566. #ifdef JLOG_PROVIDES_CLOCK
  567. if(fields & MSGFIELD_nanoTime)
  568. fprintf(handle, " Clock/ns ");
  569. else if(fields & MSGFIELD_microTime)
  570. fprintf(handle, " Clock/us ");
  571. else if(fields & MSGFIELD_milliTime)
  572. fprintf(handle, "Clock/ms ");
  573. #endif
  574. if(fields & MSGFIELD_job)
  575. fprintf(handle, " JobID ");
  576. if(fields & MSGFIELD_user)
  577. fprintf(handle, " UserID ");
  578. if(fields & MSGFIELD_component)
  579. fprintf(handle, " Compo ");
  580. fprintf(handle, "\n\n");
  581. }
  582. // Implementations of ILogMsgFilter
  583. void PassAllLogMsgFilter::addToPTree(IPropertyTree * tree) const
  584. {
  585. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  586. filterTree->setProp("@type", "all");
  587. tree->addPropTree("filter", filterTree);
  588. }
  589. void PassLocalLogMsgFilter::addToPTree(IPropertyTree * tree) const
  590. {
  591. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  592. filterTree->setProp("@type", "local");
  593. tree->addPropTree("filter", filterTree);
  594. }
  595. void PassNoneLogMsgFilter::addToPTree(IPropertyTree * tree) const
  596. {
  597. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  598. filterTree->setProp("@type", "none");
  599. tree->addPropTree("filter", filterTree);
  600. }
  601. void CategoryLogMsgFilter::addToPTree(IPropertyTree * tree) const
  602. {
  603. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  604. filterTree->setProp("@type", "category");
  605. filterTree->setPropInt("@audience", audienceMask);
  606. filterTree->setPropInt("@class", classMask);
  607. filterTree->setPropInt("@detail", maxDetail);
  608. if(localFlag) filterTree->setPropInt("@local", 1);
  609. tree->addPropTree("filter", filterTree);
  610. }
  611. void PIDLogMsgFilter::addToPTree(IPropertyTree * tree) const
  612. {
  613. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  614. filterTree->setProp("@type", "pid");
  615. filterTree->setPropInt("@pid", pid);
  616. if(localFlag) filterTree->setPropInt("@local", 1);
  617. tree->addPropTree("filter", filterTree);
  618. }
  619. void TIDLogMsgFilter::addToPTree(IPropertyTree * tree) const
  620. {
  621. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  622. filterTree->setProp("@type", "tid");
  623. filterTree->setPropInt("@tid", tid);
  624. if(localFlag) filterTree->setPropInt("@local", 1);
  625. tree->addPropTree("filter", filterTree);
  626. }
  627. void NodeLogMsgFilter::addToPTree(IPropertyTree * tree) const
  628. {
  629. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  630. filterTree->setProp("@type", "node");
  631. StringBuffer buff;
  632. node.getIpText(buff);
  633. filterTree->setProp("@ip", buff.str());
  634. filterTree->setPropInt("@port", node.port);
  635. if(localFlag) filterTree->setPropInt("@local", 1);
  636. tree->addPropTree("filter", filterTree);
  637. }
  638. void IpLogMsgFilter::addToPTree(IPropertyTree * tree) const
  639. {
  640. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  641. filterTree->setProp("@type", "ip");
  642. StringBuffer buff;
  643. ip.getIpText(buff);
  644. filterTree->setProp("@ip", buff.str());
  645. if(localFlag) filterTree->setPropInt("@local", 1);
  646. tree->addPropTree("filter", filterTree);
  647. }
  648. void JobLogMsgFilter::addToPTree(IPropertyTree * tree) const
  649. {
  650. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  651. filterTree->setProp("@type", "job");
  652. filterTree->setPropInt("@job", (int)job);
  653. if(localFlag) filterTree->setPropInt("@local", 1);
  654. tree->addPropTree("filter", filterTree);
  655. }
  656. void UserLogMsgFilter::addToPTree(IPropertyTree * tree) const
  657. {
  658. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  659. filterTree->setProp("@type", "user");
  660. filterTree->setPropInt("@user", (int)user);
  661. if(localFlag) filterTree->setPropInt("@local", 1);
  662. tree->addPropTree("filter", filterTree);
  663. }
  664. void SessionLogMsgFilter::addToPTree(IPropertyTree * tree) const
  665. {
  666. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  667. filterTree->setProp("@type", "session");
  668. filterTree->setPropInt("@session", (int)session);
  669. if(localFlag) filterTree->setPropInt("@local", 1);
  670. tree->addPropTree("filter", filterTree);
  671. }
  672. void ComponentLogMsgFilter::addToPTree(IPropertyTree * tree) const
  673. {
  674. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  675. filterTree->setProp("@type", "component");
  676. filterTree->setPropInt("@component", component);
  677. if(localFlag) filterTree->setPropInt("@local", 1);
  678. tree->addPropTree("filter", filterTree);
  679. }
  680. bool RegexLogMsgFilter::includeMessage(const LogMsg & msg) const
  681. {
  682. if(localFlag && msg.queryRemoteFlag()) return false;
  683. SpinBlock b(lock);
  684. return const_cast<RegExpr &>(regex).find(msg.queryText()) != NULL;
  685. }
  686. void RegexLogMsgFilter::addToPTree(IPropertyTree * tree) const
  687. {
  688. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  689. filterTree->setProp("@type", "regex");
  690. filterTree->setProp("@regex", regexText);
  691. if(localFlag) filterTree->setPropInt("@local", 1);
  692. tree->addPropTree("filter", filterTree);
  693. }
  694. void NotLogMsgFilter::addToPTree(IPropertyTree * tree) const
  695. {
  696. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  697. filterTree->setProp("@type", "not");
  698. arg->addToPTree(filterTree);
  699. tree->addPropTree("filter", filterTree);
  700. }
  701. void AndLogMsgFilter::addToPTree(IPropertyTree * tree) const
  702. {
  703. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  704. filterTree->setProp("@type", "and");
  705. arg1->addToPTree(filterTree);
  706. arg2->addToPTree(filterTree);
  707. tree->addPropTree("filter", filterTree);
  708. }
  709. void OrLogMsgFilter::addToPTree(IPropertyTree * tree) const
  710. {
  711. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  712. filterTree->setProp("@type", "or");
  713. arg1->addToPTree(filterTree);
  714. arg2->addToPTree(filterTree);
  715. tree->addPropTree("filter", filterTree);
  716. }
  717. void SwitchLogMsgFilter::addToPTree(IPropertyTree * tree) const
  718. {
  719. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  720. filterTree->setProp("@type", "switch");
  721. cond->addToPTree(filterTree);
  722. yes->addToPTree(filterTree);
  723. no->addToPTree(filterTree);
  724. tree->addPropTree("filter", filterTree);
  725. }
  726. void CategoryLogMsgFilter::orWithFilter(const ILogMsgFilter * filter)
  727. {
  728. audienceMask |= filter->queryAudienceMask();
  729. classMask |= filter->queryClassMask();
  730. maxDetail = std::max(maxDetail, filter->queryMaxDetail());
  731. }
  732. void CategoryLogMsgFilter::reset()
  733. {
  734. audienceMask = 0;
  735. classMask = 0;
  736. maxDetail = 0;
  737. }
  738. // HandleLogMsgHandler
  739. void HandleLogMsgHandlerTable::addToPTree(IPropertyTree * tree) const
  740. {
  741. IPropertyTree * handlerTree = createPTree(ipt_caseInsensitive);
  742. if(handle==stderr)
  743. handlerTree->setProp("@type", "stderr");
  744. else
  745. handlerTree->setProp("@type", "mischandle");
  746. handlerTree->setPropInt("@fields", messageFields);
  747. tree->addPropTree("handler", handlerTree);
  748. }
  749. void HandleLogMsgHandlerXML::addToPTree(IPropertyTree * tree) const
  750. {
  751. IPropertyTree * handlerTree = createPTree(ipt_caseInsensitive);
  752. if(handle==stderr)
  753. handlerTree->setProp("@type", "stderr");
  754. else
  755. handlerTree->setProp("@type", "mischandle");
  756. handlerTree->setPropInt("@fields", messageFields);
  757. handlerTree->setProp("@writeXML", "true");
  758. tree->addPropTree("handler", handlerTree);
  759. }
  760. // FileLogMsgHandler
  761. FileLogMsgHandler::FileLogMsgHandler(const char * _filename, const char * _headerText, unsigned _fields, bool _append, bool _flushes)
  762. : messageFields(_fields), filename(_filename), headerText(_headerText), append(_append), flushes(_flushes)
  763. {
  764. recursiveCreateDirectoryForFile(filename);
  765. if(append)
  766. handle = fopen(filename, "a");
  767. else
  768. handle = fopen(filename, "w");
  769. if(!handle) {
  770. handle = getNullHandle();
  771. StringBuffer err;
  772. err.appendf("LOGGING: could not open file '%s' for output",filename.get());
  773. ERRLOG("%s",err.str()); // make sure doesn't get lost!
  774. throw MakeStringException(3000,"%s",err.str()); // 3000: internal error
  775. }
  776. if(headerText) fprintf(handle, "--- %s ---\n", (const char *)headerText);
  777. }
  778. static void closeAndDeleteEmpty(const char * filename, FILE *handle)
  779. {
  780. if (handle) {
  781. fpos_t pos;
  782. bool del = (fgetpos(handle, &pos)==0)&&
  783. #if defined( _WIN32) || defined(__FreeBSD__)
  784. (pos==0);
  785. #else
  786. (pos.__pos==0);
  787. #endif
  788. fclose(handle);
  789. if (del)
  790. remove(filename);
  791. }
  792. }
  793. FileLogMsgHandler::~FileLogMsgHandler()
  794. {
  795. closeAndDeleteEmpty(filename,handle);
  796. }
  797. char const * FileLogMsgHandler::disable()
  798. {
  799. crit.enter();
  800. fclose(handle);
  801. handle = NULL;
  802. return filename;
  803. }
  804. void FileLogMsgHandler::enable()
  805. {
  806. recursiveCreateDirectoryForFile(filename);
  807. handle = fopen(filename, "a");
  808. if(!handle) {
  809. handle = getNullHandle();
  810. assertex(!"FileLogMsgHandler::enable : could not open file for output");
  811. }
  812. crit.leave();
  813. }
  814. void FileLogMsgHandlerTable::addToPTree(IPropertyTree * tree) const
  815. {
  816. IPropertyTree * handlerTree = createPTree(ipt_caseInsensitive);
  817. handlerTree->setProp("@type", "file");
  818. handlerTree->setProp("@filename", filename.get());
  819. if(headerText) handlerTree->setProp("@headertext", headerText.get());
  820. handlerTree->setPropInt("@fields", messageFields);
  821. handlerTree->setProp("@writeTable", "true");
  822. if(append) handlerTree->setProp("@append", "true");
  823. if(flushes) handlerTree->setProp("@flushes", "true");
  824. tree->addPropTree("handler", handlerTree);
  825. }
  826. void FileLogMsgHandlerXML::addToPTree(IPropertyTree * tree) const
  827. {
  828. IPropertyTree * handlerTree = createPTree(ipt_caseInsensitive);
  829. handlerTree->setProp("@type", "file");
  830. handlerTree->setProp("@filename", filename.get());
  831. if(headerText) handlerTree->setProp("@headertext", headerText.get());
  832. handlerTree->setPropInt("@fields", messageFields);
  833. if(append) handlerTree->setProp("@append", "true");
  834. if(flushes) handlerTree->setProp("@flushes", "true");
  835. tree->addPropTree("handler", handlerTree);
  836. }
  837. // FileLogMsgHandler
  838. RollingFileLogMsgHandler::RollingFileLogMsgHandler(const char * _filebase, const char * _fileextn, unsigned _fields, bool _append, bool _flushes, const char *initialName, const char *_alias) : messageFields(_fields), filebase(_filebase), fileextn(_fileextn), append(_append), flushes(_flushes), handle(0), alias(_alias)
  839. {
  840. time_t tNow;
  841. time(&tNow);
  842. localtime_r(&tNow, &startTime);
  843. doRollover(false, initialName);
  844. }
  845. RollingFileLogMsgHandler::~RollingFileLogMsgHandler()
  846. {
  847. closeAndDeleteEmpty(filename,handle);
  848. }
  849. char const * RollingFileLogMsgHandler::disable()
  850. {
  851. crit.enter();
  852. fclose(handle);
  853. return filename;
  854. }
  855. void RollingFileLogMsgHandler::enable()
  856. {
  857. recursiveCreateDirectoryForFile(filename);
  858. handle = fopen(filename, "a");
  859. if(!handle) {
  860. handle = getNullHandle();
  861. assertex(!"RollingFileLogMsgHandler::enable : could not open file for output");
  862. }
  863. crit.leave();
  864. }
  865. void RollingFileLogMsgHandler::addToPTree(IPropertyTree * tree) const
  866. {
  867. IPropertyTree * handlerTree = createPTree(ipt_caseInsensitive);
  868. handlerTree->setProp("@type", "rollingfile");
  869. handlerTree->setProp("@filebase", filebase.get());
  870. handlerTree->setProp("@fileextn", fileextn.get());
  871. handlerTree->setPropInt("@fields", messageFields);
  872. if(append) handlerTree->setProp("@append", "true");
  873. if(flushes) handlerTree->setProp("@flushes", "true");
  874. tree->addPropTree("handler", handlerTree);
  875. }
  876. #define ROLLOVER_PERIOD 86400
  877. void RollingFileLogMsgHandler::checkRollover() const
  878. {
  879. time_t tNow;
  880. time(&tNow);
  881. struct tm ltNow;
  882. localtime_r(&tNow, &ltNow);
  883. if(ltNow.tm_year != startTime.tm_year || ltNow.tm_yday != startTime.tm_yday)
  884. {
  885. localtime_r(&tNow, &startTime); // reset the start time for next rollover check
  886. doRollover(true);
  887. }
  888. }
  889. void RollingFileLogMsgHandler::doRollover(bool daily, const char *forceName) const
  890. {
  891. CriticalBlock block(crit);
  892. closeAndDeleteEmpty(filename,handle);
  893. handle = 0;
  894. filename.clear();
  895. if (forceName)
  896. filename.append(forceName);
  897. else
  898. {
  899. filename.clear().append(filebase.get());
  900. addFileTimestamp(filename, daily);
  901. filename.append(fileextn.get());
  902. }
  903. recursiveCreateDirectoryForFile(filename.str());
  904. handle = fopen(filename.str(), append ? "a" : "w");
  905. if (handle && alias)
  906. {
  907. fclose(handle);
  908. handle = 0;
  909. remove(alias);
  910. try
  911. {
  912. createHardLink(alias, filename.str());
  913. }
  914. catch (IException *E)
  915. {
  916. recursiveCreateDirectoryForFile(filename.str());
  917. handle = fopen(filename.str(), append ? "a" : "w");
  918. EXCLOG(E); // Log the fact that we could not create the alias - probably it is locked (tail a bit unfortunate on windows).
  919. E->Release();
  920. }
  921. if (!handle)
  922. {
  923. recursiveCreateDirectoryForFile(filename.str());
  924. handle = fopen(filename.str(), append ? "a" : "w");
  925. }
  926. }
  927. if(!handle)
  928. {
  929. handle = getNullHandle();
  930. DBGLOG("RollingFileLogMsgHandler::doRollover : could not open log file %s for output", filename.str());
  931. // actually this is pretty fatal
  932. }
  933. }
  934. // BinLogMsgHandler
  935. BinLogMsgHandler::BinLogMsgHandler(const char * _filename, bool _append) : filename(_filename), append(_append)
  936. {
  937. file.setown(createIFile(filename.get()));
  938. if(!file) assertex(!"BinLogMsgHandler::BinLogMsgHanlder : Could not create IFile");
  939. if(append)
  940. fio.setown(file->open(IFOwrite));
  941. else
  942. fio.setown(file->open(IFOcreate));
  943. if(!fio) assertex(!"BinLogMsgHandler::BinLogMsgHanlder : Could not create IFileIO");
  944. fstr.setown(createIOStream(fio));
  945. if(!fstr) assertex(!"BinLogMsgHandler::BinLogMsgHanlder : Could not create IFileIOStream");
  946. if(append)
  947. fstr->seek(0, IFSend);
  948. }
  949. BinLogMsgHandler::~BinLogMsgHandler()
  950. {
  951. fstr.clear();
  952. fio.clear();
  953. file.clear();
  954. }
  955. void BinLogMsgHandler::handleMessage(const LogMsg & msg) const
  956. {
  957. CriticalBlock block(crit);
  958. mbuff.clear();
  959. msg.serialize(mbuff);
  960. msglen = mbuff.length();
  961. fstr->write(sizeof(msglen), &msglen);
  962. fstr->write(msglen, mbuff.toByteArray());
  963. }
  964. void BinLogMsgHandler::addToPTree(IPropertyTree * tree) const
  965. {
  966. IPropertyTree * handlerTree = createPTree(ipt_caseInsensitive);
  967. handlerTree->setProp("@type", "binary");
  968. handlerTree->setProp("@filename", filename.get());
  969. if(append) handlerTree->setProp("@append", "true");
  970. tree->addPropTree("handler", handlerTree);
  971. }
  972. char const * BinLogMsgHandler::disable()
  973. {
  974. crit.enter();
  975. fstr.clear();
  976. fio.clear();
  977. return filename.get();
  978. }
  979. void BinLogMsgHandler::enable()
  980. {
  981. fio.setown(file->open(IFOwrite));
  982. if(!fio) assertex(!"BinLogMsgHandler::enable : Could not create IFileIO");
  983. fstr.setown(createIOStream(fio));
  984. if(!fstr) assertex(!"BinLogMsgHandler::enable : Could not create IFileIOStream");
  985. fstr->seek(0, IFSend);
  986. crit.leave();
  987. }
  988. // LogMsgComponentReporter
  989. void LogMsgComponentReporter::report(const LogMsgCategory & cat, const char * format, ...)
  990. {
  991. va_list args;
  992. va_start(args, format);
  993. queryLogMsgManager()->report_va(component, cat, unknownJob, format, args);
  994. va_end(args);
  995. }
  996. void LogMsgComponentReporter::report_va(const LogMsgCategory & cat, const char * format, va_list args)
  997. {
  998. queryLogMsgManager()->report_va(component, cat, unknownJob, format, args);
  999. }
  1000. void LogMsgComponentReporter::report(const LogMsgCategory & cat, LogMsgCode code, const char * format, ...)
  1001. {
  1002. va_list args;
  1003. va_start(args, format);
  1004. queryLogMsgManager()->report_va(component, cat, unknownJob, code, format, args);
  1005. va_end(args);
  1006. }
  1007. void LogMsgComponentReporter::report_va(const LogMsgCategory & cat, LogMsgCode code, const char * format, va_list args)
  1008. {
  1009. queryLogMsgManager()->report_va(component, cat, unknownJob, code, format, args);
  1010. }
  1011. void LogMsgComponentReporter::report(const LogMsgCategory & cat, const IException * exception, const char * prefix)
  1012. {
  1013. StringBuffer buff;
  1014. if(prefix) buff.append(prefix).append(" : ");
  1015. exception->errorMessage(buff);
  1016. queryLogMsgManager()->report(component, cat, unknownJob, exception->errorCode(), "%s", buff.str());
  1017. }
  1018. void LogMsgComponentReporter::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, ...)
  1019. {
  1020. va_list args;
  1021. va_start(args, format);
  1022. queryLogMsgManager()->report_va(component, cat, job, format, args);
  1023. va_end(args);
  1024. }
  1025. void LogMsgComponentReporter::report_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, va_list args)
  1026. {
  1027. queryLogMsgManager()->report_va(component, cat, job, format, args);
  1028. }
  1029. void LogMsgComponentReporter::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, ...)
  1030. {
  1031. va_list args;
  1032. va_start(args, format);
  1033. queryLogMsgManager()->report_va(component, cat, job, code, format, args);
  1034. va_end(args);
  1035. }
  1036. void LogMsgComponentReporter::report_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, va_list args)
  1037. {
  1038. queryLogMsgManager()->report_va(component, cat, job, code, format, args);
  1039. }
  1040. void LogMsgComponentReporter::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, const IException * exception, const char * prefix)
  1041. {
  1042. StringBuffer buff;
  1043. if(prefix) buff.append(prefix).append(" : ");
  1044. exception->errorMessage(buff);
  1045. queryLogMsgManager()->report(component, cat, job, exception->errorCode(), "%s", buff.str());
  1046. }
  1047. void LogMsgComponentReporter::report(const LogMsg & msg)
  1048. {
  1049. queryLogMsgManager()->report(msg);
  1050. }
  1051. // LogMsgPrepender
  1052. LogMsgPrepender * LogMsgPrepender::setContext(LogMsgComponentReporter * r, char const * f, unsigned l)
  1053. {
  1054. crit.enter();
  1055. reporter = r;
  1056. file = f;
  1057. line = l;
  1058. return this;
  1059. }
  1060. void LogMsgPrepender::report(const LogMsgCategory & cat, const char * format, ...)
  1061. {
  1062. StringBuffer buff;
  1063. buff.append(file).append("(").append(line).append(") : ").append(format);
  1064. va_list args;
  1065. va_start(args, format);
  1066. if(reporter)
  1067. reporter->report_va(cat, unknownJob, buff.str(), args);
  1068. else
  1069. queryLogMsgManager()->report_va(cat, unknownJob, buff.str(), args);
  1070. va_end(args);
  1071. crit.leave();
  1072. }
  1073. void LogMsgPrepender::report_va(const LogMsgCategory & cat, const char * format, va_list args)
  1074. {
  1075. StringBuffer buff;
  1076. buff.append(file).append("(").append(line).append(") : ").append(format);
  1077. if(reporter)
  1078. reporter->report_va(cat, unknownJob, buff.str(), args);
  1079. else
  1080. queryLogMsgManager()->report_va(cat, unknownJob, buff.str(), args);
  1081. crit.leave();
  1082. }
  1083. void LogMsgPrepender::report(const LogMsgCategory & cat, LogMsgCode code, const char * format, ...)
  1084. {
  1085. StringBuffer buff;
  1086. buff.append(file).append("(").append(line).append(") : ").append(format);
  1087. va_list args;
  1088. va_start(args, format);
  1089. if(reporter)
  1090. reporter->report_va(cat, unknownJob, buff.str(), args);
  1091. else
  1092. queryLogMsgManager()->report_va(cat, unknownJob, buff.str(), args);
  1093. va_end(args);
  1094. crit.leave();
  1095. }
  1096. void LogMsgPrepender::report_va(const LogMsgCategory & cat, LogMsgCode code, const char * format, va_list args)
  1097. {
  1098. StringBuffer buff;
  1099. buff.append(file).append("(").append(line).append(") : ").append(format);
  1100. if(reporter)
  1101. reporter->report_va(cat, unknownJob, buff.str(), args);
  1102. else
  1103. queryLogMsgManager()->report_va(cat, unknownJob, buff.str(), args);
  1104. crit.leave();
  1105. }
  1106. void LogMsgPrepender::report(const LogMsgCategory & cat, const IException * exception, const char * prefix)
  1107. {
  1108. StringBuffer buff;
  1109. buff.append(file).append("(").append(line).append(") : ");
  1110. if(prefix) buff.append(prefix).append(" : ");
  1111. exception->errorMessage(buff);
  1112. if(reporter)
  1113. reporter->report(cat, unknownJob, exception->errorCode(), "%s", buff.str());
  1114. else
  1115. queryLogMsgManager()->report(cat, unknownJob, exception->errorCode(), "%s", buff.str());
  1116. crit.leave();
  1117. }
  1118. void LogMsgPrepender::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, ...)
  1119. {
  1120. StringBuffer buff;
  1121. buff.append(file).append("(").append(line).append(") : ").append(format);
  1122. va_list args;
  1123. va_start(args, format);
  1124. if(reporter)
  1125. reporter->report_va(cat, job, buff.str(), args);
  1126. else
  1127. queryLogMsgManager()->report_va(cat, job, buff.str(), args);
  1128. va_end(args);
  1129. crit.leave();
  1130. }
  1131. void LogMsgPrepender::report_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, va_list args)
  1132. {
  1133. StringBuffer buff;
  1134. buff.append(file).append("(").append(line).append(") : ").append(format);
  1135. if(reporter)
  1136. reporter->report_va(cat, job, buff.str(), args);
  1137. else
  1138. queryLogMsgManager()->report_va(cat, job, buff.str(), args);
  1139. crit.leave();
  1140. }
  1141. void LogMsgPrepender::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, ...)
  1142. {
  1143. StringBuffer buff;
  1144. buff.append(file).append("(").append(line).append(") : ").append(format);
  1145. va_list args;
  1146. va_start(args, format);
  1147. if(reporter)
  1148. reporter->report_va(cat, job, buff.str(), args);
  1149. else
  1150. queryLogMsgManager()->report_va(cat, job, buff.str(), args);
  1151. va_end(args);
  1152. crit.leave();
  1153. }
  1154. void LogMsgPrepender::report_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, va_list args)
  1155. {
  1156. StringBuffer buff;
  1157. buff.append(file).append("(").append(line).append(") : ").append(format);
  1158. if(reporter)
  1159. reporter->report_va(cat, job, buff.str(), args);
  1160. else
  1161. queryLogMsgManager()->report_va(cat, job, buff.str(), args);
  1162. crit.leave();
  1163. }
  1164. void LogMsgPrepender::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, const IException * exception, const char * prefix)
  1165. {
  1166. StringBuffer buff;
  1167. buff.append(file).append("(").append(line).append(") : %s");
  1168. StringBuffer txt;
  1169. if (prefix)
  1170. txt.append(prefix).append(" : ");
  1171. exception->errorMessage(txt);
  1172. if(reporter)
  1173. reporter->report(cat, job, exception->errorCode(), buff.str(), txt.str());
  1174. else
  1175. queryLogMsgManager()->report(cat, job, exception->errorCode(), buff.str(), txt.str());
  1176. crit.leave();
  1177. }
  1178. IException * LogMsgPrepender::report(IException * e, const char * prefix, LogMsgClass cls)
  1179. {
  1180. report(MCexception(e, cls), unknownJob, e, prefix);
  1181. return e;
  1182. }
  1183. // LogMsgMonitor
  1184. void LogMsgMonitor::addToPTree(IPropertyTree * tree) const
  1185. {
  1186. IPropertyTree * monitorTree = createPTree(ipt_caseInsensitive);
  1187. handler->addToPTree(monitorTree);
  1188. filter->addToPTree(monitorTree);
  1189. tree->addPropTree("monitor", monitorTree);
  1190. }
  1191. // CLogMsgManager
  1192. void CLogMsgManager::MsgProcessor::push(LogMsg * msg)
  1193. {
  1194. //assertex(more); an assertex will just recurse here
  1195. if (!more) // we are effective stopped so don't bother even dropping (and leak parameter) as drop will involve
  1196. // interaction with the base class which is stopped and could easily crash (as this condition
  1197. // is expected not to occur - typically occurs if the user has incorrectly called exit on one thread
  1198. // while still in the process of logging on another)
  1199. // cf Bug #53695 for more discussion of the issue
  1200. return;
  1201. else if(droppingLimit && (q.ordinality() >= droppingLimit))
  1202. drop();
  1203. q.enqueue(msg);
  1204. }
  1205. int CLogMsgManager::MsgProcessor::run()
  1206. {
  1207. Owned<LogMsg> msg;
  1208. while(more)
  1209. {
  1210. msg.setown(q.dequeueAndNotify(this)); // notify locks mutex on non-null return
  1211. if(!msg)
  1212. break;
  1213. owner->doReport(*msg);
  1214. pullCycleMutex.unlock();
  1215. }
  1216. while(true)
  1217. {
  1218. msg.setown(q.dequeueNowAndNotify(this)); // notify locks mutex on non-null return
  1219. if(!msg)
  1220. break;
  1221. owner->doReport(*msg);
  1222. pullCycleMutex.unlock();
  1223. }
  1224. return 0;
  1225. }
  1226. void CLogMsgManager::MsgProcessor::notify(LogMsg *)
  1227. {
  1228. pullCycleMutex.lock();
  1229. }
  1230. void CLogMsgManager::MsgProcessor::setBlockingLimit(unsigned lim)
  1231. {
  1232. q.setLimit(lim);
  1233. droppingLimit = 0;
  1234. }
  1235. void CLogMsgManager::MsgProcessor::setDroppingLimit(unsigned lim, unsigned num)
  1236. {
  1237. numToDrop = num;
  1238. droppingLimit = lim;
  1239. q.setLimit(0);
  1240. }
  1241. void CLogMsgManager::MsgProcessor::resetLimit()
  1242. {
  1243. droppingLimit = 0;
  1244. q.setLimit(0);
  1245. }
  1246. void CLogMsgManager::MsgProcessor::stop()
  1247. {
  1248. more = false;
  1249. q.stop();
  1250. }
  1251. void CLogMsgManager::MsgProcessor::drop()
  1252. {
  1253. Owned<LogMsg> msg, lastMsg;
  1254. unsigned count;
  1255. unsigned prev = 0;
  1256. for(count = 0; count < numToDrop; count++)
  1257. {
  1258. msg.setown(q.dequeueTail(0));
  1259. if(!msg) break;
  1260. DropLogMsg * dmsg = dynamic_cast<DropLogMsg *>(msg.get());
  1261. if(dmsg) prev += dmsg->queryCount()-1;
  1262. lastMsg.setown(msg.getClear());
  1263. }
  1264. if(lastMsg)
  1265. q.enqueue(new DropLogMsg(owner, lastMsg->querySysInfo().queryMsgID(), count+prev));
  1266. }
  1267. bool CLogMsgManager::MsgProcessor::flush(unsigned timeout)
  1268. {
  1269. unsigned start = msTick();
  1270. if(!q.waitMaxOrdinality(0, timeout))
  1271. return false;
  1272. unsigned now = msTick();
  1273. if(now >= (start+timeout))
  1274. return false;
  1275. try
  1276. {
  1277. synchronized block(pullCycleMutex, timeout+start-now);
  1278. }
  1279. catch(IException * e)
  1280. {
  1281. e->Release();
  1282. return false;
  1283. }
  1284. return true;
  1285. }
  1286. CLogMsgManager::~CLogMsgManager()
  1287. {
  1288. CriticalBlock crit(modeLock);
  1289. if(processor)
  1290. {
  1291. processor->stop();
  1292. processor->join();
  1293. }
  1294. }
  1295. void CLogMsgManager::enterQueueingMode()
  1296. {
  1297. CriticalBlock crit(modeLock);
  1298. if(processor) return;
  1299. processor.setown(new MsgProcessor(this));
  1300. processor->setBlockingLimit(defaultMsgQueueLimit);
  1301. processor->start();
  1302. }
  1303. void CLogMsgManager::setQueueBlockingLimit(unsigned lim)
  1304. {
  1305. CriticalBlock crit(modeLock);
  1306. if(processor)
  1307. processor->setBlockingLimit(lim);
  1308. }
  1309. void CLogMsgManager::setQueueDroppingLimit(unsigned lim, unsigned numToDrop)
  1310. {
  1311. CriticalBlock crit(modeLock);
  1312. if(processor)
  1313. processor->setDroppingLimit(lim, numToDrop);
  1314. }
  1315. void CLogMsgManager::resetQueueLimit()
  1316. {
  1317. CriticalBlock crit(modeLock);
  1318. if(processor)
  1319. processor->resetLimit();
  1320. }
  1321. void CLogMsgManager::report(const LogMsgCategory & cat, const char * format, ...)
  1322. {
  1323. if(rejectsCategory(cat)) return;
  1324. va_list args;
  1325. va_start(args, format);
  1326. pushMsg(new LogMsg(cat, getNextID(), unknownJob, NoLogMsgCode, format, args, 0, port, session));
  1327. va_end(args);
  1328. }
  1329. void CLogMsgManager::report_va(const LogMsgCategory & cat, const char * format, va_list args)
  1330. {
  1331. if(rejectsCategory(cat)) return;
  1332. pushMsg(new LogMsg(cat, getNextID(), unknownJob, NoLogMsgCode, format, args, 0, port, session));
  1333. }
  1334. void CLogMsgManager::report(const LogMsgCategory & cat, LogMsgCode code, const char * format, ...)
  1335. {
  1336. if(rejectsCategory(cat)) return;
  1337. va_list args;
  1338. va_start(args, format);
  1339. pushMsg(new LogMsg(cat, getNextID(), unknownJob, code, format, args, 0, port, session));
  1340. va_end(args);
  1341. }
  1342. void CLogMsgManager::report_va(const LogMsgCategory & cat, LogMsgCode code, const char * format, va_list args)
  1343. {
  1344. if(rejectsCategory(cat)) return;
  1345. pushMsg(new LogMsg(cat, getNextID(), unknownJob, code, format, args, 0, port, session));
  1346. }
  1347. void CLogMsgManager::report(const LogMsgCategory & cat, const IException * exception, const char * prefix)
  1348. {
  1349. if(rejectsCategory(cat)) return;
  1350. StringBuffer buff;
  1351. if(prefix) buff.append(prefix).append(" : ");
  1352. exception->errorMessage(buff);
  1353. pushMsg(new LogMsg(cat, getNextID(), unknownJob, exception->errorCode(), buff.str(), 0, port, session));
  1354. }
  1355. void CLogMsgManager::report(unsigned compo, const LogMsgCategory & cat, const char * format, ...)
  1356. {
  1357. if(rejectsCategory(cat)) return;
  1358. va_list args;
  1359. va_start(args, format);
  1360. pushMsg(new LogMsg(cat, getNextID(), unknownJob, NoLogMsgCode, format, args, compo, port, session));
  1361. va_end(args);
  1362. }
  1363. void CLogMsgManager::report_va(unsigned compo, const LogMsgCategory & cat, const char * format, va_list args)
  1364. {
  1365. if(rejectsCategory(cat)) return;
  1366. pushMsg(new LogMsg(cat, getNextID(), unknownJob, NoLogMsgCode, format, args, compo, port, session));
  1367. }
  1368. void CLogMsgManager::report(unsigned compo, const LogMsgCategory & cat, LogMsgCode code, const char * format, ...)
  1369. {
  1370. if(rejectsCategory(cat)) return;
  1371. va_list args;
  1372. va_start(args, format);
  1373. pushMsg(new LogMsg(cat, getNextID(), unknownJob, code, format, args, compo, port, session));
  1374. va_end(args);
  1375. }
  1376. void CLogMsgManager::report_va(unsigned compo, const LogMsgCategory & cat, LogMsgCode code, const char * format, va_list args)
  1377. {
  1378. if(rejectsCategory(cat)) return;
  1379. pushMsg(new LogMsg(cat, getNextID(), unknownJob, code, format, args, compo, port, session));
  1380. }
  1381. void CLogMsgManager::report(unsigned compo, const LogMsgCategory & cat, const IException * exception, const char * prefix)
  1382. {
  1383. if(rejectsCategory(cat)) return;
  1384. StringBuffer buff;
  1385. if(prefix) buff.append(prefix).append(" : ");
  1386. exception->errorMessage(buff);
  1387. pushMsg(new LogMsg(cat, getNextID(), unknownJob, exception->errorCode(), buff.str(), compo, port, session));
  1388. }
  1389. void CLogMsgManager::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, ...)
  1390. {
  1391. if(rejectsCategory(cat)) return;
  1392. va_list args;
  1393. va_start(args, format);
  1394. pushMsg(new LogMsg(cat, getNextID(), job, NoLogMsgCode, format, args, 0, port, session));
  1395. va_end(args);
  1396. }
  1397. void CLogMsgManager::report_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, va_list args)
  1398. {
  1399. if(rejectsCategory(cat)) return;
  1400. pushMsg(new LogMsg(cat, getNextID(), job, NoLogMsgCode, format, args, 0, port, session));
  1401. }
  1402. void CLogMsgManager::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, ...)
  1403. {
  1404. if(rejectsCategory(cat)) return;
  1405. va_list args;
  1406. va_start(args, format);
  1407. pushMsg(new LogMsg(cat, getNextID(), job, code, format, args, 0, port, session));
  1408. va_end(args);
  1409. }
  1410. void CLogMsgManager::report_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, va_list args)
  1411. {
  1412. if(rejectsCategory(cat)) return;
  1413. pushMsg(new LogMsg(cat, getNextID(), job, code, format, args, 0, port, session));
  1414. }
  1415. void CLogMsgManager::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, const IException * exception, const char * prefix)
  1416. {
  1417. if(rejectsCategory(cat)) return;
  1418. StringBuffer buff;
  1419. if(prefix) buff.append(prefix).append(" : ");
  1420. exception->errorMessage(buff);
  1421. pushMsg(new LogMsg(cat, getNextID(), job, exception->errorCode(), buff.str(), 0, port, session));
  1422. }
  1423. void CLogMsgManager::report(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, ...)
  1424. {
  1425. if(rejectsCategory(cat)) return;
  1426. va_list args;
  1427. va_start(args, format);
  1428. pushMsg(new LogMsg(cat, getNextID(), job, NoLogMsgCode, format, args, compo, port, session));
  1429. va_end(args);
  1430. }
  1431. void CLogMsgManager::report_va(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, va_list args)
  1432. {
  1433. if(rejectsCategory(cat)) return;
  1434. pushMsg(new LogMsg(cat, getNextID(), job, NoLogMsgCode, format, args, compo, port, session));
  1435. }
  1436. void CLogMsgManager::report(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, ...)
  1437. {
  1438. if(rejectsCategory(cat)) return;
  1439. va_list args;
  1440. va_start(args, format);
  1441. pushMsg(new LogMsg(cat, getNextID(), job, code, format, args, compo, port, session));
  1442. va_end(args);
  1443. }
  1444. void CLogMsgManager::report_va(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, va_list args)
  1445. {
  1446. if(rejectsCategory(cat)) return;
  1447. pushMsg(new LogMsg(cat, getNextID(), job, code, format, args, compo, port, session));
  1448. }
  1449. void CLogMsgManager::report(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, const IException * exception, const char * prefix)
  1450. {
  1451. if(rejectsCategory(cat)) return;
  1452. StringBuffer buff;
  1453. if(prefix) buff.append(prefix).append(" : ");
  1454. exception->errorMessage(buff);
  1455. pushMsg(new LogMsg(cat, getNextID(), job, exception->errorCode(), buff.str(), compo, port, session));
  1456. }
  1457. void CLogMsgManager::pushMsg(LogMsg * _msg)
  1458. {
  1459. Owned<LogMsg> msg(_msg);
  1460. if(processor)
  1461. processor->push(msg.getLink());
  1462. else
  1463. doReport(*msg);
  1464. }
  1465. void CLogMsgManager::doReport(const LogMsg & msg) const
  1466. {
  1467. try
  1468. {
  1469. ReadLockBlock block(monitorLock);
  1470. ForEachItemIn(i, monitors)
  1471. monitors.item(i).processMessage(msg);
  1472. }
  1473. catch(IException * e)
  1474. {
  1475. StringBuffer err("exception reporting log message: ");
  1476. err.append(e->errorCode());
  1477. e->errorMessage(err);
  1478. panic(err.str());
  1479. e->Release();
  1480. }
  1481. catch(...)
  1482. {
  1483. panic("unknown exception reporting log message");
  1484. }
  1485. }
  1486. void CLogMsgManager::panic(char const * reason) const
  1487. {
  1488. fprintf(stderr, "%s", reason); // not sure there's anything more useful we can do here
  1489. }
  1490. aindex_t CLogMsgManager::find(const ILogMsgHandler * handler) const
  1491. {
  1492. // N.B. Should be used inside critical block
  1493. ForEachItemIn(i, monitors)
  1494. if(monitors.item(i).queryHandler()==handler) return i;
  1495. return NotFound;
  1496. }
  1497. bool CLogMsgManager::addMonitor(ILogMsgHandler * handler, ILogMsgFilter * filter)
  1498. {
  1499. flushQueue(10*1000);
  1500. WriteLockBlock block(monitorLock);
  1501. if(find(handler) != NotFound) return false;
  1502. monitors.append(*(new LogMsgMonitor(filter, handler)));
  1503. prefilter.orWithFilter(filter);
  1504. sendFilterToChildren(true);
  1505. return true;
  1506. }
  1507. bool CLogMsgManager::addMonitorOwn(ILogMsgHandler * handler, ILogMsgFilter * filter)
  1508. {
  1509. bool ret = addMonitor(handler, filter);
  1510. filter->Release();
  1511. handler->Release();
  1512. return ret;
  1513. }
  1514. void CLogMsgManager::buildPrefilter()
  1515. {
  1516. // N.B. Should be used inside critical block
  1517. prefilter.reset();
  1518. ForEachItemIn(i, monitors)
  1519. prefilter.orWithFilter(monitors.item(i).queryFilter());
  1520. }
  1521. bool CLogMsgManager::removeMonitor(ILogMsgHandler * handler)
  1522. {
  1523. Linked<LogMsgMonitor> todelete;
  1524. {
  1525. WriteLockBlock block(monitorLock);
  1526. aindex_t pos = find(handler);
  1527. if(pos == NotFound) return false;
  1528. todelete.set(&monitors.item(pos));
  1529. monitors.remove(pos);
  1530. buildPrefilter();
  1531. sendFilterToChildren(true);
  1532. return true;
  1533. }
  1534. }
  1535. unsigned CLogMsgManager::removeMonitorsMatching(HandlerTest & test)
  1536. {
  1537. CIArrayOf<LogMsgMonitor> todelete; // delete outside monitorLock
  1538. unsigned count = 0;
  1539. {
  1540. WriteLockBlock block(monitorLock);
  1541. ForEachItemInRev(i, monitors)
  1542. if(test(monitors.item(i).queryHandler()))
  1543. {
  1544. LogMsgMonitor &it = monitors.item(i);
  1545. it.Link();
  1546. todelete.append(it);
  1547. monitors.remove(i);
  1548. ++count;
  1549. }
  1550. buildPrefilter();
  1551. sendFilterToChildren(true);
  1552. }
  1553. return count;
  1554. }
  1555. void CLogMsgManager::removeAllMonitors()
  1556. {
  1557. CIArrayOf<LogMsgMonitor> todelete; // delete outside monitorLock
  1558. {
  1559. WriteLockBlock block(monitorLock);
  1560. ForEachItemInRev(i, monitors) {
  1561. LogMsgMonitor &it = monitors.item(i);
  1562. it.Link();
  1563. todelete.append(it);
  1564. monitors.remove(i);
  1565. }
  1566. prefilter.reset();
  1567. sendFilterToChildren(true);
  1568. }
  1569. }
  1570. void CLogMsgManager::resetMonitors()
  1571. {
  1572. suspendChildren();
  1573. removeAllMonitors();
  1574. Owned<ILogMsgFilter> defaultFilter = getDefaultLogMsgFilter();
  1575. addMonitor(theStderrHandler, defaultFilter);
  1576. unsuspendChildren();
  1577. }
  1578. ILogMsgFilter * CLogMsgManager::queryMonitorFilter(const ILogMsgHandler * handler) const
  1579. {
  1580. ReadLockBlock block(monitorLock);
  1581. aindex_t pos = find(handler);
  1582. if(pos == NotFound) return 0;
  1583. return monitors.item(pos).queryFilter();
  1584. }
  1585. bool CLogMsgManager::changeMonitorFilter(const ILogMsgHandler * handler, ILogMsgFilter * newFilter)
  1586. {
  1587. WriteLockBlock block(monitorLock);
  1588. aindex_t pos = find(handler);
  1589. if(pos == NotFound) return 0;
  1590. monitors.item(pos).setFilter(newFilter);
  1591. buildPrefilter();
  1592. sendFilterToChildren(true);
  1593. return true;
  1594. }
  1595. void CLogMsgManager::prepAllHandlers() const
  1596. {
  1597. ReadLockBlock block(monitorLock);
  1598. ForEachItemIn(i, monitors)
  1599. if(monitors.item(i).queryHandler()->needsPrep()) monitors.item(i).queryHandler()->prep();
  1600. }
  1601. aindex_t CLogMsgManager::findChild(ILogMsgLinkToChild * child) const
  1602. {
  1603. ForEachItemIn(i, children)
  1604. if(&(children.item(i)) == child ) return i;
  1605. return NotFound;
  1606. }
  1607. ILogMsgFilter * CLogMsgManager::getCompoundFilter(bool locked) const
  1608. {
  1609. if(!locked) monitorLock.lockRead();
  1610. Owned<CategoryLogMsgFilter> categoryFilter = new CategoryLogMsgFilter(0, 0, 0, false);
  1611. Owned<ILogMsgFilter> otherFilters;
  1612. ILogMsgFilter * ifilter;
  1613. bool hadCat = false;
  1614. ForEachItemIn(i, monitors)
  1615. {
  1616. ifilter = monitors.item(i).queryFilter();
  1617. if(ifilter->queryLocalFlag()) continue;
  1618. if(ifilter->isCategoryFilter())
  1619. {
  1620. categoryFilter->orWithFilter(ifilter);
  1621. hadCat = true;
  1622. }
  1623. else
  1624. {
  1625. if(otherFilters)
  1626. otherFilters.setown(getOrLogMsgFilter(otherFilters, ifilter));
  1627. else
  1628. otherFilters.set(ifilter);
  1629. }
  1630. }
  1631. if(hadCat)
  1632. {
  1633. if(otherFilters)
  1634. otherFilters.setown(getOrLogMsgFilter(otherFilters, categoryFilter));
  1635. else
  1636. otherFilters.set(categoryFilter);
  1637. }
  1638. if(!locked) monitorLock.unlock();
  1639. if(!otherFilters)
  1640. return getPassNoneLogMsgFilter();
  1641. return otherFilters.getLink();
  1642. }
  1643. void CLogMsgManager::sendFilterToChildren(bool locked) const
  1644. {
  1645. if(suspendedChildren) return;
  1646. ReadLockBlock block(childLock);
  1647. if(children.length()==0) return;
  1648. ILogMsgFilter * filter = getCompoundFilter(locked);
  1649. ForEachItemIn(i, children)
  1650. children.item(i).sendFilter(filter);
  1651. filter->Release();
  1652. }
  1653. bool CLogMsgManager::addMonitorToPTree(const ILogMsgHandler * handler, IPropertyTree * tree) const
  1654. {
  1655. ReadLockBlock block(monitorLock);
  1656. aindex_t pos = find(handler);
  1657. if(pos == NotFound) return false;
  1658. monitors.item(pos).addToPTree(tree);
  1659. return true;
  1660. }
  1661. void CLogMsgManager::addAllMonitorsToPTree(IPropertyTree * tree) const
  1662. {
  1663. ReadLockBlock block(monitorLock);
  1664. ForEachItemIn(i, monitors)
  1665. monitors.item(i).addToPTree(tree);
  1666. }
  1667. bool CLogMsgManager::rejectsCategory(const LogMsgCategory & cat) const
  1668. {
  1669. if (!prefilter.includeCategory(cat))
  1670. return true;
  1671. ReadLockBlock block(monitorLock);
  1672. ForEachItemIn(i, monitors)
  1673. {
  1674. if (monitors.item(i).queryFilter()->mayIncludeCategory(cat))
  1675. return false;
  1676. }
  1677. return true;
  1678. }
  1679. // Helper functions
  1680. ILogMsgFilter * getDeserializedLogMsgFilter(MemoryBuffer & in)
  1681. {
  1682. unsigned type;
  1683. in.read(type);
  1684. switch(type)
  1685. {
  1686. case MSGFILTER_passall : return LINK(thePassAllFilter);
  1687. case MSGFILTER_passlocal : return LINK(thePassLocalFilter);
  1688. case MSGFILTER_passnone : return LINK(thePassNoneFilter);
  1689. case MSGFILTER_category : return new CategoryLogMsgFilter(in);
  1690. case MSGFILTER_pid : return new PIDLogMsgFilter(in);
  1691. case MSGFILTER_tid : return new TIDLogMsgFilter(in);
  1692. case MSGFILTER_node : return new NodeLogMsgFilter(in);
  1693. case MSGFILTER_ip : return new IpLogMsgFilter(in);
  1694. case MSGFILTER_job : return new JobLogMsgFilter(in);
  1695. case MSGFILTER_user : return new UserLogMsgFilter(in);
  1696. case MSGFILTER_session : return new SessionLogMsgFilter(in);
  1697. case MSGFILTER_component : return new ComponentLogMsgFilter(in);
  1698. case MSGFILTER_regex : return new RegexLogMsgFilter(in);
  1699. case MSGFILTER_not : return new NotLogMsgFilter(in);
  1700. case MSGFILTER_and : return new AndLogMsgFilter(in);
  1701. case MSGFILTER_or : return new OrLogMsgFilter(in);
  1702. case MSGFILTER_switch : return new SwitchLogMsgFilter(in);
  1703. default: assertex(!"getDeserializedLogMsgFilter: unrecognized LogMsgFilterType");
  1704. }
  1705. return 0;
  1706. }
  1707. ILogMsgFilter * getLogMsgFilterFromPTree(IPropertyTree * xml)
  1708. {
  1709. /* Note that several of these constructors use GetPropInt and GetPropInt64 to get unsigneds. I think this is OK? (all int64 internally)*/
  1710. StringBuffer type;
  1711. xml->getProp("@type", type);
  1712. if(strcmp(type.str(), "all")==0) return LINK(thePassAllFilter);
  1713. else if(strcmp(type.str(), "local")==0) return LINK(thePassLocalFilter);
  1714. else if(strcmp(type.str(), "none")==0) return LINK(thePassNoneFilter);
  1715. else if(strcmp(type.str(), "category")==0) return new CategoryLogMsgFilter(xml);
  1716. else if(strcmp(type.str(), "pid")==0) return new PIDLogMsgFilter(xml);
  1717. else if(strcmp(type.str(), "tid")==0) return new TIDLogMsgFilter(xml);
  1718. else if(strcmp(type.str(), "node")==0) return new NodeLogMsgFilter(xml);
  1719. else if(strcmp(type.str(), "ip")==0) return new IpLogMsgFilter(xml);
  1720. else if(strcmp(type.str(), "job")==0) return new JobLogMsgFilter(xml);
  1721. else if(strcmp(type.str(), "user")==0) return new UserLogMsgFilter(xml);
  1722. else if(strcmp(type.str(), "session")==0) return new SessionLogMsgFilter(xml);
  1723. else if(strcmp(type.str(), "component")==0) return new ComponentLogMsgFilter(xml);
  1724. else if(strcmp(type.str(), "regex")==0) return new RegexLogMsgFilter(xml);
  1725. else if(strcmp(type.str(), "not")==0) return new NotLogMsgFilter(xml);
  1726. else if(strcmp(type.str(), "and")==0) return new AndLogMsgFilter(xml);
  1727. else if(strcmp(type.str(), "or")==0) return new OrLogMsgFilter(xml);
  1728. else if(strcmp(type.str(), "filter")==0) return new SwitchLogMsgFilter(xml);
  1729. else assertex(!"getLogMsgFilterFromPTree : unrecognized LogMsgFilter type");
  1730. return getPassAllLogMsgFilter();
  1731. }
  1732. ILogMsgFilter * getDefaultLogMsgFilter()
  1733. {
  1734. return new CategoryLogMsgFilter(MSGAUD_all, MSGCLS_all, DefaultDetail, true);
  1735. }
  1736. ILogMsgFilter * getPassAllLogMsgFilter()
  1737. {
  1738. return LINK(thePassAllFilter);
  1739. }
  1740. ILogMsgFilter * getLocalLogMsgFilter()
  1741. {
  1742. return LINK(thePassLocalFilter);
  1743. }
  1744. ILogMsgFilter * getPassNoneLogMsgFilter()
  1745. {
  1746. return LINK(thePassNoneFilter);
  1747. }
  1748. ILogMsgFilter * queryPassAllLogMsgFilter()
  1749. {
  1750. return thePassAllFilter;
  1751. }
  1752. ILogMsgFilter * queryLocalLogMsgFilter()
  1753. {
  1754. return thePassLocalFilter;
  1755. }
  1756. ILogMsgFilter * queryPassNoneLogMsgFilter()
  1757. {
  1758. return thePassNoneFilter;
  1759. }
  1760. ILogMsgFilter * getCategoryLogMsgFilter(unsigned audiences, unsigned classes, LogMsgDetail maxDetail, bool local)
  1761. {
  1762. if((audiences==MSGAUD_all) && (classes==MSGCLS_all) && (maxDetail==TopDetail))
  1763. if(local)
  1764. return LINK(thePassLocalFilter);
  1765. else
  1766. return LINK(thePassAllFilter);
  1767. return new CategoryLogMsgFilter(audiences, classes, maxDetail, local);
  1768. }
  1769. ILogMsgFilter * getPIDLogMsgFilter(unsigned pid, bool local)
  1770. {
  1771. return new PIDLogMsgFilter(pid, local);
  1772. }
  1773. ILogMsgFilter * getTIDLogMsgFilter(unsigned tid, bool local)
  1774. {
  1775. return new TIDLogMsgFilter(tid, local);
  1776. }
  1777. ILogMsgFilter * getNodeLogMsgFilter(const char * name, unsigned port, bool local)
  1778. {
  1779. return new NodeLogMsgFilter(name, port, local);
  1780. }
  1781. ILogMsgFilter * getNodeLogMsgFilter(const IpAddress & ip, unsigned port, bool local)
  1782. {
  1783. return new NodeLogMsgFilter(ip, port, local);
  1784. }
  1785. ILogMsgFilter * getNodeLogMsgFilter(unsigned port, bool local)
  1786. {
  1787. return new NodeLogMsgFilter(port, local);
  1788. }
  1789. ILogMsgFilter * getIpLogMsgFilter(const char * name, bool local)
  1790. {
  1791. return new IpLogMsgFilter(name, local);
  1792. }
  1793. ILogMsgFilter * getIpLogMsgFilter(const IpAddress & ip, bool local)
  1794. {
  1795. return new IpLogMsgFilter(ip, local);
  1796. }
  1797. ILogMsgFilter * getIpLogMsgFilter(bool local)
  1798. {
  1799. return new IpLogMsgFilter(local);
  1800. }
  1801. ILogMsgFilter * getJobLogMsgFilter(LogMsgJobId job, bool local)
  1802. {
  1803. return new JobLogMsgFilter(job, local);
  1804. }
  1805. ILogMsgFilter * getUserLogMsgFilter(LogMsgUserId user, bool local)
  1806. {
  1807. return new UserLogMsgFilter(user, local);
  1808. }
  1809. ILogMsgFilter * getSessionLogMsgFilter(LogMsgSessionId session, bool local)
  1810. {
  1811. return new SessionLogMsgFilter(session, local);
  1812. }
  1813. ILogMsgFilter * getComponentLogMsgFilter(unsigned component, bool local)
  1814. {
  1815. return new ComponentLogMsgFilter(component, local);
  1816. }
  1817. ILogMsgFilter * getRegexLogMsgFilter(const char *regex, bool local)
  1818. {
  1819. return new RegexLogMsgFilter(regex, local);
  1820. }
  1821. ILogMsgFilter * getNotLogMsgFilter(ILogMsgFilter * arg)
  1822. {
  1823. return new NotLogMsgFilter(arg);
  1824. }
  1825. ILogMsgFilter * getNotLogMsgFilterOwn(ILogMsgFilter * arg)
  1826. {
  1827. ILogMsgFilter * ret = new NotLogMsgFilter(arg);
  1828. arg->Release();
  1829. return ret;
  1830. }
  1831. ILogMsgFilter * getAndLogMsgFilter(ILogMsgFilter * arg1, ILogMsgFilter * arg2)
  1832. {
  1833. return new AndLogMsgFilter(arg1, arg2);
  1834. }
  1835. ILogMsgFilter * getAndLogMsgFilterOwn(ILogMsgFilter * arg1, ILogMsgFilter * arg2)
  1836. {
  1837. ILogMsgFilter * ret = new AndLogMsgFilter(arg1, arg2);
  1838. arg1->Release();
  1839. arg2->Release();
  1840. return ret;
  1841. }
  1842. ILogMsgFilter * getOrLogMsgFilter(ILogMsgFilter * arg1, ILogMsgFilter * arg2)
  1843. {
  1844. return new OrLogMsgFilter(arg1, arg2);
  1845. }
  1846. ILogMsgFilter * getOrLogMsgFilterOwn(ILogMsgFilter * arg1, ILogMsgFilter * arg2)
  1847. {
  1848. ILogMsgFilter * ret = new OrLogMsgFilter(arg1, arg2);
  1849. arg1->Release();
  1850. arg2->Release();
  1851. return ret;
  1852. }
  1853. ILogMsgFilter * getSwitchLogMsgFilterOwn(ILogMsgFilter * switchFilter, ILogMsgFilter * yesFilter, ILogMsgFilter * noFilter)
  1854. {
  1855. ILogMsgFilter * ret = new SwitchLogMsgFilter(switchFilter, yesFilter, noFilter);
  1856. switchFilter->Release();
  1857. yesFilter->Release();
  1858. noFilter->Release();
  1859. return ret;
  1860. }
  1861. ILogMsgHandler * getHandleLogMsgHandler(FILE * handle, unsigned fields, bool writeXML)
  1862. {
  1863. if(writeXML)
  1864. return new HandleLogMsgHandlerXML(handle, fields);
  1865. return new HandleLogMsgHandlerTable(handle, fields);
  1866. }
  1867. ILogMsgHandler * getFileLogMsgHandler(const char * filename, const char * headertext, unsigned fields, bool writeXML, bool append, bool flushes)
  1868. {
  1869. if(writeXML)
  1870. return new FileLogMsgHandlerXML(filename, headertext, fields, append, flushes);
  1871. return new FileLogMsgHandlerTable(filename, headertext, fields, append, flushes);
  1872. }
  1873. ILogMsgHandler * getRollingFileLogMsgHandler(const char * filebase, const char * fileextn, unsigned fields, bool append, bool flushes, const char *initialName, const char *alias)
  1874. {
  1875. return new RollingFileLogMsgHandler(filebase, fileextn, fields, append, flushes, initialName, alias);
  1876. }
  1877. ILogMsgHandler * getBinLogMsgHandler(const char * filename, bool append)
  1878. {
  1879. return new BinLogMsgHandler(filename, append);
  1880. }
  1881. void installLogMsgFilterSwitch(ILogMsgHandler * handler, ILogMsgFilter * switchFilter, ILogMsgFilter * newFilter)
  1882. {
  1883. queryLogMsgManager()->changeMonitorFilterOwn(handler, getSwitchLogMsgFilterOwn(switchFilter, newFilter, queryLogMsgManager()->getMonitorFilter(handler)));
  1884. }
  1885. ILogMsgHandler * getLogMsgHandlerFromPTree(IPropertyTree * tree)
  1886. {
  1887. StringBuffer type;
  1888. tree->getProp("@type", type);
  1889. unsigned fields = MSGFIELD_all;
  1890. char const * fstr = tree->queryProp("@fields");
  1891. if(fstr)
  1892. if(isdigit(fstr[0]))
  1893. fields = atoi(fstr);
  1894. else
  1895. fields = LogMsgFieldsFromAbbrevs(fstr);
  1896. if(strcmp(type.str(), "stderr")==0)
  1897. return getHandleLogMsgHandler(stderr, fields, tree->hasProp("@writeXML"));
  1898. else if(strcmp(type.str(), "file")==0)
  1899. {
  1900. StringBuffer filename;
  1901. tree->getProp("@filename", filename);
  1902. if(tree->hasProp("@headertext"))
  1903. {
  1904. StringBuffer headertext;
  1905. tree->getProp("@headertext", headertext);
  1906. return getFileLogMsgHandler(filename.str(), headertext.str(), fields, !(tree->hasProp("@writeTable")), tree->hasProp("@append"), tree->hasProp("@flushes"));
  1907. }
  1908. else
  1909. return getFileLogMsgHandler(filename.str(), 0, fields, !(tree->hasProp("@writeTable")), tree->hasProp("@append"), tree->hasProp("@flushes"));
  1910. }
  1911. else if(strcmp(type.str(), "binary")==0)
  1912. {
  1913. StringBuffer filename;
  1914. tree->getProp("@filename", filename);
  1915. return getBinLogMsgHandler(filename.str(), tree->hasProp("@append"));
  1916. }
  1917. else assertex(!"getLogMsgFilterFromPTree : unrecognized LogMsgHandler type");
  1918. return LINK(theStderrHandler);
  1919. }
  1920. ILogMsgHandler * attachStandardFileLogMsgMonitor(const char * filename, const char * headertext, unsigned fields, unsigned audiences, unsigned classes, LogMsgDetail detail, bool writeXML, bool append, bool flushes, bool local)
  1921. {
  1922. #ifdef FILE_LOG_ENABLES_QUEUEUING
  1923. queryLogMsgManager()->enterQueueingMode();
  1924. #endif
  1925. ILogMsgFilter * filter = getCategoryLogMsgFilter(audiences, classes, detail, local);
  1926. ILogMsgHandler * handler = getFileLogMsgHandler(filename, headertext, fields, writeXML, append, flushes);
  1927. queryLogMsgManager()->addMonitorOwn(handler, filter);
  1928. return handler;
  1929. }
  1930. ILogMsgHandler * attachStandardBinLogMsgMonitor(const char * filename, unsigned audiences, unsigned classes, LogMsgDetail detail, bool append, bool local)
  1931. {
  1932. #ifdef FILE_LOG_ENABLES_QUEUEUING
  1933. queryLogMsgManager()->enterQueueingMode();
  1934. #endif
  1935. ILogMsgFilter * filter = getCategoryLogMsgFilter(audiences, classes, detail, local);
  1936. ILogMsgHandler * handler = getBinLogMsgHandler(filename, append);
  1937. queryLogMsgManager()->addMonitorOwn(handler, filter);
  1938. return handler;
  1939. }
  1940. ILogMsgHandler * attachStandardHandleLogMsgMonitor(FILE * handle, unsigned fields, unsigned audiences, unsigned classes, LogMsgDetail detail, bool writeXML, bool local)
  1941. {
  1942. ILogMsgFilter * filter = getCategoryLogMsgFilter(audiences, classes, detail, local);
  1943. ILogMsgHandler * handler = getHandleLogMsgHandler(handle, fields, writeXML);
  1944. queryLogMsgManager()->addMonitorOwn(handler, filter);
  1945. return handler;
  1946. }
  1947. ILogMsgHandler * attachLogMsgMonitorFromPTree(IPropertyTree * tree)
  1948. {
  1949. Owned<IPropertyTree> handlertree = tree->getPropTree("handler");
  1950. Owned<IPropertyTree> filtertree = tree->getPropTree("filter");
  1951. ILogMsgHandler * handler = getLogMsgHandlerFromPTree(handlertree);
  1952. ILogMsgFilter * filter = getLogMsgFilterFromPTree(filtertree);
  1953. queryLogMsgManager()->addMonitorOwn(handler, filter);
  1954. return handler;
  1955. }
  1956. void attachManyLogMsgMonitorsFromPTree(IPropertyTree * tree)
  1957. {
  1958. Owned<IPropertyTreeIterator> iter = tree->getElements("monitor");
  1959. ForEach(*iter)
  1960. attachLogMsgMonitorFromPTree(&(iter->query()));
  1961. }
  1962. // Standard categories and unknown jobInfo
  1963. const LogMsgCategory MCdisaster(MSGAUD_all, MSGCLS_disaster);
  1964. const LogMsgCategory MCuserError(MSGAUD_user, MSGCLS_error);
  1965. const LogMsgCategory MCoperatorError(MSGAUD_operator, MSGCLS_error);
  1966. const LogMsgCategory MCinternalError((LogMsgAudience)(MSGAUD_internal & MSGAUD_programmer), MSGCLS_error, 1);
  1967. const LogMsgCategory MCuserWarning(MSGAUD_user, MSGCLS_warning);
  1968. const LogMsgCategory MCoperatorWarning(MSGAUD_operator, MSGCLS_warning);
  1969. const LogMsgCategory MCinternalWarning((LogMsgAudience)(MSGAUD_internal & MSGAUD_programmer), MSGCLS_warning, 1);
  1970. const LogMsgCategory MCuserProgress(MSGAUD_user, MSGCLS_progress);
  1971. const LogMsgCategory MCoperatorProgress(MSGAUD_operator, MSGCLS_progress);
  1972. const LogMsgCategory MCdebugProgress(MSGAUD_programmer, MSGCLS_progress);
  1973. const LogMsgCategory MCdebugInfo(MSGAUD_programmer, MSGCLS_information);
  1974. const LogMsgCategory MCstats(MSGAUD_performance, MSGCLS_information);
  1975. const LogMsgCategory MCevent(MSGAUD_monitor, MSGCLS_event);
  1976. const LogMsgCategory MClegacy(MSGAUD_legacy, MSGCLS_legacy, DefaultDetail);
  1977. const LogMsgJobInfo unknownJob(UnknownJob, UnknownUser);
  1978. // Calls to make, remove, and return the manager, standard handler, pass all/none filters, reporter array
  1979. PassAllLogMsgFilter * thePassAllFilter;
  1980. PassLocalLogMsgFilter * thePassLocalFilter;
  1981. PassNoneLogMsgFilter * thePassNoneFilter;
  1982. HandleLogMsgHandlerTable * theStderrHandler;
  1983. CLogMsgManager * theManager;
  1984. CSysLogEventLogger * theSysLogEventLogger;
  1985. LogMsgComponentReporter * theReporters[MSGCOMP_NUMBER];
  1986. LogMsgPrepender * thePrepender;
  1987. MODULE_INIT(INIT_PRIORITY_JLOG)
  1988. {
  1989. thePassAllFilter = new PassAllLogMsgFilter();
  1990. thePassLocalFilter = new PassLocalLogMsgFilter();
  1991. thePassNoneFilter = new PassNoneLogMsgFilter();
  1992. theStderrHandler = new HandleLogMsgHandlerTable(stderr, MSGFIELD_STANDARD);
  1993. theSysLogEventLogger = new CSysLogEventLogger;
  1994. theManager = new CLogMsgManager();
  1995. theManager->resetMonitors();
  1996. for(unsigned compo = 0; compo<MSGCOMP_NUMBER; compo++)
  1997. theReporters[compo] = new LogMsgComponentReporter(compo);
  1998. thePrepender = new LogMsgPrepender;
  1999. return true;
  2000. }
  2001. MODULE_EXIT()
  2002. {
  2003. delete thePrepender;
  2004. for(unsigned compo = 0; compo<MSGCOMP_NUMBER; compo++)
  2005. delete theReporters[compo];
  2006. delete theManager;
  2007. delete theSysLogEventLogger;
  2008. delete theStderrHandler;
  2009. delete thePassNoneFilter;
  2010. delete thePassLocalFilter;
  2011. delete thePassAllFilter;
  2012. }
  2013. ILogMsgManager * queryLogMsgManager()
  2014. {
  2015. return theManager;
  2016. }
  2017. ILogMsgHandler * queryStderrLogMsgHandler()
  2018. {
  2019. return theStderrHandler;
  2020. }
  2021. LogMsgComponentReporter * queryLogMsgComponentReporter(unsigned compo)
  2022. {
  2023. return theReporters[compo];
  2024. }
  2025. LogMsgPrepender * queryLogMsgPrepender()
  2026. {
  2027. return thePrepender;
  2028. }
  2029. ILogMsgManager * createLogMsgManager() // use with care! (needed by mplog listener facility)
  2030. {
  2031. return new CLogMsgManager();
  2032. }
  2033. // Event Logging
  2034. ISysLogEventLogger * querySysLogEventLogger()
  2035. {
  2036. return theSysLogEventLogger;
  2037. }
  2038. ILogMsgHandler * getSysLogMsgHandler(unsigned fields)
  2039. {
  2040. return new SysLogMsgHandler(theSysLogEventLogger, fields);
  2041. }
  2042. #ifdef _WIN32
  2043. #include <WINNT.H>
  2044. #include "jelog.h"
  2045. struct AuditTypeWin32Data
  2046. {
  2047. public:
  2048. unsigned eventtype;
  2049. unsigned categoryid;
  2050. unsigned eventid;
  2051. };
  2052. #define CATEGORY_AUDIT_FUNCTION_REQUIRED
  2053. #define AUDIT_TYPES_BEGIN AuditTypeWin32Data auditTypeDataMap[NUM_AUDIT_TYPES+1] = {
  2054. #define MAKE_AUDIT_TYPE(name, type, categoryid, eventid, level) {type, categoryid, eventid},
  2055. #define AUDIT_TYPES_END {0, 0, 0} };
  2056. #include "jelogtype.hpp"
  2057. #undef CATEGORY_AUDIT_FUNCTION_REQUIRED
  2058. #undef AUDIT_TYPES_BEGIN
  2059. #undef MAKE_AUDIT_TYPE
  2060. #undef AUDIT_TYPES_END
  2061. CSysLogEventLogger::CSysLogEventLogger() : hEventLog(0)
  2062. {
  2063. }
  2064. bool CSysLogEventLogger::log(AuditType auditType, char const * msg, size32_t datasize, void const * data)
  2065. {
  2066. assertex(auditType < NUM_AUDIT_TYPES);
  2067. AuditTypeWin32Data const & typeData = auditTypeDataMap[auditType];
  2068. return win32Report(typeData.eventtype, typeData.categoryid, typeData.eventid, msg, datasize, data);
  2069. }
  2070. bool CSysLogEventLogger::win32Report(unsigned eventtype, unsigned category, unsigned eventid, const char * msg, size32_t datasize, const void * data)
  2071. {
  2072. if (hEventLog==0) {
  2073. // MORE - this doesn't work on Vista/Win7 as can't copy to system32...
  2074. // Perhaps we should just kill this code
  2075. char path[_MAX_PATH+1];
  2076. GetEnvironmentVariable("SystemRoot",path,sizeof(path));
  2077. strcat(path,"\\System32\\JELOG.dll");
  2078. Owned<IFile> file = createIFile(path);
  2079. try {
  2080. if (!file->exists()) {
  2081. char src[_MAX_PATH+1];
  2082. LPTSTR tail;
  2083. DWORD res = SearchPath(NULL,"JELOG.DLL",NULL,sizeof(src),src,&tail);
  2084. if (res>0)
  2085. copyFile(path,src);
  2086. else
  2087. throw MakeOsException(GetLastError());
  2088. }
  2089. }
  2090. catch (IException *e)
  2091. {
  2092. EXCLOG(e, "reportEventLog: Could not install JELOG.DLL");
  2093. hEventLog=(HANDLE)-1;
  2094. e->Release();
  2095. return false;
  2096. }
  2097. HKEY hk;
  2098. if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\Seisint",
  2099. NULL, NULL, 0, KEY_ALL_ACCESS, NULL, &hk, NULL)==0) {
  2100. DWORD sizedata = 0;
  2101. DWORD type = REG_EXPAND_SZ;
  2102. if ((RegQueryValueEx(hk,"EventMessageFile",NULL, &type, NULL, &sizedata)!=0)||!sizedata) {
  2103. StringAttr str("%SystemRoot%\\System32\\JELOG.dll");
  2104. RegSetValueEx(hk,"EventMessageFile", 0, REG_EXPAND_SZ, (LPBYTE) str.get(), str.length() + 1);
  2105. RegSetValueEx(hk,"CategoryMessageFile", 0, REG_EXPAND_SZ, (LPBYTE) str.get(), str.length() + 1);
  2106. DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE | EVENTLOG_AUDIT_SUCCESS | EVENTLOG_AUDIT_FAILURE;
  2107. RegSetValueEx(hk, "TypesSupported", 0, REG_DWORD, (LPBYTE) &dwData, sizeof(DWORD));
  2108. dwData = 16;
  2109. RegSetValueEx(hk, "CategoryCount", 0, REG_DWORD, (LPBYTE) &dwData, sizeof(DWORD));
  2110. }
  2111. RegCloseKey(hk);
  2112. }
  2113. hEventLog = RegisterEventSource(NULL,"Seisint");
  2114. if (!hEventLog) {
  2115. ERRLOG("reportEventLog: Could not register Seisint event source");
  2116. hEventLog=(HANDLE)-1;
  2117. return false;
  2118. }
  2119. }
  2120. if (hEventLog==(HANDLE)-1)
  2121. return false;
  2122. assertex((unsigned)eventtype<=16);
  2123. if (!data)
  2124. datasize = 0;
  2125. else if (!datasize)
  2126. data = NULL;
  2127. #if 1 //useful for debugging...
  2128. ReportEvent(hEventLog, eventtype, category, eventid, NULL, 1, datasize, &msg, (LPVOID)data);
  2129. #else
  2130. if(datasize)
  2131. {
  2132. char * buff = (char *)malloc(datasize*3+1);
  2133. unsigned char const * cdata = (unsigned char *)data;
  2134. unsigned i;
  2135. for(i=0; i<datasize; i++)
  2136. sprintf(buff+i*3, "%02X ", cdata[i]);
  2137. buff[datasize*3-1] = 0;
  2138. DBGLOG("ReportEvent: type=%X categoryid=%X eventid=%X msg='%s' data=[%s]", eventtype, category, eventid, msg, buff);
  2139. free(buff);
  2140. }
  2141. else
  2142. DBGLOG("ReportEvent: type=%X categoryid=%X eventid=%X msg='%s'", eventtype, category, eventid, msg);
  2143. #endif
  2144. return true;
  2145. }
  2146. CSysLogEventLogger::~CSysLogEventLogger()
  2147. {
  2148. if (hEventLog!=0)
  2149. DeregisterEventSource(hEventLog);
  2150. }
  2151. #else
  2152. #include <syslog.h>
  2153. #define CATEGORY_AUDIT_FUNCTION_REQUIRED
  2154. #define AUDIT_TYPES_BEGIN int auditTypeDataMap[NUM_AUDIT_TYPES+1] = {
  2155. #define MAKE_AUDIT_TYPE(name, type, categoryid, eventid, level) level,
  2156. #define AUDIT_TYPES_END 0 };
  2157. #include "jelogtype.hpp"
  2158. #undef CATEGORY_AUDIT_FUNCTION_REQUIRED
  2159. #undef AUDIT_TYPES_BEGIN
  2160. #undef MAKE_AUDIT_TYPE
  2161. #undef AUDIT_TYPES_END
  2162. CSysLogEventLogger::CSysLogEventLogger() : dataLogUsed(false), dataLogName(0), dataLogFile(-1)
  2163. {
  2164. const char * processName = queryCurrentProcessName();
  2165. if (!processName||!*processName)
  2166. processName = "hpcc";
  2167. openlog(processName, LOG_PID, LOG_USER);
  2168. }
  2169. CSysLogEventLogger::~CSysLogEventLogger()
  2170. {
  2171. if(dataLogFile != -1)
  2172. close(dataLogFile);
  2173. if(dataLogName)
  2174. delete [] dataLogName;
  2175. closelog();
  2176. }
  2177. bool CSysLogEventLogger::log(AuditType auditType, const char *msg, size32_t datasize, const void * data)
  2178. {
  2179. assertex(auditType < NUM_AUDIT_TYPES);
  2180. int level = auditTypeDataMap[auditType];
  2181. return linuxReport(level, msg, datasize, data);
  2182. }
  2183. bool CSysLogEventLogger::linuxReport(int level, const char * msg, size32_t datasize, const void * data)
  2184. {
  2185. if (!data)
  2186. datasize = 0;
  2187. else if (!datasize)
  2188. data = NULL;
  2189. bool ret = true;
  2190. #if 1 //useful for debugging...
  2191. if(data)
  2192. {
  2193. if(!dataLogUsed)
  2194. openDataLog();
  2195. if(dataLogFile != -1)
  2196. {
  2197. int fpos = writeDataLog(datasize, (byte const *)data);
  2198. if(fpos != -1)
  2199. syslog(level, "%s [0x%X bytes of data at %s byte 0x%X]", msg, datasize, dataLogName, fpos);
  2200. else
  2201. syslog(level, "%s [could not write 0x%X bytes of data to %s]", msg, datasize, dataLogName);
  2202. }
  2203. else
  2204. {
  2205. ret = false;
  2206. syslog(level, "%s [could not open file of form %s to write data]", msg, AUDIT_DATA_LOG_TEMPLATE);
  2207. }
  2208. }
  2209. else
  2210. {
  2211. syslog(level, "%s", msg);
  2212. }
  2213. #else
  2214. if(datasize)
  2215. {
  2216. char * buff = (char *)malloc(datasize*3+1);
  2217. unsigned char const * cdata = (unsigned char *)data;
  2218. unsigned i;
  2219. for(i=0; i<datasize; i++)
  2220. sprintf(buff+i*3, "%02X ", cdata[i]);
  2221. buff[datasize*3-1] = 0;
  2222. DBGLOG("syslog: priority=%X msg='%s' data=[%s]", level, msg, buff);
  2223. free(buff);
  2224. }
  2225. else
  2226. DBGLOG("syslog: priority=%X msg='%s'", level, msg);
  2227. #endif
  2228. return ret;
  2229. }
  2230. void CSysLogEventLogger::openDataLog()
  2231. {
  2232. CriticalBlock block(dataLogLock);
  2233. dataLogUsed = true;
  2234. unsigned len = strlen(AUDIT_DATA_LOG_TEMPLATE);
  2235. dataLogName = new char[len+1];
  2236. strcpy(dataLogName, AUDIT_DATA_LOG_TEMPLATE);
  2237. dataLogFile = mkstemp(dataLogName);
  2238. }
  2239. int CSysLogEventLogger::writeDataLog(size32_t datasize, byte const * data)
  2240. {
  2241. CriticalBlock block(dataLogLock);
  2242. off_t fpos = lseek(dataLogFile, 0, SEEK_CUR);
  2243. while(datasize > 0)
  2244. {
  2245. size32_t written = write(dataLogFile, data, datasize);
  2246. if(written == -1)
  2247. return -1;
  2248. data += written;
  2249. datasize -= written;
  2250. }
  2251. #ifdef __linux__
  2252. fdatasync(dataLogFile);
  2253. #endif
  2254. return fpos;
  2255. }
  2256. #endif
  2257. void SysLogMsgHandler::handleMessage(const LogMsg & msg) const
  2258. {
  2259. AuditType type = categoryToAuditType(msg.queryCategory());
  2260. StringBuffer text;
  2261. msg.toStringPlain(text, fields);
  2262. logger->log(type, text.str());
  2263. }
  2264. void SysLogMsgHandler::addToPTree(IPropertyTree * tree) const
  2265. {
  2266. IPropertyTree * handlerTree = createPTree(ipt_caseInsensitive);
  2267. handlerTree->setProp("@type", "audit");
  2268. tree->addPropTree("handler", handlerTree);
  2269. }
  2270. class DummyLogCtx : implements IContextLogger
  2271. {
  2272. public:
  2273. // It's a static object - we don't want to actually link-count it...
  2274. virtual void Link() const {}
  2275. virtual bool Release() const { return false; }
  2276. virtual void CTXLOG(const char *format, ...) const
  2277. {
  2278. va_list args;
  2279. va_start(args, format);
  2280. CTXLOGva(format, args);
  2281. va_end(args);
  2282. }
  2283. virtual void CTXLOGva(const char *format, va_list args) const
  2284. {
  2285. StringBuffer ss;
  2286. ss.valist_appendf(format, args);
  2287. DBGLOG("%s", ss.str());
  2288. }
  2289. virtual void CTXLOGa(unsigned activityId, const char *text) const
  2290. {
  2291. DBGLOG("[%d] %s", activityId, text);
  2292. }
  2293. virtual StringBuffer &getLogPrefix(StringBuffer &ret) const
  2294. {
  2295. return ret;
  2296. }
  2297. virtual void logOperatorException(IException *E, const char *file, unsigned line, const char *format, ...) const
  2298. {
  2299. va_list args;
  2300. va_start(args, format);
  2301. logOperatorExceptionVA(E, file, line, format, args);
  2302. va_end(args);
  2303. }
  2304. virtual void logOperatorExceptionVA(IException *E, const char *file, unsigned line, const char *format, va_list args) const
  2305. {
  2306. StringBuffer ss;
  2307. ss.append("ERROR");
  2308. if (E)
  2309. ss.append(": ").append(E->errorCode());
  2310. if (file)
  2311. ss.appendf(": %s(%d) ", file, line);
  2312. if (E)
  2313. E->errorMessage(ss.append(": "));
  2314. if (format)
  2315. ss.append(": ").valist_appendf(format, args);
  2316. LOG(MCoperatorProgress, unknownJob, "%s", ss.str());
  2317. }
  2318. virtual bool isIntercepted() const
  2319. {
  2320. return false;
  2321. }
  2322. virtual void noteStatistic(unsigned statCode, unsigned __int64 value, unsigned count) const
  2323. {
  2324. }
  2325. virtual unsigned queryTraceLevel() const
  2326. {
  2327. return 0;
  2328. }
  2329. } dummyContextLogger;
  2330. extern jlib_decl const IContextLogger &queryDummyContextLogger()
  2331. {
  2332. return dummyContextLogger;
  2333. }
  2334. extern jlib_decl void UseSysLogForOperatorMessages(bool use)
  2335. {
  2336. static ILogMsgHandler *msgHandler=NULL;
  2337. if (use==(msgHandler!=NULL))
  2338. return;
  2339. if (use) {
  2340. msgHandler = getSysLogMsgHandler();
  2341. ILogMsgFilter * operatorFilter = getCategoryLogMsgFilter(MSGAUD_operator|MSGAUD_monitor, MSGCLS_all, DefaultDetail, true);
  2342. queryLogMsgManager()->addMonitorOwn(msgHandler, operatorFilter);
  2343. }
  2344. else {
  2345. queryLogMsgManager()->removeMonitor(msgHandler);
  2346. msgHandler = NULL;
  2347. }
  2348. }