CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
MessageLoggerScribe.cc
Go to the documentation of this file.
1 // ----------------------------------------------------------------------
2 //
3 // MessageLoggerScribe.cc
4 //
5 // Changes:
6 //
7 // 1 - 3/22/06 mf - in configure_dest()
8 // Repaired the fact that destination limits for categories
9 // were not being effective:
10 // a) use values from the destination specific default PSet
11 // rather than the overall default PSet to set these
12 // b) when an explicit value has been set - either by overall default or
13 // by a destination specific default PSet - set that limit or
14 // timespan for that dest_ctrl via a "*" msgId.
15 //
16 // 2 - 3/22/06 mf - in configure_dest()
17 // Enabled the use of -1 in the .cfg file to mean infinite limit
18 // or timespan. This is done by:
19 // a) replacing the default value of -1 (by which we recognize
20 // never-specified values) by NO_VALUE_SET = -45654
21 // b) checking for values of -1 and substituting a very large integer
22 //
23 // 3 - 4/28/06 mf - in configure_dest()
24 // Mods to help deal with the fact that checking for an empty PSet is
25 // unwise when untracked parameters are involved: The PSet will appear
26 // to be empty and if skipped, will result in limits not being applied.
27 // a) Replaced default values directly in getAparameter with variables
28 // which can be examined all in one place.
29 // b) Carefully checked that we are never comparing to the empty PSet
30 //
31 // 4 - 4/28/06 mf - in configure_dest()
32 // If a destination name does not have an extension, append .log
33 // (or in the case of a FwkJobReport, .xml).
34 // [note for this change - the filename kept as an index to stream_ps
35 // can be kept as its original name; it is just a tool for assigning
36 // the right shared stream to statistics destinations]
37 //
38 // 5 - 4/28/06 mf - in configure_dest()
39 // Provision for an overall default affecting all categories, for
40 // example, establishing a limit for all a specific category for
41 // every destination.
42 //
43 // 6 - 5/18/06 mf - in configure_dest()
44 // Implement establishing intervals between reacting to message of
45 // some type.
46 //
47 // 7 - 5/24/06 mf - in configure_dest()
48 // Corrected algorithm for estabolishing limits and intervals, avoiding
49 // interference between setting the one and getting the default for the
50 // other.
51 //
52 // 8 - 5/31/06 wmtan - in configure_errorlog()
53 // The presence of the framework job report should not affect the output
54 // to the early destination (cerr).
55 //
56 // 9 - 6/6/06 mf - in configure_dest()
57 // Support for placeholder PSet without actually creating the destination.
58 // Useful in a .cfi file, in conjunction with potential replace commands.
59 //
60 // 10 - 6/6/06 mf - in configure_dest()
61 // Changed cfg keyword interval to reportEvery
62 //
63 // 11 - 6/12/06 mf - in configure_errorlog()
64 // Check for placeholder before attaching a destination that may not be
65 // wanted.
66 //
67 // 12 - 6/14/06 mf - in configure_external_dests()
68 // Clear the list of external dests needing configuration, if there
69 // is no configuration file available.
70 //
71 // 13 - 8/7/06 mf - in configure_external_dests()
72 // Undo change 12: the list of external dests needing configuration
73 // is left intact if there is no configuration file available, the
74 // assumption being that at some later time there will be a file and
75 // the message logger will be configured again.
76 //
77 // Note: The change made in (12) and un-done here was necessary to
78 // prevent segfault behavior when a job is done with external
79 // destinations and no .cfg file under some circumstances.
80 // D. Evans (who was being hit with that behavior due to an
81 // accidental .cfg omission) asserts (8/16) that running with
82 // no .cfg file is a sufficient anomoly that the current change
83 // is acceptable.
84 //
85 // 14 - 10/18/06 mf - in configure_error_log()
86 // Finer control of output file name for a given destination:
87 // Accept a parameter extension, to specify some extension other than
88 // .log without needing to place a dot in the Pset name. Also accept
89 // an explicit filename.
90 //
91 // 15 - 2/11/07 mf - at bottom
92 // Declared static_errorlog_p
93 //
94 // 16 - 3/13/07 mf - in configure_errorlog() and addition of 3 functions
95 // Break out the configuring of each type of destination, for sanity.
96 //
97 // 17 - 3/13/07 mf - in run(), at CONFIGURE case
98 // Use the handshake to make this synchronous, and pass any throw
99 // across to the other thread.
100 //
101 // 18 - 3/14/07 mf - in configure_ordinary_destinations() and 2 others
102 // Use actual filename in a master ostream_ps list, and behave correctly
103 // when duplicates are found (duplicate names both used leads to grim
104 // file behavior when one file is opened as two streams).
105 //
106 // 19 - 3/15/07 mf - in configure_fwkJobReports()
107 // "Deturdification" - default is to not produce a job reports; a
108 // command-line option lets you produce them.
109 //
110 // 20 - 3/15/07 mf - in configure_statistics() and configure_fwkJobReports()
111 // Handle the placeholder case
112 //
113 // 21 - 3/15/07 mf - run()
114 // Improve the behavior of catches of exceptions in non-synchronous
115 // command cases: Unless the ConfigurationHandshake is used, re-throw
116 // is not an option, but exit is also not very good.
117 //
118 // 22 - 4/18/07 mf - in configure_error_log and its called functions
119 // Allow for duplicate file names if configuration happens twice.
120 //
121 // 23 - 6/13/07 mf - in configure_statistics
122 // Repared error of calling "cerr" "err", which would cause appended
123 // statistics destinations going to cerr to instead come out in a file
124 // err.log
125 //
126 // 24 - 6/15/07 mf - in configure_errlog and its descendants
127 // Major mods to hardwire defaults taken from the .cfi file
128 // To allow flexibility, this depends on MessageLoggerDefaults.h
129 //
130 // 25 - 7/24/07 mf - in run()
131 // A command SHUT_UP to deactivate, and in the LOG_A_MESSGE case, response to
132 // that command. This allows supression of the generator info in case of a
133 // completely .cfg-less cmsRun command.
134 //
135 // 26 - 8/7/07 mf - in run()
136 // A command FLUSH_LOG_Q to consume the entire queue, processing each
137 // message. Actually, the key is that on the other side, it is used in
138 // a synchronous manner (like CONFIGURE) so as soon as one gets up to
139 // the flush command, the queue has in fact been flushed!
140 //
141 // 27 - 8/16/07 mf - in run()
142 // A command GROUP_STATS to add a category to a list which ELstatistics
143 // will use to avoid separate per-module statistics for that category.
144 //
145 // 28 - 6/18/08 mf - in CONFIGURE case and FLUSH_LOG_Q case
146 // Changed expectation of p from a ParameterSet* to a void*:
147 // static cast it to the needed ParameterSet*
148 //
149 // 29 - 6/19/08 mf - in run() and a new function triggerFJRmessageSummary()
150 // Implemented filling a map with summary info for the Job Report
151 //
152 // 30 - 6/20/08 mf - in run()
153 // Setting MessageLoggerScribeIsRunning
154 //
155 // 31 - 7/9/08 mf - in configure_ordinary_destinations()
156 // and configure_statistics()
157 // using hardwired default output filename if there is one
158 //
159 // 32 - 10/21/08 mf - in ctor and in run() and new runCommand()
160 // split up run() to have ability to implement single-thread
161 //
162 // 33 - 10/22/08 mf
163 // implementation of singleThread
164 //
165 // 34 - 5/13/09 mf
166 // Allowing threshold to be set for default destination in default PSet
167 //
168 // 35 - 5/29/09 mf
169 // Avoiding throw when duplicate destination names are used, to let the
170 // validation report that and abort instead.
171 //
172 // 36 - 8/10/09 mf, cdj
173 // Use ThreadQ in place of the singleton MessageLoggerQ to consume
174 //
175 // 37 - 9/24/10 mf
176 // Establish values of debugAlwaysSuppressed, infoAlwaysSuppressed
177 // and warningAlwaysSuppressed when setting up thresholds
178 //
179 // 38 - 9/29/10 mf, ql
180 // Limit and timespan shuold be translated from -1 input to
181 // 2000000000. This was being done in all cases except the
182 // severity limits; omission rectified.
183 //
184 // ----------------------------------------------------------------------
185 
192 
196 #include "FWCore/MessageLogger/interface/MessageDrop.h" // change log 37
197 #include "FWCore/MessageLogger/interface/ELseverityLevel.h" // change log 37
198 
201 
202 #include <algorithm>
203 #include <cassert>
204 #include <fstream>
205 #include <string>
206 #include <signal.h>
207 
208 using std::cerr;
209 
210 namespace edm {
211 namespace service {
212 
213 
214 MessageLoggerScribe::MessageLoggerScribe(std::shared_ptr<ThreadQueue> queue)
215 : admin_p ( new ELadministrator() )
216 , early_dest( admin_p->attach(ELoutput(std::cerr, false)) )
217 , file_ps ( )
218 , job_pset_p( )
219 , extern_dests( )
220 , clean_slate_configuration( true )
221 , active( true )
222 , singleThread (queue.get() == 0) // changeLog 36
223 , done (false) // changeLog 32
224 , purge_mode (false) // changeLog 32
225 , count (false) // changeLog 32
226 , m_queue(queue) // changeLog 36
227 {
228 }
229 
231 {
232  admin_p->finish();
233  assert( extern_dests.empty() ); // nothing to do
234 }
235 
236 
237 void
239 {
240  MessageLoggerQ::OpCode opcode;
241  void * operand;
242 
244  MLSCRIBE_RUNNING_INDICATOR; // ChangeLog 30
245 // std::cerr << "MessageLoggerScribe::run(): \n";
246 // std::cerr << "messageLoggerScribeIsRunning = "
247 // << (int)MessageDrop::instance()->messageLoggerScribeIsRunning << "\n";
248 
249  do {
250  m_queue->consume(opcode, operand); // grab next work item from Q
251  // changeLog 36
252  runCommand (opcode, operand);
253  } while(! done);
254 
255 } // MessageLoggerScribe::run()
256 
257 void
259  MessageLoggerQ::OpCode opcode,
260  void * operand)
261 {
262  switch(opcode) { // interpret the work item
263  default: {
264  assert(false); // can't happen (we certainly hope!)
265  break;
266  }
268  assert( operand == 0 );
269  done = true;
271  (unsigned char) -1; // ChangeLog 30
272  break;
273  }
275  ErrorObj * errorobj_p = static_cast<ErrorObj *>(operand);
276  try {
277  if(active && !purge_mode) log (errorobj_p);
278  }
279  catch(cms::Exception& e)
280  {
281  ++count;
282  std::cerr << "MessageLoggerScribe caught " << count
283  << " cms::Exceptions, text = \n"
284  << e.what() << "\n";
285 
286  if(count > 25)
287  {
288  cerr << "MessageLogger will no longer be processing "
289  << "messages due to errors (entering purge mode).\n";
290  purge_mode = true;
291  }
292  }
293  catch(...)
294  {
295  std::cerr << "MessageLoggerScribe caught an unknown exception and "
296  << "will no longer be processing "
297  << "messages. (entering purge mode)\n";
298  purge_mode = true;
299  }
300  delete errorobj_p; // dispose of the message text
301  break;
302  }
303  case MessageLoggerQ::CONFIGURE: { // changelog 17
304  if (singleThread) {
305  job_pset_p.reset(static_cast<ParameterSet *>(operand));
307  break;
308  } else {
309  ConfigurationHandshake * h_p =
310  static_cast<ConfigurationHandshake *>(operand);
311  job_pset_p.reset(static_cast<ParameterSet *>(h_p->p));
312  std::lock_guard<std::mutex> sl(h_p->m); // get lock
313  try {
315  }
316  catch(edm::Exception& e)
317  {
319  if (!(*epp)) {
320  *epp = std::make_shared<edm::Exception>(e);
321  } else {
323  (*ep) << "\n and another exception: \n" << e.what();
324  }
325  }
326  // Note - since the configuring code has not made a new copy of the
327  // job parameter set, we must not delete job_pset_p (in contrast to
328  // the case for errorobj_p). On the other hand, if we instantiate
329  // a new edm::Exception pointed to by *epp, it is the responsibility
330  // of the MessageLoggerQ to delete it.
331  h_p->c.notify_all(); // Signal to MessageLoggerQ that we are done
332  // finally, release the scoped lock by letting it go out of scope
333  break;
334  }
335  }
337  try {
338  extern_dests.push_back( static_cast<NamedDestination *>(operand) );
340  }
341  catch(cms::Exception& e) // change log 21
342  {
343  std::cerr << "MessageLoggerScribe caught a cms::Exception "
344  << "during extern dest configuration:\n"
345  << e.what() << "\n"
346  << "This is a serious problem, and the extern dest "
347  << "will not be produced.\n"
348  << "However, the rest of the logger continues to run.\n";
349  }
350  catch(...) // change log 21
351  {
352  std::cerr << "MessageLoggerScribe caught unkonwn exception type\n"
353  << "during extern dest configuration. "
354  << "This is a serious problem, and the extern dest "
355  << "will not be produced.\n"
356  << "The rest of the logger will attempt to continue to run.\n";
357  }
358  break;
359  }
361  assert( operand == 0 );
362  try {
364  }
365  catch(cms::Exception& e)
366  {
367  std::cerr << "MessageLoggerScribe caught exception "
368  << "during summarize:\n"
369  << e.what() << "\n";
370  }
371  catch(...)
372  {
373  std::cerr << "MessageLoggerScribe caught unkonwn exception type "
374  << "during summarize. (Ignored)\n";
375  }
376  break;
377  }
378  case MessageLoggerQ::JOBMODE: { // change log 24
379  std::string* jobMode_p =
380  static_cast<std::string*>(operand);
381  JobMode jm = MessageLoggerDefaults::mode(*jobMode_p);
384  // Note - since messageLoggerDefaults is a value_ptr,
385  // there is no concern about deleting here.
386  delete jobMode_p; // dispose of the message text
387  // which will have been new-ed
388  // in MessageLogger.cc (service version)
389  break;
390  }
392  assert( operand == 0 );
393  active = false;
394  break;
395  }
396  case MessageLoggerQ::FLUSH_LOG_Q: { // changelog 26
397  if (singleThread) return;
398  ConfigurationHandshake * h_p =
399  static_cast<ConfigurationHandshake *>(operand);
400  job_pset_p.reset(static_cast<ParameterSet *>(h_p->p));
401  std::lock_guard<std::mutex> sl(h_p->m); // get lock
402  h_p->c.notify_all(); // Signal to MessageLoggerQ that we are done
403  // finally, release the scoped lock by letting it go out of scope
404  break;
405  }
406  case MessageLoggerQ::GROUP_STATS: { // change log 27
407  std::string* cat_p =
408  static_cast<std::string*>(operand);
410  delete cat_p; // dispose of the message text
411  break;
412  }
413  case MessageLoggerQ::FJR_SUMMARY: { // changelog 29
414  if (singleThread) {
415  std::map<std::string, double> * smp =
416  static_cast<std::map<std::string, double> *>(operand);
418  break;
419  } else {
420  ConfigurationHandshake * h_p =
421  static_cast<ConfigurationHandshake *>(operand);
422  std::lock_guard<std::mutex> sl(h_p->m); // get lock
423  std::map<std::string, double> * smp =
424  static_cast<std::map<std::string, double> *>(h_p->p);
426  h_p->c.notify_all(); // Signal to MessageLoggerQ that we are done
427  // finally, release the scoped lock by letting it go out of scope
428  break;
429  }
430  }
431  } // switch
432 
433 } // MessageLoggerScribe::runCommand(opcode, operand)
434 
435 void MessageLoggerScribe::log ( ErrorObj * errorobj_p ) {
436  std::vector<std::string> categories;
437  parseCategories(errorobj_p->xid().id, categories);
438  for (unsigned int icat = 0; icat < categories.size(); ++icat) {
439  errorobj_p->setID(categories[icat]);
440  admin_p->log( *errorobj_p ); // route the message text
441  }
442 }
443 
444 void
446 {
447  vString empty_vString;
448  String empty_String;
449  PSet empty_PSet;
450 
451  // The following is present to test pre-configuration message handling:
452  String preconfiguration_message
453  = getAparameter<String>
454  (*job_pset_p, "generate_preconfiguration_message", empty_String);
455  if (preconfiguration_message != empty_String) {
456  // To test a preconfiguration message without first going thru the
457  // configuration we are about to do, we issue the message (so it sits
458  // on the queue), then copy the processing that the LOG_A_MESSAGE case
459  // does. We suppress the timestamp to allow for automated unit testing.
461  LogError ("preconfiguration") << preconfiguration_message;
462  if (!singleThread) {
463  MessageLoggerQ::OpCode opcode;
464  void * operand;
465  m_queue->consume(opcode, operand); // grab next work item from Q
466  assert (opcode == MessageLoggerQ::LOG_A_MESSAGE);
467  ErrorObj * errorobj_p = static_cast<ErrorObj *>(operand);
468  log (errorobj_p);
469  delete errorobj_p; // dispose of the message text
470  }
471  }
472 
473  if ( !stream_ps.empty() ) {
474  LogWarning ("multiLogConfig")
475  << "The message logger has been configured multiple times";
476  clean_slate_configuration = false; // Change Log 22
477  }
478  configure_ordinary_destinations(); // Change Log 16
479  configure_statistics(); // Change Log 16
480 
482 
483 } // MessageLoggerScribe::configure_errorlog()
484 
485 
486 
487 
488 void
490  , String const & filename
491  )
492 {
493  static const int NO_VALUE_SET = -45654; // change log 2
494  vString empty_vString;
495  PSet empty_PSet;
496  String empty_String;
497 
498  // Defaults: // change log 3a
499  const std::string COMMON_DEFAULT_THRESHOLD = "INFO";
500  const int COMMON_DEFAULT_LIMIT = NO_VALUE_SET;
501  const int COMMON_DEFAULT_INTERVAL = NO_VALUE_SET; // change log 6
502  const int COMMON_DEFAULT_TIMESPAN = NO_VALUE_SET;
503 
504  char const* severity_array[] = {"WARNING", "INFO", "ERROR", "DEBUG"};
505  vString const severities(severity_array+0, severity_array+4);
506 
507  // grab list of categories
509  = getAparameter<vString>(*job_pset_p, "categories", empty_vString);
510 
511  // grab list of messageIDs -- these are a synonym for categories
512  // Note -- the use of messageIDs is deprecated in favor of categories
513  {
514  vString messageIDs
515  = getAparameter<vString>(*job_pset_p, "messageIDs", empty_vString);
516 
517  // combine the lists, not caring about possible duplicates (for now)
518  copy_all( messageIDs, std::back_inserter(categories) );
519  } // no longer need messageIDs
520 
521  // grab list of hardwired categories (hardcats) -- these are to be added
522  // to the list of categories -- change log 24
523  {
524  std::vector<std::string> hardcats = messageLoggerDefaults->categories;
525  // combine the lists, not caring about possible duplicates (for now)
526  copy_all( hardcats, std::back_inserter(categories) );
527  } // no longer need hardcats
528 
529  // grab default threshold common to all destinations
530  String default_threshold
531  = getAparameter<String>(*job_pset_p, "threshold", empty_String);
532  // change log 3a
533  // change log 24
534 
535  // grab default limit/interval/timespan common to all destinations/categories:
536  PSet default_pset
537  = getAparameter<PSet>(*job_pset_p, "default", empty_PSet);
538  int default_limit
539  = getAparameter<int>(default_pset, "limit", COMMON_DEFAULT_LIMIT);
540  int default_interval
541  = getAparameter<int>(default_pset, "reportEvery", COMMON_DEFAULT_INTERVAL);
542  // change log 6, 10
543  int default_timespan
544  = getAparameter<int>(default_pset, "timespan", COMMON_DEFAULT_TIMESPAN);
545  // change log 2a
546  // change log 3a
547  String default_pset_threshold
548  = getAparameter<String>(default_pset, "threshold", default_threshold);
549  // change log 34
550 
551  // grab all of this destination's parameters:
552  PSet dest_pset = getAparameter<PSet>(*job_pset_p, filename, empty_PSet);
553 
554  // See if this is just a placeholder // change log 9
555  bool is_placeholder
556  = getAparameter<bool>(dest_pset, "placeholder", false);
557  if (is_placeholder) return;
558 
559  // grab this destination's default limit/interval/timespan:
560  PSet dest_default_pset
561  = getAparameter<PSet>(dest_pset, "default", empty_PSet);
562  int dest_default_limit
563  = getAparameter<int>(dest_default_pset, "limit", default_limit);
564  int dest_default_interval
565  = getAparameter<int>(dest_default_pset, "reportEvery", default_interval);
566  // change log 6
567  int dest_default_timespan
568  = getAparameter<int>(dest_default_pset, "timespan", default_timespan);
569  // change log 1a
570  if ( dest_default_limit != NO_VALUE_SET ) {
571  if ( dest_default_limit < 0 ) dest_default_limit = 2000000000;
572  dest_ctrl.setLimit("*", dest_default_limit );
573  } // change log 1b, 2a, 2b
574  if ( dest_default_interval != NO_VALUE_SET ) { // change log 6
575  dest_ctrl.setInterval("*", dest_default_interval );
576  }
577  if ( dest_default_timespan != NO_VALUE_SET ) {
578  if ( dest_default_timespan < 0 ) dest_default_timespan = 2000000000;
579  dest_ctrl.setTimespan("*", dest_default_timespan );
580  } // change log 1b, 2a, 2b
581 
582  // establish this destination's threshold:
583  String dest_threshold
584  = getAparameter<String>(dest_pset, "threshold", default_threshold);
585  if (dest_threshold == empty_String) {
586  dest_threshold = default_threshold;
587  }
588  if (dest_threshold == empty_String) { // change log 34
589  dest_threshold = default_pset_threshold;
590  }
591  if (dest_threshold == empty_String) {
592  dest_threshold = messageLoggerDefaults->threshold(filename);
593  }
594  if (dest_threshold == empty_String) dest_threshold = COMMON_DEFAULT_THRESHOLD;
595  ELseverityLevel threshold_sev(dest_threshold);
596  dest_ctrl.setThreshold(threshold_sev);
597  // change log 37
598  if (threshold_sev <= ELseverityLevel::ELsev_success)
600  if (threshold_sev <= ELseverityLevel::ELsev_info)
602  if (threshold_sev <= ELseverityLevel::ELsev_warning)
604 
605  // establish this destination's limit/interval/timespan for each category:
606  for( vString::const_iterator id_it = categories.begin()
607  ; id_it != categories.end()
608  ; ++id_it
609  )
610  {
611  String msgID = *id_it;
612  PSet default_category_pset
613  = getAparameter<PSet>(default_pset, msgID, empty_PSet); // change log 5
614  PSet category_pset
615  = getAparameter<PSet>(dest_pset, msgID, default_category_pset);
616 
617  int category_default_limit
618  = getAparameter<int>(default_category_pset, "limit", NO_VALUE_SET);
619  int limit
620  = getAparameter<int>(category_pset, "limit", category_default_limit);
621  if (limit == NO_VALUE_SET) limit = dest_default_limit;
622  // change log 7
623  int category_default_interval
624  = getAparameter<int>(default_category_pset, "reportEvery", NO_VALUE_SET);
625  int interval
626  = getAparameter<int>(category_pset, "reportEvery",category_default_interval);
627  if (interval == NO_VALUE_SET) interval = dest_default_interval;
628  // change log 6 and then 7
629  int category_default_timespan
630  = getAparameter<int>(default_category_pset, "timespan", NO_VALUE_SET);
631  int timespan
632  = getAparameter<int>(category_pset, "timespan", category_default_timespan);
633  if (timespan == NO_VALUE_SET) timespan = dest_default_timespan;
634  // change log 7
635 
636  std::string category = msgID;
637  if ( limit == NO_VALUE_SET ) { // change log 24
638  limit = messageLoggerDefaults->limit(filename,category);
639  }
640  if ( interval == NO_VALUE_SET ) { // change log 24
641  interval = messageLoggerDefaults->reportEvery(filename,category);
642  }
643  if ( timespan == NO_VALUE_SET ) { // change log 24
644  timespan = messageLoggerDefaults->timespan(filename,category);
645  }
646 
647  if( limit != NO_VALUE_SET ) {
648  if ( limit < 0 ) limit = 2000000000;
649  dest_ctrl.setLimit(msgID, limit);
650  } // change log 2a, 2b
651  if( interval != NO_VALUE_SET ) {
652  dest_ctrl.setInterval(msgID, interval);
653  } // change log 6
654  if( timespan != NO_VALUE_SET ) {
655  if ( timespan < 0 ) timespan = 2000000000;
656  dest_ctrl.setTimespan(msgID, timespan);
657  } // change log 2a, 2b
658 
659  } // for
660 
661  // establish this destination's limit for each severity:
662  for( vString::const_iterator sev_it = severities.begin()
663  ; sev_it != severities.end()
664  ; ++sev_it
665  )
666  {
667  String sevID = *sev_it;
668  ELseverityLevel severity(sevID);
669  PSet default_sev_pset
670  = getAparameter<PSet>(default_pset, sevID, empty_PSet);
671  PSet sev_pset
672  = getAparameter<PSet>(dest_pset, sevID, default_sev_pset);
673  // change log 5
674  int limit = getAparameter<int>(sev_pset, "limit", NO_VALUE_SET);
675  if ( limit == NO_VALUE_SET ) { // change log 24
676  limit = messageLoggerDefaults->sev_limit(filename,sevID);
677  }
678  if( limit != NO_VALUE_SET ) {
679  if (limit < 0) limit = 2000000000; // change log 38
680  dest_ctrl.setLimit(severity, limit );
681  }
682  int interval = getAparameter<int>(sev_pset, "reportEvery", NO_VALUE_SET);
683  if ( interval == NO_VALUE_SET ) { // change log 24
684  interval = messageLoggerDefaults->sev_reportEvery(filename,sevID);
685  }
686  if( interval != NO_VALUE_SET ) dest_ctrl.setInterval(severity, interval);
687  // change log 2
688  int timespan = getAparameter<int>(sev_pset, "timespan", NO_VALUE_SET);
689  if ( timespan == NO_VALUE_SET ) { // change log 24
690  timespan = messageLoggerDefaults->sev_timespan(filename,sevID);
691  }
692  if( timespan != NO_VALUE_SET ) {
693  if (timespan < 0) timespan = 2000000000; // change log 38
694  dest_ctrl.setTimespan(severity, timespan );
695  }
696  } // for
697 
698  // establish this destination's linebreak policy:
699  bool noLineBreaks_default
700  = getAparameter<bool> (default_pset, "noLineBreaks", false);
701  // change log 5
702  bool noLineBreaks
703  = getAparameter<bool> (dest_pset, "noLineBreaks", noLineBreaks_default);
704  if (noLineBreaks) {
705  dest_ctrl.setLineLength(32000);
706  }
707  else {
708  int lenDef = 80;
709  int lineLen_default
710  = getAparameter<int> (default_pset, "lineLength", lenDef);
711  // change log 5
712  int lineLen = getAparameter<int> (dest_pset, "lineLength", lineLen_default);
713  if (lineLen != lenDef) {
714  dest_ctrl.setLineLength(lineLen);
715  }
716  }
717 
718  // if indicated, suppress time stamps in this destination's output
719  bool suppressTime_default
720  = getAparameter<bool> (default_pset, "noTimeStamps", false);
721  bool suppressTime
722  = getAparameter<bool> (dest_pset, "noTimeStamps", suppressTime_default);
723  if (suppressTime) {
724  dest_ctrl.suppressTime();
725  }
726 
727 } // MessageLoggerScribe::configure_dest()
728 
729 void
731 {
732  vString empty_vString;
733  String empty_String;
734  PSet empty_PSet;
735 
736  // Initialize unversal suppression variables
737  MessageDrop::debugAlwaysSuppressed=true; // change log 37
738  MessageDrop::infoAlwaysSuppressed=true; // change log 37
739  MessageDrop::warningAlwaysSuppressed=true; // change log 37
740 
741  // grab list of destinations:
743  = getAparameter<vString>(*job_pset_p, "destinations", empty_vString);
744 
745  // Use the default list of destinations if and only if the grabbed list is
746  // empty // change log 24
747  if (destinations.empty()) {
748  destinations = messageLoggerDefaults->destinations;
749  }
750 
751  // dial down the early destination if other dest's are supplied:
752  if( ! destinations.empty() )
754 
755  // establish each destination:
756  for( vString::const_iterator it = destinations.begin()
757  ; it != destinations.end()
758  ; ++it
759  )
760  {
761  String filename = *it;
762  String psetname = filename;
763 
764  // check that this destination is not just a placeholder // change log 11
765  PSet dest_pset = getAparameter<PSet>(*job_pset_p, psetname, empty_PSet);
766  bool is_placeholder
767  = getAparameter<bool>(dest_pset, "placeholder", false);
768  if (is_placeholder) continue;
769 
770  // Modify the file name if extension or name is explicitly specified
771  // change log 14
772 
773  // Although for an ordinary destination there is no output attribute
774  // for the cfg (you can use filename instead) we provide output() for
775  // uniformity with the statistics destinations. The "right way" to
776  // work this would have been to provide a filename() method, along with
777  // an extension() method. We recognize the potential name confusion here
778  // (filename(filename))!
779 
780  // Determine the destination file name to use if no explicit filename is
781  // supplied in the cfg.
782  String filename_default
783  = getAparameter<String>(dest_pset, "output", empty_String);
784  if ( filename_default == empty_String ) {
785  filename_default = messageLoggerDefaults->output(psetname); // change log 31
786  if (filename_default == empty_String) {
787  filename_default = filename;
788  }
789  }
790 
791  String explicit_filename
792  = getAparameter<String>(dest_pset, "filename", filename_default);
793  if (explicit_filename != empty_String) filename = explicit_filename;
794  String explicit_extension
795  = getAparameter<String>(dest_pset, "extension", empty_String);
796  if (explicit_extension != empty_String) {
797  if (explicit_extension[0] == '.') {
798  filename += explicit_extension;
799  } else {
800  filename = filename + "." + explicit_extension;
801  }
802  }
803 
804  // Attach a default extension of .log if there is no extension on a file
805  // change log 18 - this had been done in concert with attaching destination
806 
807  std::string actual_filename = filename; // change log 4
808  if ( (filename != "cout") && (filename != "cerr") ) {
809  const std::string::size_type npos = std::string::npos;
810  if ( filename.find('.') == npos ) {
811  actual_filename += ".log";
812  }
813  }
814 
815  // Check that this is not a duplicate name // change log 18
816  if ( stream_ps.find(actual_filename)!=stream_ps.end() ) {
817  if (clean_slate_configuration) { // change log 22
818 // throw edm::Exception ( edm::errors::Configuration )
819  LogError("duplicateDestination") // change log 35
820  <<"Duplicate name for a MessageLogger Destination: "
821  << actual_filename
822  << "\n" << "Only the first configuration instructions are used";
823  continue;
824  } else {
825  LogWarning("duplicateDestination")
826  <<"Duplicate name for a MessageLogger Destination: "
827  << actual_filename
828  << "\n" << "Only original configuration instructions are used";
829  continue;
830  }
831  }
832 
833  ordinary_destination_filenames.push_back(actual_filename);
834 
835  // attach the current destination, keeping a control handle to it:
836  ELdestControl dest_ctrl;
837  if( actual_filename == "cout" ) {
838  dest_ctrl = admin_p->attach( ELoutput(std::cout) );
839  stream_ps["cout"] = &std::cout;
840  }
841  else if( actual_filename == "cerr" ) {
843  dest_ctrl = early_dest;
844  stream_ps["cerr"] = &std::cerr;
845  }
846  else {
847  auto os_sp = std::make_shared<std::ofstream>(actual_filename.c_str());
848  file_ps.push_back(os_sp);
849  dest_ctrl = admin_p->attach( ELoutput(*os_sp) );
850  stream_ps[actual_filename] = os_sp.get();
851  }
852 
853  // now configure this destination:
854  configure_dest(dest_ctrl, psetname);
855 
856  } // for [it = destinations.begin() to end()]
857 
858 } // configure_ordinary_destinations
859 
860 
861 void
863 {
864  vString empty_vString;
865  String empty_String;
866  PSet empty_PSet;
867 
868  // grab list of statistics destinations:
870  = getAparameter<vString>(*job_pset_p, "statistics", empty_vString);
871 
872  bool no_statistics_configured = statistics.empty(); // change log 24
873 
874  if ( no_statistics_configured ) {
875  // Read the list of staistics destinations from hardwired defaults,
876  // but only if there is also no list of ordinary destinations.
877  // (If a cfg specifies destinations, and no statistics, assume that
878  // is what the user wants.)
880  = getAparameter<vString>(*job_pset_p, "destinations", empty_vString);
881  if (destinations.empty()) {
882  statistics = messageLoggerDefaults->statistics;
883  no_statistics_configured = statistics.empty();
884  }
885  }
886 
887  // establish each statistics destination:
888  for( vString::const_iterator it = statistics.begin()
889  ; it != statistics.end()
890  ; ++it
891  )
892  {
893  String statname = *it;
894  String psetname = statname;
895 
896  // check that this destination is not just a placeholder // change log 20
897  PSet stat_pset = getAparameter<PSet>(*job_pset_p, psetname, empty_PSet);
898  bool is_placeholder
899  = getAparameter<bool>(stat_pset, "placeholder", false);
900  if (is_placeholder) continue;
901 
902  // Determine the destination file name
904  = getAparameter<String>(stat_pset, "output", empty_String);
905  if ( filename == empty_String ) {
906  filename = messageLoggerDefaults->output(psetname); // change log 31
907  if (filename == empty_String) {
908  filename = statname;
909  }
910  }
911 
912  // Modify the file name if extension or name is explicitly specified
913  // change log 14 -- probably suspenders and a belt, because ouput option
914  // is present, but uniformity is nice.
915 
916  String explicit_filename
917  = getAparameter<String>(stat_pset, "filename", filename);
918  if (explicit_filename != empty_String) filename = explicit_filename;
919  String explicit_extension
920  = getAparameter<String>(stat_pset, "extension", empty_String);
921  if (explicit_extension != empty_String) {
922  if (explicit_extension[0] == '.') {
923  filename += explicit_extension;
924  } else {
925  filename = filename + "." + explicit_extension;
926  }
927  }
928 
929  // Attach a default extension of .log if there is no extension on a file
930  // change log 18 - this had been done in concert with attaching destination
931 
932  std::string actual_filename = filename; // change log 4
933  if ( (filename != "cout") && (filename != "cerr") ) { // change log 23
934  const std::string::size_type npos = std::string::npos;
935  if ( filename.find('.') == npos ) {
936  actual_filename += ".log";
937  }
938  }
939 
940  // Check that this is not a duplicate name -
941  // unless it is an ordinary destination (which stats can share)
942  if ( !search_all(ordinary_destination_filenames, actual_filename) ) {
943  if ( stream_ps.find(actual_filename)!=stream_ps.end() ) {
944  if (clean_slate_configuration) { // change log 22
946  <<"Duplicate name for a MessageLogger Statistics Destination: "
947  << actual_filename
948  << "\n";
949  } else {
950  LogWarning("duplicateDestination")
951  <<"Duplicate name for a MessageLogger Statistics Destination: "
952  << actual_filename
953  << "\n" << "Only original configuration instructions are used";
954  continue;
955  }
956  }
957  }
958 
959  // create (if statistics file does not match any destination file name)
960  // or note (if statistics file matches a destination file name) the ostream.
961  // But if no statistics destinations were provided in the config, do not
962  // create a new destination for this hardwired statistics - only act if
963  // it is matches a destination. (shange log 24)
964  bool statistics_destination_is_real = !no_statistics_configured;
965  std::ostream* os_p;
966  if ( stream_ps.find(actual_filename) == stream_ps.end() ) {
967  if ( actual_filename == "cout" ) {
968  os_p = &std::cout;
969  } else if ( actual_filename == "cerr" ) {
970  os_p = &std::cerr;
971  } else {
972  auto os_sp = std::make_shared<std::ofstream>(actual_filename.c_str());
973  file_ps.push_back(os_sp);
974  os_p = os_sp.get();
975  }
976  stream_ps[actual_filename] = os_p;
977  } else {
978  statistics_destination_is_real = true; // change log 24
979  os_p = stream_ps[actual_filename];
980  }
981 
982  if (statistics_destination_is_real) { // change log 24
983  // attach the statistics destination, keeping a control handle to it:
984  ELdestControl dest_ctrl;
985  dest_ctrl = admin_p->attach( ELstatistics(*os_p) );
986  statisticsDestControls.push_back(dest_ctrl);
987  bool reset = getAparameter<bool>(stat_pset, "reset", false);
988  statisticsResets.push_back(reset);
989 
990  // now configure this destination:
991  configure_dest(dest_ctrl, psetname);
992 
993  // and suppress the desire to do an extra termination summary just because
994  // of end-of-job info messages
995  dest_ctrl.noTerminationSummary();
996  }
997 
998  } // for [it = statistics.begin() to end()]
999 
1000 } // configure_statistics
1001 
1002 void
1004 {
1005  if( ! job_pset_p )
1006  {
1007 // extern_dests.clear();
1008 // change log 12, removed by change log 13
1009  return;
1010  }
1011 
1012  for( std::vector<NamedDestination*>::const_iterator it = extern_dests.begin()
1013  ; it != extern_dests.end()
1014  ; ++it
1015  )
1016  {
1017  ELdestination * dest_p = (*it)->dest_p().get();
1018  ELdestControl dest_ctrl = admin_p->attach( *dest_p );
1019 
1020  // configure the newly-attached destination:
1021  configure_dest( dest_ctrl, (*it)->name() );
1022  delete *it; // dispose of our (copy of the) NamedDestination
1023  }
1024  extern_dests.clear();
1025 
1026 } // MessageLoggerScribe::configure_external_dests
1027 
1028 void
1030  std::vector<std::string> & cats)
1031 {
1032  const std::string::size_type npos = std::string::npos;
1034  while ( i != npos ) {
1035  std::string::size_type j = s.find('|',i);
1036  cats.push_back (s.substr(i,j-i));
1037  i = j;
1038  while ( (i != npos) && (s[i] == '|') ) ++i;
1039  // the above handles cases of || and also | at end of string
1040  }
1041  // Note: This algorithm assigns, as desired, one null category if it
1042  // encounters an empty categories string
1043 }
1044 
1045 void
1047  assert (statisticsDestControls.size() == statisticsResets.size());
1048  for (unsigned int i = 0; i != statisticsDestControls.size(); ++i) {
1049  statisticsDestControls[i].summary( );
1050  if (statisticsResets[i]) statisticsDestControls[i].wipe( );
1051  }
1052 }
1053 
1054 void
1056  triggerFJRmessageSummary(std::map<std::string, double> & sm) // ChangeLog 29
1057 {
1058  if (statisticsDestControls.empty()) {
1059  sm["NoStatisticsDestinationsConfigured"] = 0.0;
1060  } else {
1061  statisticsDestControls[0].summaryForJobReport(sm);
1062  }
1063 }
1064 
1065 
1066 
1067 } // end of namespace service
1068 } // end of namespace edm
1069 
virtual char const * what() const
Definition: Exception.cc:141
static unsigned char messageLoggerScribeIsRunning
Definition: MessageDrop.h:110
int i
Definition: DBlmapReader.cc:9
virtual void runCommand(MessageLoggerQ::OpCode opcode, void *operand)
ELdestControl & setLimit(const ELstring &s, int n)
ELdestControl & setThreshold(const ELseverityLevel &sv)
tuple interval
Definition: MergeJob_cfg.py:20
std::shared_ptr< ThreadQueue > m_queue
static MessageDrop * instance()
Definition: MessageDrop.cc:60
ELdestControl & setTimespan(const ELstring &s, int n)
ELslProxy< ELhighestSeverityGen > const ELhighestSeverity
uint16_t size_type
static const unsigned char MLSCRIBE_RUNNING_INDICATOR
Definition: MessageDrop.h:121
std::vector< String > ordinary_destination_filenames
static bool debugAlwaysSuppressed
Definition: MessageDrop.h:111
const ELextendedID & xid() const
Definition: ErrorObj.cc:147
edm::Place_for_passing_exception_ptr epp
std::shared_ptr< ELadministrator > admin_p
ELslProxy< ELzeroSeverityGen > const ELzeroSeverity
std::vector< std::shared_ptr< std::ofstream > > file_ps
std::vector< NamedDestination * > extern_dests
int j
Definition: DBlmapReader.cc:9
void configure_dest(ELdestControl &dest_ctrl, String const &filename)
static void noteGroupedCategory(std::string const &cat)
void parseCategories(std::string const &s, std::vector< std::string > &cats)
static bool warningAlwaysSuppressed
Definition: MessageDrop.h:113
virtual void setID(const ELstring &ID)
Definition: ErrorObj.cc:182
std::vector< ELdestControl > statisticsDestControls
bool search_all(ForwardSequence const &s, Datum const &d)
Definition: Algorithms.h:46
static edm::JobMode mode(std::string const &jm)
ELdestControl & setInterval(const ELstring &s, int interval)
MessageLoggerScribe(std::shared_ptr< ThreadQueue > queue)
— If queue is NULL, this sets singleThread true
JobMode
Definition: JobMode.h:15
Func copy_all(ForwardSequence &s, Func f)
wrappers for copy
Definition: Algorithms.h:24
void triggerFJRmessageSummary(std::map< std::string, double > &sm)
tuple filename
Definition: lut2db_cfg.py:20
tuple destinations
Definition: gather_cfg.py:120
std::map< String, std::ostream * > stream_ps
tuple cout
Definition: gather_cfg.py:121
volatile std::atomic< bool > shutdown_flag false
static bool infoAlwaysSuppressed
Definition: MessageDrop.h:112
void reset(double vett[256])
Definition: TPedValues.cc:11
T get(const Candidate &c)
Definition: component.h:55
std::shared_ptr< Pointer_to_new_exception_on_heap > Place_for_passing_exception_ptr
value_ptr< MessageLoggerDefaults > messageLoggerDefaults
std::shared_ptr< edm::Exception > Pointer_to_new_exception_on_heap