CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_3/src/FWCore/MessageService/src/MessageLoggerScribe.cc

Go to the documentation of this file.
00001 // ----------------------------------------------------------------------
00002 //
00003 // MessageLoggerScribe.cc
00004 //
00005 // Changes:
00006 //
00007 //   1 - 3/22/06  mf  - in configure_dest()     
00008 //      Repaired the fact that destination limits for categories
00009 //      were not being effective:
00010 //      a) use values from the destination specific default PSet
00011 //         rather than the overall default PSet to set these
00012 //      b) when an explicit value has been set - either by overall default or 
00013 //         by a destination specific default PSet - set that limit or
00014 //         timespan for that dest_ctrl via a "*" msgId.
00015 // 
00016 //   2 - 3/22/06  mf  - in configure_dest()     
00017 //      Enabled the use of -1 in the .cfg file to mean infinite limit
00018 //      or timespan.  This is done by:
00019 //      a) replacing the default value of -1 (by which we recognize 
00020 //      never-specified values) by NO_VALUE_SET = -45654
00021 //      b) checking for values of -1 and substituting a very large integer  
00022 //
00023 //   3 - 4/28/06  mf  - in configure_dest()
00024 //      Mods to help deal with the fact that checking for an empty PSet is
00025 //      unwise when untracked parameters are involved:  The PSet will appear
00026 //      to be empty and if skipped, will result in limits not being applied.
00027 //      a) Replaced default values directly in getAparameter with variables
00028 //      which can be examined all in one place.
00029 //      b) Carefully checked that we are never comparing to the empty PSet
00030 //      
00031 //   4 - 4/28/06  mf  - in configure_dest()
00032 //      If a destination name does not have an extension, append .log 
00033 //      (or in the case of a FwkJobReport, .xml).
00034 //      [note for this change - the filename kept as an index to stream_ps
00035 //      can be kept as its original name; it is just a tool for assigning
00036 //      the right shared stream to statistics destinations]
00037 //
00038 //   5 - 4/28/06  mf  - in configure_dest()
00039 //      Provision for an overall default affecting all categories, for 
00040 //      example, establishing a limit for all a specific category for
00041 //      every destination. 
00042 //
00043 //   6 - 5/18/06 mf  - in configure_dest()
00044 //      Implement establishing intervals between reacting to message of
00045 //      some type.
00046 //
00047 //   7 - 5/24/06 mf  - in configure_dest()
00048 //      Corrected algorithm for estabolishing limits and intervals, avoiding
00049 //      interference between setting the one and getting the default for the 
00050 //      other.
00051 //
00052 //   8 - 5/31/06 wmtan  - in configure_errorlog()
00053 //      The presence of the framework job report should not affect the output
00054 //      to the early destination (cerr).
00055 //
00056 //   9 - 6/6/06 mf  - in configure_dest()
00057 //      Support for placeholder PSet without actually creating the destination.
00058 //      Useful in a .cfi file, in conjunction with potential replace commands.
00059 //
00060 //  10 - 6/6/06 mf  - in configure_dest()
00061 //      Changed cfg keyword interval to reportEvery
00062 //
00063 //  11 - 6/12/06 mf  - in configure_errorlog()
00064 //      Check for placeholder before attaching a destination that may not be
00065 //      wanted.
00066 //
00067 //  12 - 6/14/06 mf  - in configure_external_dests()
00068 //      Clear the list of external dests needing configuration, if there
00069 //      is no configuration file available.
00070 //
00071 //  13 - 8/7/06 mf  - in configure_external_dests()
00072 //      Undo change 12: the list of external dests needing configuration
00073 //      is left intact if there is no configuration file available, the
00074 //      assumption being that at some later time there will be a file and
00075 //      the message logger will be configured again.
00076 //
00077 //      Note: The change made in (12) and un-done here was necessary to
00078 //            prevent segfault behavior when a job is done with external
00079 //            destinations and no .cfg file under some circumstances.
00080 //            D. Evans (who was being hit with that behavior due to an
00081 //            accidental .cfg omission) asserts (8/16) that running with
00082 //            no .cfg file is a sufficient anomoly that the current change
00083 //            is acceptable. 
00084 //
00085 //  14 - 10/18/06 mf  - in configure_error_log()
00086 //      Finer control of output file name for a given destination:
00087 //      Accept a parameter extension, to specify some extension other than
00088 //      .log without needing to place a dot in the Pset name.  Also accept
00089 //      an explicit filename.
00090 //
00091 //  15 - 2/11/07 mf - at bottom
00092 //      Declared static_errorlog_p
00093 //
00094 //  16 - 3/13/07 mf - in configure_errorlog() and addition of 3 functions
00095 //       Break out the configuring of each type of destination, for sanity.
00096 //
00097 //  17 - 3/13/07 mf - in run(), at CONFIGURE case
00098 //       Use the handshake to make this synchronous, and pass any throw
00099 //       across to the other thread.
00100 //
00101 //  18 - 3/14/07 mf - in configure_ordinary_destinations() and 2 others
00102 //       Use actual filename in a master ostream_ps list, and behave correctly
00103 //       when duplicates are found (duplicate names both used leads to grim
00104 //       file behavior when one file is opened as two streams).
00105 //
00106 //  19 - 3/15/07 mf - in configure_fwkJobReports()
00107 //       "Deturdification" - default is to not produce a job reports; a
00108 //       command-line option lets you produce them.
00109 //
00110 //  20 - 3/15/07 mf - in configure_statistics() and configure_fwkJobReports()
00111 //       Handle the placeholder case 
00112 //
00113 //  21 - 3/15/07 mf - run()
00114 //       Improve the behavior of catches of exceptions in non-synchronous 
00115 //       command cases:  Unless the ConfigurationHandshake is used, re-throw
00116 //       is not an option, but exit is also not very good.
00117 //
00118 //  22 - 4/18/07 mf - in configure_error_log and its called functions
00119 //       Allow for duplicate file names if configuration happens twice.
00120 //
00121 //  23 - 6/13/07 mf - in configure_statistics 
00122 //       Repared error of calling "cerr" "err", which would cause appended
00123 //       statistics destinations going to cerr to instead come out in a file 
00124 //       err.log
00125 //
00126 //  24 - 6/15/07 mf - in configure_errlog and its descendants
00127 //       Major mods to hardwire defaults taken from the .cfi file 
00128 //       To allow flexibility, this depends on MessageLoggerDefaults.h
00129 //
00130 //  25 - 7/24/07 mf - in run() 
00131 //       A command SHUT_UP to deactivate, and in the LOG_A_MESSGE case, response to 
00132 //       that command.  This allows supression of the generator info in case of a
00133 //       completely .cfg-less cmsRun command.  
00134 //
00135 //  26 - 8/7/07 mf - in run()
00136 //       A command FLUSH_LOG_Q to consume the entire queue, processing each 
00137 //       message.  Actually, the key is that on the other side, it is used in
00138 //       a synchronous manner (like CONFIGURE) so as soon as one gets up to 
00139 //       the flush command, the queue has in fact been flushed!  
00140 //
00141 //  27 - 8/16/07 mf - in run()
00142 //       A command GROUP_STATS to add a category to a list which ELstatistics 
00143 //       will use to avoid separate per-module statistics for that category.
00144 //
00145 //  28 - 6/18/08 mf - in CONFIGURE case and FLUSH_LOG_Q case
00146 //       Changed expectation of p from a ParameterSet* to a void*:
00147 //       static cast it to the needed ParameterSet*
00148 //
00149 //  29 - 6/19/08 mf - in run() and a new function triggerFJRmessageSummary()
00150 //       Implemented filling a map with summary info for the Job Report
00151 //
00152 //  30 - 6/20/08 mf - in run() 
00153 //       Setting MessageLoggerScribeIsRunning
00154 //
00155 //  31 - 7/9/08  mf - in configure_ordinary_destinations()
00156 //               and configure_statistics()
00157 //       using hardwired default output filename if there is one
00158 //
00159 //  32 - 10/21/08 mf - in ctor and in run() and new runCommand()
00160 //       split up run() to have ability to implement single-thread
00161 //
00162 //  33 - 10/22/08 mf
00163 //       implementation of singleThread
00164 //
00165 //  34 - 5/13/09 mf
00166 //       Allowing threshold to be set for default destination in default PSet
00167 //
00168 //  35 - 5/29/09 mf
00169 //       Avoiding throw when duplicate destination names are used, to let the
00170 //       validation report that and abort instead.
00171 //
00172 //  36 - 8/10/09 mf, cdj
00173 //       Use ThreadQ in place of the singleton MessageLoggerQ to consume
00174 //
00175 //  37 - 9/24/10 mf
00176 //       Establish values of debugAlwaysSuppressed, infoAlwaysSuppressed
00177 //       and warningAlwaysSuppressed when setting up thresholds
00178 //
00179 //  38 - 9/29/10 mf, ql
00180 //       Limit and timespan shuold be translated from -1 input to 
00181 //       2000000000.  This was being done in all cases except the 
00182 //       severity limits; omission rectified.
00183 //
00184 // ----------------------------------------------------------------------
00185 
00186 #include "FWCore/MessageService/interface/MessageLoggerScribe.h"
00187 #include "FWCore/MessageService/interface/ELadministrator.h"
00188 #include "FWCore/MessageService/interface/ELoutput.h"
00189 #include "FWCore/MessageService/interface/ELstatistics.h"
00190 #include "FWCore/MessageService/interface/ELfwkJobReport.h"
00191 #include "FWCore/MessageService/interface/ErrorLog.h"
00192 #include "FWCore/MessageService/interface/NamedDestination.h"
00193 #include "FWCore/MessageService/interface/ThreadQueue.h"
00194 
00195 #include "FWCore/MessageLogger/interface/ErrorObj.h"
00196 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00197 #include "FWCore/MessageLogger/interface/ConfigurationHandshake.h"
00198 #include "FWCore/MessageLogger/interface/MessageDrop.h"         // change log 37
00199 #include "FWCore/MessageLogger/interface/ELseverityLevel.h"     // change log 37
00200 
00201 #include "FWCore/Utilities/interface/EDMException.h"
00202 #include "FWCore/Utilities/interface/Algorithms.h"
00203 
00204 #include <algorithm>
00205 #include <cassert>
00206 #include <fstream>
00207 #include <string>
00208 #include <signal.h>
00209 
00210 using std::cerr;
00211 
00212 namespace edm {
00213 namespace service {
00214 
00215 
00216 MessageLoggerScribe::MessageLoggerScribe(boost::shared_ptr<ThreadQueue> queue)
00217 : admin_p   ( ELadministrator::instance() )
00218 , early_dest( admin_p->attach(ELoutput(std::cerr, false)) )
00219 , errorlog_p( new ErrorLog() )
00220 , file_ps   ( )
00221 , job_pset_p( )
00222 , extern_dests( )
00223 , jobReportOption( )
00224 , clean_slate_configuration( true )
00225 , active( true )
00226 , singleThread (queue.get() == 0)                               // changeLog 36
00227 , done (false)                                                  // changeLog 32
00228 , purge_mode (false)                                            // changeLog 32
00229 , count (false)                                                 // changeLog 32
00230 , m_queue(queue)                                                // changeLog 36
00231 {
00232   admin_p->setContextSupplier(msg_context);
00233 }
00234 
00235 MessageLoggerScribe::~MessageLoggerScribe()
00236 {
00237   admin_p->finish();
00238   assert( extern_dests.empty() );  // nothing to do
00239 }
00240 
00241 
00242 void
00243   MessageLoggerScribe::run()
00244 {
00245   MessageLoggerQ::OpCode  opcode;
00246   void *                  operand;
00247 
00248   MessageDrop::instance()->messageLoggerScribeIsRunning = 
00249                                 MLSCRIBE_RUNNING_INDICATOR;     // ChangeLog 30
00250 //  std::cerr << "MessageLoggerScribe::run(): \n";
00251 //  std::cerr << "messageLoggerScribeIsRunning = "
00252 //      << (int)MessageDrop::instance()->messageLoggerScribeIsRunning << "\n";
00253 
00254   do  {
00255     m_queue->consume(opcode, operand);  // grab next work item from Q 
00256                                         // changeLog 36
00257     runCommand (opcode, operand);
00258   } while(! done);
00259 
00260 }  // MessageLoggerScribe::run()
00261 
00262 void
00263   MessageLoggerScribe::runCommand(                              // changeLog 32
00264         MessageLoggerQ::OpCode  opcode, 
00265         void * operand)
00266 {
00267   switch(opcode)  {  // interpret the work item
00268     default:  {
00269       assert(false);  // can't happen (we certainly hope!)
00270       break;
00271     }
00272     case MessageLoggerQ::END_THREAD:  {
00273       assert( operand == 0 );
00274       done = true;
00275       MessageDrop::instance()->messageLoggerScribeIsRunning = 
00276               (unsigned char) -1;                               // ChangeLog 30
00277       break;
00278     }
00279     case MessageLoggerQ::LOG_A_MESSAGE:  {
00280       ErrorObj *  errorobj_p = static_cast<ErrorObj *>(operand);
00281       try {
00282         if(active && !purge_mode) log (errorobj_p);        
00283       }
00284       catch(cms::Exception& e)
00285       {
00286           ++count;
00287           std::cerr << "MessageLoggerScribe caught " << count
00288                << " cms::Exceptions, text = \n"
00289                << e.what() << "\n";
00290 
00291           if(count > 25)
00292             {
00293               cerr << "MessageLogger will no longer be processing "
00294                    << "messages due to errors (entering purge mode).\n";
00295               purge_mode = true;
00296             }
00297       }
00298       catch(...)
00299       {
00300           std::cerr << "MessageLoggerScribe caught an unknown exception and "
00301                << "will no longer be processing "
00302                << "messages. (entering purge mode)\n";
00303           purge_mode = true;
00304       }
00305       delete errorobj_p;  // dispose of the message text
00306       break;
00307     }
00308     case MessageLoggerQ::CONFIGURE:  {                  // changelog 17
00309       if (singleThread) {
00310         job_pset_p.reset(static_cast<ParameterSet *>(operand));
00311         configure_errorlog();
00312         break;
00313       } else {
00314         ConfigurationHandshake * h_p = 
00315                 static_cast<ConfigurationHandshake *>(operand);
00316         job_pset_p.reset(static_cast<ParameterSet *>(h_p->p));
00317         boost::mutex::scoped_lock sl(h_p->m);   // get lock
00318         try {
00319           configure_errorlog();
00320         }
00321         catch(edm::Exception& e)
00322           {
00323             Place_for_passing_exception_ptr epp = h_p->epp;
00324             if (!(*epp)) { 
00325               *epp = boost::shared_ptr<edm::Exception>(new edm::Exception(e));
00326             } else {
00327               Pointer_to_new_exception_on_heap ep = *epp;
00328               (*ep) << "\n and another exception: \n" << e.what();
00329             }
00330           }
00331         // Note - since the configuring code has not made a new copy of the 
00332         // job parameter set, we must not delete job_pset_p (in contrast to
00333         // the case for errorobj_p).  On the other hand, if we instantiate
00334         // a new edm::Exception pointed to by *epp, it is the responsibility
00335         // of the MessageLoggerQ to delete it.
00336         h_p->c.notify_all();  // Signal to MessageLoggerQ that we are done
00337         // finally, release the scoped lock by letting it go out of scope 
00338         break;
00339       }
00340     }
00341     case MessageLoggerQ::EXTERN_DEST: {
00342       try {
00343         extern_dests.push_back( static_cast<NamedDestination *>(operand) );
00344         configure_external_dests();
00345       }
00346       catch(cms::Exception& e)                          // change log 21
00347         {
00348           std::cerr << "MessageLoggerScribe caught a cms::Exception "
00349                << "during extern dest configuration:\n"
00350                << e.what() << "\n"
00351                << "This is a serious problem, and the extern dest " 
00352                << "will not be produced.\n"
00353                << "However, the rest of the logger continues to run.\n";
00354         }
00355       catch(...)                                                // change log 21
00356         {
00357           std::cerr << "MessageLoggerScribe caught unkonwn exception type\n"
00358                << "during extern dest configuration. "
00359                << "This is a serious problem, and the extern dest " 
00360                << "will not be produced.\n"
00361                << "The rest of the logger will attempt to continue to run.\n";
00362         }
00363       break;
00364     }
00365     case MessageLoggerQ::SUMMARIZE: {
00366       assert( operand == 0 );
00367       try {
00368         triggerStatisticsSummaries();
00369       }
00370       catch(cms::Exception& e)
00371         {
00372           std::cerr << "MessageLoggerScribe caught exception "
00373                << "during summarize:\n"
00374                << e.what() << "\n";
00375         }
00376       catch(...)
00377         {
00378           std::cerr << "MessageLoggerScribe caught unkonwn exception type "
00379                << "during summarize. (Ignored)\n";
00380         }
00381       break;
00382     }
00383     case MessageLoggerQ::JOBREPORT:  {                  // change log 19
00384       std::string* jobReportOption_p =
00385               static_cast<std::string*>(operand);
00386       try {
00387         jobReportOption = *jobReportOption_p;
00388       }
00389       catch(cms::Exception& e)
00390         {
00391           std::cerr << "MessageLoggerScribe caught a cms::Exception "
00392                << "during processing of --jobReport option:\n"
00393                << e.what() << "\n"
00394                << "This likely will affect or prevent the job report.\n"
00395                << "However, the rest of the logger continues to run.\n";
00396         }
00397       catch(...)
00398         {
00399           std::cerr << "MessageLoggerScribe caught unkonwn exception type\n"
00400                << "during processing of --jobReport option.\n"
00401                << "This likely will affect or prevent the job report.\n"
00402                << "However, the rest of the logger continues to run.\n";
00403         }
00404       delete jobReportOption_p;  // dispose of the message text
00405                                  // which will have been new-ed
00406                                  // in MessageLogger.cc (service version)
00407       break;
00408     }
00409     case MessageLoggerQ::JOBMODE:  {                    // change log 24
00410       std::string* jobMode_p =
00411               static_cast<std::string*>(operand);
00412       JobMode jm = MessageLoggerDefaults::mode(*jobMode_p);
00413       messageLoggerDefaults = 
00414         value_ptr<MessageLoggerDefaults>(new MessageLoggerDefaults(jm));
00415               // Note - since messageLoggerDefaults is a value_ptr, 
00416               //        there is no concern about deleting here.
00417       delete jobMode_p;  // dispose of the message text
00418                          // which will have been new-ed
00419                          // in MessageLogger.cc (service version)
00420       break;
00421     }
00422     case MessageLoggerQ::SHUT_UP:  {
00423       assert( operand == 0 );
00424       active = false;
00425       break;
00426     }
00427     case MessageLoggerQ::FLUSH_LOG_Q:  {                        // changelog 26
00428       if (singleThread) return;
00429       ConfigurationHandshake * h_p = 
00430               static_cast<ConfigurationHandshake *>(operand);
00431       job_pset_p.reset(static_cast<ParameterSet *>(h_p->p));
00432       boost::mutex::scoped_lock sl(h_p->m);   // get lock
00433       h_p->c.notify_all();  // Signal to MessageLoggerQ that we are done
00434       // finally, release the scoped lock by letting it go out of scope 
00435       break;
00436     }
00437     case MessageLoggerQ::GROUP_STATS:  {                        // change log 27
00438       std::string* cat_p =
00439               static_cast<std::string*>(operand);
00440       ELstatistics::noteGroupedCategory(*cat_p);
00441       delete cat_p;  // dispose of the message text
00442       break;
00443     }
00444     case MessageLoggerQ::FJR_SUMMARY:  {                        // changelog 29
00445       if (singleThread) {
00446         std::map<std::string, double> * smp = 
00447                 static_cast<std::map<std::string, double> *>(operand);
00448         triggerFJRmessageSummary(*smp);
00449         break;
00450       } else {
00451         ConfigurationHandshake * h_p = 
00452                 static_cast<ConfigurationHandshake *>(operand);
00453         boost::mutex::scoped_lock sl(h_p->m);   // get lock
00454         std::map<std::string, double> * smp = 
00455                 static_cast<std::map<std::string, double> *>(h_p->p);
00456         triggerFJRmessageSummary(*smp);
00457         h_p->c.notify_all();  // Signal to MessageLoggerQ that we are done
00458         // finally, release the scoped lock by letting it go out of scope 
00459         break;
00460       }
00461     }
00462   }  // switch
00463 
00464 }  // MessageLoggerScribe::runCommand(opcode, operand)
00465 
00466 void MessageLoggerScribe::log ( ErrorObj *  errorobj_p ) {
00467   ELcontextSupplier& cs =
00468     const_cast<ELcontextSupplier&>(admin_p->getContextSupplier());
00469   MsgContext& mc = dynamic_cast<MsgContext&>(cs);
00470   mc.setContext(errorobj_p->context());
00471   std::vector<std::string> categories;
00472   parseCategories(errorobj_p->xid().id, categories);
00473   for (unsigned int icat = 0; icat < categories.size(); ++icat) {
00474     errorobj_p->setID(categories[icat]);
00475     (*errorlog_p)( *errorobj_p );  // route the message text
00476   } 
00477 }
00478 
00479 void
00480   MessageLoggerScribe::configure_errorlog()
00481 {
00482   vString  empty_vString;
00483   String   empty_String;
00484   PSet     empty_PSet;
00485   
00486   // The following is present to test pre-configuration message handling:
00487   String preconfiguration_message 
00488        = getAparameter<String>
00489         (*job_pset_p, "generate_preconfiguration_message", empty_String);
00490   if (preconfiguration_message != empty_String) {
00491     // To test a preconfiguration message without first going thru the 
00492     // configuration we are about to do, we issue the message (so it sits
00493     // on the queue), then copy the processing that the LOG_A_MESSAGE case
00494     // does.  We suppress the timestamp to allow for automated unit testing.
00495     early_dest.suppressTime();
00496     LogError ("preconfiguration") << preconfiguration_message;
00497     if (!singleThread) {
00498       MessageLoggerQ::OpCode  opcode;
00499       void *                  operand;
00500       m_queue->consume(opcode, operand);  // grab next work item from Q
00501       assert (opcode == MessageLoggerQ::LOG_A_MESSAGE);
00502       ErrorObj *  errorobj_p = static_cast<ErrorObj *>(operand);
00503       log (errorobj_p);        
00504       delete errorobj_p;  // dispose of the message text
00505     }
00506   }
00507 
00508   if ( !stream_ps.empty() ) {
00509     LogWarning ("multiLogConfig") 
00510         << "The message logger has been configured multiple times"; 
00511     clean_slate_configuration = false;                          // Change Log 22
00512   }
00513   configure_fwkJobReports();                                    // Change Log 16
00514   configure_ordinary_destinations();                            // Change Log 16
00515   configure_statistics();                                       // Change Log 16
00516 
00517   configure_external_dests();
00518 
00519 }  // MessageLoggerScribe::configure_errorlog()
00520 
00521 
00522 
00523 
00524 void
00525   MessageLoggerScribe::configure_dest( ELdestControl & dest_ctrl
00526                                      , String const &  filename
00527                                      )
00528 {
00529   static const int NO_VALUE_SET = -45654;                       // change log 2
00530   vString  empty_vString;
00531   PSet     empty_PSet;
00532   String   empty_String;
00533 
00534   // Defaults:                                                  // change log 3a
00535   const std::string COMMON_DEFAULT_THRESHOLD = "INFO";
00536   const         int COMMON_DEFAULT_LIMIT     = NO_VALUE_SET; 
00537   const         int COMMON_DEFAULT_INTERVAL  = NO_VALUE_SET;    // change log 6
00538   const         int COMMON_DEFAULT_TIMESPAN  = NO_VALUE_SET; 
00539 
00540   char const*  severity_array[] = {"WARNING", "INFO", "ERROR", "DEBUG"};
00541   vString const  severities(severity_array+0, severity_array+4);
00542 
00543   // grab list of categories
00544   vString  categories
00545      = getAparameter<vString>(*job_pset_p, "categories", empty_vString);
00546 
00547   // grab list of messageIDs -- these are a synonym for categories
00548   // Note -- the use of messageIDs is deprecated in favor of categories
00549   {
00550     vString  messageIDs
00551       = getAparameter<vString>(*job_pset_p, "messageIDs", empty_vString);
00552 
00553   // combine the lists, not caring about possible duplicates (for now)
00554     copy_all( messageIDs, std::back_inserter(categories) );
00555   }  // no longer need messageIDs
00556 
00557   // grab list of hardwired categories (hardcats) -- these are to be added
00558   // to the list of categories -- change log 24
00559   {
00560     std::vector<std::string> hardcats = messageLoggerDefaults->categories;
00561   // combine the lists, not caring about possible duplicates (for now)
00562     copy_all( hardcats, std::back_inserter(categories) );
00563   }  // no longer need hardcats
00564 
00565   // grab default threshold common to all destinations
00566   String default_threshold
00567      = getAparameter<String>(*job_pset_p, "threshold", empty_String);
00568                                                 // change log 3a
00569                                                 // change log 24
00570 
00571   // grab default limit/interval/timespan common to all destinations/categories:
00572   PSet  default_pset
00573      = getAparameter<PSet>(*job_pset_p, "default", empty_PSet);
00574   int  default_limit
00575     = getAparameter<int>(default_pset, "limit", COMMON_DEFAULT_LIMIT);
00576   int  default_interval
00577     = getAparameter<int>(default_pset, "reportEvery", COMMON_DEFAULT_INTERVAL);
00578                                                 // change log 6, 10
00579   int  default_timespan
00580     = getAparameter<int>(default_pset, "timespan", COMMON_DEFAULT_TIMESPAN);
00581                                                 // change log 2a
00582                                                 // change log 3a
00583   String default_pset_threshold                         
00584      = getAparameter<String>(default_pset, "threshold", default_threshold);
00585                                                 // change log 34
00586                                         
00587   // grab all of this destination's parameters:
00588   PSet  dest_pset = getAparameter<PSet>(*job_pset_p, filename, empty_PSet);
00589 
00590   // See if this is just a placeholder                  // change log 9
00591   bool is_placeholder 
00592       = getAparameter<bool>(dest_pset, "placeholder", false);
00593   if (is_placeholder) return;
00594   
00595   // grab this destination's default limit/interval/timespan:
00596   PSet  dest_default_pset
00597      = getAparameter<PSet>(dest_pset, "default", empty_PSet);
00598   int  dest_default_limit
00599     = getAparameter<int>(dest_default_pset, "limit", default_limit);
00600   int  dest_default_interval
00601     = getAparameter<int>(dest_default_pset, "reportEvery", default_interval);
00602                                                 // change log 6
00603   int  dest_default_timespan
00604     = getAparameter<int>(dest_default_pset, "timespan", default_timespan);
00605                                                 // change log 1a
00606   if ( dest_default_limit != NO_VALUE_SET ) {
00607     if ( dest_default_limit < 0 ) dest_default_limit = 2000000000;
00608     dest_ctrl.setLimit("*", dest_default_limit );
00609   }                                             // change log 1b, 2a, 2b
00610   if ( dest_default_interval != NO_VALUE_SET ) {  // change log 6
00611     dest_ctrl.setInterval("*", dest_default_interval );
00612   }                                             
00613   if ( dest_default_timespan != NO_VALUE_SET ) {
00614     if ( dest_default_timespan < 0 ) dest_default_timespan = 2000000000;
00615     dest_ctrl.setTimespan("*", dest_default_timespan );
00616   }                                             // change log 1b, 2a, 2b
00617                                                   
00618   // establish this destination's threshold:
00619   String dest_threshold
00620      = getAparameter<String>(dest_pset, "threshold", default_threshold);
00621   if (dest_threshold == empty_String) {  
00622     dest_threshold = default_threshold;
00623   }
00624   if (dest_threshold == empty_String) {                 // change log 34
00625       dest_threshold = default_pset_threshold;
00626   }
00627   if (dest_threshold == empty_String) {
00628     dest_threshold = messageLoggerDefaults->threshold(filename);
00629   }
00630   if (dest_threshold == empty_String) dest_threshold = COMMON_DEFAULT_THRESHOLD;
00631   ELseverityLevel  threshold_sev(dest_threshold);
00632   dest_ctrl.setThreshold(threshold_sev);
00633   // change log 37
00634   if (threshold_sev <= ELseverityLevel::ELsev_success) 
00635         { edm::MessageDrop::debugAlwaysSuppressed = false; }
00636   if (threshold_sev <= ELseverityLevel::ELsev_info) 
00637         { edm::MessageDrop::infoAlwaysSuppressed = false; }
00638   if (threshold_sev <= ELseverityLevel::ELsev_warning) 
00639         { edm::MessageDrop::warningAlwaysSuppressed = false; }
00640 
00641   // establish this destination's limit/interval/timespan for each category:
00642   for( vString::const_iterator id_it = categories.begin()
00643      ; id_it != categories.end()
00644      ; ++id_it
00645      )
00646   {
00647     String  msgID = *id_it;
00648     PSet default_category_pset 
00649        = getAparameter<PSet>(default_pset, msgID, empty_PSet);  // change log 5
00650     PSet  category_pset
00651        = getAparameter<PSet>(dest_pset, msgID, default_category_pset);
00652 
00653     int  category_default_limit 
00654        = getAparameter<int>(default_category_pset, "limit", NO_VALUE_SET);
00655     int  limit
00656       = getAparameter<int>(category_pset, "limit", category_default_limit);
00657     if (limit == NO_VALUE_SET) limit = dest_default_limit;
00658                                                                 // change log 7 
00659     int  category_default_interval 
00660        = getAparameter<int>(default_category_pset, "reportEvery", NO_VALUE_SET);
00661     int  interval
00662       = getAparameter<int>(category_pset, "reportEvery",category_default_interval);
00663     if (interval == NO_VALUE_SET) interval = dest_default_interval;
00664                                                 // change log 6  and then 7
00665     int  category_default_timespan 
00666        = getAparameter<int>(default_category_pset, "timespan", NO_VALUE_SET);
00667     int  timespan
00668       = getAparameter<int>(category_pset, "timespan", category_default_timespan);
00669     if (timespan == NO_VALUE_SET) timespan = dest_default_timespan;
00670                                                                 // change log 7 
00671 
00672     std::string category = msgID;
00673     if ( limit     == NO_VALUE_SET )  {                         // change log 24
00674        limit = messageLoggerDefaults->limit(filename,category);
00675     }  
00676     if ( interval     == NO_VALUE_SET )  {                      // change log 24
00677        interval = messageLoggerDefaults->reportEvery(filename,category);
00678     }  
00679     if ( timespan     == NO_VALUE_SET )  {                      // change log 24
00680        timespan = messageLoggerDefaults->timespan(filename,category);
00681     }  
00682      
00683     if( limit     != NO_VALUE_SET )  {
00684       if ( limit < 0 ) limit = 2000000000;  
00685       dest_ctrl.setLimit(msgID, limit);
00686     }                                           // change log 2a, 2b
00687     if( interval  != NO_VALUE_SET )  {
00688       dest_ctrl.setInterval(msgID, interval);
00689     }                                           // change log 6
00690     if( timespan  != NO_VALUE_SET )  {
00691       if ( timespan < 0 ) timespan = 2000000000;  
00692       dest_ctrl.setTimespan(msgID, timespan);
00693     }                                           // change log 2a, 2b
00694                                                 
00695   }  // for
00696 
00697   // establish this destination's limit for each severity:
00698   for( vString::const_iterator sev_it = severities.begin()
00699      ; sev_it != severities.end()
00700      ; ++sev_it
00701      )
00702   {
00703     String  sevID = *sev_it;
00704     ELseverityLevel  severity(sevID);
00705     PSet  default_sev_pset 
00706         = getAparameter<PSet>(default_pset, sevID, empty_PSet);
00707     PSet  sev_pset 
00708         = getAparameter<PSet>(dest_pset, sevID, default_sev_pset);
00709                                                 // change log 5
00710     int  limit     = getAparameter<int>(sev_pset, "limit", NO_VALUE_SET);
00711     if ( limit     == NO_VALUE_SET )  {                         // change log 24
00712        limit = messageLoggerDefaults->sev_limit(filename,sevID);
00713     }  
00714     if( limit    != NO_VALUE_SET )  {
00715       if (limit < 0) limit = 2000000000;                        // change log 38
00716       dest_ctrl.setLimit(severity, limit   );
00717     }
00718     int  interval  = getAparameter<int>(sev_pset, "reportEvery", NO_VALUE_SET);
00719     if ( interval     == NO_VALUE_SET )  {                      // change log 24
00720        interval = messageLoggerDefaults->sev_reportEvery(filename,sevID);
00721     }  
00722     if( interval != NO_VALUE_SET )  dest_ctrl.setInterval(severity, interval);
00723                                                 // change log 2
00724     int  timespan  = getAparameter<int>(sev_pset, "timespan", NO_VALUE_SET);
00725     if ( timespan     == NO_VALUE_SET )  {                      // change log 24
00726        timespan = messageLoggerDefaults->sev_timespan(filename,sevID);
00727     }  
00728     if( timespan    != NO_VALUE_SET )  {
00729       if (timespan < 0) timespan = 2000000000;                  // change log 38
00730       dest_ctrl.setTimespan(severity, timespan   );
00731     }
00732   }  // for
00733 
00734   // establish this destination's linebreak policy:
00735   bool noLineBreaks_default 
00736         = getAparameter<bool> (default_pset, "noLineBreaks", false);
00737                                                 // change log 5
00738   bool noLineBreaks 
00739         = getAparameter<bool> (dest_pset, "noLineBreaks", noLineBreaks_default);
00740   if (noLineBreaks) {
00741     dest_ctrl.setLineLength(32000);
00742   }
00743   else {
00744     int  lenDef = 80;
00745     int  lineLen_default
00746          = getAparameter<int> (default_pset, "lineLength", lenDef);
00747                                                 // change log 5
00748     int  lineLen = getAparameter<int> (dest_pset, "lineLength", lineLen_default);
00749     if (lineLen != lenDef) {
00750       dest_ctrl.setLineLength(lineLen);
00751     }
00752   }
00753 
00754   // if indicated, suppress time stamps in this destination's output
00755   bool suppressTime_default 
00756         = getAparameter<bool> (default_pset, "noTimeStamps", false);
00757   bool suppressTime 
00758         = getAparameter<bool> (dest_pset, "noTimeStamps", suppressTime_default);
00759   if (suppressTime) {
00760     dest_ctrl.suppressTime();
00761   }
00762 
00763 }  // MessageLoggerScribe::configure_dest()
00764 
00765 void
00766   MessageLoggerScribe::configure_default_fwkJobReport 
00767                                 ( ELdestControl & dest_ctrl ) 
00768 {
00769  
00770   dest_ctrl.setLimit("*", 0 );
00771   String  msgID = "FwkJob";
00772   int FwkJob_limit = 10000000;
00773   dest_ctrl.setLimit(msgID, FwkJob_limit);
00774   dest_ctrl.setLineLength(32000);
00775   dest_ctrl.suppressTime();
00776  
00777 }  // MessageLoggerScribe::configure_default_fwkJobReport()
00778 
00779 
00780 void
00781   MessageLoggerScribe::configure_fwkJobReports()                // Changelog 16
00782 {
00783   vString  empty_vString;
00784   String   empty_String;
00785   PSet     empty_PSet;
00786   
00787   // decide whether to configure any job reports at all         // Changelog 19
00788   bool jobReportExists  = false;
00789   bool enableJobReports = false;
00790   #ifdef DEFINE_THIS_TO_MAKE_REPORTS_THE_DEFAULT
00791   enableJobReports = true;
00792   #endif
00793   if (jobReportOption != empty_String) enableJobReports = true;
00794   if (jobReportOption == "~") enableJobReports = false; //  --nojobReport
00795   if (!enableJobReports) return;
00796    
00797   if ((jobReportOption != "*") && (jobReportOption != empty_String)) {
00798     const std::string::size_type npos = std::string::npos;
00799     if ( jobReportOption.find('.') == npos ) {
00800       jobReportOption += ".xml";
00801     }  
00802   }
00803 
00804   // grab list of fwkJobReports:
00805   vString  fwkJobReports
00806      = getAparameter<vString>(*job_pset_p, "fwkJobReports", empty_vString);
00807 
00808   // Use the default list of fwkJobReports if and only if the grabbed list is
00809   // empty                                                      // change log 24
00810   if (fwkJobReports.empty()) {
00811     fwkJobReports = messageLoggerDefaults->fwkJobReports;
00812   }
00813   
00814   // establish each fwkJobReports destination:
00815   for( vString::const_iterator it = fwkJobReports.begin()
00816      ; it != fwkJobReports.end()
00817      ; ++it
00818      )
00819   {
00820     String filename = *it;
00821     String psetname = filename;
00822 
00823     // check that this destination is not just a placeholder // change log 20
00824     PSet  fjr_pset = getAparameter<PSet>(*job_pset_p, psetname, empty_PSet);
00825     bool is_placeholder 
00826         = getAparameter<bool>(fjr_pset, "placeholder", false);
00827     if (is_placeholder) continue;
00828 
00829     // Modify the file name if extension or name is explicitly specified
00830     // change log 14 
00831     String explicit_filename 
00832         = getAparameter<String>(fjr_pset, "filename", empty_String);
00833     if (explicit_filename != empty_String) filename = explicit_filename;
00834     String explicit_extension 
00835         = getAparameter<String>(fjr_pset, "extension", empty_String);
00836     if (explicit_extension != empty_String) {
00837       if (explicit_extension[0] == '.') {
00838         filename += explicit_extension;             
00839       } else {
00840         filename = filename + "." + explicit_extension;   
00841       }
00842     }
00843 
00844     // Attach a default extension of .xml if there is no extension on a file
00845     std::string actual_filename = filename;                     // change log 4
00846     const std::string::size_type npos = std::string::npos;
00847     if ( filename.find('.') == npos ) {
00848       actual_filename += ".xml";
00849     }  
00850 
00851      // Check that this is not a duplicate name                 // change log 18
00852     if ( stream_ps.find(actual_filename)!=stream_ps.end() ) {        
00853       if (clean_slate_configuration) {                          // change log 22
00854        throw edm::Exception ( edm::errors::Configuration ) 
00855        <<"Duplicate name for a MessageLogger Framework Job Report Destination: " 
00856        << actual_filename
00857        << "\n";
00858       } else {
00859        LogWarning("duplicateDestination")
00860        <<"Duplicate name for a MessageLogger Framework Job Report Destination: " 
00861        << actual_filename
00862        << "\n" << "Only original configuration instructions are used";
00863        continue;
00864       }
00865      } 
00866     
00867     jobReportExists = true;                                     // Changelog 19
00868     if ( actual_filename == jobReportOption ) jobReportOption = empty_String;   
00869     
00870     boost::shared_ptr<std::ofstream> os_sp(new std::ofstream(actual_filename.c_str()));
00871     file_ps.push_back(os_sp);
00872     ELdestControl dest_ctrl;
00873     dest_ctrl = admin_p->attach( ELfwkJobReport(*os_sp) );
00874     stream_ps[actual_filename] = os_sp.get();
00875 
00876     // now configure this destination:
00877     configure_dest(dest_ctrl, psetname);        
00878 
00879   }  // for [it = fwkJobReports.begin() to end()]
00880 
00881   // Now possibly add the file specified by --jobReport         // Changelog 19
00882   if (jobReportOption==empty_String) return;
00883   if (jobReportExists && ( jobReportOption=="*" )) return;
00884   if (jobReportOption=="*") jobReportOption = "FrameworkJobReport.xml";
00885   // Check that this report is not already on order -- here the duplicate
00886   // name would not be a configuration error, but we shouldn't do it twice                      
00887   std::string actual_filename = jobReportOption;
00888   if ( stream_ps.find(actual_filename)!=stream_ps.end() ) return;
00889 
00890   boost::shared_ptr<std::ofstream> os_sp(new std::ofstream(actual_filename.c_str()));
00891   file_ps.push_back(os_sp);
00892   ELdestControl dest_ctrl;
00893   dest_ctrl = admin_p->attach( ELfwkJobReport(*os_sp) );
00894   stream_ps[actual_filename] = os_sp.get();
00895 
00896   // now configure this destination, in the jobreport default manner:
00897   configure_default_fwkJobReport (dest_ctrl);   
00898 
00899 }
00900 
00901 void
00902   MessageLoggerScribe::configure_ordinary_destinations()        // Changelog 16
00903 {
00904   vString  empty_vString;
00905   String   empty_String;
00906   PSet     empty_PSet;
00907 
00908   // Initialize unversal suppression variables
00909   MessageDrop::debugAlwaysSuppressed=true;              // change log 37
00910   MessageDrop::infoAlwaysSuppressed=true;               // change log 37
00911   MessageDrop::warningAlwaysSuppressed=true;            // change log 37
00912 
00913   // grab list of destinations:
00914   vString  destinations
00915      = getAparameter<vString>(*job_pset_p, "destinations", empty_vString);
00916 
00917   // Use the default list of destinations if and only if the grabbed list is
00918   // empty                                                      // change log 24
00919   if (destinations.empty()) {
00920     destinations = messageLoggerDefaults->destinations;
00921   }
00922   
00923   // dial down the early destination if other dest's are supplied:
00924   if( ! destinations.empty() )
00925     early_dest.setThreshold(ELhighestSeverity);
00926 
00927   // establish each destination:
00928   for( vString::const_iterator it = destinations.begin()
00929      ; it != destinations.end()
00930      ; ++it
00931      )
00932   {
00933     String filename = *it;
00934     String psetname = filename;
00935     
00936     // check that this destination is not just a placeholder // change log 11
00937     PSet  dest_pset = getAparameter<PSet>(*job_pset_p, psetname, empty_PSet);
00938     bool is_placeholder 
00939         = getAparameter<bool>(dest_pset, "placeholder", false);
00940     if (is_placeholder) continue;
00941 
00942     // Modify the file name if extension or name is explicitly specified
00943     // change log 14 
00944 
00945     // Although for an ordinary destination there is no output attribute
00946     // for the cfg (you can use filename instead) we provide output() for
00947     // uniformity with the statistics destinations.  The "right way" to
00948     // work this would have been to provide a filename() method, along with 
00949     // an extension() method.  We recognize the potential name confusion here
00950     // (filename(filename))!
00951     
00952     // Determine the destination file name to use if no explicit filename is
00953     // supplied in the cfg.
00954     String filename_default 
00955         = getAparameter<String>(dest_pset, "output", empty_String);
00956     if ( filename_default == empty_String ) {
00957       filename_default = messageLoggerDefaults->output(psetname); // change log 31
00958       if (filename_default  == empty_String) {
00959         filename_default  = filename;
00960       }        
00961     }
00962 
00963     String explicit_filename 
00964         = getAparameter<String>(dest_pset, "filename", filename_default);
00965     if (explicit_filename != empty_String) filename = explicit_filename;
00966     String explicit_extension 
00967         = getAparameter<String>(dest_pset, "extension", empty_String);
00968     if (explicit_extension != empty_String) {
00969       if (explicit_extension[0] == '.') {
00970         filename += explicit_extension;             
00971       } else {
00972         filename = filename + "." + explicit_extension;   
00973       }
00974     }
00975 
00976     // Attach a default extension of .log if there is no extension on a file
00977     // change log 18 - this had been done in concert with attaching destination
00978     
00979     std::string actual_filename = filename;                     // change log 4
00980     if ( (filename != "cout") && (filename != "cerr") )  {
00981       const std::string::size_type npos = std::string::npos;
00982       if ( filename.find('.') == npos ) {
00983         actual_filename += ".log";
00984       }  
00985     }
00986 
00987      // Check that this is not a duplicate name                 // change log 18
00988     if ( stream_ps.find(actual_filename)!=stream_ps.end() ) {        
00989       if (clean_slate_configuration) {                          // change log 22
00990 //        throw edm::Exception ( edm::errors::Configuration )   
00991         LogError("duplicateDestination")                        // change log 35
00992         <<"Duplicate name for a MessageLogger Destination: " 
00993         << actual_filename
00994         << "\n" << "Only the first configuration instructions are used";
00995         continue;
00996       } else {
00997         LogWarning("duplicateDestination")
00998         <<"Duplicate name for a MessageLogger Destination: " 
00999         << actual_filename
01000         << "\n" << "Only original configuration instructions are used";
01001         continue;
01002       }
01003     } 
01004     
01005     ordinary_destination_filenames.push_back(actual_filename);
01006 
01007     // attach the current destination, keeping a control handle to it:
01008     ELdestControl dest_ctrl;
01009     if( actual_filename == "cout" )  {
01010       dest_ctrl = admin_p->attach( ELoutput(std::cout) );
01011       stream_ps["cout"] = &std::cout;
01012     }
01013     else if( actual_filename == "cerr" )  {
01014       early_dest.setThreshold(ELzeroSeverity); 
01015       dest_ctrl = early_dest;
01016       stream_ps["cerr"] = &std::cerr;
01017     }
01018     else  {
01019       boost::shared_ptr<std::ofstream> os_sp(new std::ofstream(actual_filename.c_str()));
01020       file_ps.push_back(os_sp);
01021       dest_ctrl = admin_p->attach( ELoutput(*os_sp) );
01022       stream_ps[actual_filename] = os_sp.get();
01023     }
01024     //(*errorlog_p)( ELinfo, "added_dest") << filename << endmsg;
01025 
01026     // now configure this destination:
01027     configure_dest(dest_ctrl, psetname);
01028 
01029   }  // for [it = destinations.begin() to end()]
01030 
01031 } // configure_ordinary_destinations
01032 
01033 
01034 void
01035   MessageLoggerScribe::configure_statistics()
01036 {
01037   vString  empty_vString;
01038   String   empty_String;
01039   PSet     empty_PSet;
01040 
01041   // grab list of statistics destinations:
01042   vString  statistics 
01043      = getAparameter<vString>(*job_pset_p, "statistics", empty_vString);
01044   
01045   bool no_statistics_configured = statistics.empty();           // change log 24
01046   
01047   if ( no_statistics_configured ) {
01048     // Read the list of staistics destinations from hardwired defaults,
01049     // but only if there is also no list of ordinary destinations.
01050     // (If a cfg specifies destinations, and no statistics, assume that
01051     // is what the user wants.)
01052     vString  destinations
01053      = getAparameter<vString>(*job_pset_p, "destinations", empty_vString);
01054     if (destinations.empty()) { 
01055       statistics = messageLoggerDefaults->statistics;
01056       no_statistics_configured = statistics.empty();
01057     }
01058   }
01059 
01060    // establish each statistics destination:
01061   for( vString::const_iterator it = statistics.begin()
01062      ; it != statistics.end()
01063      ; ++it
01064      )
01065   {
01066     String statname = *it;
01067     String psetname = statname;
01068 
01069     // check that this destination is not just a placeholder // change log 20
01070     PSet  stat_pset = getAparameter<PSet>(*job_pset_p, psetname, empty_PSet);
01071     bool is_placeholder 
01072         = getAparameter<bool>(stat_pset, "placeholder", false);
01073     if (is_placeholder) continue;
01074 
01075     // Determine the destination file name
01076     String filename 
01077         = getAparameter<String>(stat_pset, "output", empty_String);
01078     if ( filename == empty_String ) {
01079       filename = messageLoggerDefaults->output(psetname);       // change log 31
01080       if (filename == empty_String) {
01081         filename = statname;
01082       }        
01083     }
01084 
01085     // Modify the file name if extension or name is explicitly specified
01086     // change log 14 -- probably suspenders and a belt, because ouput option
01087     // is present, but uniformity is nice.
01088                                         
01089     String explicit_filename 
01090         = getAparameter<String>(stat_pset, "filename", filename);
01091     if (explicit_filename != empty_String) filename = explicit_filename;
01092     String explicit_extension 
01093         = getAparameter<String>(stat_pset, "extension", empty_String);
01094     if (explicit_extension != empty_String) {
01095       if (explicit_extension[0] == '.') {
01096         filename += explicit_extension;             
01097       } else {
01098         filename = filename + "." + explicit_extension;   
01099       }
01100     }
01101 
01102     // Attach a default extension of .log if there is no extension on a file
01103     // change log 18 - this had been done in concert with attaching destination
01104     
01105     std::string actual_filename = filename;                     // change log 4
01106     if ( (filename != "cout") && (filename != "cerr") )  {      // change log 23
01107       const std::string::size_type npos = std::string::npos;
01108       if ( filename.find('.') == npos ) {
01109         actual_filename += ".log";
01110       }  
01111     }
01112 
01113     // Check that this is not a duplicate name - 
01114     // unless it is an ordinary destination (which stats can share)
01115     if ( !search_all(ordinary_destination_filenames, actual_filename) ) {
01116       if ( stream_ps.find(actual_filename)!=stream_ps.end() ) {        
01117         if (clean_slate_configuration) {                        // change log 22
01118           throw edm::Exception ( edm::errors::Configuration ) 
01119           <<"Duplicate name for a MessageLogger Statistics Destination: " 
01120           << actual_filename
01121           << "\n";
01122         } else {
01123           LogWarning("duplicateDestination")
01124           <<"Duplicate name for a MessageLogger Statistics Destination: " 
01125           << actual_filename
01126           << "\n" << "Only original configuration instructions are used";
01127           continue;
01128         } 
01129       }
01130     }
01131     
01132     // create (if statistics file does not match any destination file name)
01133     // or note (if statistics file matches a destination file name) the ostream.
01134     // But if no statistics destinations were provided in the config, do not
01135     // create a new destination for this hardwired statistics - only act if
01136     // it is matches a destination.  (shange log 24)
01137     bool statistics_destination_is_real = !no_statistics_configured;
01138     std::ostream* os_p;
01139     if ( stream_ps.find(actual_filename) == stream_ps.end() ) {
01140       if ( actual_filename == "cout" ) {
01141         os_p = &std::cout;
01142       } else if ( actual_filename == "cerr" ) {
01143         os_p = &std::cerr;
01144       } else {
01145         boost::shared_ptr<std::ofstream> os_sp(new std::ofstream(actual_filename.c_str()));
01146         file_ps.push_back(os_sp);
01147         os_p = os_sp.get();
01148       }
01149       stream_ps[actual_filename] = os_p;
01150     } else { 
01151       statistics_destination_is_real = true;                    // change log 24
01152       os_p = stream_ps[actual_filename];
01153     }
01154        
01155     if (statistics_destination_is_real) {                       // change log 24
01156       // attach the statistics destination, keeping a control handle to it:
01157       ELdestControl dest_ctrl;
01158       dest_ctrl = admin_p->attach( ELstatistics(*os_p) );
01159       statisticsDestControls.push_back(dest_ctrl);
01160       bool reset = getAparameter<bool>(stat_pset, "reset", false);
01161       statisticsResets.push_back(reset);
01162     
01163       // now configure this destination:
01164       configure_dest(dest_ctrl, psetname);
01165 
01166       // and suppress the desire to do an extra termination summary just because
01167       // of end-of-job info messages
01168       dest_ctrl.noTerminationSummary();
01169     }
01170      
01171   }  // for [it = statistics.begin() to end()]
01172 
01173 } // configure_statistics
01174 
01175 void
01176   MessageLoggerScribe::configure_external_dests()
01177 {
01178   if( ! job_pset_p )  
01179   {
01180 //  extern_dests.clear();                               
01181 //  change log 12, removed by change log 13
01182     return;
01183   }
01184 
01185   for( std::vector<NamedDestination*>::const_iterator it = extern_dests.begin()
01186      ; it != extern_dests.end()
01187      ;  ++it
01188      )
01189   {
01190     ELdestination *  dest_p = (*it)->dest_p().get();
01191     ELdestControl  dest_ctrl = admin_p->attach( *dest_p );
01192 
01193     // configure the newly-attached destination:
01194     configure_dest( dest_ctrl, (*it)->name() );
01195     delete *it;  // dispose of our (copy of the) NamedDestination
01196   }
01197   extern_dests.clear();
01198  
01199 }  // MessageLoggerScribe::configure_external_dests
01200 
01201 void
01202   MessageLoggerScribe::parseCategories (std::string const & s,
01203                                         std::vector<std::string> & cats)
01204 {
01205   const std::string::size_type npos = std::string::npos;
01206         std::string::size_type i    = 0;
01207   while ( i != npos ) {    
01208     std::string::size_type j = s.find('|',i);   
01209     cats.push_back (s.substr(i,j-i));
01210     i = j;
01211     while ( (i != npos) && (s[i] == '|') ) ++i; 
01212     // the above handles cases of || and also | at end of string
01213   } 
01214   // Note:  This algorithm assigns, as desired, one null category if it
01215   //        encounters an empty categories string
01216 }
01217 
01218 void
01219   MessageLoggerScribe::triggerStatisticsSummaries() {
01220     assert (statisticsDestControls.size() == statisticsResets.size());
01221     for (unsigned int i = 0; i != statisticsDestControls.size(); ++i) {
01222       statisticsDestControls[i].summary( );
01223       if (statisticsResets[i]) statisticsDestControls[i].wipe( );
01224     }
01225 }
01226 
01227 void
01228   MessageLoggerScribe::
01229   triggerFJRmessageSummary(std::map<std::string, double> & sm)  // ChangeLog 29
01230 {
01231   if (statisticsDestControls.empty()) {
01232     sm["NoStatisticsDestinationsConfigured"] = 0.0;
01233   } else {
01234     statisticsDestControls[0].summaryForJobReport(sm);
01235   }
01236 }
01237 
01238 ErrorLog * MessageLoggerScribe::static_errorlog_p;
01239 
01240 
01241 } // end of namespace service  
01242 } // end of namespace edm  
01243