CMS 3D CMS Logo

ELoutput.cc
Go to the documentation of this file.
1 // ----------------------------------------------------------------------
2 //
3 // ELoutput.cc
4 //
5 //
6 // 7/8/98 mf Created
7 // 6/10/99 jv JV:1 puts a \n after each log using suppressContext()
8 // 6/11/99 jv JV:2 accounts for newline at the beginning and end of
9 // an emitted ELstring
10 // 6/14/99 mf Made the static char* in formatTime into auto so that
11 // ctime(&t) is called each time - corrects the bug of
12 // never changing the first timestamp.
13 // 6/15/99 mf Inserted operator<<(void (*f)(ErrorLog&) to avoid
14 // mystery characters being inserted when users <<
15 // endmsg to an ErrorObj.
16 // 7/2/99 jv Added separate/attachTime, Epilogue, and Serial options
17 // 8/2/99 jv Modified handling of newline in an emmitted ELstring
18 // 2/22/00 mf Changed usage of myDestX to myOutputX. Added
19 // constructor of ELoutput from ELoutputX * to allow for
20 // inheritance.
21 // 6/7/00 web Reflect consolidation of ELdestination/X; consolidate
22 // ELoutput/X; add filterModule() and query logic
23 // 10/4/00 mf excludeModule()
24 // 1/15/01 mf line length control: changed ELoutputLineLen to
25 // the base class lineLen (no longer static const)
26 // 2/13/01 mf Added emitAtStart argument to two constructors
27 // { Enh 001 }.
28 // 4/4/01 mf Simplify filter/exclude logic by useing base class
29 // method thisShouldBeIgnored(). Eliminate
30 // moduleOfinterest and moduleToexclude.
31 // 6/15/01 mf Repaired Bug 005 by explicitly setting all
32 // ELdestination member data appropriately.
33 //10/18/01 mf When epilogue not on separate line, preceed by space
34 // 6/23/03 mf changeFile(), flush()
35 // 4/09/04 mf Add 1 to length in strftime call in formatTime, to
36 // correctly provide the time zone. Had been providing
37 // CST every time.
38 //
39 // 12/xx/06 mf Tailoring to CMS MessageLogger
40 // 1/11/06 mf Eliminate time stamp from starting message
41 // 3/20/06 mf Major formatting change to do no formatting
42 // except the header and line separation.
43 // 4/04/06 mf Move the line feed between header and text
44 // till after the first 3 items (FILE:LINE) for
45 // debug messages.
46 // 6/06/06 mf Verbatim
47 // 6/12/06 mf Set preambleMode true when printing the header
48 //
49 // Change Log
50 //
51 // 1 10/18/06 mf In format_time(): Initialized ts[] with 5 extra
52 // spaces, to cover cases where time zone is more than
53 // 3 characters long
54 //
55 // 2 10/30/06 mf In log(): if severity indicated is SEVERE, do not
56 // impose limits. This is to implement the LogSystem
57 // feature: Those messages are never to be ignored.
58 //
59 // 3 6/11/07 mf In emitToken(): In preamble mode, do not break and indent
60 // even if exceeding nominal line length.
61 //
62 // 4 6/11/07 mf In log(): After the message, add a %MSG on its own line
63 //
64 // 5 3/27/09 mf Properly treat charsOnLine, which had been fouled due to
65 // change 3. In log() and emitToken().
66 //
67 // 6 9/2/10 mf Initialize preambleMode in each ctor, and remove the
68 // unnecessary use of tprm which was preserving a moot
69 // initial value.
70 //
71 // 7 9/30/10 wmtan make formatTime() thread safe by not using statics.
72 //
73 // ----------------------------------------------------------------------
74 
76 
78 
80 
81 // Possible Traces:
82 // #define ELoutputCONSTRUCTOR_TRACE
83 // #define ELoutputTRACE_LOG
84 // #define ELoutput_EMIT_TRACE
85 
86 #include <iostream>
87 #include <fstream>
88 #include <cstring>
89 #include <cassert>
90 
91 namespace edm {
92  namespace service {
93 
94  // ----------------------------------------------------------------------
95  // Useful function:
96  // ----------------------------------------------------------------------
97 
98  static ELstring formatTime(const time_t t) { // Change log 7
99 
100  static char const dummy[] = "dd-Mon-yyyy hh:mm:ss TZN "; // Change log 7 for length only
101  char ts[sizeof(dummy)]; // Change log 7
102 
103  struct tm timebuf; // Change log 7
104 
105  strftime(ts, sizeof(dummy), "%d-%b-%Y %H:%M:%S %Z", localtime_r(&t, &timebuf)); // Change log 7
106  // mf 4-9-04
107 
108 #ifdef STRIP_TRAILING_BLANKS_IN_TIMEZONE
109  // strip trailing blanks that would come when the time zone is not as
110  // long as the maximum allowed - probably not worth the time
111  unsigned int b = strlen(ts);
112  while (ts[--b] == ' ') {
113  ts[b] = 0;
114  }
115 #endif
116 
117  ELstring result(ts); // Change log 7
118  return result; // Change log 7
119  } // formatTime()
120 
121  // ----------------------------------------------------------------------
122  // Constructors:
123  // ----------------------------------------------------------------------
124 
126  : ELdestination(),
127  os(&std::cerr, do_nothing_deleter()),
128  charsOnLine(0),
129  xid(),
130  wantTimestamp(true),
131  wantModule(true),
132  wantSubroutine(true),
133  wantText(true),
134  wantSomeContext(true),
135  wantSerial(false),
136  wantFullContext(false),
137  wantTimeSeparate(false),
138  wantEpilogueSeparate(false),
139  preambleMode(true) // 006 9/2/10 mf
140  {
141 #ifdef ELoutputCONSTRUCTOR_TRACE
142  std::cerr << "Constructor for ELoutput()\n";
143 #endif
144 
145  emitToken("\n=================================================", true);
146  emitToken("\nMessage Log File written by MessageLogger service \n");
147  emitToken("\n=================================================\n", true);
148 
149  } // ELoutput()
150 
151  ELoutput::ELoutput(std::ostream& os_, bool emitAtStart)
152  : ELdestination(),
153  os(&os_, do_nothing_deleter()),
154  charsOnLine(0),
155  xid(),
157  wantModule(true),
159  wantText(true),
161  wantSerial(false),
165  preambleMode(true) // 006 9/2/10 mf
166  {
167 #ifdef ELoutputCONSTRUCTOR_TRACE
168  std::cerr << "Constructor for ELoutput( os )\n";
169 #endif
170 
171  // Enh 001 2/13/01 mf
172  if (emitAtStart) {
173  preambleMode = true;
174  emitToken("\n=================================================", true);
175  emitToken("\nMessage Log File written by MessageLogger service \n");
176  emitToken("\n=================================================\n", true);
177  }
178 
179  } // ELoutput()
180 
181  ELoutput::ELoutput(const ELstring& fileName, bool emitAtStart)
182  : ELdestination(),
183  os(new std::ofstream(fileName.c_str(), std::ios /*_base*/ ::app), close_and_delete()),
184  charsOnLine(0),
185  xid(),
187  wantModule(true),
189  wantText(true),
191  wantSerial(false),
195  preambleMode(true) // 006 9/2/10 mf
196  {
197 #ifdef ELoutputCONSTRUCTOR_TRACE
198  std::cerr << "Constructor for ELoutput( " << fileName << " )\n";
199 #endif
200 
201  preambleMode = true;
202  if (os && *os) {
203 #ifdef ELoutputCONSTRUCTOR_TRACE
204  std::cerr << " Testing if os is owned\n";
205 #endif
206 #ifdef ELoutputCONSTRUCTOR_TRACE
207  std::cerr << " About to do first emit\n";
208 #endif
209  // Enh 001 2/13/01 mf
210  if (emitAtStart) {
211  emitToken("\n=======================================================", true);
212  emitToken("\nError Log File ");
213  emitToken(fileName);
214  emitToken(" \n");
215  }
216  } else {
217 #ifdef ELoutputCONSTRUCTOR_TRACE
218  std::cerr << " Deleting os\n";
219 #endif
220  os.reset(&std::cerr, do_nothing_deleter());
221 #ifdef ELoutputCONSTRUCTOR_TRACE
222  std::cerr << " about to emit to cerr\n";
223 #endif
224  if (emitAtStart) {
225  emitToken("\n=======================================================", true);
226  emitToken("\n%MSG** Logging to cerr is being substituted");
227  emitToken(" for specified log file \"");
228  emitToken(fileName);
229  emitToken("\" which could not be opened for write or append.\n");
230  }
231  }
232  if (emitAtStart) {
233  ELstring const& ftime = formatTime(time(nullptr)); // Change log 7
234  emitToken(ftime, true);
235  emitToken("\n=======================================================\n", true);
236  }
237  // preambleMode = tprm; removed 9/2/10 mf see change log 6
238 
239 #ifdef ELoutputCONSTRUCTOR_TRACE
240  std::cerr << "Constructor for ELoutput completed.\n";
241 #endif
242 
243  } // ELoutput()
244 
246  : ELdestination(),
247  os(orig.os),
248  charsOnLine(orig.charsOnLine),
249  xid(orig.xid),
251  wantModule(orig.wantModule),
253  wantText(orig.wantText),
255  wantSerial(orig.wantSerial),
259  preambleMode(orig.preambleMode) // 006 9/2/10 mf
260  {
261 #ifdef ELoutputCONSTRUCTOR_TRACE
262  std::cerr << "Copy constructor for ELoutput\n";
263 #endif
264 
265  // mf 6/15/01 fix of Bug 005
266  threshold = orig.threshold;
268  limits = orig.limits;
269  preamble = orig.preamble;
270  newline = orig.newline;
271  indent = orig.indent;
272  lineLength = orig.lineLength;
273 
277  ignoreThese = orig.ignoreThese;
278 
279  } // ELoutput()
280 
282 #ifdef ELoutputCONSTRUCTOR_TRACE
283  std::cerr << "Destructor for ELoutput\n";
284 #endif
285 
286  } // ~ELoutput()
287 
288  // ----------------------------------------------------------------------
289  // Methods invoked by the ELadministrator:
290  // ----------------------------------------------------------------------
291 
292  //#define THRESHTRACE
293  //#define ELoutputTRACE_LOG
294 
296 #ifdef ELoutputTRACE_LOG
297  std::cerr << " =:=:=: Log to an ELoutput \n";
298 #endif
299 
300  xid = msg.xid(); // Save the xid.
301 
302 #ifdef THRESHTRACE
303  std::cerr << " =:=:=: Log to an ELoutput \n"
304  << " severity = " << xid.severity << "\n"
305  << " threshold = " << threshold << "\n"
306  << " id = " << xid.id << "\n";
307 #endif
308 
309  // See if this message is to be acted upon, and add it to limits table
310  // if it was not already present:
311  //
312  if (xid.severity < threshold)
313  return false;
314  if (thisShouldBeIgnored(xid.module) && (xid.severity < ELsevere) /* change log 2 */)
315  return false;
316  if (!limits.add(xid) && (xid.severity < ELsevere) /* change log 2 */)
317  return false;
318 
319 #ifdef ELoutputTRACE_LOG
320  std::cerr << " =:=:=: Limits table work done \n";
321 #endif
322 
323  // Output the prologue:
324  //
325  preambleMode = true;
326 
327  if (!msg.is_verbatim()) {
328  charsOnLine = 0; // Change log 5
331  emitToken(" ");
332  emitToken(xid.id);
333  emitToken(msg.idOverflow());
334  emitToken(": ");
335  }
336 
337 #ifdef ELoutputTRACE_LOG
338  std::cerr << " =:=:=: Prologue done \n";
339 #endif
340  // Output serial number of message:
341  //
342  if (!msg.is_verbatim()) {
343  if (wantSerial) {
344  std::ostringstream s;
345  s << msg.serial();
346  emitToken("[serial #" + s.str() + ELstring("] "));
347  }
348  }
349 
350 #ifdef OUTPUT_FORMATTED_ERROR_MESSAGES
351  // Output each item in the message (before the epilogue):
352  //
353  if (wantText) {
354  ELlist_string::const_iterator it;
355  for (it = msg.items().begin(); it != msg.items().end(); ++it) {
356 #ifdef ELoutputTRACE_LOG
357  std::cerr << " =:=:=: Item: " << *it << '\n';
358 #endif
359  emitToken(*it);
360  }
361  }
362 #endif
363 
364  // Provide further identification:
365  //
366  bool needAspace = true;
367  if (!msg.is_verbatim()) {
368  if (wantEpilogueSeparate) {
369  if (xid.module.length() + xid.subroutine.length() > 0) {
370  emitToken("\n");
371  needAspace = false;
372  } else if (wantTimestamp && !wantTimeSeparate) {
373  emitToken("\n");
374  needAspace = false;
375  }
376  }
377  if (wantModule && (xid.module.length() > 0)) {
378  if (needAspace) {
379  emitToken(ELstring(" "));
380  needAspace = false;
381  }
382  emitToken(xid.module + ELstring(" "));
383  }
384  if (wantSubroutine && (xid.subroutine.length() > 0)) {
385  if (needAspace) {
386  emitToken(ELstring(" "));
387  needAspace = false;
388  }
389  emitToken(xid.subroutine + "()" + ELstring(" "));
390  }
391  }
392 
393 #ifdef ELoutputTRACE_LOG
394  std::cerr << " =:=:=: Module and Subroutine done \n";
395 #endif
396 
397  // Provide time stamp:
398  //
399  if (!msg.is_verbatim()) {
400  if (wantTimestamp) {
401  if (wantTimeSeparate) {
402  emitToken(ELstring("\n"));
403  needAspace = false;
404  }
405  if (needAspace) {
406  emitToken(ELstring(" "));
407  needAspace = false;
408  }
409  ELstring const& ftime = formatTime(msg.timestamp()); // Change log 7
410  emitToken(ftime + ELstring(" "));
411  }
412  }
413 
414 #ifdef ELoutputTRACE_LOG
415  std::cerr << " =:=:=: TimeStamp done \n";
416 #endif
417 
418  // Provide the context information:
419  //
420  if (!msg.is_verbatim()) {
421  if (wantSomeContext) {
422  if (needAspace) {
423  emitToken(ELstring(" "));
424  needAspace = false;
425  }
426  assert(!needAspace);
427  if (wantFullContext) {
428  emitToken(msg.context());
429 #ifdef ELoutputTRACE_LOG
430  std::cerr << " =:=:=: fullContext done: \n";
431 #endif
432  } else {
433  emitToken(msg.context());
434 #ifdef ELoutputTRACE_LOG
435  std::cerr << " =:=:=: Context done: \n";
436 #endif
437  }
438  }
439  }
440 
441  // Provide traceback information:
442  //
443 
444  bool insertNewlineAfterHeader = (msg.xid().severity != ELdebug);
445  // ELdebug is what LogDebug issues
446 
447  if (!msg.is_verbatim()) {
448  if (msg.xid().severity >= traceThreshold) {
449  emitToken(ELstring("\n"), insertNewlineAfterHeader);
450  } else { //else statement added JV:1
451  emitToken("", insertNewlineAfterHeader);
452  }
453  }
454 #ifdef ELoutputTRACE_LOG
455  std::cerr << " =:=:=: Trace routine done: \n";
456 #endif
457 
458 #ifndef OUTPUT_FORMATTED_ERROR_MESSAGES
459  // Finally, output each item in the message:
460  //
461  preambleMode = false;
462  if (wantText) {
463  ELlist_string::const_iterator it;
464  int item_count = 0;
465  for (it = msg.items().begin(); it != msg.items().end(); ++it) {
466 #ifdef ELoutputTRACE_LOG
467  std::cerr << " =:=:=: Item: " << *it << '\n';
468 #endif
469  ++item_count;
470  if (!msg.is_verbatim()) {
471  if (!insertNewlineAfterHeader && (item_count == 3)) {
472  // in a LogDebug message, the first 3 items are FILE, :, and LINE
473  emitToken(*it, true);
474  } else {
475  emitToken(*it);
476  }
477  } else {
478  emitToken(*it);
479  }
480  }
481  }
482 #endif
483 
484  // And after the message, add a %MSG on its own line
485  // Change log 4 6/11/07 mf
486 
487  if (!msg.is_verbatim()) {
488  emitToken("\n%MSG");
489  }
490 
491  // Done; message has been fully processed; separate, flush, and leave
492  //
493 
494  (*os) << newline;
495  flush();
496 
497 #ifdef ELoutputTRACE_LOG
498  std::cerr << " =:=:=: log(msg) done: \n";
499 #endif
500 
501  return true;
502 
503  } // log()
504 
505  // Remainder are from base class.
506 
507  // ----------------------------------------------------------------------
508  // Output methods:
509  // ----------------------------------------------------------------------
510 
511  void ELoutput::emitToken(const ELstring& s, bool nl) {
512 #ifdef ELoutput_EMIT_TRACE
513  std::cerr << "[][][] in emit: charsOnLine is " << charsOnLine << '\n';
514  std::cerr << "[][][] in emit: s.length() " << s.length() << '\n';
515  std::cerr << "[][][] in emit: lineLength is " << lineLength << '\n';
516 #endif
517 
518  if (s.length() == 0) {
519  if (nl) {
520  (*os) << newline << std::flush;
521  charsOnLine = 0;
522  }
523  return;
524  }
525 
526  char first = s[0];
527  char second, last, last2;
528  second = (s.length() < 2) ? '\0' : s[1];
529  last = (s.length() < 2) ? '\0' : s[s.length() - 1];
530  last2 = (s.length() < 3) ? '\0' : s[s.length() - 2];
531  //checking -2 because the very last char is sometimes a ' ' inserted
532  //by ErrorLog::operator<<
533 
534  if (preambleMode) {
535  //Accounts for newline @ the beginning of the ELstring JV:2
536  if (first == '\n' || (charsOnLine + static_cast<int>(s.length())) > lineLength) {
537 #ifdef ELoutput_EMIT_TRACE
538  std::cerr << "[][][] in emit: about to << to *os \n";
539 #endif
540 #ifdef HEADERS_BROKEN_INTO_LINES_AND_INDENTED
541  // Change log 3: Removed this code 6/11/07 mf
542  (*os) << newline << indent;
543  charsOnLine = indent.length();
544 #else
545  charsOnLine = 0; // Change log 5
546 #endif
547  if (second != ' ') {
548  (*os) << ' ';
549  charsOnLine++;
550  }
551  if (first == '\n') {
552  (*os) << s.substr(1);
553  } else {
554  (*os) << s;
555  }
556  }
557 #ifdef ELoutput_EMIT_TRACE
558  std::cerr << "[][][] in emit: about to << s to *os: " << s << " \n";
559 #endif
560  else {
561  (*os) << s;
562  }
563 
564  if (last == '\n' || last2 == '\n') { //accounts for newline @ end $$ JV:2
565  (*os) << indent; //of the ELstring
566  if (last != ' ')
567  (*os) << ' ';
568  charsOnLine = indent.length() + 1;
569  }
570 
571  if (nl) {
572  (*os) << newline << std::flush;
573  charsOnLine = 0;
574  } else {
575  charsOnLine += s.length();
576  }
577  }
578 
579  if (!preambleMode) {
580  (*os) << s;
581  }
582 
583 #ifdef ELoutput_EMIT_TRACE
584  std::cerr << "[][][] in emit: completed \n";
585 #endif
586 
587  } // emitToken()
588 
589  // ----------------------------------------------------------------------
590  // Methods controlling message formatting:
591  // ----------------------------------------------------------------------
592 
595 
598 
601 
602  void ELoutput::includeText() { wantText = true; }
603  void ELoutput::suppressText() { wantText = false; }
604 
607 
610 
613 
616 
619 
620  // ----------------------------------------------------------------------
621  // Changing ostream:
622  // ----------------------------------------------------------------------
623 
624  void ELoutput::changeFile(std::ostream& os_) {
625  os.reset(&os_, do_nothing_deleter());
626  emitToken("\n=======================================================", true);
627  emitToken("\nError Log changed to this stream\n");
628  ELstring const& ftime = formatTime(time(nullptr)); // Change log 7
629  emitToken(ftime, true);
630  emitToken("\n=======================================================\n", true);
631  }
632 
634  os.reset(new std::ofstream(filename.c_str(), std::ios /*_base*/ ::app), close_and_delete());
635  emitToken("\n=======================================================", true);
636  emitToken("\nError Log changed to this file\n");
637  ELstring const& ftime = formatTime(time(nullptr)); // Change log 7
638  emitToken(ftime, true);
639  emitToken("\n=======================================================\n", true);
640  }
641 
642  void ELoutput::flush() { os->flush(); }
643 
644  // ----------------------------------------------------------------------
645 
646  } // end of namespace service
647 } // end of namespace edm
ELslProxy< ELdebugGen > const ELdebug
ELseverityLevel traceThreshold
ELseverityLevel severity
Definition: ELextendedID.h:29
const ELstring & idOverflow() const
Definition: ErrorObj.cc:134
std::unordered_set< std::string > ignoreThese
void suppressText() override
Definition: ELoutput.cc:603
time_t timestamp() const
Definition: ErrorObj.cc:135
virtual bool thisShouldBeIgnored(const ELstring &s) const
~ELoutput() override
Definition: ELoutput.cc:281
void separateEpilogue() override
Definition: ELoutput.cc:617
edm::ELextendedID xid
Definition: ELoutput.h:97
U second(std::pair< T, U > const &p)
const ELstring getSymbol() const
static ELstring formatTime(const time_t t)
Definition: ELoutput.cc:98
const ELextendedID & xid() const
Definition: ErrorObj.cc:133
void flush() override
Definition: ELoutput.cc:642
void includeModule() override
Definition: ELoutput.cc:596
void includeSubroutine() override
Definition: ELoutput.cc:599
bool add(const ELextendedID &xid)
void includeContext() override
Definition: ELoutput.cc:605
void attachEpilogue() override
Definition: ELoutput.cc:618
void suppressSerial() override
Definition: ELoutput.cc:608
int serial() const
Definition: ErrorObj.cc:132
std::unordered_set< std::string > respondToThese
ELstring subroutine
Definition: ELextendedID.h:31
void separateTime() override
Definition: ELoutput.cc:614
void suppressTime() override
Definition: ELoutput.cc:594
std::shared_ptr< std::ostream > os
Definition: ELoutput.h:95
const ELlist_string & items() const
Definition: ErrorObj.cc:136
ELslProxy< ELsevereGen > const ELsevere
void useFullContext() override
Definition: ELoutput.cc:611
void includeSerial() override
Definition: ELoutput.cc:609
void emitToken(const ELstring &s, bool nl=false)
Definition: ELoutput.cc:511
double b
Definition: hdecay.h:120
void attachTime() override
Definition: ELoutput.cc:615
void suppressModule() override
Definition: ELoutput.cc:597
tuple msg
Definition: mps_check.py:279
void includeTime() override
Definition: ELoutput.cc:593
void useContext() override
Definition: ELoutput.cc:612
HLT enums.
bool log(const edm::ErrorObj &msg) override
Definition: ELoutput.cc:295
T first(std::pair< T, U > const &p)
bool is_verbatim() const
Definition: ErrorObj.cc:138
void suppressContext() override
Definition: ELoutput.cc:606
std::string ELstring
Definition: ELstring.h:21
void changeFile(std::ostream &os) override
Definition: ELoutput.cc:624
ELstring context() const
Definition: ErrorObj.cc:140
void includeText() override
Definition: ELoutput.cc:602
void suppressSubroutine() override
Definition: ELoutput.cc:600