jlog.cpp 122 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "platform.h"
  14. #include <algorithm>
  15. #include "stdio.h"
  16. #include "jlog.hpp"
  17. #include "jlog.ipp"
  18. #include "jmutex.hpp"
  19. #include "jarray.hpp"
  20. #include "jsocket.hpp"
  21. #include "jmisc.hpp"
  22. #include "jprop.hpp"
  23. #include "lnuid.h"
  24. using namespace ln_uid;
  25. #define MSGCOMP_NUMBER 1000
  26. #define FILE_LOG_ENABLES_QUEUEUING
  27. #ifndef _WIN32
  28. #define AUDIT_DATA_LOG_TEMPLATE "/var/log/seisint/log_data_XXXXXX"
  29. #endif
  30. // Time, in nanoseconds, after which the clock field loops --- 3600000000000ns = 1hr
  31. #define CLOCK_LOOP_NANOSECONDS I64C(3600000000000)
  32. // Standard filters, handlers, manager, and audit event logger
  33. static ILogMsgManager * theManager = nullptr;
  34. static PassAllLogMsgFilter * thePassAllFilter = nullptr;
  35. static PassLocalLogMsgFilter * thePassLocalFilter = nullptr;
  36. static PassNoneLogMsgFilter * thePassNoneFilter = nullptr;
  37. static HandleLogMsgHandlerTable * theStderrHandler = nullptr;
  38. static CSysLogEventLogger * theSysLogEventLogger = nullptr;
  39. // LogMsgSysInfo
  40. static FILE *getNullHandle()
  41. {
  42. #ifdef _WIN32
  43. return fopen("nul","w");
  44. #else
  45. return fopen("/dev/null","w");
  46. #endif
  47. }
  48. LogMsgSysInfo::LogMsgSysInfo(LogMsgId _id, unsigned port, LogMsgSessionId session)
  49. {
  50. id = _id;
  51. #ifdef _WIN32
  52. // Hack for the fact that Windows doesn't handle gettimeofday
  53. // Subsecond timing granularities in log files will not be available
  54. time(&timeStarted);
  55. #else
  56. gettimeofday(&timeStarted, NULL);
  57. #endif
  58. processID = GetCurrentProcessId();
  59. threadID = threadLogID();
  60. sessionID = session;
  61. #ifdef INCLUDE_LOGMSGSYSINFO_NODE
  62. node.setLocalHost(port);
  63. #endif
  64. }
  65. void LogMsgSysInfo::serialize(MemoryBuffer & out) const
  66. {
  67. out.append(id).append((unsigned) queryTime()).append(processID).append(threadID).append(sessionID); node.serialize(out);
  68. }
  69. void LogMsgSysInfo::deserialize(MemoryBuffer & in)
  70. {
  71. unsigned t;
  72. in.read(id).read(t).read(processID).read(threadID).read(sessionID); node.deserialize(in);
  73. #ifdef _WIN32
  74. timeStarted = t;
  75. #else
  76. timeStarted.tv_sec = t;
  77. timeStarted.tv_usec = 0; // For back-compatibility reasons, the subsecond timings are not serialized
  78. #endif
  79. }
  80. class LoggingFieldColumns
  81. {
  82. const EnumMapping MsgFieldMap[16] =
  83. {
  84. { MSGFIELD_msgID, "MsgID " },
  85. { MSGFIELD_audience, "Audience " },
  86. { MSGFIELD_class, "Class " },
  87. { MSGFIELD_detail, "Detail " },
  88. { MSGFIELD_date, "Date " },
  89. { MSGFIELD_microTime, "Time(micro) " },
  90. { MSGFIELD_milliTime, "Time(milli) " },
  91. { MSGFIELD_time, "Time " },
  92. { MSGFIELD_process, "PID " },
  93. { MSGFIELD_thread, "TID " },
  94. { MSGFIELD_session, "SessionID " },
  95. { MSGFIELD_node, "Node " },
  96. { MSGFIELD_job, "JobID " },
  97. { MSGFIELD_user, "UserID " },
  98. { MSGFIELD_component, "Compo " },
  99. { MSGFIELD_quote, "Quoted "}
  100. };
  101. const unsigned sizeMsgFieldMap = arraysize(MsgFieldMap);
  102. public:
  103. unsigned getMaxHeaderSize()
  104. {
  105. // Note: return length is slightly longer than necessary as only one time field is valid
  106. // but the length of all time fields are added
  107. unsigned size = 0;
  108. for (unsigned i=0; i<sizeMsgFieldMap; ++i)
  109. size += strlen(MsgFieldMap[i].str);
  110. return size+2; // 2 extra characters for \r\n
  111. }
  112. unsigned getPositionOfField(unsigned logfields, unsigned positionoffield)
  113. {
  114. unsigned pos = 0;
  115. for (unsigned i=0; i<sizeMsgFieldMap; ++i)
  116. {
  117. if (MsgFieldMap[i].val==MSGFIELD_time && (logfields & (MSGFIELD_microTime|MSGFIELD_milliTime)) )
  118. continue;
  119. if (MsgFieldMap[i].val & positionoffield)
  120. break;
  121. if (MsgFieldMap[i].val & logfields)
  122. ++pos;
  123. }
  124. return pos;
  125. }
  126. unsigned extractMessageFieldsFromHeader(const char *line, bool hashPrefixed)
  127. {
  128. unsigned fieldHeader = 0;
  129. if (line && *line=='#')
  130. {
  131. ++line;
  132. const unsigned sizeFieldMap = arraysize(MsgFieldMap);
  133. for (unsigned i=0; i<sizeFieldMap; ++i)
  134. {
  135. const char * linep = line;
  136. const char * fieldp = MsgFieldMap[i].str;
  137. while( *fieldp && *linep==*fieldp)
  138. {
  139. ++linep;
  140. ++fieldp;
  141. }
  142. if (*fieldp==0) // At the end of the field, so whole field matched
  143. {
  144. fieldHeader |= MsgFieldMap[i].val;
  145. if (*linep==0 || *linep=='\n')
  146. break;
  147. line = linep;
  148. }
  149. }
  150. }
  151. if (fieldHeader & (MSGFIELD_microTime | MSGFIELD_milliTime))
  152. fieldHeader |= MSGFIELD_time;
  153. return fieldHeader;
  154. }
  155. StringBuffer & generateHeaderRow(StringBuffer & out, unsigned fields, bool prefixHash)
  156. {
  157. if (prefixHash)
  158. out.append('#');
  159. for (unsigned i=0; i<sizeMsgFieldMap; ++i)
  160. if (fields & MsgFieldMap[i].val)
  161. {
  162. if (MsgFieldMap[i].val==MSGFIELD_time && (fields & (MSGFIELD_microTime|MSGFIELD_milliTime)) )
  163. continue;
  164. out.append(MsgFieldMap[i].str);
  165. }
  166. return out;
  167. }
  168. } loggingFieldColumns;
  169. unsigned getPositionOfField(unsigned logfields, unsigned positionoffield)
  170. {
  171. return loggingFieldColumns.getPositionOfField(logfields, positionoffield);
  172. }
  173. // LogMsg
  174. LogMsgJobInfo::~LogMsgJobInfo()
  175. {
  176. if (isDeserialized)
  177. free((void *) jobIDStr);
  178. }
  179. const char * LogMsgJobInfo::queryJobIDStr() const
  180. {
  181. if (isDeserialized)
  182. return jobIDStr;
  183. else if (jobID == UnknownJob)
  184. return "UNK";
  185. else
  186. return theManager->queryJobId(jobID);
  187. }
  188. LogMsgJobId LogMsgJobInfo::queryJobID() const
  189. {
  190. if (isDeserialized)
  191. return UnknownJob; // Or assert?
  192. else
  193. return jobID;
  194. }
  195. void LogMsgJobInfo::setJobID(LogMsgUserId id)
  196. {
  197. if (isDeserialized)
  198. free((void *) jobIDStr);
  199. jobID = id;
  200. isDeserialized = false;
  201. }
  202. void LogMsgJobInfo::serialize(MemoryBuffer & out) const
  203. {
  204. if (isDeserialized)
  205. out.append(jobIDStr);
  206. else
  207. out.append(theManager->queryJobId(jobID));
  208. out.append(userID);
  209. }
  210. void LogMsgJobInfo::deserialize(MemoryBuffer & in)
  211. {
  212. // kludge for backward compatibility of pre 8.0 clients that send a LogMsgJobId: (_uint64), not a string
  213. // NB: jobID pre 8.0 was redundant as always equal to UnknownJob
  214. dbgassertex(in.remaining() >= sizeof(LogMsgJobId)); // should always be at least this amount, because userID follows the jobID
  215. if (0 == memcmp(in.toByteArray()+in.getPos(), &UnknownJob, sizeof(LogMsgJobId))) // pre 8.0 client
  216. {
  217. in.skip(sizeof(jobID));
  218. jobID = UnknownJob;
  219. isDeserialized = false;
  220. }
  221. else
  222. {
  223. // >= 8.0 client
  224. StringBuffer idStr;
  225. in.read(idStr);
  226. jobIDStr = idStr.detach();
  227. isDeserialized = true;
  228. }
  229. in.read(userID);
  230. }
  231. static LogMsgJobInfo globalDefaultJobInfo(UnknownJob, UnknownUser);
  232. static thread_local LogMsgJobInfo defaultJobInfo = globalDefaultJobInfo;
  233. const LogMsgJobInfo unknownJob(UnknownJob, UnknownUser);
  234. void resetThreadLogging()
  235. {
  236. // Note - as implemented the thread default job info is determined by what the global one was when the thread was created.
  237. // There is an alternative interpretation, that an unset thread-local one should default to whatever the global one is at the time the thread one is used.
  238. // In practice I doubt there's a lot of difference as global one is likely to be set once at program startup
  239. defaultJobInfo = globalDefaultJobInfo;
  240. }
  241. const LogMsgJobInfo & checkDefaultJobInfo(const LogMsgJobInfo & _jobInfo)
  242. {
  243. if (&_jobInfo == &unknownJob)
  244. {
  245. return defaultJobInfo;
  246. }
  247. return _jobInfo;
  248. }
  249. void setDefaultJobId(const char *id, bool threaded)
  250. {
  251. setDefaultJobId(theManager->addJobId(id), threaded);
  252. }
  253. void setDefaultJobId(LogMsgJobId id, bool threaded)
  254. {
  255. if (!threaded)
  256. globalDefaultJobInfo.setJobID(id);
  257. defaultJobInfo.setJobID(id);
  258. }
  259. LogMsg::LogMsg(LogMsgJobId id, const char *job) : category(MSGAUD_programmer, job ? MSGCLS_addid : MSGCLS_removeid), sysInfo(), jobInfo(id), remoteFlag(false)
  260. {
  261. if (job)
  262. text.append(job);
  263. }
  264. LogMsg::LogMsg(const LogMsgCategory & _cat, LogMsgId _id, const LogMsgJobInfo & _jobInfo, LogMsgCode _code, const char * _text, unsigned _compo, unsigned port, LogMsgSessionId session)
  265. : category(_cat), sysInfo(_id, port, session), jobInfo(checkDefaultJobInfo(_jobInfo)), msgCode(_code), component(_compo), remoteFlag(false)
  266. {
  267. text.append(_text);
  268. }
  269. LogMsg::LogMsg(const LogMsgCategory & _cat, LogMsgId _id, const LogMsgJobInfo & _jobInfo, LogMsgCode _code, size32_t sz, const char * _text, unsigned _compo, unsigned port, LogMsgSessionId session)
  270. : category(_cat), sysInfo(_id, port, session), jobInfo(checkDefaultJobInfo(_jobInfo)), msgCode(_code), component(_compo), remoteFlag(false)
  271. {
  272. text.append(sz, _text);
  273. }
  274. LogMsg::LogMsg(const LogMsgCategory & _cat, LogMsgId _id, const LogMsgJobInfo & _jobInfo, LogMsgCode _code, const char * format, va_list args,
  275. unsigned _compo, unsigned port, LogMsgSessionId session)
  276. : category(_cat), sysInfo(_id, port, session), jobInfo(checkDefaultJobInfo(_jobInfo)), msgCode(_code), component(_compo), remoteFlag(false)
  277. {
  278. text.valist_appendf(format, args);
  279. }
  280. StringBuffer & LogMsg::toStringPlain(StringBuffer & out, unsigned fields) const
  281. {
  282. out.ensureCapacity(LOG_MSG_FORMAT_BUFFER_LENGTH);
  283. if(fields & MSGFIELD_msgID)
  284. out.appendf("id=%X ", sysInfo.queryMsgID());
  285. if(fields & MSGFIELD_audience)
  286. out.append("aud=").append(LogMsgAudienceToVarString(category.queryAudience())).append(' ');
  287. if(fields & MSGFIELD_class)
  288. out.append("cls=").append(LogMsgClassToFixString(category.queryClass())).append(' ');
  289. if(fields & MSGFIELD_detail)
  290. out.appendf("det=%d ", category.queryDetail());
  291. if(fields & MSGFIELD_timeDate)
  292. {
  293. time_t timeNum = sysInfo.queryTime();
  294. char timeString[12];
  295. struct tm timeStruct;
  296. localtime_r(&timeNum, &timeStruct);
  297. if(fields & MSGFIELD_date)
  298. {
  299. strftime(timeString, 12, "%Y-%m-%d ", &timeStruct);
  300. out.append(timeString);
  301. }
  302. if(fields & MSGFIELD_microTime)
  303. {
  304. out.appendf("%02d:%02d:%02d.%06d ", timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec, sysInfo.queryUSecs());
  305. }
  306. else if(fields & MSGFIELD_milliTime)
  307. {
  308. out.appendf("%02d:%02d:%02d.%03d ", timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec, sysInfo.queryUSecs()/1000);
  309. }
  310. else if(fields & MSGFIELD_time)
  311. {
  312. strftime(timeString, 12, "%H:%M:%S ", &timeStruct);
  313. out.append(timeString);
  314. }
  315. }
  316. if(fields & MSGFIELD_process)
  317. out.appendf("pid=%d ",sysInfo.queryProcessID());
  318. if(fields & MSGFIELD_thread)
  319. out.appendf("tid=%d ",sysInfo.queryThreadID());
  320. if(fields & MSGFIELD_session)
  321. {
  322. if(sysInfo.querySessionID() == UnknownSession)
  323. out.append("sid=unknown ");
  324. else
  325. out.appendf("sid=%" I64F "u ", sysInfo.querySessionID());
  326. }
  327. if(fields & MSGFIELD_node)
  328. {
  329. sysInfo.queryNode()->getUrlStr(out);
  330. out.append(" ");
  331. }
  332. if(fields & MSGFIELD_job)
  333. {
  334. out.appendf("job=%s ", jobInfo.queryJobIDStr());
  335. }
  336. if(fields & MSGFIELD_user)
  337. {
  338. if(jobInfo.queryUserID() == UnknownUser)
  339. out.append("usr=unknown ");
  340. else
  341. out.appendf("usr=%" I64F "u ", jobInfo.queryUserID());
  342. }
  343. if(fields & MSGFIELD_component)
  344. out.appendf("cmp=%u ", component);
  345. if (fields & MSGFIELD_quote)
  346. out.append('"');
  347. if (fields & MSGFIELD_prefix)
  348. out.append(msgPrefix(category.queryClass()));
  349. if((fields & MSGFIELD_code) && (msgCode != NoLogMsgCode))
  350. out.append(msgCode).append(": ").append(text.str());
  351. else
  352. out.append(text.str());
  353. if (fields & MSGFIELD_quote)
  354. out.append('"');
  355. return out;
  356. }
  357. StringBuffer & LogMsg::toStringXML(StringBuffer & out, unsigned fields) const
  358. {
  359. out.ensureCapacity(LOG_MSG_FORMAT_BUFFER_LENGTH);
  360. out.append("<msg ");
  361. if(fields & MSGFIELD_msgID)
  362. out.append("MessageID=\"").append(sysInfo.queryMsgID()).append("\" ");
  363. if(fields & MSGFIELD_audience)
  364. out.append("Audience=\"").append(LogMsgAudienceToVarString(category.queryAudience())).append("\" ");
  365. if(fields & MSGFIELD_class)
  366. out.append("Class=\"").append(LogMsgClassToVarString(category.queryClass())).append("\" ");
  367. if(fields & MSGFIELD_detail)
  368. out.append("Detail=\"").append(category.queryDetail()).append("\" ");
  369. #ifdef LOG_MSG_NEWLINE
  370. if(fields & MSGFIELD_allCategory) out.append("\n ");
  371. #endif
  372. if(fields & MSGFIELD_timeDate)
  373. {
  374. time_t timeNum = sysInfo.queryTime();
  375. char timeString[20];
  376. struct tm timeStruct;
  377. localtime_r(&timeNum, &timeStruct);
  378. if(fields & MSGFIELD_date)
  379. {
  380. strftime(timeString, 20, "date=\"%Y-%m-%d\" ", &timeStruct);
  381. out.append(timeString);
  382. }
  383. if(fields & MSGFIELD_microTime)
  384. {
  385. out.appendf("time=\"%02d:%02d:%02d.%06d\" ", timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec, sysInfo.queryUSecs());
  386. }
  387. else if(fields & MSGFIELD_milliTime)
  388. {
  389. out.appendf("time=\"%02d:%02d:%02d.%03d\" ", timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec, sysInfo.queryUSecs()/1000);
  390. }
  391. else if(fields & MSGFIELD_time)
  392. {
  393. strftime(timeString, 20, "time=\"%H:%M:%S\" ", &timeStruct);
  394. out.append(timeString);
  395. }
  396. }
  397. if(fields & MSGFIELD_process)
  398. out.append("PID=\"").append(sysInfo.queryProcessID()).append("\" ");
  399. if(fields & MSGFIELD_thread)
  400. out.append("TID=\"").append(sysInfo.queryThreadID()).append("\" ");
  401. if(fields & MSGFIELD_session)
  402. {
  403. if(sysInfo.querySessionID() == UnknownSession)
  404. out.append("SessionID=\"unknown\" ");
  405. else
  406. out.append("SessionID=\"").append(sysInfo.querySessionID()).append("\" ");
  407. }
  408. if(fields & MSGFIELD_node)
  409. {
  410. out.append("Node=\"");
  411. sysInfo.queryNode()->getUrlStr(out);
  412. out.append("\" ");
  413. }
  414. #ifdef LOG_MSG_NEWLINE
  415. if(fields & MSGFIELD_allSysInfo) out.append("\n ");
  416. #endif
  417. if(fields & MSGFIELD_job)
  418. {
  419. out.appendf("JobID=\"%s\" ", jobInfo.queryJobIDStr());
  420. }
  421. if(fields & MSGFIELD_user)
  422. {
  423. if(jobInfo.queryUserID() == UnknownUser)
  424. out.append("UserID=\"unknown\" ");
  425. else
  426. out.append("UserID=\"").append(jobInfo.queryUserID()).append("\" ");
  427. }
  428. #ifdef LOG_MSG_NEWLINE
  429. if(fields & MSGFIELD_allJobInfo) out.append("\n ");
  430. #endif
  431. if(fields & MSGFIELD_component) out.append("Component=\"").append(component).append("\" ");
  432. if((fields & MSGFIELD_code) && (msgCode != NoLogMsgCode))
  433. out.append("code=\"").append(msgCode).append("\" ");
  434. out.append("text=\"").append(text.str()).append("\" />\n");
  435. return out;
  436. }
  437. StringBuffer & LogMsg::toStringTable(StringBuffer & out, unsigned fields) const
  438. {
  439. if(fields & MSGFIELD_msgID)
  440. out.appendf("%8X ", sysInfo.queryMsgID());
  441. out.ensureCapacity(LOG_MSG_FORMAT_BUFFER_LENGTH);
  442. if(fields & MSGFIELD_audience)
  443. out.appendf("%s ", LogMsgAudienceToFixString(category.queryAudience()));
  444. if(fields & MSGFIELD_class)
  445. out.appendf("%s ", LogMsgClassToFixString(category.queryClass()));
  446. if(fields & MSGFIELD_detail)
  447. out.appendf("%10d ", category.queryDetail());
  448. if(fields & MSGFIELD_timeDate)
  449. {
  450. time_t timeNum = sysInfo.queryTime();
  451. char timeString[12];
  452. struct tm timeStruct;
  453. localtime_r(&timeNum, &timeStruct);
  454. if(fields & MSGFIELD_date)
  455. {
  456. strftime(timeString, 12, "%Y-%m-%d ", &timeStruct);
  457. out.append(timeString);
  458. }
  459. if(fields & MSGFIELD_microTime)
  460. {
  461. out.appendf("%02d:%02d:%02d.%06d ", timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec, sysInfo.queryUSecs());
  462. }
  463. else if(fields & MSGFIELD_milliTime)
  464. {
  465. out.appendf("%02d:%02d:%02d.%03d ", timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec, sysInfo.queryUSecs()/1000);
  466. }
  467. else if(fields & MSGFIELD_time)
  468. {
  469. strftime(timeString, 12, "%H:%M:%S ", &timeStruct);
  470. out.append(timeString);
  471. }
  472. }
  473. if(fields & MSGFIELD_process)
  474. out.appendf("%5d ",sysInfo.queryProcessID());
  475. if(fields & MSGFIELD_thread)
  476. out.appendf("%5d ",sysInfo.queryThreadID());
  477. if(fields & MSGFIELD_session)
  478. {
  479. if(sysInfo.querySessionID() == UnknownSession)
  480. out.append(" unknown ");
  481. else
  482. out.appendf("%20" I64F "u ", sysInfo.querySessionID());
  483. }
  484. if(fields & MSGFIELD_node)
  485. {
  486. size32_t len = out.length();
  487. sysInfo.queryNode()->getUrlStr(out);
  488. out.appendN(20 + len - out.length(), ' ');
  489. }
  490. if(fields & MSGFIELD_job)
  491. {
  492. out.appendf("%-7s ", jobInfo.queryJobIDStr());
  493. }
  494. if(fields & MSGFIELD_user)
  495. {
  496. if(jobInfo.queryUserID() == UnknownUser)
  497. out.append("unknown ");
  498. else
  499. out.appendf("%7" I64F "u ", jobInfo.queryUserID());
  500. }
  501. if(fields & MSGFIELD_component)
  502. out.appendf("%6u ", component);
  503. if (fields & MSGFIELD_quote)
  504. out.append('"');
  505. if (fields & MSGFIELD_prefix)
  506. out.append(msgPrefix(category.queryClass()));
  507. if((fields & MSGFIELD_code) && (msgCode != NoLogMsgCode))
  508. out.append(msgCode).append(": ").append(text.str());
  509. else
  510. out.append(text.str());
  511. if (fields & MSGFIELD_quote)
  512. out.append('"');
  513. out.append('\n');
  514. return out;
  515. }
  516. StringBuffer & LogMsg::toStringTableHead(StringBuffer & out, unsigned fields)
  517. {
  518. loggingFieldColumns.generateHeaderRow(out, fields, false).append("\n\n");
  519. return out;
  520. }
  521. void LogMsg::fprintPlain(FILE * handle, unsigned fields) const
  522. {
  523. if(fields & MSGFIELD_msgID)
  524. fprintf(handle, "id=%X ", sysInfo.queryMsgID());
  525. if(fields & MSGFIELD_audience)
  526. fprintf(handle, "aud=%s", LogMsgAudienceToVarString(category.queryAudience()));
  527. if(fields & MSGFIELD_class)
  528. fprintf(handle, "cls=%s ", LogMsgClassToFixString(category.queryClass()));
  529. if(fields & MSGFIELD_detail)
  530. fprintf(handle, "det=%d ", category.queryDetail());
  531. if(fields & MSGFIELD_timeDate)
  532. {
  533. time_t timeNum = sysInfo.queryTime();
  534. char timeString[12];
  535. struct tm timeStruct;
  536. localtime_r(&timeNum, &timeStruct);
  537. if(fields & MSGFIELD_date)
  538. {
  539. strftime(timeString, 12, "%Y-%m-%d ", &timeStruct);
  540. fputs(timeString, handle);
  541. }
  542. if(fields & MSGFIELD_microTime)
  543. {
  544. fprintf(handle, "%02d:%02d:%02d.%06d ", timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec, sysInfo.queryUSecs());
  545. }
  546. else if(fields & MSGFIELD_milliTime)
  547. {
  548. fprintf(handle, "%02d:%02d:%02d.%03d ", timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec, sysInfo.queryUSecs()/1000);
  549. }
  550. else if(fields & MSGFIELD_time)
  551. {
  552. strftime(timeString, 12, "%H:%M:%S ", &timeStruct);
  553. fputs(timeString, handle);
  554. }
  555. }
  556. if(fields & MSGFIELD_process)
  557. fprintf(handle, "pid=%d ",sysInfo.queryProcessID());
  558. if(fields & MSGFIELD_thread)
  559. fprintf(handle, "tid=%d ",sysInfo.queryThreadID());
  560. if(fields & MSGFIELD_session)
  561. {
  562. if(sysInfo.querySessionID() == UnknownSession)
  563. fprintf(handle, "sid=unknown ");
  564. else
  565. fprintf(handle, "sid=%" I64F "u ", sysInfo.querySessionID());
  566. }
  567. if(fields & MSGFIELD_node)
  568. {
  569. StringBuffer buff;
  570. sysInfo.queryNode()->getUrlStr(buff);
  571. fprintf(handle, "%s ", buff.str());
  572. }
  573. if(fields & MSGFIELD_job)
  574. {
  575. fprintf(handle, "job=%s ", jobInfo.queryJobIDStr());
  576. }
  577. if(fields & MSGFIELD_user)
  578. {
  579. if(jobInfo.queryUserID() == UnknownUser)
  580. fprintf(handle, "usr=unknown ");
  581. else
  582. fprintf(handle, "usr=%" I64F "u ", jobInfo.queryUserID());
  583. }
  584. if(fields & MSGFIELD_component)
  585. fprintf(handle, "cmp=%u ", component);
  586. const char * quote = (fields & MSGFIELD_quote) ? "\"" : "";
  587. const char * prefix = (fields & MSGFIELD_prefix) ? msgPrefix(category.queryClass()) : "";
  588. if((fields & MSGFIELD_code) && (msgCode != NoLogMsgCode))
  589. fprintf(handle, "%s%s%d: %s%s", quote, prefix, msgCode, text.str(), quote);
  590. else
  591. fprintf(handle, "%s%s%s%s", quote, prefix, text.str(), quote);
  592. }
  593. void LogMsg::fprintXML(FILE * handle, unsigned fields) const
  594. {
  595. fprintf(handle, "<msg ");
  596. if(fields & MSGFIELD_msgID)
  597. fprintf(handle, "MessageID=\"%d\" ",sysInfo.queryMsgID());
  598. if(fields & MSGFIELD_audience)
  599. fprintf(handle, "Audience=\"%s\" ", LogMsgAudienceToVarString(category.queryAudience()));
  600. if(fields & MSGFIELD_class)
  601. fprintf(handle, "Class=\"%s\" ", LogMsgClassToVarString(category.queryClass()));
  602. if(fields & MSGFIELD_detail)
  603. fprintf(handle, "Detail=\"%d\" ", category.queryDetail());
  604. #ifdef LOG_MSG_NEWLINE
  605. if(fields & MSGFIELD_allCategory) fprintf(handle, "\n ");
  606. #endif
  607. if(fields & MSGFIELD_timeDate)
  608. {
  609. time_t timeNum = sysInfo.queryTime();
  610. char timeString[20];
  611. struct tm timeStruct;
  612. localtime_r(&timeNum, &timeStruct);
  613. if(fields & MSGFIELD_date)
  614. {
  615. strftime(timeString, 20, "date=\"%Y-%m-%d\" ", &timeStruct);
  616. fputs(timeString, handle);
  617. }
  618. if(fields & MSGFIELD_microTime)
  619. {
  620. fprintf(handle, "time=\"%02d:%02d:%02d.%06d\" ", timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec, sysInfo.queryUSecs());
  621. }
  622. else if(fields & MSGFIELD_milliTime)
  623. {
  624. fprintf(handle, "time=\"%02d:%02d:%02d.%03d\" ", timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec, sysInfo.queryUSecs()/1000);
  625. }
  626. else if(fields & MSGFIELD_time)
  627. {
  628. strftime(timeString, 20, "time=\"%H:%M:%S\" ", &timeStruct);
  629. fputs(timeString, handle);
  630. }
  631. }
  632. if(fields & MSGFIELD_process)
  633. fprintf(handle, "PID=\"%d\" ", sysInfo.queryProcessID());
  634. if(fields & MSGFIELD_thread)
  635. fprintf(handle, "TID=\"%d\" ", sysInfo.queryThreadID());
  636. if(fields & MSGFIELD_session)
  637. {
  638. if(sysInfo.querySessionID() == UnknownSession)
  639. fprintf(handle, "SessionID=\"unknown\" ");
  640. else
  641. fprintf(handle, "SessionID=\"%" I64F "u\" ", sysInfo.querySessionID());
  642. }
  643. if(fields & MSGFIELD_node)
  644. {
  645. StringBuffer buff;
  646. sysInfo.queryNode()->getUrlStr(buff);
  647. fprintf(handle, "Node=\"%s\" ", buff.str());
  648. }
  649. #ifdef LOG_MSG_NEWLINE
  650. if(fields & MSGFIELD_allSysInfo) fprintf(handle, "\n ");
  651. #endif
  652. if(fields & MSGFIELD_job)
  653. {
  654. fprintf(handle, "JobID=\"%s\" ", jobInfo.queryJobIDStr());
  655. }
  656. if(fields & MSGFIELD_user)
  657. {
  658. if(jobInfo.queryUserID() == UnknownUser)
  659. fprintf(handle, "UserID=\"unknown\" ");
  660. else
  661. fprintf(handle, "UserID=\"%" I64F "u\" ", jobInfo.queryUserID());
  662. }
  663. if(fields & MSGFIELD_component)
  664. fprintf(handle, "Component=\"%6u\" ", component);
  665. #ifdef LOG_MSG_NEWLINE
  666. if(fields & MSGFIELD_allJobInfo) fprintf(handle, "\n ");
  667. #endif
  668. if((fields & MSGFIELD_code) && (msgCode != NoLogMsgCode))
  669. fprintf(handle, "code=\"%d\" ", msgCode);
  670. fprintf(handle, "text=\"%s\" />\n", text.str());
  671. }
  672. void LogMsg::fprintTable(FILE * handle, unsigned fields) const
  673. {
  674. if(fields & MSGFIELD_msgID)
  675. fprintf(handle, "%08X ", sysInfo.queryMsgID());
  676. if(fields & MSGFIELD_audience)
  677. fprintf(handle, "%s ", LogMsgAudienceToFixString(category.queryAudience()));
  678. if(fields & MSGFIELD_class)
  679. fprintf(handle, "%s ", LogMsgClassToFixString(category.queryClass()));
  680. if(fields & MSGFIELD_detail)
  681. fprintf(handle, "%10d ", category.queryDetail());
  682. if(fields & MSGFIELD_timeDate)
  683. {
  684. time_t timeNum = sysInfo.queryTime();
  685. char timeString[12];
  686. struct tm timeStruct;
  687. localtime_r(&timeNum, &timeStruct);
  688. if(fields & MSGFIELD_date)
  689. {
  690. strftime(timeString, 12, "%Y-%m-%d ", &timeStruct);
  691. fputs(timeString, handle);
  692. }
  693. if(fields & MSGFIELD_microTime)
  694. {
  695. fprintf(handle, "%02d:%02d:%02d.%06d ", timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec, sysInfo.queryUSecs());
  696. }
  697. else if(fields & MSGFIELD_milliTime)
  698. {
  699. fprintf(handle, "%02d:%02d:%02d.%03d ", timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec, sysInfo.queryUSecs()/1000);
  700. }
  701. else if(fields & MSGFIELD_time)
  702. {
  703. strftime(timeString, 12, "%H:%M:%S ", &timeStruct);
  704. fputs(timeString, handle);
  705. }
  706. }
  707. if(fields & MSGFIELD_process)
  708. fprintf(handle, "%5d ",sysInfo.queryProcessID());
  709. if(fields & MSGFIELD_thread)
  710. fprintf(handle, "%5d ",sysInfo.queryThreadID());
  711. if(fields & MSGFIELD_session)
  712. {
  713. if(sysInfo.querySessionID() == UnknownSession)
  714. fprintf(handle, " unknown ");
  715. else
  716. fprintf(handle, "%20" I64F "u ", sysInfo.querySessionID());
  717. }
  718. if(fields & MSGFIELD_node)
  719. {
  720. StringBuffer buff;
  721. static const char * twenty_spaces = " ";
  722. sysInfo.queryNode()->getUrlStr(buff);
  723. fprintf(handle, "%s%s", buff.str(), (buff.length()<=20) ? twenty_spaces+buff.length() : "");
  724. }
  725. if(fields & MSGFIELD_job)
  726. {
  727. fprintf(handle, "%-7s ", jobInfo.queryJobIDStr());
  728. }
  729. if(fields & MSGFIELD_user)
  730. {
  731. if(jobInfo.queryUserID() == UnknownUser)
  732. fprintf(handle, "unknown ");
  733. else
  734. fprintf(handle, "%7" I64F "u ", jobInfo.queryUserID());
  735. }
  736. if(fields & MSGFIELD_component)
  737. fprintf(handle, "%6u ", component);
  738. const char * quote = (fields & MSGFIELD_quote) ? "\"" : "";
  739. const char * prefix = (fields & MSGFIELD_prefix) ? msgPrefix(category.queryClass()) : "";
  740. if((fields & MSGFIELD_code) && (msgCode != NoLogMsgCode))
  741. fprintf(handle, "%s%s%d: %s%s\n", quote, prefix, msgCode, text.str(), quote);
  742. else
  743. fprintf(handle, "%s%s%s%s\n", quote, prefix, text.str(), quote);
  744. }
  745. void LogMsg::fprintTableHead(FILE * handle, unsigned fields)
  746. {
  747. StringBuffer header;
  748. loggingFieldColumns.generateHeaderRow(header, fields, true).append("\n");
  749. fputs(header.str(), handle);
  750. }
  751. void LogMsg::deserialize(MemoryBuffer & in)
  752. {
  753. remoteFlag = true;
  754. category.deserialize(in);
  755. sysInfo.deserialize(in);
  756. jobInfo.deserialize(in);
  757. in.read(msgCode);
  758. text.clear();
  759. text.deserialize(in);
  760. }
  761. unsigned getMessageFieldsFromHeader(FILE *handle)
  762. {
  763. unsigned currentFieldHeader = 0;
  764. try
  765. {
  766. MemoryBuffer mb(loggingFieldColumns.getMaxHeaderSize());
  767. fpos_t pos;
  768. fgetpos (handle,&pos);
  769. rewind (handle);
  770. mb.reserve(loggingFieldColumns.getMaxHeaderSize());
  771. const char * line = fgets (static_cast<char *>(mb.bufferBase()), loggingFieldColumns.getMaxHeaderSize(), handle );
  772. if (line && *line)
  773. currentFieldHeader = loggingFieldColumns.extractMessageFieldsFromHeader(line, true);
  774. fsetpos (handle, &pos);
  775. }
  776. catch (...)
  777. {
  778. currentFieldHeader = 0;
  779. }
  780. return currentFieldHeader;
  781. }
  782. unsigned getMessageFieldsFromHeader(const char * line)
  783. {
  784. return loggingFieldColumns.extractMessageFieldsFromHeader(line, true);
  785. }
  786. // Implementations of ILogMsgFilter
  787. void PassAllLogMsgFilter::addToPTree(IPropertyTree * tree) const
  788. {
  789. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  790. filterTree->setProp("@type", "all");
  791. tree->addPropTree("filter", filterTree);
  792. }
  793. void PassLocalLogMsgFilter::addToPTree(IPropertyTree * tree) const
  794. {
  795. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  796. filterTree->setProp("@type", "local");
  797. tree->addPropTree("filter", filterTree);
  798. }
  799. void PassNoneLogMsgFilter::addToPTree(IPropertyTree * tree) const
  800. {
  801. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  802. filterTree->setProp("@type", "none");
  803. tree->addPropTree("filter", filterTree);
  804. }
  805. void CategoryLogMsgFilter::addToPTree(IPropertyTree * tree) const
  806. {
  807. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  808. filterTree->setProp("@type", "category");
  809. filterTree->setPropInt("@audience", audienceMask);
  810. filterTree->setPropInt("@class", classMask);
  811. filterTree->setPropInt("@detail", maxDetail);
  812. if(localFlag) filterTree->setPropInt("@local", 1);
  813. tree->addPropTree("filter", filterTree);
  814. }
  815. void PIDLogMsgFilter::addToPTree(IPropertyTree * tree) const
  816. {
  817. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  818. filterTree->setProp("@type", "pid");
  819. filterTree->setPropInt("@pid", pid);
  820. if(localFlag) filterTree->setPropInt("@local", 1);
  821. tree->addPropTree("filter", filterTree);
  822. }
  823. void TIDLogMsgFilter::addToPTree(IPropertyTree * tree) const
  824. {
  825. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  826. filterTree->setProp("@type", "tid");
  827. filterTree->setPropInt("@tid", tid);
  828. if(localFlag) filterTree->setPropInt("@local", 1);
  829. tree->addPropTree("filter", filterTree);
  830. }
  831. void NodeLogMsgFilter::addToPTree(IPropertyTree * tree) const
  832. {
  833. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  834. filterTree->setProp("@type", "node");
  835. StringBuffer buff;
  836. node.getIpText(buff);
  837. filterTree->setProp("@ip", buff.str());
  838. filterTree->setPropInt("@port", node.port);
  839. if(localFlag) filterTree->setPropInt("@local", 1);
  840. tree->addPropTree("filter", filterTree);
  841. }
  842. void IpLogMsgFilter::addToPTree(IPropertyTree * tree) const
  843. {
  844. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  845. filterTree->setProp("@type", "ip");
  846. StringBuffer buff;
  847. ip.getIpText(buff);
  848. filterTree->setProp("@ip", buff.str());
  849. if(localFlag) filterTree->setPropInt("@local", 1);
  850. tree->addPropTree("filter", filterTree);
  851. }
  852. void SessionLogMsgFilter::addToPTree(IPropertyTree * tree) const
  853. {
  854. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  855. filterTree->setProp("@type", "session");
  856. filterTree->setPropInt("@session", (int)session);
  857. if(localFlag) filterTree->setPropInt("@local", 1);
  858. tree->addPropTree("filter", filterTree);
  859. }
  860. void ComponentLogMsgFilter::addToPTree(IPropertyTree * tree) const
  861. {
  862. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  863. filterTree->setProp("@type", "component");
  864. filterTree->setPropInt("@component", component);
  865. if(localFlag) filterTree->setPropInt("@local", 1);
  866. tree->addPropTree("filter", filterTree);
  867. }
  868. bool RegexLogMsgFilter::includeMessage(const LogMsg & msg) const
  869. {
  870. if(localFlag && msg.queryRemoteFlag()) return false;
  871. SpinBlock b(lock);
  872. return const_cast<RegExpr &>(regex).find(msg.queryText()) != NULL;
  873. }
  874. void RegexLogMsgFilter::addToPTree(IPropertyTree * tree) const
  875. {
  876. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  877. filterTree->setProp("@type", "regex");
  878. filterTree->setProp("@regex", regexText);
  879. if(localFlag) filterTree->setPropInt("@local", 1);
  880. tree->addPropTree("filter", filterTree);
  881. }
  882. void NotLogMsgFilter::addToPTree(IPropertyTree * tree) const
  883. {
  884. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  885. filterTree->setProp("@type", "not");
  886. arg->addToPTree(filterTree);
  887. tree->addPropTree("filter", filterTree);
  888. }
  889. void AndLogMsgFilter::addToPTree(IPropertyTree * tree) const
  890. {
  891. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  892. filterTree->setProp("@type", "and");
  893. arg1->addToPTree(filterTree);
  894. arg2->addToPTree(filterTree);
  895. tree->addPropTree("filter", filterTree);
  896. }
  897. void OrLogMsgFilter::addToPTree(IPropertyTree * tree) const
  898. {
  899. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  900. filterTree->setProp("@type", "or");
  901. arg1->addToPTree(filterTree);
  902. arg2->addToPTree(filterTree);
  903. tree->addPropTree("filter", filterTree);
  904. }
  905. void SwitchLogMsgFilter::addToPTree(IPropertyTree * tree) const
  906. {
  907. IPropertyTree * filterTree = createPTree(ipt_caseInsensitive);
  908. filterTree->setProp("@type", "switch");
  909. cond->addToPTree(filterTree);
  910. yes->addToPTree(filterTree);
  911. no->addToPTree(filterTree);
  912. tree->addPropTree("filter", filterTree);
  913. }
  914. void CategoryLogMsgFilter::orWithFilter(const ILogMsgFilter * filter)
  915. {
  916. audienceMask |= filter->queryAudienceMask();
  917. classMask |= filter->queryClassMask();
  918. maxDetail = std::max(maxDetail, filter->queryMaxDetail());
  919. }
  920. void CategoryLogMsgFilter::reset()
  921. {
  922. audienceMask = 0;
  923. classMask = 0;
  924. maxDetail = 0;
  925. }
  926. // HandleLogMsgHandler
  927. void HandleLogMsgHandlerTable::addToPTree(IPropertyTree * tree) const
  928. {
  929. IPropertyTree * handlerTree = createPTree(ipt_caseInsensitive);
  930. if(handle==stderr)
  931. handlerTree->setProp("@type", "stderr");
  932. else
  933. handlerTree->setProp("@type", "mischandle");
  934. handlerTree->setPropInt("@fields", messageFields);
  935. tree->addPropTree("handler", handlerTree);
  936. }
  937. void HandleLogMsgHandlerXML::addToPTree(IPropertyTree * tree) const
  938. {
  939. IPropertyTree * handlerTree = createPTree(ipt_caseInsensitive);
  940. if(handle==stderr)
  941. handlerTree->setProp("@type", "stderr");
  942. else
  943. handlerTree->setProp("@type", "mischandle");
  944. handlerTree->setPropInt("@fields", messageFields);
  945. handlerTree->setProp("@writeXML", "true");
  946. tree->addPropTree("handler", handlerTree);
  947. }
  948. // FileLogMsgHandler
  949. FileLogMsgHandler::FileLogMsgHandler(const char * _filename, const char * _headerText, unsigned _fields, bool _append, bool _flushes)
  950. : messageFields(_fields), filename(_filename), headerText(_headerText), append(_append), flushes(_flushes)
  951. {
  952. recursiveCreateDirectoryForFile(filename);
  953. if(append)
  954. handle = fopen(filename, "a");
  955. else
  956. handle = fopen(filename, "w");
  957. if(!handle) {
  958. handle = getNullHandle();
  959. StringBuffer err;
  960. err.appendf("LOGGING: could not open file '%s' for output",filename.get());
  961. OERRLOG("%s",err.str()); // make sure doesn't get lost!
  962. throw MakeStringException(3000,"%s",err.str()); // 3000: internal error
  963. }
  964. if(headerText) fprintf(handle, "--- %s ---\n", (const char *)headerText);
  965. }
  966. static void closeAndDeleteEmpty(const char * filename, FILE *handle)
  967. {
  968. if (handle) {
  969. fpos_t pos;
  970. bool del = (fgetpos(handle, &pos)==0)&&
  971. #if defined( _WIN32) || defined(__FreeBSD__) || defined(__APPLE__)
  972. (pos==0);
  973. #else
  974. (pos.__pos==0);
  975. #endif
  976. fclose(handle);
  977. if (del)
  978. remove(filename);
  979. }
  980. }
  981. FileLogMsgHandler::~FileLogMsgHandler()
  982. {
  983. closeAndDeleteEmpty(filename,handle);
  984. }
  985. char const * FileLogMsgHandler::disable()
  986. {
  987. crit.enter();
  988. fclose(handle);
  989. handle = NULL;
  990. return filename;
  991. }
  992. void FileLogMsgHandler::enable()
  993. {
  994. recursiveCreateDirectoryForFile(filename);
  995. handle = fopen(filename, "a");
  996. if(!handle) {
  997. handle = getNullHandle();
  998. assertex(!"FileLogMsgHandler::enable : could not open file for output");
  999. }
  1000. crit.leave();
  1001. }
  1002. void FileLogMsgHandlerTable::addToPTree(IPropertyTree * tree) const
  1003. {
  1004. IPropertyTree * handlerTree = createPTree(ipt_caseInsensitive);
  1005. handlerTree->setProp("@type", "file");
  1006. handlerTree->setProp("@filename", filename.get());
  1007. if(headerText) handlerTree->setProp("@headertext", headerText.get());
  1008. handlerTree->setPropInt("@fields", messageFields);
  1009. handlerTree->setProp("@writeTable", "true");
  1010. if(append) handlerTree->setProp("@append", "true");
  1011. if(flushes) handlerTree->setProp("@flushes", "true");
  1012. tree->addPropTree("handler", handlerTree);
  1013. }
  1014. void FileLogMsgHandlerXML::addToPTree(IPropertyTree * tree) const
  1015. {
  1016. IPropertyTree * handlerTree = createPTree(ipt_caseInsensitive);
  1017. handlerTree->setProp("@type", "file");
  1018. handlerTree->setProp("@filename", filename.get());
  1019. if(headerText) handlerTree->setProp("@headertext", headerText.get());
  1020. handlerTree->setPropInt("@fields", messageFields);
  1021. if(append) handlerTree->setProp("@append", "true");
  1022. if(flushes) handlerTree->setProp("@flushes", "true");
  1023. tree->addPropTree("handler", handlerTree);
  1024. }
  1025. // PostMortemLogMsgHandler
  1026. PostMortemLogMsgHandler::PostMortemLogMsgHandler(const char * _filebase, unsigned _maxLinesToKeep, unsigned _messageFields)
  1027. : filebase(_filebase), maxLinesToKeep(_maxLinesToKeep), messageFields(_messageFields)
  1028. {
  1029. openFile();
  1030. }
  1031. PostMortemLogMsgHandler::~PostMortemLogMsgHandler()
  1032. {
  1033. closeAndDeleteEmpty(filename, handle);
  1034. }
  1035. void PostMortemLogMsgHandler::handleMessage(const LogMsg & msg)
  1036. {
  1037. CriticalBlock block(crit);
  1038. if (handle)
  1039. {
  1040. checkRollover();
  1041. msg.fprintTable(handle, messageFields);
  1042. if(flushes)
  1043. fflush(handle);
  1044. linesInCurrent++;
  1045. }
  1046. }
  1047. void PostMortemLogMsgHandler::addToPTree(IPropertyTree * tree) const
  1048. {
  1049. }
  1050. void PostMortemLogMsgHandler::checkRollover()
  1051. {
  1052. if (linesInCurrent>=maxLinesToKeep)
  1053. {
  1054. doRollover();
  1055. }
  1056. }
  1057. void PostMortemLogMsgHandler::doRollover()
  1058. {
  1059. closeAndDeleteEmpty(filename, handle);
  1060. handle = 0;
  1061. if (sequence > 0)
  1062. {
  1063. StringBuffer agedName;
  1064. agedName.append(filebase).append('.').append(sequence-1);
  1065. remove(agedName);
  1066. }
  1067. sequence++;
  1068. openFile();
  1069. }
  1070. void PostMortemLogMsgHandler::openFile()
  1071. {
  1072. filename.clear().append(filebase).append('.').append(sequence);
  1073. recursiveCreateDirectoryForFile(filename.str());
  1074. handle = fopen(filename.str(), "wt");
  1075. if(!handle)
  1076. handle = getNullHandle(); // If we can't write where we expected, write to /dev/null instead
  1077. linesInCurrent = 0;
  1078. }
  1079. // RollingFileLogMsgHandler
  1080. #define MIN_LOGFILE_SIZE_LIMIT 10000
  1081. #define LOG_LINE_SIZE_ESTIMATE 80
  1082. RollingFileLogMsgHandler::RollingFileLogMsgHandler(const char * _filebase, const char * _fileextn, unsigned _fields, bool _append, bool _flushes, const char *initialName, const char *_alias, bool daily, long _maxLogFileSize)
  1083. : handle(0), messageFields(_fields), alias(_alias), filebase(_filebase), fileextn(_fileextn), append(_append), flushes(_flushes), maxLogFileSize(_maxLogFileSize)
  1084. {
  1085. if (_maxLogFileSize)
  1086. {
  1087. if (_maxLogFileSize < MIN_LOGFILE_SIZE_LIMIT) // Setting the cap too low, doesn't work well
  1088. maxLogFileSize = MIN_LOGFILE_SIZE_LIMIT;
  1089. maxLogFileSize = _maxLogFileSize - (LOG_LINE_SIZE_ESTIMATE*2); // Trying to keep log file size below capped
  1090. };
  1091. time_t tNow;
  1092. time(&tNow);
  1093. localtime_r(&tNow, &startTime);
  1094. doRollover(daily, initialName);
  1095. checkRollover();
  1096. }
  1097. RollingFileLogMsgHandler::~RollingFileLogMsgHandler()
  1098. {
  1099. closeAndDeleteEmpty(filename,handle);
  1100. }
  1101. void RollingFileLogMsgHandler::addToPTree(IPropertyTree * tree) const
  1102. {
  1103. IPropertyTree * handlerTree = createPTree(ipt_caseInsensitive);
  1104. handlerTree->setProp("@type", "rollingfile");
  1105. handlerTree->setProp("@filebase", filebase.get());
  1106. handlerTree->setProp("@fileextn", fileextn.get());
  1107. handlerTree->setPropInt("@fields", messageFields);
  1108. if(append) handlerTree->setProp("@append", "true");
  1109. if(flushes) handlerTree->setProp("@flushes", "true");
  1110. tree->addPropTree("handler", handlerTree);
  1111. }
  1112. void RollingFileLogMsgHandler::checkRollover()
  1113. {
  1114. time_t tNow;
  1115. time(&tNow);
  1116. struct tm ltNow;
  1117. localtime_r(&tNow, &ltNow);
  1118. if(ltNow.tm_year != startTime.tm_year || ltNow.tm_yday != startTime.tm_yday)
  1119. {
  1120. localtime_r(&tNow, &startTime); // reset the start time for next rollover check
  1121. doRollover(true);
  1122. }
  1123. else if (maxLogFileSize)
  1124. {
  1125. linesSinceSizeChecked++;
  1126. if (linesSinceSizeChecked > sizeCheckNext)
  1127. {
  1128. long fsize = ftell(handle);
  1129. if ((fsize==-1 && errno==EOVERFLOW) || (fsize >= maxLogFileSize))
  1130. {
  1131. localtime_r(&tNow, &startTime);
  1132. doRollover(false);
  1133. }
  1134. else
  1135. // Calc how many lines to skip before next log file size check
  1136. // - using (LOG_LINE_SIZE_ESTIMATE*2) to ensure the size check is done well before limit
  1137. sizeCheckNext = (maxLogFileSize - fsize) / (LOG_LINE_SIZE_ESTIMATE*2);
  1138. linesSinceSizeChecked = 0;
  1139. }
  1140. }
  1141. }
  1142. void RollingFileLogMsgHandler::doRollover(bool daily, const char *forceName)
  1143. {
  1144. CriticalBlock block(crit);
  1145. closeAndDeleteEmpty(filename,handle);
  1146. handle = 0;
  1147. filename.clear();
  1148. if (forceName)
  1149. filename.append(forceName);
  1150. else
  1151. {
  1152. filename.clear().append(filebase.get());
  1153. addFileTimestamp(filename, daily);
  1154. filename.append(fileextn.get());
  1155. }
  1156. recursiveCreateDirectoryForFile(filename.str());
  1157. handle = fopen(filename.str(), append ? "a+" : "w");
  1158. printHeader = true;
  1159. currentLogFields = 0;
  1160. if (handle)
  1161. {
  1162. if (append)
  1163. {
  1164. fseek(handle, 0, SEEK_END);
  1165. long pos = ftell(handle);
  1166. if (pos > 0 || (pos==-1 && errno==EOVERFLOW)) // If current file is not empty
  1167. {
  1168. printHeader = false;
  1169. unsigned logfields = getMessageFieldsFromHeader(handle);
  1170. if (logfields == 0) // No header file so write log lines legacy field format
  1171. currentLogFields = MSGFIELD_LEGACY;
  1172. else if (logfields != messageFields) // Different log format from format in current log file
  1173. currentLogFields = logfields;
  1174. }
  1175. }
  1176. if (alias && alias.length())
  1177. {
  1178. fclose(handle);
  1179. handle = 0;
  1180. remove(alias);
  1181. try
  1182. {
  1183. createHardLink(alias, filename.str());
  1184. }
  1185. catch (IException *E)
  1186. {
  1187. recursiveCreateDirectoryForFile(filename.str());
  1188. handle = fopen(filename.str(), append ? "a" : "w");
  1189. EXCLOG(E); // Log the fact that we could not create the alias - probably it is locked (tail a bit unfortunate on windows).
  1190. E->Release();
  1191. }
  1192. if (!handle)
  1193. {
  1194. recursiveCreateDirectoryForFile(filename.str());
  1195. handle = fopen(filename.str(), append ? "a" : "w");
  1196. }
  1197. }
  1198. }
  1199. if(!handle)
  1200. {
  1201. handle = getNullHandle();
  1202. OWARNLOG("RollingFileLogMsgHandler::doRollover : could not open log file %s for output", filename.str());
  1203. // actually this is pretty fatal
  1204. }
  1205. }
  1206. // BinLogMsgHandler
  1207. BinLogMsgHandler::BinLogMsgHandler(const char * _filename, bool _append) : filename(_filename), append(_append)
  1208. {
  1209. file.setown(createIFile(filename.get()));
  1210. if(!file) assertex(!"BinLogMsgHandler::BinLogMsgHandler : Could not create IFile");
  1211. if(append)
  1212. fio.setown(file->open(IFOwrite));
  1213. else
  1214. fio.setown(file->open(IFOcreate));
  1215. if(!fio) assertex(!"BinLogMsgHandler::BinLogMsgHandler : Could not create IFileIO");
  1216. fstr.setown(createIOStream(fio));
  1217. if(!fstr) assertex(!"BinLogMsgHandler::BinLogMsgHandler : Could not create IFileIOStream");
  1218. if(append)
  1219. fstr->seek(0, IFSend);
  1220. }
  1221. BinLogMsgHandler::~BinLogMsgHandler()
  1222. {
  1223. fstr.clear();
  1224. fio.clear();
  1225. file.clear();
  1226. }
  1227. void BinLogMsgHandler::handleMessage(const LogMsg & msg)
  1228. {
  1229. CriticalBlock block(crit);
  1230. mbuff.clear();
  1231. msg.serialize(mbuff);
  1232. size32_t msglen = mbuff.length();
  1233. fstr->write(sizeof(msglen), &msglen);
  1234. fstr->write(msglen, mbuff.toByteArray());
  1235. }
  1236. void BinLogMsgHandler::addToPTree(IPropertyTree * tree) const
  1237. {
  1238. IPropertyTree * handlerTree = createPTree(ipt_caseInsensitive);
  1239. handlerTree->setProp("@type", "binary");
  1240. handlerTree->setProp("@filename", filename.get());
  1241. if(append) handlerTree->setProp("@append", "true");
  1242. tree->addPropTree("handler", handlerTree);
  1243. }
  1244. // LogMsgComponentReporter
  1245. void LogMsgComponentReporter::report(const LogMsgCategory & cat, const char * format, ...)
  1246. {
  1247. va_list args;
  1248. va_start(args, format);
  1249. queryLogMsgManager()->report_va(component, cat, unknownJob, format, args);
  1250. va_end(args);
  1251. }
  1252. void LogMsgComponentReporter::report_va(const LogMsgCategory & cat, const char * format, va_list args)
  1253. {
  1254. queryLogMsgManager()->report_va(component, cat, unknownJob, format, args);
  1255. }
  1256. void LogMsgComponentReporter::report(const LogMsgCategory & cat, LogMsgCode code, const char * format, ...)
  1257. {
  1258. va_list args;
  1259. va_start(args, format);
  1260. queryLogMsgManager()->report_va(component, cat, unknownJob, code, format, args);
  1261. va_end(args);
  1262. }
  1263. void LogMsgComponentReporter::report_va(const LogMsgCategory & cat, LogMsgCode code, const char * format, va_list args)
  1264. {
  1265. queryLogMsgManager()->report_va(component, cat, unknownJob, code, format, args);
  1266. }
  1267. void LogMsgComponentReporter::report(const LogMsgCategory & cat, const IException * exception, const char * prefix)
  1268. {
  1269. StringBuffer buff;
  1270. if(prefix) buff.append(prefix).append(" : ");
  1271. exception->errorMessage(buff);
  1272. queryLogMsgManager()->report(component, cat, unknownJob, exception->errorCode(), "%s", buff.str());
  1273. }
  1274. void LogMsgComponentReporter::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, ...)
  1275. {
  1276. va_list args;
  1277. va_start(args, format);
  1278. queryLogMsgManager()->report_va(component, cat, job, format, args);
  1279. va_end(args);
  1280. }
  1281. void LogMsgComponentReporter::report_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, va_list args)
  1282. {
  1283. queryLogMsgManager()->report_va(component, cat, job, format, args);
  1284. }
  1285. void LogMsgComponentReporter::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, ...)
  1286. {
  1287. va_list args;
  1288. va_start(args, format);
  1289. queryLogMsgManager()->report_va(component, cat, job, code, format, args);
  1290. va_end(args);
  1291. }
  1292. void LogMsgComponentReporter::report_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, va_list args)
  1293. {
  1294. queryLogMsgManager()->report_va(component, cat, job, code, format, args);
  1295. }
  1296. void LogMsgComponentReporter::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, const IException * exception, const char * prefix)
  1297. {
  1298. StringBuffer buff;
  1299. if(prefix) buff.append(prefix).append(" : ");
  1300. exception->errorMessage(buff);
  1301. queryLogMsgManager()->report(component, cat, job, exception->errorCode(), "%s", buff.str());
  1302. }
  1303. void LogMsgComponentReporter::report(const LogMsg & msg)
  1304. {
  1305. queryLogMsgManager()->report(msg);
  1306. }
  1307. void LogMsgComponentReporter::mreport_direct(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * msg)
  1308. {
  1309. queryLogMsgManager()->mreport_direct(component, cat, job, msg);
  1310. }
  1311. void LogMsgComponentReporter::mreport_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, va_list args)
  1312. {
  1313. queryLogMsgManager()->mreport_va(component, cat, job, format, args);
  1314. }
  1315. // LogMsgPrepender
  1316. void LogMsgPrepender::report(const LogMsgCategory & cat, const char * format, ...)
  1317. {
  1318. StringBuffer buff;
  1319. buff.append(file).append("(").append(line).append(") : ").append(format);
  1320. va_list args;
  1321. va_start(args, format);
  1322. if(reporter)
  1323. reporter->report_va(cat, unknownJob, buff.str(), args);
  1324. else
  1325. queryLogMsgManager()->report_va(cat, unknownJob, buff.str(), args);
  1326. va_end(args);
  1327. }
  1328. void LogMsgPrepender::report_va(const LogMsgCategory & cat, const char * format, va_list args)
  1329. {
  1330. StringBuffer buff;
  1331. buff.append(file).append("(").append(line).append(") : ").append(format);
  1332. if(reporter)
  1333. reporter->report_va(cat, unknownJob, buff.str(), args);
  1334. else
  1335. queryLogMsgManager()->report_va(cat, unknownJob, buff.str(), args);
  1336. }
  1337. void LogMsgPrepender::report(const LogMsgCategory & cat, LogMsgCode code, const char * format, ...)
  1338. {
  1339. StringBuffer buff;
  1340. buff.append(file).append("(").append(line).append(") : ").append(format);
  1341. va_list args;
  1342. va_start(args, format);
  1343. if(reporter)
  1344. reporter->report_va(cat, unknownJob, buff.str(), args);
  1345. else
  1346. queryLogMsgManager()->report_va(cat, unknownJob, buff.str(), args);
  1347. va_end(args);
  1348. }
  1349. void LogMsgPrepender::report_va(const LogMsgCategory & cat, LogMsgCode code, const char * format, va_list args)
  1350. {
  1351. StringBuffer buff;
  1352. buff.append(file).append("(").append(line).append(") : ").append(format);
  1353. if(reporter)
  1354. reporter->report_va(cat, unknownJob, buff.str(), args);
  1355. else
  1356. queryLogMsgManager()->report_va(cat, unknownJob, buff.str(), args);
  1357. }
  1358. void LogMsgPrepender::report(const LogMsgCategory & cat, const IException * exception, const char * prefix)
  1359. {
  1360. StringBuffer buff;
  1361. buff.append(file).append("(").append(line).append(") : ");
  1362. if(prefix) buff.append(prefix).append(" : ");
  1363. exception->errorMessage(buff);
  1364. if(reporter)
  1365. reporter->report(cat, unknownJob, exception->errorCode(), "%s", buff.str());
  1366. else
  1367. queryLogMsgManager()->report(cat, unknownJob, exception->errorCode(), "%s", buff.str());
  1368. }
  1369. void LogMsgPrepender::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, ...)
  1370. {
  1371. StringBuffer buff;
  1372. buff.append(file).append("(").append(line).append(") : ").append(format);
  1373. va_list args;
  1374. va_start(args, format);
  1375. if(reporter)
  1376. reporter->report_va(cat, job, buff.str(), args);
  1377. else
  1378. queryLogMsgManager()->report_va(cat, job, buff.str(), args);
  1379. va_end(args);
  1380. }
  1381. void LogMsgPrepender::report_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, va_list args)
  1382. {
  1383. StringBuffer buff;
  1384. buff.append(file).append("(").append(line).append(") : ").append(format);
  1385. if(reporter)
  1386. reporter->report_va(cat, job, buff.str(), args);
  1387. else
  1388. queryLogMsgManager()->report_va(cat, job, buff.str(), args);
  1389. }
  1390. void LogMsgPrepender::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, ...)
  1391. {
  1392. StringBuffer buff;
  1393. buff.append(file).append("(").append(line).append(") : ").append(format);
  1394. va_list args;
  1395. va_start(args, format);
  1396. if(reporter)
  1397. reporter->report_va(cat, job, buff.str(), args);
  1398. else
  1399. queryLogMsgManager()->report_va(cat, job, buff.str(), args);
  1400. va_end(args);
  1401. }
  1402. void LogMsgPrepender::report_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, va_list args)
  1403. {
  1404. StringBuffer buff;
  1405. buff.append(file).append("(").append(line).append(") : ").append(format);
  1406. if(reporter)
  1407. reporter->report_va(cat, job, buff.str(), args);
  1408. else
  1409. queryLogMsgManager()->report_va(cat, job, buff.str(), args);
  1410. }
  1411. void LogMsgPrepender::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, const IException * exception, const char * prefix)
  1412. {
  1413. StringBuffer txt;
  1414. if (prefix)
  1415. txt.append(prefix).append(" : ");
  1416. exception->errorMessage(txt);
  1417. if (reporter)
  1418. reporter->report(cat, job, exception->errorCode(), "%s(%d) : %s", file, line, txt.str());
  1419. else
  1420. queryLogMsgManager()->report(cat, job, exception->errorCode(), "%s(%d) : %s", file, line, txt.str());
  1421. }
  1422. IException * LogMsgPrepender::report(IException * e, const char * prefix, LogMsgClass cls)
  1423. {
  1424. report(MCexception(e, cls), unknownJob, e, prefix);
  1425. return e;
  1426. }
  1427. // LogMsgMonitor
  1428. void LogMsgMonitor::addToPTree(IPropertyTree * tree) const
  1429. {
  1430. IPropertyTree * monitorTree = createPTree(ipt_caseInsensitive);
  1431. handler->addToPTree(monitorTree);
  1432. filter->addToPTree(monitorTree);
  1433. tree->addPropTree("monitor", monitorTree);
  1434. }
  1435. // CLogMsgManager
  1436. void CLogMsgManager::MsgProcessor::push(LogMsg * msg)
  1437. {
  1438. //assertex(more); an assertex will just recurse here
  1439. if (!more) // we are effective stopped so don't bother even dropping (and leak parameter) as drop will involve
  1440. // interaction with the base class which is stopped and could easily crash (as this condition
  1441. // is expected not to occur - typically occurs if the user has incorrectly called exit on one thread
  1442. // while still in the process of logging on another)
  1443. // cf Bug #53695 for more discussion of the issue
  1444. return;
  1445. else if(droppingLimit && (q.ordinality() >= droppingLimit))
  1446. drop();
  1447. q.enqueue(msg);
  1448. }
  1449. int CLogMsgManager::MsgProcessor::run()
  1450. {
  1451. Owned<LogMsg> msg;
  1452. while(more)
  1453. {
  1454. msg.setown(q.dequeueAndNotify(this)); // notify locks mutex on non-null return
  1455. if(!msg)
  1456. break;
  1457. owner->doReport(*msg);
  1458. pullCycleMutex.unlock();
  1459. }
  1460. while(true)
  1461. {
  1462. msg.setown(q.dequeueNowAndNotify(this)); // notify locks mutex on non-null return
  1463. if(!msg)
  1464. break;
  1465. owner->doReport(*msg);
  1466. pullCycleMutex.unlock();
  1467. }
  1468. return 0;
  1469. }
  1470. void CLogMsgManager::MsgProcessor::notify(LogMsg *)
  1471. {
  1472. pullCycleMutex.lock();
  1473. }
  1474. void CLogMsgManager::MsgProcessor::setBlockingLimit(unsigned lim)
  1475. {
  1476. q.setLimit(lim);
  1477. droppingLimit = 0;
  1478. }
  1479. void CLogMsgManager::MsgProcessor::setDroppingLimit(unsigned lim, unsigned num)
  1480. {
  1481. numToDrop = num;
  1482. droppingLimit = lim;
  1483. q.setLimit(0);
  1484. }
  1485. void CLogMsgManager::MsgProcessor::resetLimit()
  1486. {
  1487. droppingLimit = 0;
  1488. q.setLimit(0);
  1489. }
  1490. void CLogMsgManager::MsgProcessor::stop()
  1491. {
  1492. more = false;
  1493. q.stop();
  1494. }
  1495. void CLogMsgManager::MsgProcessor::drop()
  1496. {
  1497. Owned<LogMsg> msg, lastMsg;
  1498. unsigned count;
  1499. unsigned prev = 0;
  1500. for(count = 0; count < numToDrop; count++)
  1501. {
  1502. msg.setown(q.dequeueTail(0));
  1503. if(!msg) break;
  1504. DropLogMsg * dmsg = dynamic_cast<DropLogMsg *>(msg.get());
  1505. if(dmsg) prev += dmsg->queryCount()-1;
  1506. lastMsg.setown(msg.getClear());
  1507. }
  1508. if(lastMsg)
  1509. q.enqueue(new DropLogMsg(owner, lastMsg->querySysInfo().queryMsgID(), count+prev));
  1510. }
  1511. bool CLogMsgManager::MsgProcessor::flush(unsigned timeout)
  1512. {
  1513. unsigned start = msTick();
  1514. if(!q.waitMaxOrdinality(0, timeout))
  1515. return false;
  1516. unsigned now = msTick();
  1517. if(now >= (start+timeout))
  1518. return false;
  1519. try
  1520. {
  1521. synchronized block(pullCycleMutex, timeout+start-now);
  1522. }
  1523. catch(IException * e)
  1524. {
  1525. e->Release();
  1526. return false;
  1527. }
  1528. return true;
  1529. }
  1530. CLogMsgManager::~CLogMsgManager()
  1531. {
  1532. CriticalBlock crit(modeLock);
  1533. if(processor)
  1534. {
  1535. processor->stop();
  1536. processor->join();
  1537. }
  1538. }
  1539. LogMsgJobId CLogMsgManager::addJobId(const char *job)
  1540. {
  1541. LogMsgJobId ret = ++nextJobId;
  1542. pushMsg(new LogMsg(ret, job));
  1543. return ret;
  1544. }
  1545. void CLogMsgManager::removeJobId(LogMsgJobId id)
  1546. {
  1547. pushMsg(new LogMsg(id, nullptr));
  1548. }
  1549. const char * CLogMsgManager::queryJobId(LogMsgJobId id) const
  1550. {
  1551. // NOTE - thread safety is important here. We have to consider two things:
  1552. // 1. Whether an id (and therefore an entry in this table) can be invalidated between the return statement and someone using the result
  1553. // It is up to the calling application to ensure that it does not call removeJobId() on an ID that may still be being used for logging by another thread.
  1554. // 2. Whether the table lookup may coincide with a table add, and crash in getValue/setValue
  1555. // This is a non-issue in queueing mode as all gets/sets happen on a single thread, but we lock to be on the safe side
  1556. CriticalBlock b(jobIdLock);
  1557. StringAttr *found = jobIds.getValue(id);
  1558. return found ? found->get() : "invalid";
  1559. }
  1560. void CLogMsgManager::doAddJobId(LogMsgJobId id, const char *text) const
  1561. {
  1562. CriticalBlock b(jobIdLock);
  1563. jobIds.setValue(id, text);
  1564. }
  1565. void CLogMsgManager::doRemoveJobId(LogMsgJobId id) const
  1566. {
  1567. CriticalBlock b(jobIdLock);
  1568. jobIds.remove(id);
  1569. }
  1570. void CLogMsgManager::enterQueueingMode()
  1571. {
  1572. CriticalBlock crit(modeLock);
  1573. if(processor) return;
  1574. processor.setown(new MsgProcessor(this));
  1575. processor->setBlockingLimit(defaultMsgQueueLimit);
  1576. processor->start();
  1577. }
  1578. void CLogMsgManager::setQueueBlockingLimit(unsigned lim)
  1579. {
  1580. CriticalBlock crit(modeLock);
  1581. if(processor)
  1582. processor->setBlockingLimit(lim);
  1583. }
  1584. void CLogMsgManager::setQueueDroppingLimit(unsigned lim, unsigned numToDrop)
  1585. {
  1586. CriticalBlock crit(modeLock);
  1587. if(processor)
  1588. processor->setDroppingLimit(lim, numToDrop);
  1589. }
  1590. void CLogMsgManager::resetQueueLimit()
  1591. {
  1592. CriticalBlock crit(modeLock);
  1593. if(processor)
  1594. processor->resetLimit();
  1595. }
  1596. void CLogMsgManager::report(const LogMsgCategory & cat, const char * format, ...)
  1597. {
  1598. if(rejectsCategory(cat)) return;
  1599. va_list args;
  1600. va_start(args, format);
  1601. pushMsg(new LogMsg(cat, getNextID(), unknownJob, NoLogMsgCode, format, args, 0, port, session));
  1602. va_end(args);
  1603. }
  1604. void CLogMsgManager::report_va(const LogMsgCategory & cat, const char * format, va_list args)
  1605. {
  1606. if(rejectsCategory(cat)) return;
  1607. pushMsg(new LogMsg(cat, getNextID(), unknownJob, NoLogMsgCode, format, args, 0, port, session));
  1608. }
  1609. void CLogMsgManager::report(const LogMsgCategory & cat, LogMsgCode code, const char * format, ...)
  1610. {
  1611. if(rejectsCategory(cat)) return;
  1612. va_list args;
  1613. va_start(args, format);
  1614. pushMsg(new LogMsg(cat, getNextID(), unknownJob, code, format, args, 0, port, session));
  1615. va_end(args);
  1616. }
  1617. void CLogMsgManager::report_va(const LogMsgCategory & cat, LogMsgCode code, const char * format, va_list args)
  1618. {
  1619. if(rejectsCategory(cat)) return;
  1620. pushMsg(new LogMsg(cat, getNextID(), unknownJob, code, format, args, 0, port, session));
  1621. }
  1622. void CLogMsgManager::mreport_direct(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * msg)
  1623. {
  1624. if(rejectsCategory(cat)) return;
  1625. const char *cursor = msg;
  1626. const char *lineStart = cursor;
  1627. while (true)
  1628. {
  1629. switch (*cursor)
  1630. {
  1631. case '\0':
  1632. if (cursor != lineStart || cursor==msg)
  1633. pushMsg(new LogMsg(cat, getNextID(), job, NoLogMsgCode, (int)(cursor-lineStart), lineStart, compo, port, session));
  1634. return;
  1635. case '\r':
  1636. // NB: \r or \r\n translated into newline
  1637. pushMsg(new LogMsg(cat, getNextID(), job, NoLogMsgCode, (int)(cursor-lineStart), lineStart, compo, port, session));
  1638. if ('\n' == *(cursor+1))
  1639. cursor++;
  1640. lineStart = cursor+1;
  1641. break;
  1642. case '\n':
  1643. pushMsg(new LogMsg(cat, getNextID(), job, NoLogMsgCode, (int)(cursor-lineStart), lineStart, compo, port, session));
  1644. lineStart = cursor+1;
  1645. break;
  1646. }
  1647. ++cursor;
  1648. }
  1649. }
  1650. void CLogMsgManager::mreport_direct(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * msg)
  1651. {
  1652. mreport_direct(0, cat, job, msg);
  1653. }
  1654. void CLogMsgManager::mreport_va(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, va_list args)
  1655. {
  1656. if(rejectsCategory(cat)) return;
  1657. StringBuffer log;
  1658. log.limited_valist_appendf(1024*1024, format, args);
  1659. mreport_direct(compo, cat, job, log);
  1660. }
  1661. void CLogMsgManager::mreport_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, va_list args)
  1662. {
  1663. if(rejectsCategory(cat)) return;
  1664. StringBuffer log;
  1665. log.limited_valist_appendf(1024*1024, format, args);
  1666. mreport_direct(cat, job, log);
  1667. }
  1668. void CLogMsgManager::report(const LogMsgCategory & cat, const IException * exception, const char * prefix)
  1669. {
  1670. if(rejectsCategory(cat)) return;
  1671. StringBuffer buff;
  1672. if(prefix) buff.append(prefix).append(" : ");
  1673. exception->errorMessage(buff);
  1674. pushMsg(new LogMsg(cat, getNextID(), unknownJob, exception->errorCode(), buff.str(), 0, port, session));
  1675. }
  1676. void CLogMsgManager::report(unsigned compo, const LogMsgCategory & cat, const char * format, ...)
  1677. {
  1678. if(rejectsCategory(cat)) return;
  1679. va_list args;
  1680. va_start(args, format);
  1681. pushMsg(new LogMsg(cat, getNextID(), unknownJob, NoLogMsgCode, format, args, compo, port, session));
  1682. va_end(args);
  1683. }
  1684. void CLogMsgManager::report_va(unsigned compo, const LogMsgCategory & cat, const char * format, va_list args)
  1685. {
  1686. if(rejectsCategory(cat)) return;
  1687. pushMsg(new LogMsg(cat, getNextID(), unknownJob, NoLogMsgCode, format, args, compo, port, session));
  1688. }
  1689. void CLogMsgManager::report(unsigned compo, const LogMsgCategory & cat, LogMsgCode code, const char * format, ...)
  1690. {
  1691. if(rejectsCategory(cat)) return;
  1692. va_list args;
  1693. va_start(args, format);
  1694. pushMsg(new LogMsg(cat, getNextID(), unknownJob, code, format, args, compo, port, session));
  1695. va_end(args);
  1696. }
  1697. void CLogMsgManager::report_va(unsigned compo, const LogMsgCategory & cat, LogMsgCode code, const char * format, va_list args)
  1698. {
  1699. if(rejectsCategory(cat)) return;
  1700. pushMsg(new LogMsg(cat, getNextID(), unknownJob, code, format, args, compo, port, session));
  1701. }
  1702. void CLogMsgManager::report(unsigned compo, const LogMsgCategory & cat, const IException * exception, const char * prefix)
  1703. {
  1704. if(rejectsCategory(cat)) return;
  1705. StringBuffer buff;
  1706. if(prefix) buff.append(prefix).append(" : ");
  1707. exception->errorMessage(buff);
  1708. pushMsg(new LogMsg(cat, getNextID(), unknownJob, exception->errorCode(), buff.str(), compo, port, session));
  1709. }
  1710. void CLogMsgManager::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, ...)
  1711. {
  1712. if(rejectsCategory(cat)) return;
  1713. va_list args;
  1714. va_start(args, format);
  1715. pushMsg(new LogMsg(cat, getNextID(), job, NoLogMsgCode, format, args, 0, port, session));
  1716. va_end(args);
  1717. }
  1718. void CLogMsgManager::report_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, va_list args)
  1719. {
  1720. if(rejectsCategory(cat)) return;
  1721. pushMsg(new LogMsg(cat, getNextID(), job, NoLogMsgCode, format, args, 0, port, session));
  1722. }
  1723. void CLogMsgManager::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, ...)
  1724. {
  1725. if(rejectsCategory(cat)) return;
  1726. va_list args;
  1727. va_start(args, format);
  1728. pushMsg(new LogMsg(cat, getNextID(), job, code, format, args, 0, port, session));
  1729. va_end(args);
  1730. }
  1731. void CLogMsgManager::report_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, va_list args)
  1732. {
  1733. if(rejectsCategory(cat)) return;
  1734. pushMsg(new LogMsg(cat, getNextID(), job, code, format, args, 0, port, session));
  1735. }
  1736. void CLogMsgManager::report(const LogMsgCategory & cat, const LogMsgJobInfo & job, const IException * exception, const char * prefix)
  1737. {
  1738. if(rejectsCategory(cat)) return;
  1739. StringBuffer buff;
  1740. if(prefix) buff.append(prefix).append(" : ");
  1741. exception->errorMessage(buff);
  1742. pushMsg(new LogMsg(cat, getNextID(), job, exception->errorCode(), buff.str(), 0, port, session));
  1743. }
  1744. void CLogMsgManager::report(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, ...)
  1745. {
  1746. if(rejectsCategory(cat)) return;
  1747. va_list args;
  1748. va_start(args, format);
  1749. pushMsg(new LogMsg(cat, getNextID(), job, NoLogMsgCode, format, args, compo, port, session));
  1750. va_end(args);
  1751. }
  1752. void CLogMsgManager::report_va(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, va_list args)
  1753. {
  1754. if(rejectsCategory(cat)) return;
  1755. pushMsg(new LogMsg(cat, getNextID(), job, NoLogMsgCode, format, args, compo, port, session));
  1756. }
  1757. void CLogMsgManager::report(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, ...)
  1758. {
  1759. if(rejectsCategory(cat)) return;
  1760. va_list args;
  1761. va_start(args, format);
  1762. pushMsg(new LogMsg(cat, getNextID(), job, code, format, args, compo, port, session));
  1763. va_end(args);
  1764. }
  1765. void CLogMsgManager::report_va(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code, const char * format, va_list args)
  1766. {
  1767. if(rejectsCategory(cat)) return;
  1768. pushMsg(new LogMsg(cat, getNextID(), job, code, format, args, compo, port, session));
  1769. }
  1770. void CLogMsgManager::report(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, const IException * exception, const char * prefix)
  1771. {
  1772. if(rejectsCategory(cat)) return;
  1773. StringBuffer buff;
  1774. if(prefix) buff.append(prefix).append(" : ");
  1775. exception->errorMessage(buff);
  1776. pushMsg(new LogMsg(cat, getNextID(), job, exception->errorCode(), buff.str(), compo, port, session));
  1777. }
  1778. void CLogMsgManager::pushMsg(LogMsg * _msg)
  1779. {
  1780. Owned<LogMsg> msg(_msg);
  1781. if(processor)
  1782. processor->push(msg.getLink());
  1783. else
  1784. doReport(*msg);
  1785. }
  1786. void CLogMsgManager::doReport(const LogMsg & msg) const
  1787. {
  1788. try
  1789. {
  1790. switch (msg.queryCategory().queryClass())
  1791. {
  1792. case MSGCLS_addid:
  1793. doAddJobId(msg.queryJobInfo().queryJobID(), msg.queryText());
  1794. break;
  1795. case MSGCLS_removeid:
  1796. doRemoveJobId(msg.queryJobInfo().queryJobID());
  1797. break;
  1798. default:
  1799. ReadLockBlock block(monitorLock);
  1800. ForEachItemIn(i, monitors)
  1801. monitors.item(i).processMessage(msg);
  1802. break;
  1803. }
  1804. }
  1805. catch(IException * e)
  1806. {
  1807. StringBuffer err("exception reporting log message: ");
  1808. err.append(e->errorCode());
  1809. e->errorMessage(err);
  1810. panic(err.str());
  1811. e->Release();
  1812. }
  1813. catch(...)
  1814. {
  1815. panic("unknown exception reporting log message");
  1816. }
  1817. }
  1818. void CLogMsgManager::panic(char const * reason) const
  1819. {
  1820. fprintf(stderr, "%s", reason); // not sure there's anything more useful we can do here
  1821. }
  1822. offset_t CLogMsgManager::getLogPosition(StringBuffer &logFileName, const ILogMsgHandler * handler) const
  1823. {
  1824. if (processor)
  1825. processor->flush(10*1000);
  1826. WriteLockBlock block(monitorLock); // Prevents any incoming messages as we are doing this
  1827. return handler->getLogPosition(logFileName);
  1828. }
  1829. aindex_t CLogMsgManager::find(const ILogMsgHandler * handler) const
  1830. {
  1831. // N.B. Should be used inside critical block
  1832. ForEachItemIn(i, monitors)
  1833. if(monitors.item(i).queryHandler()==handler) return i;
  1834. return NotFound;
  1835. }
  1836. bool CLogMsgManager::addMonitor(ILogMsgHandler * handler, ILogMsgFilter * filter)
  1837. {
  1838. flushQueue(10*1000);
  1839. WriteLockBlock block(monitorLock);
  1840. if(find(handler) != NotFound) return false;
  1841. monitors.append(*(new LogMsgMonitor(filter, handler)));
  1842. prefilter.orWithFilter(filter);
  1843. sendFilterToChildren(true);
  1844. return true;
  1845. }
  1846. bool CLogMsgManager::addMonitorOwn(ILogMsgHandler * handler, ILogMsgFilter * filter)
  1847. {
  1848. bool ret = addMonitor(handler, filter);
  1849. filter->Release();
  1850. handler->Release();
  1851. return ret;
  1852. }
  1853. void CLogMsgManager::buildPrefilter()
  1854. {
  1855. // N.B. Should be used inside critical block
  1856. prefilter.reset();
  1857. ForEachItemIn(i, monitors)
  1858. prefilter.orWithFilter(monitors.item(i).queryFilter());
  1859. }
  1860. bool CLogMsgManager::removeMonitor(ILogMsgHandler * handler)
  1861. {
  1862. Linked<LogMsgMonitor> todelete;
  1863. {
  1864. WriteLockBlock block(monitorLock);
  1865. aindex_t pos = find(handler);
  1866. if(pos == NotFound) return false;
  1867. todelete.set(&monitors.item(pos));
  1868. monitors.remove(pos);
  1869. buildPrefilter();
  1870. sendFilterToChildren(true);
  1871. return true;
  1872. }
  1873. }
  1874. unsigned CLogMsgManager::removeMonitorsMatching(HandlerTest & test)
  1875. {
  1876. CIArrayOf<LogMsgMonitor> todelete; // delete outside monitorLock
  1877. unsigned count = 0;
  1878. {
  1879. WriteLockBlock block(monitorLock);
  1880. ForEachItemInRev(i, monitors)
  1881. if(test(monitors.item(i).queryHandler()))
  1882. {
  1883. LogMsgMonitor &it = monitors.item(i);
  1884. it.Link();
  1885. todelete.append(it);
  1886. monitors.remove(i);
  1887. ++count;
  1888. }
  1889. buildPrefilter();
  1890. sendFilterToChildren(true);
  1891. }
  1892. return count;
  1893. }
  1894. void CLogMsgManager::removeAllMonitors()
  1895. {
  1896. CIArrayOf<LogMsgMonitor> todelete; // delete outside monitorLock
  1897. {
  1898. WriteLockBlock block(monitorLock);
  1899. ForEachItemInRev(i, monitors) {
  1900. LogMsgMonitor &it = monitors.item(i);
  1901. it.Link();
  1902. todelete.append(it);
  1903. monitors.remove(i);
  1904. }
  1905. prefilter.reset();
  1906. sendFilterToChildren(true);
  1907. }
  1908. }
  1909. void CLogMsgManager::resetMonitors()
  1910. {
  1911. suspendChildren();
  1912. removeAllMonitors();
  1913. Owned<ILogMsgFilter> defaultFilter = getDefaultLogMsgFilter();
  1914. addMonitor(theStderrHandler, defaultFilter);
  1915. unsuspendChildren();
  1916. }
  1917. ILogMsgFilter * CLogMsgManager::queryMonitorFilter(const ILogMsgHandler * handler) const
  1918. {
  1919. ReadLockBlock block(monitorLock);
  1920. aindex_t pos = find(handler);
  1921. if(pos == NotFound) return 0;
  1922. return monitors.item(pos).queryFilter();
  1923. }
  1924. bool CLogMsgManager::changeMonitorFilter(const ILogMsgHandler * handler, ILogMsgFilter * newFilter)
  1925. {
  1926. WriteLockBlock block(monitorLock);
  1927. aindex_t pos = find(handler);
  1928. if(pos == NotFound) return 0;
  1929. monitors.item(pos).setFilter(newFilter);
  1930. buildPrefilter();
  1931. sendFilterToChildren(true);
  1932. return true;
  1933. }
  1934. void CLogMsgManager::prepAllHandlers() const
  1935. {
  1936. ReadLockBlock block(monitorLock);
  1937. ForEachItemIn(i, monitors)
  1938. if(monitors.item(i).queryHandler()->needsPrep()) monitors.item(i).queryHandler()->prep();
  1939. }
  1940. aindex_t CLogMsgManager::findChild(ILogMsgLinkToChild * child) const
  1941. {
  1942. ForEachItemIn(i, children)
  1943. if(&(children.item(i)) == child ) return i;
  1944. return NotFound;
  1945. }
  1946. ILogMsgFilter * CLogMsgManager::getCompoundFilter(bool locked) const
  1947. {
  1948. if(!locked) monitorLock.lockRead();
  1949. Owned<CategoryLogMsgFilter> categoryFilter = new CategoryLogMsgFilter(0, 0, 0, false);
  1950. Owned<ILogMsgFilter> otherFilters;
  1951. ILogMsgFilter * ifilter;
  1952. bool hadCat = false;
  1953. ForEachItemIn(i, monitors)
  1954. {
  1955. ifilter = monitors.item(i).queryFilter();
  1956. if(ifilter->queryLocalFlag()) continue;
  1957. if(ifilter->isCategoryFilter())
  1958. {
  1959. categoryFilter->orWithFilter(ifilter);
  1960. hadCat = true;
  1961. }
  1962. else
  1963. {
  1964. if(otherFilters)
  1965. otherFilters.setown(getOrLogMsgFilter(otherFilters, ifilter));
  1966. else
  1967. otherFilters.set(ifilter);
  1968. }
  1969. }
  1970. if(hadCat)
  1971. {
  1972. if(otherFilters)
  1973. otherFilters.setown(getOrLogMsgFilter(otherFilters, categoryFilter));
  1974. else
  1975. otherFilters.set(categoryFilter);
  1976. }
  1977. if(!locked) monitorLock.unlock();
  1978. if(!otherFilters)
  1979. return getPassNoneLogMsgFilter();
  1980. return otherFilters.getLink();
  1981. }
  1982. void CLogMsgManager::sendFilterToChildren(bool locked) const
  1983. {
  1984. if(suspendedChildren) return;
  1985. ReadLockBlock block(childLock);
  1986. if(children.length()==0) return;
  1987. ILogMsgFilter * filter = getCompoundFilter(locked);
  1988. ForEachItemIn(i, children)
  1989. children.item(i).sendFilter(filter);
  1990. filter->Release();
  1991. }
  1992. bool CLogMsgManager::addMonitorToPTree(const ILogMsgHandler * handler, IPropertyTree * tree) const
  1993. {
  1994. ReadLockBlock block(monitorLock);
  1995. aindex_t pos = find(handler);
  1996. if(pos == NotFound) return false;
  1997. monitors.item(pos).addToPTree(tree);
  1998. return true;
  1999. }
  2000. void CLogMsgManager::addAllMonitorsToPTree(IPropertyTree * tree) const
  2001. {
  2002. ReadLockBlock block(monitorLock);
  2003. ForEachItemIn(i, monitors)
  2004. monitors.item(i).addToPTree(tree);
  2005. }
  2006. bool CLogMsgManager::rejectsCategory(const LogMsgCategory & cat) const
  2007. {
  2008. if (!prefilter.includeCategory(cat))
  2009. return true;
  2010. ReadLockBlock block(monitorLock);
  2011. ForEachItemIn(i, monitors)
  2012. {
  2013. if (monitors.item(i).queryFilter()->mayIncludeCategory(cat))
  2014. return false;
  2015. }
  2016. return true;
  2017. }
  2018. // Helper functions
  2019. ILogMsgFilter * getDeserializedLogMsgFilter(MemoryBuffer & in)
  2020. {
  2021. unsigned type;
  2022. in.read(type);
  2023. switch(type)
  2024. {
  2025. case MSGFILTER_passall : return LINK(thePassAllFilter);
  2026. case MSGFILTER_passlocal : return LINK(thePassLocalFilter);
  2027. case MSGFILTER_passnone : return LINK(thePassNoneFilter);
  2028. case MSGFILTER_category : return new CategoryLogMsgFilter(in);
  2029. case MSGFILTER_pid : return new PIDLogMsgFilter(in);
  2030. case MSGFILTER_tid : return new TIDLogMsgFilter(in);
  2031. case MSGFILTER_node : return new NodeLogMsgFilter(in);
  2032. case MSGFILTER_ip : return new IpLogMsgFilter(in);
  2033. case MSGFILTER_session : return new SessionLogMsgFilter(in);
  2034. case MSGFILTER_component : return new ComponentLogMsgFilter(in);
  2035. case MSGFILTER_regex : return new RegexLogMsgFilter(in);
  2036. case MSGFILTER_not : return new NotLogMsgFilter(in);
  2037. case MSGFILTER_and : return new AndLogMsgFilter(in);
  2038. case MSGFILTER_or : return new OrLogMsgFilter(in);
  2039. case MSGFILTER_switch : return new SwitchLogMsgFilter(in);
  2040. default: assertex(!"getDeserializedLogMsgFilter: unrecognized LogMsgFilterType");
  2041. }
  2042. return 0;
  2043. }
  2044. ILogMsgFilter * getLogMsgFilterFromPTree(IPropertyTree * xml)
  2045. {
  2046. /* Note that several of these constructors use GetPropInt and GetPropInt64 to get unsigneds. I think this is OK? (all int64 internally)*/
  2047. StringBuffer type;
  2048. xml->getProp("@type", type);
  2049. if(strcmp(type.str(), "all")==0) return LINK(thePassAllFilter);
  2050. else if(strcmp(type.str(), "local")==0) return LINK(thePassLocalFilter);
  2051. else if(strcmp(type.str(), "none")==0) return LINK(thePassNoneFilter);
  2052. else if(strcmp(type.str(), "category")==0) return new CategoryLogMsgFilter(xml);
  2053. else if(strcmp(type.str(), "pid")==0) return new PIDLogMsgFilter(xml);
  2054. else if(strcmp(type.str(), "tid")==0) return new TIDLogMsgFilter(xml);
  2055. else if(strcmp(type.str(), "node")==0) return new NodeLogMsgFilter(xml);
  2056. else if(strcmp(type.str(), "ip")==0) return new IpLogMsgFilter(xml);
  2057. else if(strcmp(type.str(), "session")==0) return new SessionLogMsgFilter(xml);
  2058. else if(strcmp(type.str(), "component")==0) return new ComponentLogMsgFilter(xml);
  2059. else if(strcmp(type.str(), "regex")==0) return new RegexLogMsgFilter(xml);
  2060. else if(strcmp(type.str(), "not")==0) return new NotLogMsgFilter(xml);
  2061. else if(strcmp(type.str(), "and")==0) return new AndLogMsgFilter(xml);
  2062. else if(strcmp(type.str(), "or")==0) return new OrLogMsgFilter(xml);
  2063. else if(strcmp(type.str(), "filter")==0) return new SwitchLogMsgFilter(xml);
  2064. else assertex(!"getLogMsgFilterFromPTree : unrecognized LogMsgFilter type");
  2065. return getPassAllLogMsgFilter();
  2066. }
  2067. ILogMsgFilter * getDefaultLogMsgFilter()
  2068. {
  2069. return new CategoryLogMsgFilter(MSGAUD_all, MSGCLS_all, DefaultDetail, true);
  2070. }
  2071. ILogMsgFilter * getPassAllLogMsgFilter()
  2072. {
  2073. return LINK(thePassAllFilter);
  2074. }
  2075. ILogMsgFilter * getLocalLogMsgFilter()
  2076. {
  2077. return LINK(thePassLocalFilter);
  2078. }
  2079. ILogMsgFilter * getPassNoneLogMsgFilter()
  2080. {
  2081. return LINK(thePassNoneFilter);
  2082. }
  2083. ILogMsgFilter * queryPassAllLogMsgFilter()
  2084. {
  2085. return thePassAllFilter;
  2086. }
  2087. ILogMsgFilter * queryLocalLogMsgFilter()
  2088. {
  2089. return thePassLocalFilter;
  2090. }
  2091. ILogMsgFilter * queryPassNoneLogMsgFilter()
  2092. {
  2093. return thePassNoneFilter;
  2094. }
  2095. ILogMsgFilter * getCategoryLogMsgFilter(unsigned audiences, unsigned classes, LogMsgDetail maxDetail, bool local)
  2096. {
  2097. if((audiences==MSGAUD_all) && (classes==MSGCLS_all) && (maxDetail==TopDetail))
  2098. {
  2099. if(local)
  2100. return LINK(thePassLocalFilter);
  2101. else
  2102. return LINK(thePassAllFilter);
  2103. }
  2104. return new CategoryLogMsgFilter(audiences, classes, maxDetail, local);
  2105. }
  2106. ILogMsgFilter * getPIDLogMsgFilter(unsigned pid, bool local)
  2107. {
  2108. return new PIDLogMsgFilter(pid, local);
  2109. }
  2110. ILogMsgFilter * getTIDLogMsgFilter(unsigned tid, bool local)
  2111. {
  2112. return new TIDLogMsgFilter(tid, local);
  2113. }
  2114. ILogMsgFilter * getNodeLogMsgFilter(const char * name, unsigned port, bool local)
  2115. {
  2116. return new NodeLogMsgFilter(name, port, local);
  2117. }
  2118. ILogMsgFilter * getNodeLogMsgFilter(const IpAddress & ip, unsigned port, bool local)
  2119. {
  2120. return new NodeLogMsgFilter(ip, port, local);
  2121. }
  2122. ILogMsgFilter * getNodeLogMsgFilter(unsigned port, bool local)
  2123. {
  2124. return new NodeLogMsgFilter(port, local);
  2125. }
  2126. ILogMsgFilter * getIpLogMsgFilter(const char * name, bool local)
  2127. {
  2128. return new IpLogMsgFilter(name, local);
  2129. }
  2130. ILogMsgFilter * getIpLogMsgFilter(const IpAddress & ip, bool local)
  2131. {
  2132. return new IpLogMsgFilter(ip, local);
  2133. }
  2134. ILogMsgFilter * getIpLogMsgFilter(bool local)
  2135. {
  2136. return new IpLogMsgFilter(local);
  2137. }
  2138. ILogMsgFilter * getSessionLogMsgFilter(LogMsgSessionId session, bool local)
  2139. {
  2140. return new SessionLogMsgFilter(session, local);
  2141. }
  2142. ILogMsgFilter * getComponentLogMsgFilter(unsigned component, bool local)
  2143. {
  2144. return new ComponentLogMsgFilter(component, local);
  2145. }
  2146. ILogMsgFilter * getRegexLogMsgFilter(const char *regex, bool local)
  2147. {
  2148. return new RegexLogMsgFilter(regex, local);
  2149. }
  2150. ILogMsgFilter * getNotLogMsgFilter(ILogMsgFilter * arg)
  2151. {
  2152. return new NotLogMsgFilter(arg);
  2153. }
  2154. ILogMsgFilter * getNotLogMsgFilterOwn(ILogMsgFilter * arg)
  2155. {
  2156. ILogMsgFilter * ret = new NotLogMsgFilter(arg);
  2157. arg->Release();
  2158. return ret;
  2159. }
  2160. ILogMsgFilter * getAndLogMsgFilter(ILogMsgFilter * arg1, ILogMsgFilter * arg2)
  2161. {
  2162. return new AndLogMsgFilter(arg1, arg2);
  2163. }
  2164. ILogMsgFilter * getAndLogMsgFilterOwn(ILogMsgFilter * arg1, ILogMsgFilter * arg2)
  2165. {
  2166. ILogMsgFilter * ret = new AndLogMsgFilter(arg1, arg2);
  2167. arg1->Release();
  2168. arg2->Release();
  2169. return ret;
  2170. }
  2171. ILogMsgFilter * getOrLogMsgFilter(ILogMsgFilter * arg1, ILogMsgFilter * arg2)
  2172. {
  2173. return new OrLogMsgFilter(arg1, arg2);
  2174. }
  2175. ILogMsgFilter * getOrLogMsgFilterOwn(ILogMsgFilter * arg1, ILogMsgFilter * arg2)
  2176. {
  2177. ILogMsgFilter * ret = new OrLogMsgFilter(arg1, arg2);
  2178. arg1->Release();
  2179. arg2->Release();
  2180. return ret;
  2181. }
  2182. ILogMsgFilter * getSwitchLogMsgFilterOwn(ILogMsgFilter * switchFilter, ILogMsgFilter * yesFilter, ILogMsgFilter * noFilter)
  2183. {
  2184. ILogMsgFilter * ret = new SwitchLogMsgFilter(switchFilter, yesFilter, noFilter);
  2185. switchFilter->Release();
  2186. yesFilter->Release();
  2187. noFilter->Release();
  2188. return ret;
  2189. }
  2190. ILogMsgHandler * getHandleLogMsgHandler(FILE * handle, unsigned fields, bool writeXML)
  2191. {
  2192. if(writeXML)
  2193. return new HandleLogMsgHandlerXML(handle, fields);
  2194. return new HandleLogMsgHandlerTable(handle, fields);
  2195. }
  2196. ILogMsgHandler * getFileLogMsgHandler(const char * filename, const char * headertext, unsigned fields, bool writeXML, bool append, bool flushes)
  2197. {
  2198. if(writeXML)
  2199. return new FileLogMsgHandlerXML(filename, headertext, fields, append, flushes);
  2200. return new FileLogMsgHandlerTable(filename, headertext, fields, append, flushes);
  2201. }
  2202. ILogMsgHandler * getRollingFileLogMsgHandler(const char * filebase, const char * fileextn, unsigned fields, bool append, bool flushes, const char *initialName, const char *alias, bool daily, long maxLogSize)
  2203. {
  2204. return new RollingFileLogMsgHandler(filebase, fileextn, fields, append, flushes, initialName, alias, daily, maxLogSize);
  2205. }
  2206. ILogMsgHandler * getBinLogMsgHandler(const char * filename, bool append)
  2207. {
  2208. return new BinLogMsgHandler(filename, append);
  2209. }
  2210. ILogMsgHandler * getPostMortemLogMsgHandler(const char * filebase, unsigned maxLinesToKeep, unsigned messageFields)
  2211. {
  2212. return new PostMortemLogMsgHandler(filebase, maxLinesToKeep, messageFields);
  2213. }
  2214. void installLogMsgFilterSwitch(ILogMsgHandler * handler, ILogMsgFilter * switchFilter, ILogMsgFilter * newFilter)
  2215. {
  2216. queryLogMsgManager()->changeMonitorFilterOwn(handler, getSwitchLogMsgFilterOwn(switchFilter, newFilter, queryLogMsgManager()->getMonitorFilter(handler)));
  2217. }
  2218. ILogMsgHandler * getLogMsgHandlerFromPTree(IPropertyTree * tree)
  2219. {
  2220. StringBuffer type;
  2221. tree->getProp("@type", type);
  2222. unsigned fields = MSGFIELD_all;
  2223. char const * fstr = tree->queryProp("@fields");
  2224. if(fstr)
  2225. {
  2226. if(isdigit(fstr[0]))
  2227. fields = atoi(fstr);
  2228. else
  2229. fields = logMsgFieldsFromAbbrevs(fstr);
  2230. }
  2231. if(strcmp(type.str(), "stderr")==0)
  2232. return getHandleLogMsgHandler(stderr, fields, tree->hasProp("@writeXML"));
  2233. else if(strcmp(type.str(), "file")==0)
  2234. {
  2235. StringBuffer filename;
  2236. tree->getProp("@filename", filename);
  2237. if(tree->hasProp("@headertext"))
  2238. {
  2239. StringBuffer headertext;
  2240. tree->getProp("@headertext", headertext);
  2241. return getFileLogMsgHandler(filename.str(), headertext.str(), fields, !(tree->hasProp("@writeTable")), tree->hasProp("@append"), tree->hasProp("@flushes"));
  2242. }
  2243. else
  2244. return getFileLogMsgHandler(filename.str(), 0, fields, !(tree->hasProp("@writeTable")), tree->hasProp("@append"), tree->hasProp("@flushes"));
  2245. }
  2246. else if(strcmp(type.str(), "binary")==0)
  2247. {
  2248. StringBuffer filename;
  2249. tree->getProp("@filename", filename);
  2250. return getBinLogMsgHandler(filename.str(), tree->hasProp("@append"));
  2251. }
  2252. else assertex(!"getLogMsgFilterFromPTree : unrecognized LogMsgHandler type");
  2253. return LINK(theStderrHandler);
  2254. }
  2255. ILogMsgHandler * attachStandardFileLogMsgMonitor(const char * filename, const char * headertext, unsigned fields, unsigned audiences, unsigned classes, LogMsgDetail detail, bool writeXML, bool append, bool flushes, bool local)
  2256. {
  2257. #ifdef FILE_LOG_ENABLES_QUEUEUING
  2258. queryLogMsgManager()->enterQueueingMode();
  2259. #endif
  2260. ILogMsgFilter * filter = getCategoryLogMsgFilter(audiences, classes, detail, local);
  2261. ILogMsgHandler * handler = getFileLogMsgHandler(filename, headertext, fields, writeXML, append, flushes);
  2262. queryLogMsgManager()->addMonitorOwn(handler, filter);
  2263. return handler;
  2264. }
  2265. ILogMsgHandler * attachStandardBinLogMsgMonitor(const char * filename, unsigned audiences, unsigned classes, LogMsgDetail detail, bool append, bool local)
  2266. {
  2267. #ifdef FILE_LOG_ENABLES_QUEUEUING
  2268. queryLogMsgManager()->enterQueueingMode();
  2269. #endif
  2270. ILogMsgFilter * filter = getCategoryLogMsgFilter(audiences, classes, detail, local);
  2271. ILogMsgHandler * handler = getBinLogMsgHandler(filename, append);
  2272. queryLogMsgManager()->addMonitorOwn(handler, filter);
  2273. return handler;
  2274. }
  2275. ILogMsgHandler * attachStandardHandleLogMsgMonitor(FILE * handle, unsigned fields, unsigned audiences, unsigned classes, LogMsgDetail detail, bool writeXML, bool local)
  2276. {
  2277. ILogMsgFilter * filter = getCategoryLogMsgFilter(audiences, classes, detail, local);
  2278. ILogMsgHandler * handler = getHandleLogMsgHandler(handle, fields, writeXML);
  2279. queryLogMsgManager()->addMonitorOwn(handler, filter);
  2280. return handler;
  2281. }
  2282. ILogMsgHandler * attachLogMsgMonitorFromPTree(IPropertyTree * tree)
  2283. {
  2284. Owned<IPropertyTree> handlertree = tree->getPropTree("handler");
  2285. Owned<IPropertyTree> filtertree = tree->getPropTree("filter");
  2286. ILogMsgHandler * handler = getLogMsgHandlerFromPTree(handlertree);
  2287. ILogMsgFilter * filter = getLogMsgFilterFromPTree(filtertree);
  2288. queryLogMsgManager()->addMonitorOwn(handler, filter);
  2289. return handler;
  2290. }
  2291. void attachManyLogMsgMonitorsFromPTree(IPropertyTree * tree)
  2292. {
  2293. Owned<IPropertyTreeIterator> iter = tree->getElements("monitor");
  2294. ForEach(*iter)
  2295. attachLogMsgMonitorFromPTree(&(iter->query()));
  2296. }
  2297. // Calls to make, remove, and return the manager, standard handler, pass all/none filters, reporter array
  2298. LogMsgComponentReporter * theReporters[MSGCOMP_NUMBER];
  2299. class CNullManager : implements ILogMsgManager
  2300. {
  2301. public:
  2302. // IInterface impl.
  2303. virtual void Link() const override {}
  2304. virtual bool Release() const override { return false; }
  2305. // ILogMsgListener impl.
  2306. virtual bool addMonitor(ILogMsgHandler * handler, ILogMsgFilter * filter) override { return true; }
  2307. virtual bool addMonitorOwn(ILogMsgHandler * handler, ILogMsgFilter * filter) override { return true; }
  2308. virtual bool removeMonitor(ILogMsgHandler * handler) override { return true; }
  2309. virtual unsigned removeMonitorsMatching(HandlerTest & test) override { return 0; }
  2310. virtual void removeAllMonitors() override {}
  2311. virtual bool isActiveMonitor(const ILogMsgHandler * handler) const override { return false; }
  2312. virtual ILogMsgFilter * queryMonitorFilter(const ILogMsgHandler * handler) const override { return nullptr; }
  2313. virtual ILogMsgFilter * getMonitorFilter(const ILogMsgHandler * handler) const override { return nullptr; }
  2314. virtual bool changeMonitorFilter(const ILogMsgHandler * handler, ILogMsgFilter * newFilter) override { return true; }
  2315. virtual bool changeMonitorFilterOwn(const ILogMsgHandler * handler, ILogMsgFilter * newFilter) override { return true; }
  2316. virtual void prepAllHandlers() const override {}
  2317. virtual void addChildOwn(ILogMsgLinkToChild * child) override {}
  2318. virtual void removeChild(ILogMsgLinkToChild * child) override {}
  2319. virtual void removeAllChildren() override {}
  2320. virtual ILogMsgFilter * getCompoundFilter(bool locked = false) const override { return nullptr; }
  2321. virtual void suspendChildren() override {}
  2322. virtual void unsuspendChildren() override {}
  2323. virtual bool addMonitorToPTree(const ILogMsgHandler * handler, IPropertyTree * tree) const override { return true; }
  2324. virtual void addAllMonitorsToPTree(IPropertyTree * tree) const override {}
  2325. virtual void setPort(unsigned _port) override {}
  2326. virtual unsigned queryPort() const override { return 0; }
  2327. virtual void setSession(LogMsgSessionId _session) override {}
  2328. virtual LogMsgSessionId querySession() const override { return 0; }
  2329. // ILogMsgManager impl.
  2330. virtual void enterQueueingMode() override {}
  2331. virtual void setQueueBlockingLimit(unsigned lim) override {}
  2332. virtual void setQueueDroppingLimit(unsigned lim, unsigned numToDrop) override {}
  2333. virtual void resetQueueLimit() override {}
  2334. virtual bool flushQueue(unsigned timeout) override { return true; }
  2335. virtual void resetMonitors() override {}
  2336. virtual void report(const LogMsgCategory & cat, const char * format, ...) override {}
  2337. virtual void report_va(const LogMsgCategory & cat, const char * format, va_list args) override {}
  2338. virtual void report(const LogMsgCategory & cat, LogMsgCode code , const char * format, ...) override {}
  2339. virtual void report_va(const LogMsgCategory & cat, LogMsgCode code , const char * format, va_list args) override {}
  2340. virtual void report(const LogMsgCategory & cat, const IException * e, const char * prefix = NULL) override {}
  2341. virtual void report(unsigned compo, const LogMsgCategory & cat, const char * format, ...) override {}
  2342. virtual void report_va(unsigned compo, const LogMsgCategory & cat, const char * format, va_list args) override {}
  2343. virtual void report(unsigned compo, const LogMsgCategory & cat, LogMsgCode code , const char * format, ...) override {}
  2344. virtual void report_va(unsigned compo, const LogMsgCategory & cat, LogMsgCode code , const char * format, va_list args) override {}
  2345. virtual void report(unsigned compo, const LogMsgCategory & cat, const IException * e, const char * prefix = NULL) override {}
  2346. virtual void report(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, ...) override {}
  2347. virtual void report_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, va_list args) override {}
  2348. virtual void report(const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code , const char * format, ...) override {}
  2349. virtual void report_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code , const char * format, va_list args) override {}
  2350. virtual void report(const LogMsgCategory & cat, const LogMsgJobInfo & job, const IException * e, const char * prefix = NULL) override {}
  2351. virtual void report(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, ...) override {}
  2352. virtual void report_va(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, va_list args) override {}
  2353. virtual void report(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code , const char * format, ...) override {}
  2354. virtual void report_va(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, LogMsgCode code , const char * format, va_list args) override {}
  2355. virtual void report(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, const IException * e, const char * prefix = NULL) override {}
  2356. virtual void mreport_direct(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * msg) override {}
  2357. virtual void mreport_direct(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * msg) override {}
  2358. virtual void mreport_va(unsigned compo, const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, va_list args) override {}
  2359. virtual void mreport_va(const LogMsgCategory & cat, const LogMsgJobInfo & job, const char * format, va_list args) override {}
  2360. virtual void report(const LogMsg & msg) const override {}
  2361. virtual LogMsgId getNextID() override { return 0; }
  2362. virtual bool rejectsCategory(const LogMsgCategory & cat) const override { return true; }
  2363. virtual offset_t getLogPosition(StringBuffer &logFileName, const ILogMsgHandler * handler) const override { return 0; }
  2364. virtual LogMsgJobId addJobId(const char *job) override { return 0; }
  2365. virtual void removeJobId(LogMsgJobId) override {}
  2366. virtual const char * queryJobId(LogMsgJobId id) const override { return ""; }
  2367. };
  2368. static CNullManager nullManager;
  2369. static Singleton<IRemoteLogAccess> logAccessor;
  2370. static CriticalSection logAccessCrit;
  2371. MODULE_INIT(INIT_PRIORITY_JLOG)
  2372. {
  2373. thePassAllFilter = new PassAllLogMsgFilter();
  2374. thePassLocalFilter = new PassLocalLogMsgFilter();
  2375. thePassNoneFilter = new PassNoneLogMsgFilter();
  2376. theStderrHandler = new HandleLogMsgHandlerTable(stderr, MSGFIELD_STANDARD);
  2377. theSysLogEventLogger = new CSysLogEventLogger;
  2378. theManager = new CLogMsgManager();
  2379. theManager->resetMonitors();
  2380. for(unsigned compo = 0; compo<MSGCOMP_NUMBER; compo++)
  2381. theReporters[compo] = new LogMsgComponentReporter(compo);
  2382. return true;
  2383. }
  2384. MODULE_EXIT()
  2385. {
  2386. for(unsigned compo = 0; compo<MSGCOMP_NUMBER; compo++)
  2387. {
  2388. delete theReporters[compo];
  2389. theReporters[compo] = NULL;
  2390. }
  2391. ::Release(theManager);
  2392. theManager = &nullManager;
  2393. delete theSysLogEventLogger;
  2394. delete theStderrHandler;
  2395. delete thePassNoneFilter;
  2396. delete thePassLocalFilter;
  2397. delete thePassAllFilter;
  2398. theSysLogEventLogger = nullptr;
  2399. theStderrHandler = nullptr;
  2400. thePassNoneFilter = nullptr;
  2401. thePassLocalFilter = nullptr;
  2402. thePassAllFilter = nullptr;
  2403. delete logAccessor.queryExisting();
  2404. }
  2405. static constexpr const char * logFieldsAtt = "@fields";
  2406. static constexpr const char * logMsgDetailAtt = "@detail";
  2407. static constexpr const char * logMsgAudiencesAtt = "@audiences";
  2408. static constexpr const char * logMsgClassesAtt = "@classes";
  2409. static constexpr const char * useLogQueueAtt = "@useLogQueue";
  2410. static constexpr const char * logQueueLenAtt = "@queueLen";
  2411. static constexpr const char * logQueueDropAtt = "@queueDrop";
  2412. static constexpr const char * logDisabledAtt = "@disabled";
  2413. static constexpr const char * useSysLogpAtt ="@enableSysLog";
  2414. static constexpr const char * capturePostMortemAtt ="@postMortem";
  2415. #ifdef _DEBUG
  2416. static constexpr bool useQueueDefault = false;
  2417. #else
  2418. static constexpr bool useQueueDefault = true;
  2419. #endif
  2420. static constexpr unsigned queueLenDefault = 512;
  2421. static constexpr unsigned queueDropDefault = 32;
  2422. static constexpr bool useSysLogDefault = false;
  2423. void setupContainerizedLogMsgHandler()
  2424. {
  2425. Owned<IPropertyTree> logConfig = getComponentConfigSP()->getPropTree("logging");
  2426. if (logConfig)
  2427. {
  2428. if (logConfig->getPropBool(logDisabledAtt, false))
  2429. {
  2430. removeLog();
  2431. return;
  2432. }
  2433. if (logConfig->hasProp(logFieldsAtt))
  2434. {
  2435. //Supported logging fields: AUD,CLS,DET,MID,TIM,DAT,PID,TID,NOD,JOB,USE,SES,COD,MLT,MCT,NNT,COM,QUO,PFX,ALL,STD
  2436. const char *logFields = logConfig->queryProp(logFieldsAtt);
  2437. if (!isEmptyString(logFields))
  2438. theStderrHandler->setMessageFields(logMsgFieldsFromAbbrevs(logFields));
  2439. }
  2440. //Only recreate filter if at least one filter attribute configured
  2441. if (logConfig->hasProp(logMsgDetailAtt) || logConfig->hasProp(logMsgAudiencesAtt) || logConfig->hasProp(logMsgClassesAtt))
  2442. {
  2443. LogMsgDetail logDetail = logConfig->getPropInt(logMsgDetailAtt, DefaultDetail);
  2444. unsigned msgClasses = MSGCLS_all;
  2445. const char *logClasses = logConfig->queryProp(logMsgClassesAtt);
  2446. if (!isEmptyString(logClasses))
  2447. msgClasses = logMsgClassesFromAbbrevs(logClasses);
  2448. unsigned msgAudiences = MSGAUD_all;
  2449. const char *logAudiences = logConfig->queryProp(logMsgAudiencesAtt);
  2450. if (!isEmptyString(logAudiences))
  2451. msgAudiences = logMsgAudsFromAbbrevs(logAudiences);
  2452. const bool local = true; // Do not include remote messages from other components
  2453. Owned<ILogMsgFilter> filter = getCategoryLogMsgFilter(msgAudiences, msgClasses, logDetail, local);
  2454. theManager->changeMonitorFilter(theStderrHandler, filter);
  2455. }
  2456. bool useLogQueue = logConfig->getPropBool(useLogQueueAtt, useQueueDefault);
  2457. if (useLogQueue)
  2458. {
  2459. unsigned queueLen = logConfig->getPropInt(logQueueLenAtt, queueLenDefault);
  2460. unsigned queueDrop = logConfig->getPropInt(logQueueDropAtt, queueDropDefault);
  2461. queryLogMsgManager()->enterQueueingMode();
  2462. queryLogMsgManager()->setQueueDroppingLimit(queueLen, queueDrop);
  2463. }
  2464. if (logConfig->getPropBool(useSysLogpAtt, useSysLogDefault))
  2465. UseSysLogForOperatorMessages();
  2466. unsigned postMortemLines = logConfig->getPropInt(capturePostMortemAtt, 0);
  2467. if (postMortemLines)
  2468. {
  2469. ILogMsgHandler *fileMsgHandler = getPostMortemLogMsgHandler("/tmp/postmortem.log", postMortemLines, MSGFIELD_STANDARD);
  2470. queryLogMsgManager()->addMonitorOwn(fileMsgHandler, getCategoryLogMsgFilter(MSGAUD_all, MSGCLS_all, TopDetail));
  2471. }
  2472. }
  2473. }
  2474. ILogMsgManager * queryLogMsgManager()
  2475. {
  2476. return theManager;
  2477. }
  2478. ILogMsgHandler * queryStderrLogMsgHandler()
  2479. {
  2480. return theStderrHandler;
  2481. }
  2482. LogMsgComponentReporter * queryLogMsgComponentReporter(unsigned compo)
  2483. {
  2484. return theReporters[compo];
  2485. }
  2486. ILogMsgManager * createLogMsgManager() // use with care! (needed by mplog listener facility)
  2487. {
  2488. return new CLogMsgManager();
  2489. }
  2490. // Event Logging
  2491. ISysLogEventLogger * querySysLogEventLogger()
  2492. {
  2493. return theSysLogEventLogger;
  2494. }
  2495. ILogMsgHandler * getSysLogMsgHandler(unsigned fields)
  2496. {
  2497. return new SysLogMsgHandler(theSysLogEventLogger, fields);
  2498. }
  2499. #ifdef _WIN32
  2500. #include <WINNT.H>
  2501. #include "jelog.h"
  2502. struct AuditTypeWin32Data
  2503. {
  2504. public:
  2505. unsigned eventtype;
  2506. unsigned categoryid;
  2507. unsigned eventid;
  2508. };
  2509. #define CATEGORY_AUDIT_FUNCTION_REQUIRED
  2510. #define AUDIT_TYPES_BEGIN AuditTypeWin32Data auditTypeDataMap[NUM_AUDIT_TYPES+1] = {
  2511. #define MAKE_AUDIT_TYPE(name, type, categoryid, eventid, level) {type, categoryid, eventid},
  2512. #define AUDIT_TYPES_END {0, 0, 0} };
  2513. #include "jelogtype.hpp"
  2514. #undef CATEGORY_AUDIT_FUNCTION_REQUIRED
  2515. #undef AUDIT_TYPES_BEGIN
  2516. #undef MAKE_AUDIT_TYPE
  2517. #undef AUDIT_TYPES_END
  2518. CSysLogEventLogger::CSysLogEventLogger() : hEventLog(0)
  2519. {
  2520. }
  2521. bool CSysLogEventLogger::log(AuditType auditType, char const * msg, size32_t datasize, void const * data)
  2522. {
  2523. assertex(auditType < NUM_AUDIT_TYPES);
  2524. AuditTypeWin32Data const & typeData = auditTypeDataMap[auditType];
  2525. return win32Report(typeData.eventtype, typeData.categoryid, typeData.eventid, msg, datasize, data);
  2526. }
  2527. bool CSysLogEventLogger::win32Report(unsigned eventtype, unsigned category, unsigned eventid, const char * msg, size32_t datasize, const void * data)
  2528. {
  2529. if (hEventLog==0) {
  2530. // MORE - this doesn't work on Vista/Win7 as can't copy to system32...
  2531. // Perhaps we should just kill this code
  2532. char path[_MAX_PATH+1];
  2533. GetEnvironmentVariable("SystemRoot",path,sizeof(path));
  2534. strcat(path,"\\System32\\JELOG.dll");
  2535. Owned<IFile> file = createIFile(path);
  2536. try {
  2537. if (!file->exists()) {
  2538. char src[_MAX_PATH+1];
  2539. LPTSTR tail;
  2540. DWORD res = SearchPath(NULL,"JELOG.DLL",NULL,sizeof(src),src,&tail);
  2541. if (res>0)
  2542. copyFile(path,src);
  2543. else
  2544. throw makeOsException(GetLastError());
  2545. }
  2546. }
  2547. catch (IException *e)
  2548. {
  2549. EXCLOG(e, "reportEventLog: Could not install JELOG.DLL");
  2550. hEventLog=(HANDLE)-1;
  2551. e->Release();
  2552. return false;
  2553. }
  2554. HKEY hk;
  2555. if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\Seisint",
  2556. NULL, NULL, 0, KEY_ALL_ACCESS, NULL, &hk, NULL)==0) {
  2557. DWORD sizedata = 0;
  2558. DWORD type = REG_EXPAND_SZ;
  2559. if ((RegQueryValueEx(hk,"EventMessageFile",NULL, &type, NULL, &sizedata)!=0)||!sizedata) {
  2560. StringAttr str("%SystemRoot%\\System32\\JELOG.dll");
  2561. RegSetValueEx(hk,"EventMessageFile", 0, REG_EXPAND_SZ, (LPBYTE) str.get(), (DWORD)str.length() + 1);
  2562. RegSetValueEx(hk,"CategoryMessageFile", 0, REG_EXPAND_SZ, (LPBYTE) str.get(), (DWORD)str.length() + 1);
  2563. DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE | EVENTLOG_AUDIT_SUCCESS | EVENTLOG_AUDIT_FAILURE;
  2564. RegSetValueEx(hk, "TypesSupported", 0, REG_DWORD, (LPBYTE) &dwData, sizeof(DWORD));
  2565. dwData = 16;
  2566. RegSetValueEx(hk, "CategoryCount", 0, REG_DWORD, (LPBYTE) &dwData, sizeof(DWORD));
  2567. }
  2568. RegCloseKey(hk);
  2569. }
  2570. hEventLog = RegisterEventSource(NULL,"Seisint");
  2571. if (!hEventLog) {
  2572. OERRLOG("reportEventLog: Could not register Seisint event source");
  2573. hEventLog=(HANDLE)-1;
  2574. return false;
  2575. }
  2576. }
  2577. if (hEventLog==(HANDLE)-1)
  2578. return false;
  2579. assertex((unsigned)eventtype<=16);
  2580. if (!data)
  2581. datasize = 0;
  2582. else if (!datasize)
  2583. data = NULL;
  2584. #if 1 //useful for debugging...
  2585. ReportEvent(hEventLog, eventtype, category, eventid, NULL, 1, datasize, &msg, (LPVOID)data);
  2586. #else
  2587. if(datasize)
  2588. {
  2589. char * buff = (char *)malloc(datasize*3+1);
  2590. unsigned char const * cdata = (unsigned char *)data;
  2591. unsigned i;
  2592. for(i=0; i<datasize; i++)
  2593. sprintf(buff+i*3, "%02X ", cdata[i]);
  2594. buff[datasize*3-1] = 0;
  2595. DBGLOG("ReportEvent: type=%X categoryid=%X eventid=%X msg='%s' data=[%s]", eventtype, category, eventid, msg, buff);
  2596. free(buff);
  2597. }
  2598. else
  2599. DBGLOG("ReportEvent: type=%X categoryid=%X eventid=%X msg='%s'", eventtype, category, eventid, msg);
  2600. #endif
  2601. return true;
  2602. }
  2603. CSysLogEventLogger::~CSysLogEventLogger()
  2604. {
  2605. if (hEventLog!=0)
  2606. DeregisterEventSource(hEventLog);
  2607. }
  2608. #else
  2609. #include <syslog.h>
  2610. #define CATEGORY_AUDIT_FUNCTION_REQUIRED
  2611. #define AUDIT_TYPES_BEGIN int auditTypeDataMap[NUM_AUDIT_TYPES+1] = {
  2612. #define MAKE_AUDIT_TYPE(name, type, categoryid, eventid, level) level,
  2613. #define AUDIT_TYPES_END 0 };
  2614. #include "jelogtype.hpp"
  2615. #undef CATEGORY_AUDIT_FUNCTION_REQUIRED
  2616. #undef AUDIT_TYPES_BEGIN
  2617. #undef MAKE_AUDIT_TYPE
  2618. #undef AUDIT_TYPES_END
  2619. CSysLogEventLogger::CSysLogEventLogger() : dataLogUsed(false), dataLogName(0), dataLogFile(-1)
  2620. {
  2621. StringBuffer folder;
  2622. const char * processName = splitDirTail(queryCurrentProcessPath(), folder);
  2623. if (!processName||!*processName)
  2624. processName = "hpcc";
  2625. openlog(processName, LOG_PID, LOG_USER);
  2626. }
  2627. CSysLogEventLogger::~CSysLogEventLogger()
  2628. {
  2629. if(dataLogFile != -1)
  2630. close(dataLogFile);
  2631. if(dataLogName)
  2632. delete [] dataLogName;
  2633. closelog();
  2634. }
  2635. bool CSysLogEventLogger::log(AuditType auditType, const char *msg, size32_t datasize, const void * data)
  2636. {
  2637. assertex(auditType < NUM_AUDIT_TYPES);
  2638. int level = auditTypeDataMap[auditType];
  2639. return linuxReport(level, msg, datasize, data);
  2640. }
  2641. bool CSysLogEventLogger::linuxReport(int level, const char * msg, size32_t datasize, const void * data)
  2642. {
  2643. if (!data)
  2644. datasize = 0;
  2645. else if (!datasize)
  2646. data = NULL;
  2647. bool ret = true;
  2648. #if 1 //useful for debugging...
  2649. if(data)
  2650. {
  2651. if(!dataLogUsed)
  2652. openDataLog();
  2653. if(dataLogFile != -1)
  2654. {
  2655. int fpos = writeDataLog(datasize, (byte const *)data);
  2656. if(fpos != -1)
  2657. syslog(level, "%s [0x%X bytes of data at %s byte 0x%X]", msg, datasize, dataLogName, fpos);
  2658. else
  2659. syslog(level, "%s [could not write 0x%X bytes of data to %s]", msg, datasize, dataLogName);
  2660. }
  2661. else
  2662. {
  2663. ret = false;
  2664. syslog(level, "%s [could not open file of form %s to write data]", msg, AUDIT_DATA_LOG_TEMPLATE);
  2665. }
  2666. }
  2667. else
  2668. {
  2669. syslog(level, "%s", msg);
  2670. }
  2671. #else
  2672. if(datasize)
  2673. {
  2674. char * buff = (char *)malloc(datasize*3+1);
  2675. unsigned char const * cdata = (unsigned char *)data;
  2676. unsigned i;
  2677. for(i=0; i<datasize; i++)
  2678. sprintf(buff+i*3, "%02X ", cdata[i]);
  2679. buff[datasize*3-1] = 0;
  2680. DBGLOG("syslog: priority=%X msg='%s' data=[%s]", level, msg, buff);
  2681. free(buff);
  2682. }
  2683. else
  2684. DBGLOG("syslog: priority=%X msg='%s'", level, msg);
  2685. #endif
  2686. return ret;
  2687. }
  2688. void CSysLogEventLogger::openDataLog()
  2689. {
  2690. CriticalBlock block(dataLogLock);
  2691. dataLogUsed = true;
  2692. unsigned len = strlen(AUDIT_DATA_LOG_TEMPLATE);
  2693. dataLogName = new char[len+1];
  2694. strcpy(dataLogName, AUDIT_DATA_LOG_TEMPLATE);
  2695. dataLogFile = mkstemp(dataLogName);
  2696. }
  2697. int CSysLogEventLogger::writeDataLog(size32_t datasize, byte const * data)
  2698. {
  2699. CriticalBlock block(dataLogLock);
  2700. off_t fpos = lseek(dataLogFile, 0, SEEK_CUR);
  2701. while(datasize > 0)
  2702. {
  2703. ssize_t written = write(dataLogFile, data, datasize);
  2704. if (written == -1)
  2705. return -1;
  2706. data += written;
  2707. datasize -= written;
  2708. }
  2709. #ifndef _WIN32
  2710. #ifdef F_FULLFSYNC
  2711. fcntl(dataLogFile, F_FULLFSYNC);
  2712. #else
  2713. fdatasync(dataLogFile);
  2714. #endif
  2715. #ifdef POSIX_FADV_DONTNEED
  2716. posix_fadvise(dataLogFile, 0, 0, POSIX_FADV_DONTNEED);
  2717. #endif
  2718. #endif
  2719. return fpos;
  2720. }
  2721. #endif
  2722. void SysLogMsgHandler::handleMessage(const LogMsg & msg)
  2723. {
  2724. AuditType type = categoryToAuditType(msg.queryCategory());
  2725. StringBuffer text;
  2726. msg.toStringPlain(text, fields);
  2727. logger->log(type, text.str());
  2728. }
  2729. void SysLogMsgHandler::addToPTree(IPropertyTree * tree) const
  2730. {
  2731. IPropertyTree * handlerTree = createPTree(ipt_caseInsensitive);
  2732. handlerTree->setProp("@type", "audit");
  2733. tree->addPropTree("handler", handlerTree);
  2734. }
  2735. // Default implementations of the functions in IContextLogger interface
  2736. void IContextLogger::CTXLOG(const char *format, ...) const
  2737. {
  2738. va_list args;
  2739. va_start(args, format);
  2740. CTXLOGva(format, args);
  2741. va_end(args);
  2742. }
  2743. void IContextLogger::mCTXLOG(const char *format, ...) const
  2744. {
  2745. va_list args;
  2746. va_start(args, format);
  2747. StringBuffer log;
  2748. log.limited_valist_appendf(1024*1024, format, args);
  2749. va_end(args);
  2750. const char *cursor = log;
  2751. const char *lineStart = cursor;
  2752. while (true)
  2753. {
  2754. switch (*cursor)
  2755. {
  2756. case '\0':
  2757. CTXLOG("%.*s", (int)(cursor-lineStart), lineStart);
  2758. return;
  2759. case '\r':
  2760. // NB: \r or \r\n translated into newline
  2761. CTXLOG("%.*s", (int)(cursor-lineStart), lineStart);
  2762. if ('\n' == *(cursor+1))
  2763. cursor++;
  2764. lineStart = cursor+1;
  2765. break;
  2766. case '\n':
  2767. CTXLOG("%.*s", (int)(cursor-lineStart), lineStart);
  2768. lineStart = cursor+1;
  2769. break;
  2770. }
  2771. ++cursor;
  2772. }
  2773. }
  2774. void IContextLogger::logOperatorException(IException *E, const char *file, unsigned line, const char *format, ...) const
  2775. {
  2776. va_list args;
  2777. va_start(args, format);
  2778. logOperatorExceptionVA(E, file, line, format, args);
  2779. va_end(args);
  2780. }
  2781. class DummyLogCtx : implements IContextLogger
  2782. {
  2783. private:
  2784. StringAttr globalId;
  2785. StringAttr callerId;
  2786. StringBuffer localId;
  2787. StringAttr globalIdHeader;
  2788. StringAttr callerIdHeader;
  2789. public:
  2790. // It's a static object - we don't want to actually link-count it...
  2791. virtual void Link() const {}
  2792. virtual bool Release() const { return false; }
  2793. virtual void CTXLOGva(const char *format, va_list args) const __attribute__((format(printf,2,0)))
  2794. {
  2795. StringBuffer ss;
  2796. ss.valist_appendf(format, args);
  2797. DBGLOG("%s", ss.str());
  2798. }
  2799. virtual void logOperatorExceptionVA(IException *E, const char *file, unsigned line, const char *format, va_list args) const __attribute__((format(printf,5,0)))
  2800. {
  2801. StringBuffer ss;
  2802. ss.append("ERROR");
  2803. if (E)
  2804. ss.append(": ").append(E->errorCode());
  2805. if (file)
  2806. ss.appendf(": %s(%d) ", sanitizeSourceFile(file), line);
  2807. if (E)
  2808. E->errorMessage(ss.append(": "));
  2809. if (format)
  2810. ss.append(": ").valist_appendf(format, args);
  2811. LOG(MCoperatorProgress, unknownJob, "%s", ss.str());
  2812. }
  2813. virtual void noteStatistic(StatisticKind kind, unsigned __int64 value) const
  2814. {
  2815. }
  2816. virtual void setStatistic(StatisticKind kind, unsigned __int64 value) const
  2817. {
  2818. }
  2819. virtual void mergeStats(const CRuntimeStatisticCollection &from) const
  2820. {
  2821. }
  2822. virtual unsigned queryTraceLevel() const
  2823. {
  2824. return 0;
  2825. }
  2826. virtual void setGlobalId(const char *id, SocketEndpoint &ep, unsigned pid) override
  2827. {
  2828. globalId.set(id);
  2829. appendGloballyUniqueId(localId.clear());
  2830. }
  2831. virtual void setCallerId(const char *id) override
  2832. {
  2833. callerId.set(id);
  2834. }
  2835. virtual const char *queryGlobalId() const
  2836. {
  2837. return globalId.get();
  2838. }
  2839. virtual const char *queryCallerId() const override
  2840. {
  2841. return callerId.str();
  2842. }
  2843. virtual const char *queryLocalId() const
  2844. {
  2845. return localId.str();
  2846. }
  2847. virtual void setHttpIdHeaders(const char *global, const char *caller)
  2848. {
  2849. if (global && *global)
  2850. globalIdHeader.set(global);
  2851. if (caller && *caller)
  2852. callerIdHeader.set(caller);
  2853. }
  2854. virtual const char *queryGlobalIdHttpHeader() const
  2855. {
  2856. return globalIdHeader.str();
  2857. }
  2858. virtual const char *queryCallerIdHttpHeader() const
  2859. {
  2860. return callerIdHeader.str();
  2861. }
  2862. } dummyContextLogger;
  2863. extern jlib_decl const IContextLogger &queryDummyContextLogger()
  2864. {
  2865. return dummyContextLogger;
  2866. }
  2867. extern jlib_decl IContextLogger &updateDummyContextLogger()
  2868. {
  2869. return dummyContextLogger;
  2870. }
  2871. extern jlib_decl StringBuffer &appendGloballyUniqueId(StringBuffer &s)
  2872. {
  2873. string uid = createUniqueIdString();
  2874. return s.append(uid.c_str());
  2875. }
  2876. extern jlib_decl void UseSysLogForOperatorMessages(bool use)
  2877. {
  2878. static ILogMsgHandler *msgHandler=NULL;
  2879. if (use==(msgHandler!=NULL))
  2880. return;
  2881. if (use) {
  2882. msgHandler = getSysLogMsgHandler();
  2883. ILogMsgFilter * operatorFilter = getCategoryLogMsgFilter(MSGAUD_operator, MSGCLS_all, DefaultDetail, true);
  2884. queryLogMsgManager()->addMonitorOwn(msgHandler, operatorFilter);
  2885. }
  2886. else {
  2887. queryLogMsgManager()->removeMonitor(msgHandler);
  2888. msgHandler = NULL;
  2889. }
  2890. }
  2891. extern jlib_decl void AuditSystemAccess(const char *userid, bool success, char const * msg,...)
  2892. {
  2893. va_list args;
  2894. va_start(args, msg);
  2895. VStringBuffer s("User %s: ", userid);
  2896. SYSLOG((success) ? AUDIT_TYPE_ACCESS_SUCCESS : AUDIT_TYPE_ACCESS_FAILURE, s.valist_appendf(msg, args).str());
  2897. va_end(args);
  2898. }
  2899. //--------------------------------------------------------------
  2900. class jlib_decl CComponentLogFileCreator : implements IComponentLogFileCreator, public CInterface
  2901. {
  2902. private:
  2903. StringBuffer component;
  2904. //filename parts
  2905. StringBuffer prefix;
  2906. StringBuffer name;
  2907. StringBuffer postfix;
  2908. StringBuffer extension;
  2909. StringBuffer fullFileSpec;
  2910. bool createAlias;
  2911. StringBuffer aliasName;
  2912. StringBuffer logDirSubdir;
  2913. bool rolling;
  2914. //ILogMsgHandler fields
  2915. bool append;
  2916. bool flushes;
  2917. unsigned msgFields;
  2918. //ILogMsgFilter fields
  2919. unsigned msgAudiences;
  2920. unsigned msgClasses;
  2921. LogMsgDetail maxDetail;
  2922. bool local;
  2923. //available after logging started
  2924. StringBuffer logDir; //access via queryLogDir()
  2925. StringBuffer aliasFileSpec; //access via queryAliasFileSpec()
  2926. StringBuffer expandedLogSpec;//access via queryLogFileSpec()
  2927. long maxLogFileSize = 0;
  2928. private:
  2929. void setDefaults()
  2930. {
  2931. rolling = true;
  2932. append = true;
  2933. flushes = true;
  2934. #ifdef _CONTAINERIZED
  2935. const char *logFields = nullptr;
  2936. #else
  2937. const char *logFields = queryEnvironmentConf().queryProp("logfields");
  2938. #endif
  2939. if (!isEmptyString(logFields))
  2940. msgFields = logMsgFieldsFromAbbrevs(logFields);
  2941. else
  2942. msgFields = MSGFIELD_STANDARD;
  2943. msgAudiences = MSGAUD_all;
  2944. msgClasses = MSGCLS_all;
  2945. maxDetail = DefaultDetail;
  2946. name.set(component); //logfile defaults to component name. Change via setName(), setPrefix() and setPostfix()
  2947. extension.set(".log");
  2948. local = false;
  2949. createAlias = true;
  2950. }
  2951. public:
  2952. IMPLEMENT_IINTERFACE;
  2953. CComponentLogFileCreator(IPropertyTree * _properties, const char *_component) : component(_component)
  2954. {
  2955. setDefaults();
  2956. if (_properties && !getConfigurationDirectory(_properties->queryPropTree("Directories"), "log", _component, _properties->queryProp("@name"), logDir))
  2957. _properties->getProp("@logDir", logDir);
  2958. }
  2959. CComponentLogFileCreator(const char *_logDir, const char *_component) : component(_component), logDir(_logDir)
  2960. {
  2961. setDefaults();
  2962. }
  2963. CComponentLogFileCreator(const char *_component) : component(_component)
  2964. {
  2965. setDefaults();
  2966. if (!getConfigurationDirectory(NULL, "log", _component, _component, logDir))
  2967. {
  2968. appendCurrentDirectory(logDir,false);
  2969. }
  2970. }
  2971. //set methods
  2972. void setExtension(const char * _ext) { extension.set(_ext); }
  2973. void setPrefix(const char * _prefix) { prefix.set(_prefix); }
  2974. void setName(const char * _name) { name.set(_name); }
  2975. void setCompleteFilespec(const char * _fs){fullFileSpec.set(_fs); setExtension(NULL); setRolling(false);}
  2976. void setPostfix(const char * _postfix) { postfix.set(_postfix); }
  2977. void setCreateAliasFile(bool _create) { createAlias = _create; }
  2978. void setAliasName(const char * _aliasName) { aliasName.set(_aliasName); }
  2979. void setLogDirSubdir(const char * _subdir) { logDirSubdir.set(_subdir); }
  2980. void setRolling(const bool _rolls) { rolling = _rolls; }
  2981. void setMaxLogFileSize( const long _size) { maxLogFileSize = _size; }
  2982. //ILogMsgHandler fields
  2983. void setAppend(const bool _append) { append = _append; }
  2984. void setFlushes(const bool _flushes) { flushes = _flushes; }
  2985. void setMsgFields(const unsigned _fields){ msgFields = _fields; }
  2986. //ILogMsgFilter fields
  2987. void setMsgAudiences(const unsigned _audiences){ msgAudiences = _audiences; }
  2988. void setMsgClasses(const unsigned _classes) { msgClasses = _classes; }
  2989. void setMaxDetail(const LogMsgDetail _maxDetail) { maxDetail = _maxDetail; }
  2990. void setLocal(const bool _local) { local = _local; }
  2991. //query methods (not valid until logging started)
  2992. const char * queryLogDir() const { return logDir.str(); }
  2993. const char * queryLogFileSpec() const { return expandedLogSpec.str(); }
  2994. const char * queryAliasFileSpec() const { return aliasFileSpec.str(); }
  2995. ILogMsgHandler * beginLogging()
  2996. {
  2997. //build directory path
  2998. StringBuffer logFileSpec;
  2999. if (!fullFileSpec.length())//user specify complete logfile specification?
  3000. {
  3001. if (!logDir.length())
  3002. {
  3003. appendCurrentDirectory(logDir,false).append(PATHSEPSTR).append("logs");
  3004. OWARNLOG("No logfile directory specified - logs will be written locally to %s", logDir.str());
  3005. }
  3006. makeAbsolutePath(logDir);
  3007. //build log file name (without date string or extension)
  3008. StringBuffer logFileName;
  3009. if (prefix.length())
  3010. logFileName.append(prefix).append(".");
  3011. logFileName.append(name);
  3012. if (postfix.length())
  3013. logFileName.append(".").append(postfix);
  3014. //build log file spec
  3015. if (logDirSubdir.length())
  3016. logDir.append(PATHSEPCHAR).append(logDirSubdir);//user specified subfolder
  3017. logFileSpec.append(logDir).append(PATHSEPCHAR).append(logFileName);
  3018. //build alias file spec
  3019. if (createAlias)
  3020. {
  3021. if (aliasName.length()==0)
  3022. aliasName.set(logFileName);
  3023. aliasFileSpec.append(logDir).append(PATHSEPCHAR).append(aliasName).append(extension);
  3024. }
  3025. }
  3026. else
  3027. makeAbsolutePath(fullFileSpec);
  3028. ILogMsgHandler * lmh;
  3029. if (rolling)
  3030. {
  3031. lmh = getRollingFileLogMsgHandler(logFileSpec.str(), extension, msgFields, append, flushes, NULL, aliasFileSpec.str(), true, maxLogFileSize);
  3032. }
  3033. else
  3034. {
  3035. StringBuffer lfs;
  3036. if (fullFileSpec.length())
  3037. lfs.set(fullFileSpec);
  3038. else
  3039. lfs.set(logFileSpec.append(extension).str());
  3040. lmh = getFileLogMsgHandler(lfs.str(), NULL, msgFields, false);
  3041. }
  3042. lmh->getLogName(expandedLogSpec);
  3043. queryLogMsgManager()->addMonitorOwn( lmh, getCategoryLogMsgFilter(msgAudiences, msgClasses, maxDetail, local));
  3044. return lmh;
  3045. }
  3046. };
  3047. IComponentLogFileCreator * createComponentLogFileCreator(IPropertyTree * _properties, const char *_component)
  3048. {
  3049. return new CComponentLogFileCreator(_properties, _component);
  3050. }
  3051. IComponentLogFileCreator * createComponentLogFileCreator(const char *_logDir, const char *_component)
  3052. {
  3053. return new CComponentLogFileCreator(_logDir, _component);
  3054. }
  3055. IComponentLogFileCreator * createComponentLogFileCreator(const char *_component)
  3056. {
  3057. return new CComponentLogFileCreator(_component);
  3058. }
  3059. ILogAccessFilter * getLogAccessFilterFromPTree(IPropertyTree * xml)
  3060. {
  3061. if (xml == nullptr)
  3062. throw makeStringException(-2,"getLogAccessFilterFromPTree: input tree cannot be null");
  3063. StringBuffer type;
  3064. xml->getProp("@type", type);
  3065. if (streq(type.str(), "jobid"))
  3066. return new FieldLogAccessFilter(xml, LOGACCESS_FILTER_jobid);
  3067. else if (streq(type.str(), "audience"))
  3068. return new FieldLogAccessFilter(xml, LOGACCESS_FILTER_audience);
  3069. else if (streq(type.str(), "class"))
  3070. return new FieldLogAccessFilter(xml, LOGACCESS_FILTER_class);
  3071. else if (streq(type.str(), "component"))
  3072. return new FieldLogAccessFilter(xml, LOGACCESS_FILTER_component);
  3073. else if (streq(type.str(), "and"))
  3074. return new BinaryLogAccessFilter(xml, LOGACCESS_FILTER_and);
  3075. else if (streq(type.str(), "or"))
  3076. return new BinaryLogAccessFilter(xml, LOGACCESS_FILTER_or);
  3077. else
  3078. throwUnexpectedX("getLogAccessFilterFromPTree : unrecognized LogAccessFilter type");
  3079. }
  3080. ILogAccessFilter * getWildCardLogAccessFilter()
  3081. {
  3082. return new FieldLogAccessFilter("", LOGACCESS_FILTER_wildcard);
  3083. }
  3084. ILogAccessFilter * getJobIDLogAccessFilter(const char * jobId)
  3085. {
  3086. return new FieldLogAccessFilter(jobId, LOGACCESS_FILTER_jobid);
  3087. }
  3088. ILogAccessFilter * getComponentLogAccessFilter(const char * component)
  3089. {
  3090. return new FieldLogAccessFilter(component, LOGACCESS_FILTER_component);
  3091. }
  3092. ILogAccessFilter * getAudienceLogAccessFilter(MessageAudience audience)
  3093. {
  3094. return new FieldLogAccessFilter(LogMsgAudienceToFixString(audience), LOGACCESS_FILTER_audience);
  3095. }
  3096. ILogAccessFilter * getClassLogAccessFilter(LogMsgClass logclass)
  3097. {
  3098. return new FieldLogAccessFilter(LogMsgClassToFixString(logclass), LOGACCESS_FILTER_class);
  3099. }
  3100. ILogAccessFilter * getBinaryLogAccessFilter(ILogAccessFilter * arg1, ILogAccessFilter * arg2, LogAccessFilterType type)
  3101. {
  3102. return new BinaryLogAccessFilter(arg1, arg2, type);
  3103. }
  3104. ILogAccessFilter * getBinaryLogAccessFilterOwn(ILogAccessFilter * arg1, ILogAccessFilter * arg2, LogAccessFilterType type)
  3105. {
  3106. ILogAccessFilter * ret = new BinaryLogAccessFilter(arg1, arg2, type);
  3107. arg1->Release();
  3108. arg2->Release();
  3109. return ret;
  3110. }
  3111. // LOG ACCESS HELPER METHODS
  3112. // Fetches log entries - based on provided filter, via provided IRemoteLogAccess instance
  3113. bool fetchLog(StringBuffer & returnbuf, IRemoteLogAccess & logAccess, ILogAccessFilter * filter, LogAccessTimeRange timeRange, const StringArray & cols, LogAccessLogFormat format)
  3114. {
  3115. LogAccessConditions logFetchOptions;
  3116. logFetchOptions.setTimeRange(timeRange);
  3117. logFetchOptions.setFilter(filter);
  3118. logFetchOptions.copyLogFieldNames(cols); //ensure these fields are declared in m_logMapping->queryProp("WorkUnits/@contentcolumn")? or in LogMap/Fields?"
  3119. return logAccess.fetchLog(logFetchOptions, returnbuf, format);
  3120. }
  3121. // Fetches log entries based on provided JobID, via provided IRemoteLogAccess instance
  3122. bool fetchJobIDLog(StringBuffer & returnbuf, IRemoteLogAccess & logAccess, const char *jobid, LogAccessTimeRange timeRange, StringArray & cols, LogAccessLogFormat format = LOGACCESS_LOGFORMAT_json)
  3123. {
  3124. return fetchLog(returnbuf, logAccess, getJobIDLogAccessFilter(jobid), timeRange, cols, format);
  3125. }
  3126. // Fetches log entries based on provided component name, via provided IRemoteLogAccess instance
  3127. bool fetchComponentLog(StringBuffer & returnbuf, IRemoteLogAccess & logAccess, const char * component, LogAccessTimeRange timeRange, StringArray & cols, LogAccessLogFormat format = LOGACCESS_LOGFORMAT_json)
  3128. {
  3129. return fetchLog(returnbuf, logAccess, getComponentLogAccessFilter(component), timeRange, cols, format);
  3130. }
  3131. // Fetches log entries based on provided audience, via provided IRemoteLogAccess instance
  3132. bool fetchLogByAudience(StringBuffer & returnbuf, IRemoteLogAccess & logAccess, MessageAudience audience, LogAccessTimeRange timeRange, StringArray & cols, LogAccessLogFormat format = LOGACCESS_LOGFORMAT_json)
  3133. {
  3134. return fetchLog(returnbuf, logAccess, getAudienceLogAccessFilter(audience), timeRange, cols, format);
  3135. }
  3136. // Fetches log entries based on provided log message class, via provided IRemoteLogAccess instance
  3137. bool fetchLogByClass(StringBuffer & returnbuf, IRemoteLogAccess & logAccess, LogMsgClass logclass, LogAccessTimeRange timeRange, StringArray & cols, LogAccessLogFormat format = LOGACCESS_LOGFORMAT_json)
  3138. {
  3139. return fetchLog(returnbuf, logAccess, getClassLogAccessFilter(logclass), timeRange, cols, format);
  3140. }
  3141. //logAccessPluginConfig expected to contain connectivity and log mapping information
  3142. typedef IRemoteLogAccess * (*newLogAccessPluginMethod_t_)(IPropertyTree & logAccessPluginConfig);
  3143. IRemoteLogAccess &queryRemoteLogAccessor()
  3144. {
  3145. return *logAccessor.query([]
  3146. {
  3147. Owned<IPropertyTree> logAccessPluginConfig = getGlobalConfigSP()->getPropTree("logAccess");
  3148. #ifdef LOGACCESSDEBUG
  3149. if (!logAccessPluginConfig)
  3150. {
  3151. const char * simulatedGlobalYaml = R"!!(global:
  3152. logAccess:
  3153. name: "localES"
  3154. type: "elasticstack"
  3155. connection:
  3156. protocol: "http"
  3157. host: "elasticsearch-master.default.svc.cluster.local"
  3158. port: 9200
  3159. logMaps:
  3160. - type: "global"
  3161. storeName: "filebeat-*"
  3162. searchColumn: "message"
  3163. timeStampColumn: "created_ts"
  3164. - type: "workunits"
  3165. storeName: "filebeat-*"
  3166. searchColumn: "hpcc.log.jobid"
  3167. - type: "components"
  3168. searchColumn: "kubernetes.container.name"
  3169. - type: "audience"
  3170. searchColumn: "hpcc.log.audience"
  3171. - type: "class"
  3172. searchColumn: "hpcc.log.class"
  3173. )!!";
  3174. Owned<IPropertyTree> testTree = createPTreeFromYAMLString(simulatedGlobalYaml, ipt_none, ptr_ignoreWhiteSpace, nullptr);
  3175. logAccessPluginConfig.setown(testTree->getPropTree("global/logAccess"));
  3176. }
  3177. #endif
  3178. if (!logAccessPluginConfig)
  3179. throw makeStringException(-1, "RemoteLogAccessLoader: logaccess configuration not available!");
  3180. constexpr const char * methodName = "queryRemoteLogAccessor";
  3181. constexpr const char * instFactoryName = "createInstance";
  3182. StringBuffer libName; //lib<type>logaccess.so
  3183. StringBuffer type;
  3184. logAccessPluginConfig->getProp("@type", type);
  3185. if (type.isEmpty())
  3186. throw makeStringExceptionV(-1, "%s RemoteLogAccess plugin kind not specified.", methodName);
  3187. libName.append("lib").append(type.str()).append("logaccess");
  3188. //Load the DLL/SO
  3189. HINSTANCE logAccessPluginLib = LoadSharedObject(libName.str(), false, true);
  3190. newLogAccessPluginMethod_t_ xproc = (newLogAccessPluginMethod_t_)GetSharedProcedure(logAccessPluginLib, instFactoryName);
  3191. if (xproc == nullptr)
  3192. throw makeStringExceptionV(-1, "%s cannot locate procedure %s in library '%s'", methodName, instFactoryName, libName.str());
  3193. //Call logaccessplugin instance factory and return the new instance
  3194. DBGLOG("Calling '%s' in log access plugin '%s'", instFactoryName, libName.str());
  3195. return xproc(*logAccessPluginConfig);
  3196. }
  3197. );
  3198. }