jlog.cpp 85 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593
  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__) || defined(__APPLE__)
  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 txt;
  1167. if (prefix)
  1168. txt.append(prefix).append(" : ");
  1169. exception->errorMessage(txt);
  1170. if (reporter)
  1171. reporter->report(cat, job, exception->errorCode(), "%s(%d) : %s", file, line, txt.str());
  1172. else
  1173. queryLogMsgManager()->report(cat, job, exception->errorCode(), "%s(%d) : %s", file, line, txt.str());
  1174. crit.leave();
  1175. }
  1176. IException * LogMsgPrepender::report(IException * e, const char * prefix, LogMsgClass cls)
  1177. {
  1178. report(MCexception(e, cls), unknownJob, e, prefix);
  1179. return e;
  1180. }
  1181. // LogMsgMonitor
  1182. void LogMsgMonitor::addToPTree(IPropertyTree * tree) const
  1183. {
  1184. IPropertyTree * monitorTree = createPTree(ipt_caseInsensitive);
  1185. handler->addToPTree(monitorTree);
  1186. filter->addToPTree(monitorTree);
  1187. tree->addPropTree("monitor", monitorTree);
  1188. }
  1189. // CLogMsgManager
  1190. void CLogMsgManager::MsgProcessor::push(LogMsg * msg)
  1191. {
  1192. //assertex(more); an assertex will just recurse here
  1193. if (!more) // we are effective stopped so don't bother even dropping (and leak parameter) as drop will involve
  1194. // interaction with the base class which is stopped and could easily crash (as this condition
  1195. // is expected not to occur - typically occurs if the user has incorrectly called exit on one thread
  1196. // while still in the process of logging on another)
  1197. // cf Bug #53695 for more discussion of the issue
  1198. return;
  1199. else if(droppingLimit && (q.ordinality() >= droppingLimit))
  1200. drop();
  1201. q.enqueue(msg);
  1202. }
  1203. int CLogMsgManager::MsgProcessor::run()
  1204. {
  1205. Owned<LogMsg> msg;
  1206. while(more)
  1207. {
  1208. msg.setown(q.dequeueAndNotify(this)); // notify locks mutex on non-null return
  1209. if(!msg)
  1210. break;
  1211. owner->doReport(*msg);
  1212. pullCycleMutex.unlock();
  1213. }
  1214. while(true)
  1215. {
  1216. msg.setown(q.dequeueNowAndNotify(this)); // notify locks mutex on non-null return
  1217. if(!msg)
  1218. break;
  1219. owner->doReport(*msg);
  1220. pullCycleMutex.unlock();
  1221. }
  1222. return 0;
  1223. }
  1224. void CLogMsgManager::MsgProcessor::notify(LogMsg *)
  1225. {
  1226. pullCycleMutex.lock();
  1227. }
  1228. void CLogMsgManager::MsgProcessor::setBlockingLimit(unsigned lim)
  1229. {
  1230. q.setLimit(lim);
  1231. droppingLimit = 0;
  1232. }
  1233. void CLogMsgManager::MsgProcessor::setDroppingLimit(unsigned lim, unsigned num)
  1234. {
  1235. numToDrop = num;
  1236. droppingLimit = lim;
  1237. q.setLimit(0);
  1238. }
  1239. void CLogMsgManager::MsgProcessor::resetLimit()
  1240. {
  1241. droppingLimit = 0;
  1242. q.setLimit(0);
  1243. }
  1244. void CLogMsgManager::MsgProcessor::stop()
  1245. {
  1246. more = false;
  1247. q.stop();
  1248. }
  1249. void CLogMsgManager::MsgProcessor::drop()
  1250. {
  1251. Owned<LogMsg> msg, lastMsg;
  1252. unsigned count;
  1253. unsigned prev = 0;
  1254. for(count = 0; count < numToDrop; count++)
  1255. {
  1256. msg.setown(q.dequeueTail(0));
  1257. if(!msg) break;
  1258. DropLogMsg * dmsg = dynamic_cast<DropLogMsg *>(msg.get());
  1259. if(dmsg) prev += dmsg->queryCount()-1;
  1260. lastMsg.setown(msg.getClear());
  1261. }
  1262. if(lastMsg)
  1263. q.enqueue(new DropLogMsg(owner, lastMsg->querySysInfo().queryMsgID(), count+prev));
  1264. }
  1265. bool CLogMsgManager::MsgProcessor::flush(unsigned timeout)
  1266. {
  1267. unsigned start = msTick();
  1268. if(!q.waitMaxOrdinality(0, timeout))
  1269. return false;
  1270. unsigned now = msTick();
  1271. if(now >= (start+timeout))
  1272. return false;
  1273. try
  1274. {
  1275. synchronized block(pullCycleMutex, timeout+start-now);
  1276. }
  1277. catch(IException * e)
  1278. {
  1279. e->Release();
  1280. return false;
  1281. }
  1282. return true;
  1283. }
  1284. CLogMsgManager::~CLogMsgManager()
  1285. {
  1286. CriticalBlock crit(modeLock);
  1287. if(processor)
  1288. {
  1289. processor->stop();
  1290. processor->join();
  1291. }
  1292. }
  1293. void CLogMsgManager::enterQueueingMode()
  1294. {
  1295. CriticalBlock crit(modeLock);
  1296. if(processor) return;
  1297. processor.setown(new MsgProcessor(this));
  1298. processor->setBlockingLimit(defaultMsgQueueLimit);
  1299. processor->start();
  1300. }
  1301. void CLogMsgManager::setQueueBlockingLimit(unsigned lim)
  1302. {
  1303. CriticalBlock crit(modeLock);
  1304. if(processor)
  1305. processor->setBlockingLimit(lim);
  1306. }
  1307. void CLogMsgManager::setQueueDroppingLimit(unsigned lim, unsigned numToDrop)
  1308. {
  1309. CriticalBlock crit(modeLock);
  1310. if(processor)
  1311. processor->setDroppingLimit(lim, numToDrop);
  1312. }
  1313. void CLogMsgManager::resetQueueLimit()
  1314. {
  1315. CriticalBlock crit(modeLock);
  1316. if(processor)
  1317. processor->resetLimit();
  1318. }
  1319. void CLogMsgManager::report(const LogMsgCategory & cat, const char * format, ...)
  1320. {
  1321. if(rejectsCategory(cat)) return;
  1322. va_list args;
  1323. va_start(args, format);
  1324. pushMsg(new LogMsg(cat, getNextID(), unknownJob, NoLogMsgCode, format, args, 0, port, session));
  1325. va_end(args);
  1326. }
  1327. void CLogMsgManager::report_va(const LogMsgCategory & cat, const char * format, va_list args)
  1328. {
  1329. if(rejectsCategory(cat)) return;
  1330. pushMsg(new LogMsg(cat, getNextID(), unknownJob, NoLogMsgCode, format, args, 0, port, session));
  1331. }
  1332. void CLogMsgManager::report(const LogMsgCategory & cat, LogMsgCode code, const char * format, ...)
  1333. {
  1334. if(rejectsCategory(cat)) return;
  1335. va_list args;
  1336. va_start(args, format);
  1337. pushMsg(new LogMsg(cat, getNextID(), unknownJob, code, format, args, 0, port, session));
  1338. va_end(args);
  1339. }
  1340. void CLogMsgManager::report_va(const LogMsgCategory & cat, LogMsgCode code, const char * format, va_list args)
  1341. {
  1342. if(rejectsCategory(cat)) return;
  1343. pushMsg(new LogMsg(cat, getNextID(), unknownJob, code, format, args, 0, port, session));
  1344. }
  1345. void CLogMsgManager::report(const LogMsgCategory & cat, const IException * exception, const char * prefix)
  1346. {
  1347. if(rejectsCategory(cat)) return;
  1348. StringBuffer buff;
  1349. if(prefix) buff.append(prefix).append(" : ");
  1350. exception->errorMessage(buff);
  1351. pushMsg(new LogMsg(cat, getNextID(), unknownJob, exception->errorCode(), buff.str(), 0, port, session));
  1352. }
  1353. void CLogMsgManager::report(unsigned compo, const LogMsgCategory & cat, const char * format, ...)
  1354. {
  1355. if(rejectsCategory(cat)) return;
  1356. va_list args;
  1357. va_start(args, format);
  1358. pushMsg(new LogMsg(cat, getNextID(), unknownJob, NoLogMsgCode, format, args, compo, port, session));
  1359. va_end(args);
  1360. }
  1361. void CLogMsgManager::report_va(unsigned compo, const LogMsgCategory & cat, const char * format, va_list args)
  1362. {
  1363. if(rejectsCategory(cat)) return;
  1364. pushMsg(new LogMsg(cat, getNextID(), unknownJob, NoLogMsgCode, format, args, compo, port, session));
  1365. }
  1366. void CLogMsgManager::report(unsigned compo, const LogMsgCategory & cat, LogMsgCode code, const char * format, ...)
  1367. {
  1368. if(rejectsCategory(cat)) return;
  1369. va_list args;
  1370. va_start(args, format);
  1371. pushMsg(new LogMsg(cat, getNextID(), unknownJob, code, format, args, compo, port, session));
  1372. va_end(args);
  1373. }
  1374. void CLogMsgManager::report_va(unsigned compo, const LogMsgCategory & cat, LogMsgCode code, const char * format, va_list args)
  1375. {
  1376. if(rejectsCategory(cat)) return;
  1377. pushMsg(new LogMsg(cat, getNextID(), unknownJob, code, format, args, compo, port, session));
  1378. }
  1379. void CLogMsgManager::report(unsigned compo, const LogMsgCategory & cat, const IException * exception, const char * prefix)
  1380. {
  1381. if(rejectsCategory(cat)) return;
  1382. StringBuffer buff;
  1383. if(prefix) buff.append(prefix).append(" : ");
  1384. exception->errorMessage(buff);
  1385. pushMsg(new LogMsg(cat, getNextID(), unknownJob, exception->errorCode(), buff.str(), compo, port, session));
  1386. }
  1387. void CLogMsgManager::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, ...)
  1388. {
  1389. if(rejectsCategory(cat)) return;
  1390. va_list args;
  1391. va_start(args, format);
  1392. pushMsg(new LogMsg(cat, getNextID(), job, NoLogMsgCode, format, args, 0, port, session));
  1393. va_end(args);
  1394. }
  1395. void CLogMsgManager::report_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, va_list args)
  1396. {
  1397. if(rejectsCategory(cat)) return;
  1398. pushMsg(new LogMsg(cat, getNextID(), job, NoLogMsgCode, format, args, 0, port, session));
  1399. }
  1400. void CLogMsgManager::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, ...)
  1401. {
  1402. if(rejectsCategory(cat)) return;
  1403. va_list args;
  1404. va_start(args, format);
  1405. pushMsg(new LogMsg(cat, getNextID(), job, code, format, args, 0, port, session));
  1406. va_end(args);
  1407. }
  1408. void CLogMsgManager::report_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, va_list args)
  1409. {
  1410. if(rejectsCategory(cat)) return;
  1411. pushMsg(new LogMsg(cat, getNextID(), job, code, format, args, 0, port, session));
  1412. }
  1413. void CLogMsgManager::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, const IException * exception, const char * prefix)
  1414. {
  1415. if(rejectsCategory(cat)) return;
  1416. StringBuffer buff;
  1417. if(prefix) buff.append(prefix).append(" : ");
  1418. exception->errorMessage(buff);
  1419. pushMsg(new LogMsg(cat, getNextID(), job, exception->errorCode(), buff.str(), 0, port, session));
  1420. }
  1421. void CLogMsgManager::report(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, ...)
  1422. {
  1423. if(rejectsCategory(cat)) return;
  1424. va_list args;
  1425. va_start(args, format);
  1426. pushMsg(new LogMsg(cat, getNextID(), job, NoLogMsgCode, format, args, compo, port, session));
  1427. va_end(args);
  1428. }
  1429. void CLogMsgManager::report_va(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, va_list args)
  1430. {
  1431. if(rejectsCategory(cat)) return;
  1432. pushMsg(new LogMsg(cat, getNextID(), job, NoLogMsgCode, format, args, compo, port, session));
  1433. }
  1434. void CLogMsgManager::report(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, ...)
  1435. {
  1436. if(rejectsCategory(cat)) return;
  1437. va_list args;
  1438. va_start(args, format);
  1439. pushMsg(new LogMsg(cat, getNextID(), job, code, format, args, compo, port, session));
  1440. va_end(args);
  1441. }
  1442. void CLogMsgManager::report_va(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, va_list args)
  1443. {
  1444. if(rejectsCategory(cat)) return;
  1445. pushMsg(new LogMsg(cat, getNextID(), job, code, format, args, compo, port, session));
  1446. }
  1447. void CLogMsgManager::report(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, const IException * exception, const char * prefix)
  1448. {
  1449. if(rejectsCategory(cat)) return;
  1450. StringBuffer buff;
  1451. if(prefix) buff.append(prefix).append(" : ");
  1452. exception->errorMessage(buff);
  1453. pushMsg(new LogMsg(cat, getNextID(), job, exception->errorCode(), buff.str(), compo, port, session));
  1454. }
  1455. void CLogMsgManager::pushMsg(LogMsg * _msg)
  1456. {
  1457. Owned<LogMsg> msg(_msg);
  1458. if(processor)
  1459. processor->push(msg.getLink());
  1460. else
  1461. doReport(*msg);
  1462. }
  1463. void CLogMsgManager::doReport(const LogMsg & msg) const
  1464. {
  1465. try
  1466. {
  1467. ReadLockBlock block(monitorLock);
  1468. ForEachItemIn(i, monitors)
  1469. monitors.item(i).processMessage(msg);
  1470. }
  1471. catch(IException * e)
  1472. {
  1473. StringBuffer err("exception reporting log message: ");
  1474. err.append(e->errorCode());
  1475. e->errorMessage(err);
  1476. panic(err.str());
  1477. e->Release();
  1478. }
  1479. catch(...)
  1480. {
  1481. panic("unknown exception reporting log message");
  1482. }
  1483. }
  1484. void CLogMsgManager::panic(char const * reason) const
  1485. {
  1486. fprintf(stderr, "%s", reason); // not sure there's anything more useful we can do here
  1487. }
  1488. aindex_t CLogMsgManager::find(const ILogMsgHandler * handler) const
  1489. {
  1490. // N.B. Should be used inside critical block
  1491. ForEachItemIn(i, monitors)
  1492. if(monitors.item(i).queryHandler()==handler) return i;
  1493. return NotFound;
  1494. }
  1495. bool CLogMsgManager::addMonitor(ILogMsgHandler * handler, ILogMsgFilter * filter)
  1496. {
  1497. flushQueue(10*1000);
  1498. WriteLockBlock block(monitorLock);
  1499. if(find(handler) != NotFound) return false;
  1500. monitors.append(*(new LogMsgMonitor(filter, handler)));
  1501. prefilter.orWithFilter(filter);
  1502. sendFilterToChildren(true);
  1503. return true;
  1504. }
  1505. bool CLogMsgManager::addMonitorOwn(ILogMsgHandler * handler, ILogMsgFilter * filter)
  1506. {
  1507. bool ret = addMonitor(handler, filter);
  1508. filter->Release();
  1509. handler->Release();
  1510. return ret;
  1511. }
  1512. void CLogMsgManager::buildPrefilter()
  1513. {
  1514. // N.B. Should be used inside critical block
  1515. prefilter.reset();
  1516. ForEachItemIn(i, monitors)
  1517. prefilter.orWithFilter(monitors.item(i).queryFilter());
  1518. }
  1519. bool CLogMsgManager::removeMonitor(ILogMsgHandler * handler)
  1520. {
  1521. Linked<LogMsgMonitor> todelete;
  1522. {
  1523. WriteLockBlock block(monitorLock);
  1524. aindex_t pos = find(handler);
  1525. if(pos == NotFound) return false;
  1526. todelete.set(&monitors.item(pos));
  1527. monitors.remove(pos);
  1528. buildPrefilter();
  1529. sendFilterToChildren(true);
  1530. return true;
  1531. }
  1532. }
  1533. unsigned CLogMsgManager::removeMonitorsMatching(HandlerTest & test)
  1534. {
  1535. CIArrayOf<LogMsgMonitor> todelete; // delete outside monitorLock
  1536. unsigned count = 0;
  1537. {
  1538. WriteLockBlock block(monitorLock);
  1539. ForEachItemInRev(i, monitors)
  1540. if(test(monitors.item(i).queryHandler()))
  1541. {
  1542. LogMsgMonitor &it = monitors.item(i);
  1543. it.Link();
  1544. todelete.append(it);
  1545. monitors.remove(i);
  1546. ++count;
  1547. }
  1548. buildPrefilter();
  1549. sendFilterToChildren(true);
  1550. }
  1551. return count;
  1552. }
  1553. void CLogMsgManager::removeAllMonitors()
  1554. {
  1555. CIArrayOf<LogMsgMonitor> todelete; // delete outside monitorLock
  1556. {
  1557. WriteLockBlock block(monitorLock);
  1558. ForEachItemInRev(i, monitors) {
  1559. LogMsgMonitor &it = monitors.item(i);
  1560. it.Link();
  1561. todelete.append(it);
  1562. monitors.remove(i);
  1563. }
  1564. prefilter.reset();
  1565. sendFilterToChildren(true);
  1566. }
  1567. }
  1568. void CLogMsgManager::resetMonitors()
  1569. {
  1570. suspendChildren();
  1571. removeAllMonitors();
  1572. Owned<ILogMsgFilter> defaultFilter = getDefaultLogMsgFilter();
  1573. addMonitor(theStderrHandler, defaultFilter);
  1574. unsuspendChildren();
  1575. }
  1576. ILogMsgFilter * CLogMsgManager::queryMonitorFilter(const ILogMsgHandler * handler) const
  1577. {
  1578. ReadLockBlock block(monitorLock);
  1579. aindex_t pos = find(handler);
  1580. if(pos == NotFound) return 0;
  1581. return monitors.item(pos).queryFilter();
  1582. }
  1583. bool CLogMsgManager::changeMonitorFilter(const ILogMsgHandler * handler, ILogMsgFilter * newFilter)
  1584. {
  1585. WriteLockBlock block(monitorLock);
  1586. aindex_t pos = find(handler);
  1587. if(pos == NotFound) return 0;
  1588. monitors.item(pos).setFilter(newFilter);
  1589. buildPrefilter();
  1590. sendFilterToChildren(true);
  1591. return true;
  1592. }
  1593. void CLogMsgManager::prepAllHandlers() const
  1594. {
  1595. ReadLockBlock block(monitorLock);
  1596. ForEachItemIn(i, monitors)
  1597. if(monitors.item(i).queryHandler()->needsPrep()) monitors.item(i).queryHandler()->prep();
  1598. }
  1599. aindex_t CLogMsgManager::findChild(ILogMsgLinkToChild * child) const
  1600. {
  1601. ForEachItemIn(i, children)
  1602. if(&(children.item(i)) == child ) return i;
  1603. return NotFound;
  1604. }
  1605. ILogMsgFilter * CLogMsgManager::getCompoundFilter(bool locked) const
  1606. {
  1607. if(!locked) monitorLock.lockRead();
  1608. Owned<CategoryLogMsgFilter> categoryFilter = new CategoryLogMsgFilter(0, 0, 0, false);
  1609. Owned<ILogMsgFilter> otherFilters;
  1610. ILogMsgFilter * ifilter;
  1611. bool hadCat = false;
  1612. ForEachItemIn(i, monitors)
  1613. {
  1614. ifilter = monitors.item(i).queryFilter();
  1615. if(ifilter->queryLocalFlag()) continue;
  1616. if(ifilter->isCategoryFilter())
  1617. {
  1618. categoryFilter->orWithFilter(ifilter);
  1619. hadCat = true;
  1620. }
  1621. else
  1622. {
  1623. if(otherFilters)
  1624. otherFilters.setown(getOrLogMsgFilter(otherFilters, ifilter));
  1625. else
  1626. otherFilters.set(ifilter);
  1627. }
  1628. }
  1629. if(hadCat)
  1630. {
  1631. if(otherFilters)
  1632. otherFilters.setown(getOrLogMsgFilter(otherFilters, categoryFilter));
  1633. else
  1634. otherFilters.set(categoryFilter);
  1635. }
  1636. if(!locked) monitorLock.unlock();
  1637. if(!otherFilters)
  1638. return getPassNoneLogMsgFilter();
  1639. return otherFilters.getLink();
  1640. }
  1641. void CLogMsgManager::sendFilterToChildren(bool locked) const
  1642. {
  1643. if(suspendedChildren) return;
  1644. ReadLockBlock block(childLock);
  1645. if(children.length()==0) return;
  1646. ILogMsgFilter * filter = getCompoundFilter(locked);
  1647. ForEachItemIn(i, children)
  1648. children.item(i).sendFilter(filter);
  1649. filter->Release();
  1650. }
  1651. bool CLogMsgManager::addMonitorToPTree(const ILogMsgHandler * handler, IPropertyTree * tree) const
  1652. {
  1653. ReadLockBlock block(monitorLock);
  1654. aindex_t pos = find(handler);
  1655. if(pos == NotFound) return false;
  1656. monitors.item(pos).addToPTree(tree);
  1657. return true;
  1658. }
  1659. void CLogMsgManager::addAllMonitorsToPTree(IPropertyTree * tree) const
  1660. {
  1661. ReadLockBlock block(monitorLock);
  1662. ForEachItemIn(i, monitors)
  1663. monitors.item(i).addToPTree(tree);
  1664. }
  1665. bool CLogMsgManager::rejectsCategory(const LogMsgCategory & cat) const
  1666. {
  1667. if (!prefilter.includeCategory(cat))
  1668. return true;
  1669. ReadLockBlock block(monitorLock);
  1670. ForEachItemIn(i, monitors)
  1671. {
  1672. if (monitors.item(i).queryFilter()->mayIncludeCategory(cat))
  1673. return false;
  1674. }
  1675. return true;
  1676. }
  1677. // Helper functions
  1678. ILogMsgFilter * getDeserializedLogMsgFilter(MemoryBuffer & in)
  1679. {
  1680. unsigned type;
  1681. in.read(type);
  1682. switch(type)
  1683. {
  1684. case MSGFILTER_passall : return LINK(thePassAllFilter);
  1685. case MSGFILTER_passlocal : return LINK(thePassLocalFilter);
  1686. case MSGFILTER_passnone : return LINK(thePassNoneFilter);
  1687. case MSGFILTER_category : return new CategoryLogMsgFilter(in);
  1688. case MSGFILTER_pid : return new PIDLogMsgFilter(in);
  1689. case MSGFILTER_tid : return new TIDLogMsgFilter(in);
  1690. case MSGFILTER_node : return new NodeLogMsgFilter(in);
  1691. case MSGFILTER_ip : return new IpLogMsgFilter(in);
  1692. case MSGFILTER_job : return new JobLogMsgFilter(in);
  1693. case MSGFILTER_user : return new UserLogMsgFilter(in);
  1694. case MSGFILTER_session : return new SessionLogMsgFilter(in);
  1695. case MSGFILTER_component : return new ComponentLogMsgFilter(in);
  1696. case MSGFILTER_regex : return new RegexLogMsgFilter(in);
  1697. case MSGFILTER_not : return new NotLogMsgFilter(in);
  1698. case MSGFILTER_and : return new AndLogMsgFilter(in);
  1699. case MSGFILTER_or : return new OrLogMsgFilter(in);
  1700. case MSGFILTER_switch : return new SwitchLogMsgFilter(in);
  1701. default: assertex(!"getDeserializedLogMsgFilter: unrecognized LogMsgFilterType");
  1702. }
  1703. return 0;
  1704. }
  1705. ILogMsgFilter * getLogMsgFilterFromPTree(IPropertyTree * xml)
  1706. {
  1707. /* Note that several of these constructors use GetPropInt and GetPropInt64 to get unsigneds. I think this is OK? (all int64 internally)*/
  1708. StringBuffer type;
  1709. xml->getProp("@type", type);
  1710. if(strcmp(type.str(), "all")==0) return LINK(thePassAllFilter);
  1711. else if(strcmp(type.str(), "local")==0) return LINK(thePassLocalFilter);
  1712. else if(strcmp(type.str(), "none")==0) return LINK(thePassNoneFilter);
  1713. else if(strcmp(type.str(), "category")==0) return new CategoryLogMsgFilter(xml);
  1714. else if(strcmp(type.str(), "pid")==0) return new PIDLogMsgFilter(xml);
  1715. else if(strcmp(type.str(), "tid")==0) return new TIDLogMsgFilter(xml);
  1716. else if(strcmp(type.str(), "node")==0) return new NodeLogMsgFilter(xml);
  1717. else if(strcmp(type.str(), "ip")==0) return new IpLogMsgFilter(xml);
  1718. else if(strcmp(type.str(), "job")==0) return new JobLogMsgFilter(xml);
  1719. else if(strcmp(type.str(), "user")==0) return new UserLogMsgFilter(xml);
  1720. else if(strcmp(type.str(), "session")==0) return new SessionLogMsgFilter(xml);
  1721. else if(strcmp(type.str(), "component")==0) return new ComponentLogMsgFilter(xml);
  1722. else if(strcmp(type.str(), "regex")==0) return new RegexLogMsgFilter(xml);
  1723. else if(strcmp(type.str(), "not")==0) return new NotLogMsgFilter(xml);
  1724. else if(strcmp(type.str(), "and")==0) return new AndLogMsgFilter(xml);
  1725. else if(strcmp(type.str(), "or")==0) return new OrLogMsgFilter(xml);
  1726. else if(strcmp(type.str(), "filter")==0) return new SwitchLogMsgFilter(xml);
  1727. else assertex(!"getLogMsgFilterFromPTree : unrecognized LogMsgFilter type");
  1728. return getPassAllLogMsgFilter();
  1729. }
  1730. ILogMsgFilter * getDefaultLogMsgFilter()
  1731. {
  1732. return new CategoryLogMsgFilter(MSGAUD_all, MSGCLS_all, DefaultDetail, true);
  1733. }
  1734. ILogMsgFilter * getPassAllLogMsgFilter()
  1735. {
  1736. return LINK(thePassAllFilter);
  1737. }
  1738. ILogMsgFilter * getLocalLogMsgFilter()
  1739. {
  1740. return LINK(thePassLocalFilter);
  1741. }
  1742. ILogMsgFilter * getPassNoneLogMsgFilter()
  1743. {
  1744. return LINK(thePassNoneFilter);
  1745. }
  1746. ILogMsgFilter * queryPassAllLogMsgFilter()
  1747. {
  1748. return thePassAllFilter;
  1749. }
  1750. ILogMsgFilter * queryLocalLogMsgFilter()
  1751. {
  1752. return thePassLocalFilter;
  1753. }
  1754. ILogMsgFilter * queryPassNoneLogMsgFilter()
  1755. {
  1756. return thePassNoneFilter;
  1757. }
  1758. ILogMsgFilter * getCategoryLogMsgFilter(unsigned audiences, unsigned classes, LogMsgDetail maxDetail, bool local)
  1759. {
  1760. if((audiences==MSGAUD_all) && (classes==MSGCLS_all) && (maxDetail==TopDetail))
  1761. if(local)
  1762. return LINK(thePassLocalFilter);
  1763. else
  1764. return LINK(thePassAllFilter);
  1765. return new CategoryLogMsgFilter(audiences, classes, maxDetail, local);
  1766. }
  1767. ILogMsgFilter * getPIDLogMsgFilter(unsigned pid, bool local)
  1768. {
  1769. return new PIDLogMsgFilter(pid, local);
  1770. }
  1771. ILogMsgFilter * getTIDLogMsgFilter(unsigned tid, bool local)
  1772. {
  1773. return new TIDLogMsgFilter(tid, local);
  1774. }
  1775. ILogMsgFilter * getNodeLogMsgFilter(const char * name, unsigned port, bool local)
  1776. {
  1777. return new NodeLogMsgFilter(name, port, local);
  1778. }
  1779. ILogMsgFilter * getNodeLogMsgFilter(const IpAddress & ip, unsigned port, bool local)
  1780. {
  1781. return new NodeLogMsgFilter(ip, port, local);
  1782. }
  1783. ILogMsgFilter * getNodeLogMsgFilter(unsigned port, bool local)
  1784. {
  1785. return new NodeLogMsgFilter(port, local);
  1786. }
  1787. ILogMsgFilter * getIpLogMsgFilter(const char * name, bool local)
  1788. {
  1789. return new IpLogMsgFilter(name, local);
  1790. }
  1791. ILogMsgFilter * getIpLogMsgFilter(const IpAddress & ip, bool local)
  1792. {
  1793. return new IpLogMsgFilter(ip, local);
  1794. }
  1795. ILogMsgFilter * getIpLogMsgFilter(bool local)
  1796. {
  1797. return new IpLogMsgFilter(local);
  1798. }
  1799. ILogMsgFilter * getJobLogMsgFilter(LogMsgJobId job, bool local)
  1800. {
  1801. return new JobLogMsgFilter(job, local);
  1802. }
  1803. ILogMsgFilter * getUserLogMsgFilter(LogMsgUserId user, bool local)
  1804. {
  1805. return new UserLogMsgFilter(user, local);
  1806. }
  1807. ILogMsgFilter * getSessionLogMsgFilter(LogMsgSessionId session, bool local)
  1808. {
  1809. return new SessionLogMsgFilter(session, local);
  1810. }
  1811. ILogMsgFilter * getComponentLogMsgFilter(unsigned component, bool local)
  1812. {
  1813. return new ComponentLogMsgFilter(component, local);
  1814. }
  1815. ILogMsgFilter * getRegexLogMsgFilter(const char *regex, bool local)
  1816. {
  1817. return new RegexLogMsgFilter(regex, local);
  1818. }
  1819. ILogMsgFilter * getNotLogMsgFilter(ILogMsgFilter * arg)
  1820. {
  1821. return new NotLogMsgFilter(arg);
  1822. }
  1823. ILogMsgFilter * getNotLogMsgFilterOwn(ILogMsgFilter * arg)
  1824. {
  1825. ILogMsgFilter * ret = new NotLogMsgFilter(arg);
  1826. arg->Release();
  1827. return ret;
  1828. }
  1829. ILogMsgFilter * getAndLogMsgFilter(ILogMsgFilter * arg1, ILogMsgFilter * arg2)
  1830. {
  1831. return new AndLogMsgFilter(arg1, arg2);
  1832. }
  1833. ILogMsgFilter * getAndLogMsgFilterOwn(ILogMsgFilter * arg1, ILogMsgFilter * arg2)
  1834. {
  1835. ILogMsgFilter * ret = new AndLogMsgFilter(arg1, arg2);
  1836. arg1->Release();
  1837. arg2->Release();
  1838. return ret;
  1839. }
  1840. ILogMsgFilter * getOrLogMsgFilter(ILogMsgFilter * arg1, ILogMsgFilter * arg2)
  1841. {
  1842. return new OrLogMsgFilter(arg1, arg2);
  1843. }
  1844. ILogMsgFilter * getOrLogMsgFilterOwn(ILogMsgFilter * arg1, ILogMsgFilter * arg2)
  1845. {
  1846. ILogMsgFilter * ret = new OrLogMsgFilter(arg1, arg2);
  1847. arg1->Release();
  1848. arg2->Release();
  1849. return ret;
  1850. }
  1851. ILogMsgFilter * getSwitchLogMsgFilterOwn(ILogMsgFilter * switchFilter, ILogMsgFilter * yesFilter, ILogMsgFilter * noFilter)
  1852. {
  1853. ILogMsgFilter * ret = new SwitchLogMsgFilter(switchFilter, yesFilter, noFilter);
  1854. switchFilter->Release();
  1855. yesFilter->Release();
  1856. noFilter->Release();
  1857. return ret;
  1858. }
  1859. ILogMsgHandler * getHandleLogMsgHandler(FILE * handle, unsigned fields, bool writeXML)
  1860. {
  1861. if(writeXML)
  1862. return new HandleLogMsgHandlerXML(handle, fields);
  1863. return new HandleLogMsgHandlerTable(handle, fields);
  1864. }
  1865. ILogMsgHandler * getFileLogMsgHandler(const char * filename, const char * headertext, unsigned fields, bool writeXML, bool append, bool flushes)
  1866. {
  1867. if(writeXML)
  1868. return new FileLogMsgHandlerXML(filename, headertext, fields, append, flushes);
  1869. return new FileLogMsgHandlerTable(filename, headertext, fields, append, flushes);
  1870. }
  1871. ILogMsgHandler * getRollingFileLogMsgHandler(const char * filebase, const char * fileextn, unsigned fields, bool append, bool flushes, const char *initialName, const char *alias)
  1872. {
  1873. return new RollingFileLogMsgHandler(filebase, fileextn, fields, append, flushes, initialName, alias);
  1874. }
  1875. ILogMsgHandler * getBinLogMsgHandler(const char * filename, bool append)
  1876. {
  1877. return new BinLogMsgHandler(filename, append);
  1878. }
  1879. void installLogMsgFilterSwitch(ILogMsgHandler * handler, ILogMsgFilter * switchFilter, ILogMsgFilter * newFilter)
  1880. {
  1881. queryLogMsgManager()->changeMonitorFilterOwn(handler, getSwitchLogMsgFilterOwn(switchFilter, newFilter, queryLogMsgManager()->getMonitorFilter(handler)));
  1882. }
  1883. ILogMsgHandler * getLogMsgHandlerFromPTree(IPropertyTree * tree)
  1884. {
  1885. StringBuffer type;
  1886. tree->getProp("@type", type);
  1887. unsigned fields = MSGFIELD_all;
  1888. char const * fstr = tree->queryProp("@fields");
  1889. if(fstr)
  1890. if(isdigit(fstr[0]))
  1891. fields = atoi(fstr);
  1892. else
  1893. fields = LogMsgFieldsFromAbbrevs(fstr);
  1894. if(strcmp(type.str(), "stderr")==0)
  1895. return getHandleLogMsgHandler(stderr, fields, tree->hasProp("@writeXML"));
  1896. else if(strcmp(type.str(), "file")==0)
  1897. {
  1898. StringBuffer filename;
  1899. tree->getProp("@filename", filename);
  1900. if(tree->hasProp("@headertext"))
  1901. {
  1902. StringBuffer headertext;
  1903. tree->getProp("@headertext", headertext);
  1904. return getFileLogMsgHandler(filename.str(), headertext.str(), fields, !(tree->hasProp("@writeTable")), tree->hasProp("@append"), tree->hasProp("@flushes"));
  1905. }
  1906. else
  1907. return getFileLogMsgHandler(filename.str(), 0, fields, !(tree->hasProp("@writeTable")), tree->hasProp("@append"), tree->hasProp("@flushes"));
  1908. }
  1909. else if(strcmp(type.str(), "binary")==0)
  1910. {
  1911. StringBuffer filename;
  1912. tree->getProp("@filename", filename);
  1913. return getBinLogMsgHandler(filename.str(), tree->hasProp("@append"));
  1914. }
  1915. else assertex(!"getLogMsgFilterFromPTree : unrecognized LogMsgHandler type");
  1916. return LINK(theStderrHandler);
  1917. }
  1918. ILogMsgHandler * attachStandardFileLogMsgMonitor(const char * filename, const char * headertext, unsigned fields, unsigned audiences, unsigned classes, LogMsgDetail detail, bool writeXML, bool append, bool flushes, bool local)
  1919. {
  1920. #ifdef FILE_LOG_ENABLES_QUEUEUING
  1921. queryLogMsgManager()->enterQueueingMode();
  1922. #endif
  1923. ILogMsgFilter * filter = getCategoryLogMsgFilter(audiences, classes, detail, local);
  1924. ILogMsgHandler * handler = getFileLogMsgHandler(filename, headertext, fields, writeXML, append, flushes);
  1925. queryLogMsgManager()->addMonitorOwn(handler, filter);
  1926. return handler;
  1927. }
  1928. ILogMsgHandler * attachStandardBinLogMsgMonitor(const char * filename, unsigned audiences, unsigned classes, LogMsgDetail detail, bool append, bool local)
  1929. {
  1930. #ifdef FILE_LOG_ENABLES_QUEUEUING
  1931. queryLogMsgManager()->enterQueueingMode();
  1932. #endif
  1933. ILogMsgFilter * filter = getCategoryLogMsgFilter(audiences, classes, detail, local);
  1934. ILogMsgHandler * handler = getBinLogMsgHandler(filename, append);
  1935. queryLogMsgManager()->addMonitorOwn(handler, filter);
  1936. return handler;
  1937. }
  1938. ILogMsgHandler * attachStandardHandleLogMsgMonitor(FILE * handle, unsigned fields, unsigned audiences, unsigned classes, LogMsgDetail detail, bool writeXML, bool local)
  1939. {
  1940. ILogMsgFilter * filter = getCategoryLogMsgFilter(audiences, classes, detail, local);
  1941. ILogMsgHandler * handler = getHandleLogMsgHandler(handle, fields, writeXML);
  1942. queryLogMsgManager()->addMonitorOwn(handler, filter);
  1943. return handler;
  1944. }
  1945. ILogMsgHandler * attachLogMsgMonitorFromPTree(IPropertyTree * tree)
  1946. {
  1947. Owned<IPropertyTree> handlertree = tree->getPropTree("handler");
  1948. Owned<IPropertyTree> filtertree = tree->getPropTree("filter");
  1949. ILogMsgHandler * handler = getLogMsgHandlerFromPTree(handlertree);
  1950. ILogMsgFilter * filter = getLogMsgFilterFromPTree(filtertree);
  1951. queryLogMsgManager()->addMonitorOwn(handler, filter);
  1952. return handler;
  1953. }
  1954. void attachManyLogMsgMonitorsFromPTree(IPropertyTree * tree)
  1955. {
  1956. Owned<IPropertyTreeIterator> iter = tree->getElements("monitor");
  1957. ForEach(*iter)
  1958. attachLogMsgMonitorFromPTree(&(iter->query()));
  1959. }
  1960. // Standard categories and unknown jobInfo
  1961. const LogMsgCategory MCdisaster(MSGAUD_all, MSGCLS_disaster);
  1962. const LogMsgCategory MCuserError(MSGAUD_user, MSGCLS_error);
  1963. const LogMsgCategory MCoperatorError(MSGAUD_operator, MSGCLS_error);
  1964. const LogMsgCategory MCinternalError((LogMsgAudience)(MSGAUD_internal & MSGAUD_programmer), MSGCLS_error, 1);
  1965. const LogMsgCategory MCuserWarning(MSGAUD_user, MSGCLS_warning);
  1966. const LogMsgCategory MCoperatorWarning(MSGAUD_operator, MSGCLS_warning);
  1967. const LogMsgCategory MCinternalWarning((LogMsgAudience)(MSGAUD_internal & MSGAUD_programmer), MSGCLS_warning, 1);
  1968. const LogMsgCategory MCuserProgress(MSGAUD_user, MSGCLS_progress);
  1969. const LogMsgCategory MCoperatorProgress(MSGAUD_operator, MSGCLS_progress);
  1970. const LogMsgCategory MCdebugProgress(MSGAUD_programmer, MSGCLS_progress);
  1971. const LogMsgCategory MCdebugInfo(MSGAUD_programmer, MSGCLS_information);
  1972. const LogMsgCategory MCstats(MSGAUD_performance, MSGCLS_information);
  1973. const LogMsgCategory MCevent(MSGAUD_monitor, MSGCLS_event);
  1974. const LogMsgCategory MClegacy(MSGAUD_legacy, MSGCLS_legacy, DefaultDetail);
  1975. const LogMsgJobInfo unknownJob(UnknownJob, UnknownUser);
  1976. // Calls to make, remove, and return the manager, standard handler, pass all/none filters, reporter array
  1977. PassAllLogMsgFilter * thePassAllFilter;
  1978. PassLocalLogMsgFilter * thePassLocalFilter;
  1979. PassNoneLogMsgFilter * thePassNoneFilter;
  1980. HandleLogMsgHandlerTable * theStderrHandler;
  1981. CLogMsgManager * theManager;
  1982. CSysLogEventLogger * theSysLogEventLogger;
  1983. LogMsgComponentReporter * theReporters[MSGCOMP_NUMBER];
  1984. LogMsgPrepender * thePrepender;
  1985. MODULE_INIT(INIT_PRIORITY_JLOG)
  1986. {
  1987. thePassAllFilter = new PassAllLogMsgFilter();
  1988. thePassLocalFilter = new PassLocalLogMsgFilter();
  1989. thePassNoneFilter = new PassNoneLogMsgFilter();
  1990. theStderrHandler = new HandleLogMsgHandlerTable(stderr, MSGFIELD_STANDARD);
  1991. theSysLogEventLogger = new CSysLogEventLogger;
  1992. theManager = new CLogMsgManager();
  1993. theManager->resetMonitors();
  1994. for(unsigned compo = 0; compo<MSGCOMP_NUMBER; compo++)
  1995. theReporters[compo] = new LogMsgComponentReporter(compo);
  1996. thePrepender = new LogMsgPrepender;
  1997. return true;
  1998. }
  1999. MODULE_EXIT()
  2000. {
  2001. delete thePrepender;
  2002. for(unsigned compo = 0; compo<MSGCOMP_NUMBER; compo++)
  2003. delete theReporters[compo];
  2004. delete theManager;
  2005. delete theSysLogEventLogger;
  2006. delete theStderrHandler;
  2007. delete thePassNoneFilter;
  2008. delete thePassLocalFilter;
  2009. delete thePassAllFilter;
  2010. }
  2011. ILogMsgManager * queryLogMsgManager()
  2012. {
  2013. return theManager;
  2014. }
  2015. ILogMsgHandler * queryStderrLogMsgHandler()
  2016. {
  2017. return theStderrHandler;
  2018. }
  2019. LogMsgComponentReporter * queryLogMsgComponentReporter(unsigned compo)
  2020. {
  2021. return theReporters[compo];
  2022. }
  2023. LogMsgPrepender * queryLogMsgPrepender()
  2024. {
  2025. return thePrepender;
  2026. }
  2027. ILogMsgManager * createLogMsgManager() // use with care! (needed by mplog listener facility)
  2028. {
  2029. return new CLogMsgManager();
  2030. }
  2031. // Event Logging
  2032. ISysLogEventLogger * querySysLogEventLogger()
  2033. {
  2034. return theSysLogEventLogger;
  2035. }
  2036. ILogMsgHandler * getSysLogMsgHandler(unsigned fields)
  2037. {
  2038. return new SysLogMsgHandler(theSysLogEventLogger, fields);
  2039. }
  2040. #ifdef _WIN32
  2041. #include <WINNT.H>
  2042. #include "jelog.h"
  2043. struct AuditTypeWin32Data
  2044. {
  2045. public:
  2046. unsigned eventtype;
  2047. unsigned categoryid;
  2048. unsigned eventid;
  2049. };
  2050. #define CATEGORY_AUDIT_FUNCTION_REQUIRED
  2051. #define AUDIT_TYPES_BEGIN AuditTypeWin32Data auditTypeDataMap[NUM_AUDIT_TYPES+1] = {
  2052. #define MAKE_AUDIT_TYPE(name, type, categoryid, eventid, level) {type, categoryid, eventid},
  2053. #define AUDIT_TYPES_END {0, 0, 0} };
  2054. #include "jelogtype.hpp"
  2055. #undef CATEGORY_AUDIT_FUNCTION_REQUIRED
  2056. #undef AUDIT_TYPES_BEGIN
  2057. #undef MAKE_AUDIT_TYPE
  2058. #undef AUDIT_TYPES_END
  2059. CSysLogEventLogger::CSysLogEventLogger() : hEventLog(0)
  2060. {
  2061. }
  2062. bool CSysLogEventLogger::log(AuditType auditType, char const * msg, size32_t datasize, void const * data)
  2063. {
  2064. assertex(auditType < NUM_AUDIT_TYPES);
  2065. AuditTypeWin32Data const & typeData = auditTypeDataMap[auditType];
  2066. return win32Report(typeData.eventtype, typeData.categoryid, typeData.eventid, msg, datasize, data);
  2067. }
  2068. bool CSysLogEventLogger::win32Report(unsigned eventtype, unsigned category, unsigned eventid, const char * msg, size32_t datasize, const void * data)
  2069. {
  2070. if (hEventLog==0) {
  2071. // MORE - this doesn't work on Vista/Win7 as can't copy to system32...
  2072. // Perhaps we should just kill this code
  2073. char path[_MAX_PATH+1];
  2074. GetEnvironmentVariable("SystemRoot",path,sizeof(path));
  2075. strcat(path,"\\System32\\JELOG.dll");
  2076. Owned<IFile> file = createIFile(path);
  2077. try {
  2078. if (!file->exists()) {
  2079. char src[_MAX_PATH+1];
  2080. LPTSTR tail;
  2081. DWORD res = SearchPath(NULL,"JELOG.DLL",NULL,sizeof(src),src,&tail);
  2082. if (res>0)
  2083. copyFile(path,src);
  2084. else
  2085. throw MakeOsException(GetLastError());
  2086. }
  2087. }
  2088. catch (IException *e)
  2089. {
  2090. EXCLOG(e, "reportEventLog: Could not install JELOG.DLL");
  2091. hEventLog=(HANDLE)-1;
  2092. e->Release();
  2093. return false;
  2094. }
  2095. HKEY hk;
  2096. if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\Seisint",
  2097. NULL, NULL, 0, KEY_ALL_ACCESS, NULL, &hk, NULL)==0) {
  2098. DWORD sizedata = 0;
  2099. DWORD type = REG_EXPAND_SZ;
  2100. if ((RegQueryValueEx(hk,"EventMessageFile",NULL, &type, NULL, &sizedata)!=0)||!sizedata) {
  2101. StringAttr str("%SystemRoot%\\System32\\JELOG.dll");
  2102. RegSetValueEx(hk,"EventMessageFile", 0, REG_EXPAND_SZ, (LPBYTE) str.get(), str.length() + 1);
  2103. RegSetValueEx(hk,"CategoryMessageFile", 0, REG_EXPAND_SZ, (LPBYTE) str.get(), str.length() + 1);
  2104. DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE | EVENTLOG_AUDIT_SUCCESS | EVENTLOG_AUDIT_FAILURE;
  2105. RegSetValueEx(hk, "TypesSupported", 0, REG_DWORD, (LPBYTE) &dwData, sizeof(DWORD));
  2106. dwData = 16;
  2107. RegSetValueEx(hk, "CategoryCount", 0, REG_DWORD, (LPBYTE) &dwData, sizeof(DWORD));
  2108. }
  2109. RegCloseKey(hk);
  2110. }
  2111. hEventLog = RegisterEventSource(NULL,"Seisint");
  2112. if (!hEventLog) {
  2113. ERRLOG("reportEventLog: Could not register Seisint event source");
  2114. hEventLog=(HANDLE)-1;
  2115. return false;
  2116. }
  2117. }
  2118. if (hEventLog==(HANDLE)-1)
  2119. return false;
  2120. assertex((unsigned)eventtype<=16);
  2121. if (!data)
  2122. datasize = 0;
  2123. else if (!datasize)
  2124. data = NULL;
  2125. #if 1 //useful for debugging...
  2126. ReportEvent(hEventLog, eventtype, category, eventid, NULL, 1, datasize, &msg, (LPVOID)data);
  2127. #else
  2128. if(datasize)
  2129. {
  2130. char * buff = (char *)malloc(datasize*3+1);
  2131. unsigned char const * cdata = (unsigned char *)data;
  2132. unsigned i;
  2133. for(i=0; i<datasize; i++)
  2134. sprintf(buff+i*3, "%02X ", cdata[i]);
  2135. buff[datasize*3-1] = 0;
  2136. DBGLOG("ReportEvent: type=%X categoryid=%X eventid=%X msg='%s' data=[%s]", eventtype, category, eventid, msg, buff);
  2137. free(buff);
  2138. }
  2139. else
  2140. DBGLOG("ReportEvent: type=%X categoryid=%X eventid=%X msg='%s'", eventtype, category, eventid, msg);
  2141. #endif
  2142. return true;
  2143. }
  2144. CSysLogEventLogger::~CSysLogEventLogger()
  2145. {
  2146. if (hEventLog!=0)
  2147. DeregisterEventSource(hEventLog);
  2148. }
  2149. #else
  2150. #include <syslog.h>
  2151. #define CATEGORY_AUDIT_FUNCTION_REQUIRED
  2152. #define AUDIT_TYPES_BEGIN int auditTypeDataMap[NUM_AUDIT_TYPES+1] = {
  2153. #define MAKE_AUDIT_TYPE(name, type, categoryid, eventid, level) level,
  2154. #define AUDIT_TYPES_END 0 };
  2155. #include "jelogtype.hpp"
  2156. #undef CATEGORY_AUDIT_FUNCTION_REQUIRED
  2157. #undef AUDIT_TYPES_BEGIN
  2158. #undef MAKE_AUDIT_TYPE
  2159. #undef AUDIT_TYPES_END
  2160. CSysLogEventLogger::CSysLogEventLogger() : dataLogUsed(false), dataLogName(0), dataLogFile(-1)
  2161. {
  2162. const char * processName = queryCurrentProcessName();
  2163. if (!processName||!*processName)
  2164. processName = "hpcc";
  2165. openlog(processName, LOG_PID, LOG_USER);
  2166. }
  2167. CSysLogEventLogger::~CSysLogEventLogger()
  2168. {
  2169. if(dataLogFile != -1)
  2170. close(dataLogFile);
  2171. if(dataLogName)
  2172. delete [] dataLogName;
  2173. closelog();
  2174. }
  2175. bool CSysLogEventLogger::log(AuditType auditType, const char *msg, size32_t datasize, const void * data)
  2176. {
  2177. assertex(auditType < NUM_AUDIT_TYPES);
  2178. int level = auditTypeDataMap[auditType];
  2179. return linuxReport(level, msg, datasize, data);
  2180. }
  2181. bool CSysLogEventLogger::linuxReport(int level, const char * msg, size32_t datasize, const void * data)
  2182. {
  2183. if (!data)
  2184. datasize = 0;
  2185. else if (!datasize)
  2186. data = NULL;
  2187. bool ret = true;
  2188. #if 1 //useful for debugging...
  2189. if(data)
  2190. {
  2191. if(!dataLogUsed)
  2192. openDataLog();
  2193. if(dataLogFile != -1)
  2194. {
  2195. int fpos = writeDataLog(datasize, (byte const *)data);
  2196. if(fpos != -1)
  2197. syslog(level, "%s [0x%X bytes of data at %s byte 0x%X]", msg, datasize, dataLogName, fpos);
  2198. else
  2199. syslog(level, "%s [could not write 0x%X bytes of data to %s]", msg, datasize, dataLogName);
  2200. }
  2201. else
  2202. {
  2203. ret = false;
  2204. syslog(level, "%s [could not open file of form %s to write data]", msg, AUDIT_DATA_LOG_TEMPLATE);
  2205. }
  2206. }
  2207. else
  2208. {
  2209. syslog(level, "%s", msg);
  2210. }
  2211. #else
  2212. if(datasize)
  2213. {
  2214. char * buff = (char *)malloc(datasize*3+1);
  2215. unsigned char const * cdata = (unsigned char *)data;
  2216. unsigned i;
  2217. for(i=0; i<datasize; i++)
  2218. sprintf(buff+i*3, "%02X ", cdata[i]);
  2219. buff[datasize*3-1] = 0;
  2220. DBGLOG("syslog: priority=%X msg='%s' data=[%s]", level, msg, buff);
  2221. free(buff);
  2222. }
  2223. else
  2224. DBGLOG("syslog: priority=%X msg='%s'", level, msg);
  2225. #endif
  2226. return ret;
  2227. }
  2228. void CSysLogEventLogger::openDataLog()
  2229. {
  2230. CriticalBlock block(dataLogLock);
  2231. dataLogUsed = true;
  2232. unsigned len = strlen(AUDIT_DATA_LOG_TEMPLATE);
  2233. dataLogName = new char[len+1];
  2234. strcpy(dataLogName, AUDIT_DATA_LOG_TEMPLATE);
  2235. dataLogFile = mkstemp(dataLogName);
  2236. }
  2237. int CSysLogEventLogger::writeDataLog(size32_t datasize, byte const * data)
  2238. {
  2239. CriticalBlock block(dataLogLock);
  2240. off_t fpos = lseek(dataLogFile, 0, SEEK_CUR);
  2241. while(datasize > 0)
  2242. {
  2243. size32_t written = write(dataLogFile, data, datasize);
  2244. if(written == -1)
  2245. return -1;
  2246. data += written;
  2247. datasize -= written;
  2248. }
  2249. #ifdef __linux__
  2250. fdatasync(dataLogFile);
  2251. #endif
  2252. return fpos;
  2253. }
  2254. #endif
  2255. void SysLogMsgHandler::handleMessage(const LogMsg & msg) const
  2256. {
  2257. AuditType type = categoryToAuditType(msg.queryCategory());
  2258. StringBuffer text;
  2259. msg.toStringPlain(text, fields);
  2260. logger->log(type, text.str());
  2261. }
  2262. void SysLogMsgHandler::addToPTree(IPropertyTree * tree) const
  2263. {
  2264. IPropertyTree * handlerTree = createPTree(ipt_caseInsensitive);
  2265. handlerTree->setProp("@type", "audit");
  2266. tree->addPropTree("handler", handlerTree);
  2267. }
  2268. class DummyLogCtx : implements IContextLogger
  2269. {
  2270. public:
  2271. // It's a static object - we don't want to actually link-count it...
  2272. virtual void Link() const {}
  2273. virtual bool Release() const { return false; }
  2274. virtual void CTXLOG(const char *format, ...) const
  2275. {
  2276. va_list args;
  2277. va_start(args, format);
  2278. CTXLOGva(format, args);
  2279. va_end(args);
  2280. }
  2281. virtual void CTXLOGva(const char *format, va_list args) const
  2282. {
  2283. StringBuffer ss;
  2284. ss.valist_appendf(format, args);
  2285. DBGLOG("%s", ss.str());
  2286. }
  2287. virtual void CTXLOGa(unsigned activityId, const char *text) const
  2288. {
  2289. DBGLOG("[%d] %s", activityId, text);
  2290. }
  2291. virtual StringBuffer &getLogPrefix(StringBuffer &ret) const
  2292. {
  2293. return ret;
  2294. }
  2295. virtual void logOperatorException(IException *E, const char *file, unsigned line, const char *format, ...) const
  2296. {
  2297. va_list args;
  2298. va_start(args, format);
  2299. logOperatorExceptionVA(E, file, line, format, args);
  2300. va_end(args);
  2301. }
  2302. virtual void logOperatorExceptionVA(IException *E, const char *file, unsigned line, const char *format, va_list args) const
  2303. {
  2304. StringBuffer ss;
  2305. ss.append("ERROR");
  2306. if (E)
  2307. ss.append(": ").append(E->errorCode());
  2308. if (file)
  2309. ss.appendf(": %s(%d) ", file, line);
  2310. if (E)
  2311. E->errorMessage(ss.append(": "));
  2312. if (format)
  2313. ss.append(": ").valist_appendf(format, args);
  2314. LOG(MCoperatorProgress, unknownJob, "%s", ss.str());
  2315. }
  2316. virtual bool isIntercepted() const
  2317. {
  2318. return false;
  2319. }
  2320. virtual void noteStatistic(unsigned statCode, unsigned __int64 value, unsigned count) const
  2321. {
  2322. }
  2323. virtual unsigned queryTraceLevel() const
  2324. {
  2325. return 0;
  2326. }
  2327. } dummyContextLogger;
  2328. extern jlib_decl const IContextLogger &queryDummyContextLogger()
  2329. {
  2330. return dummyContextLogger;
  2331. }
  2332. extern jlib_decl void UseSysLogForOperatorMessages(bool use)
  2333. {
  2334. static ILogMsgHandler *msgHandler=NULL;
  2335. if (use==(msgHandler!=NULL))
  2336. return;
  2337. if (use) {
  2338. msgHandler = getSysLogMsgHandler();
  2339. ILogMsgFilter * operatorFilter = getCategoryLogMsgFilter(MSGAUD_operator|MSGAUD_monitor, MSGCLS_all, DefaultDetail, true);
  2340. queryLogMsgManager()->addMonitorOwn(msgHandler, operatorFilter);
  2341. }
  2342. else {
  2343. queryLogMsgManager()->removeMonitor(msgHandler);
  2344. msgHandler = NULL;
  2345. }
  2346. }
  2347. extern jlib_decl void AuditSystemAccess(const char *userid, bool success, char const * msg,...)
  2348. {
  2349. va_list args;
  2350. va_start(args, msg);
  2351. VStringBuffer s("User %s: ", userid);
  2352. SYSLOG((success) ? AUDIT_TYPE_ACCESS_SUCCESS : AUDIT_TYPE_ACCESS_FAILURE, s.valist_appendf(msg, args).str());
  2353. va_end(args);
  2354. }