CMS 3D CMS Logo

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 keyward 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 // ----------------------------------------------------------------------
00160 
00161 #include "FWCore/MessageService/interface/ELadministrator.h"
00162 #include "FWCore/MessageService/interface/ELoutput.h"
00163 #include "FWCore/MessageService/interface/ELstatistics.h"
00164 #include "FWCore/MessageService/interface/ELfwkJobReport.h"
00165 #include "FWCore/MessageService/interface/ErrorLog.h"
00166 #include "FWCore/MessageService/interface/MessageLoggerScribe.h"
00167 
00168 #include "FWCore/MessageLogger/interface/ErrorObj.h"
00169 #include "FWCore/MessageLogger/interface/MessageLoggerQ.h"
00170 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00171 #include "FWCore/MessageLogger/interface/ConfigurationHandshake.h"
00172 
00173 #include "FWCore/Utilities/interface/EDMException.h"
00174 #include "FWCore/Utilities/interface/Algorithms.h"
00175 
00176 #include <algorithm>
00177 #include <cassert>
00178 #include <fstream>
00179 #include <iostream>
00180 #include <string>
00181 #include <signal.h>
00182 
00183 using std::cerr;
00184 
00185 namespace edm {
00186 namespace service {
00187 
00188 
00189 MessageLoggerScribe::MessageLoggerScribe()
00190 : admin_p   ( ELadministrator::instance() )
00191 , early_dest( admin_p->attach(ELoutput(std::cerr, false)) )
00192 , errorlog_p( new ErrorLog() )
00193 , file_ps   ( )
00194 , job_pset_p( 0 )
00195 , extern_dests( )
00196 , jobReportOption( )
00197 , clean_slate_configuration( true )
00198 , active( true )
00199 {
00200   admin_p->setContextSupplier(msg_context);
00201 }
00202 
00203 MessageLoggerScribe::~MessageLoggerScribe()
00204 {
00205   admin_p->finish();
00206   delete errorlog_p;
00207   for( ;  not file_ps.empty();  file_ps.pop_back() )  {
00208     delete file_ps.back();
00209   }
00210   delete job_pset_p; // dispose of our (copy of the) ParameterSet
00211   assert( extern_dests.empty() );  // nothing to do
00212 }
00213 
00214 
00215 void
00216   MessageLoggerScribe::run()
00217 {
00218   MessageLoggerQ::OpCode  opcode;
00219   void *                  operand;
00220   bool  done = false;
00221   bool  purge_mode = false;
00222   int count = 0;
00223 
00224   MessageDrop::instance()->messageLoggerScribeIsRunning = 
00225                                 MLSCRIBE_RUNNING_INDICATOR;     // ChangeLog 30
00226 //  std::cerr << "MessageLoggerScribe::run(): \n";
00227 //  std::cerr << "messageLoggerScribeIsRunning = "
00228 //      << (int)MessageDrop::instance()->messageLoggerScribeIsRunning << "\n";
00229 
00230   do  {
00231     MessageLoggerQ::consume(opcode, operand);  // grab next work item from Q
00232     switch(opcode)  {  // interpret the work item
00233       default:  {
00234         assert(false);  // can't happen (we certainly hope!)
00235         break;
00236       }
00237       case MessageLoggerQ::END_THREAD:  {
00238         assert( operand == 0 );
00239         done = true;
00240         MessageDrop::instance()->messageLoggerScribeIsRunning = 
00241                 (unsigned char) -1;                             // ChangeLog 30
00242         break;
00243       }
00244       case MessageLoggerQ::LOG_A_MESSAGE:  {
00245         ErrorObj *  errorobj_p = static_cast<ErrorObj *>(operand);
00246         try {
00247           if(active && !purge_mode) log (errorobj_p);        
00248         }
00249         catch(cms::Exception& e)
00250         {
00251             ++count;
00252             std::cerr << "MessageLoggerScribe caught " << count
00253                  << " cms::Exceptions, text = \n"
00254                  << e.what() << "\n";
00255 
00256             if(count > 25)
00257               {
00258                 cerr << "MessageLogger will no longer be processing "
00259                      << "messages due to errors (entering purge mode).\n";
00260                 purge_mode = true;
00261               }
00262         }
00263         catch(...)
00264         {
00265             std::cerr << "MessageLoggerScribe caught an unknown exception and "
00266                  << "will no longer be processing "
00267                  << "messages. (entering purge mode)\n";
00268             purge_mode = true;
00269         }
00270         delete errorobj_p;  // dispose of the message text
00271         break;
00272       }
00273       case MessageLoggerQ::CONFIGURE:  {                        // changelog 17
00274         ConfigurationHandshake * h_p = 
00275                 static_cast<ConfigurationHandshake *>(operand);
00276         job_pset_p = static_cast<ParameterSet *>(h_p->p);
00277         boost::mutex::scoped_lock sl(h_p->m);   // get lock
00278         try {
00279           configure_errorlog();
00280         }
00281         catch(edm::Exception& e)
00282           {
00283             Place_for_passing_exception_ptr epp = h_p->epp;
00284             if ( *epp == 0 ) { 
00285               *epp = new edm::Exception(e);
00286             } else {
00287               Pointer_to_new_exception_on_heap ep = *epp;
00288               (*ep) << "\n and another exception: \n" << e.what();
00289             }
00290           }
00291         // Note - since the configuring code has not made a new copy of the 
00292         // job parameter set, we must not delete job_pset_p (in contrast to
00293         // the case for errorobj_p).  On the other hand, if we instantiate
00294         // a new edm::Exception pointed to by *epp, it is the responsibility
00295         // of the MessageLoggerQ to delete it.
00296         h_p->c.notify_all();  // Signal to MessageLoggerQ that we are done
00297         // finally, release the scoped lock by letting it go out of scope 
00298         break;
00299       }
00300       case MessageLoggerQ::EXTERN_DEST: {
00301         try {
00302           extern_dests.push_back( static_cast<NamedDestination *>(operand) );
00303           configure_external_dests();
00304         }
00305         catch(cms::Exception& e)                                // change log 21
00306           {
00307             std::cerr << "MessageLoggerScribe caught a cms::Exception "
00308                  << "during extern dest configuration:\n"
00309                  << e.what() << "\n"
00310                  << "This is a serious problem, and the extern dest " 
00311                  << "will not be produced.\n"
00312                  << "However, the rest of the logger continues to run.\n";
00313           }
00314         catch(...)                                              // change log 21
00315           {
00316             std::cerr << "MessageLoggerScribe caught unkonwn exception type\n"
00317                  << "during extern dest configuration. "
00318                  << "This is a serious problem, and the extern dest " 
00319                  << "will not be produced.\n"
00320                  << "The rest of the logger will attempt to continue to run.\n";
00321           }
00322         break;
00323       }
00324       case MessageLoggerQ::SUMMARIZE: {
00325         assert( operand == 0 );
00326         try {
00327           triggerStatisticsSummaries();
00328         }
00329         catch(cms::Exception& e)
00330           {
00331             std::cerr << "MessageLoggerScribe caught exception "
00332                  << "during summarize:\n"
00333                  << e.what() << "\n";
00334           }
00335         catch(...)
00336           {
00337             std::cerr << "MessageLoggerScribe caught unkonwn exception type "
00338                  << "during summarize. (Ignored)\n";
00339           }
00340         break;
00341       }
00342       case MessageLoggerQ::JOBREPORT:  {                        // change log 19
00343         std::string* jobReportOption_p =
00344                 static_cast<std::string*>(operand);
00345         try {
00346           jobReportOption = *jobReportOption_p;
00347         }
00348         catch(cms::Exception& e)
00349           {
00350             std::cerr << "MessageLoggerScribe caught a cms::Exception "
00351                  << "during processing of --jobReport option:\n"
00352                  << e.what() << "\n"
00353                  << "This likely will affect or prevent the job reoport.\n"
00354                  << "However, the rest of the logger continues to run.\n";
00355           }
00356         catch(...)
00357           {
00358             std::cerr << "MessageLoggerScribe caught unkonwn exception type\n"
00359                  << "during processing of --jobReport option.\n"
00360                  << "This likely will affect or prevent the job reoport.\n"
00361                  << "However, the rest of the logger continues to run.\n";
00362           }
00363         delete jobReportOption_p;  // dispose of the message text
00364         break;
00365       }
00366       case MessageLoggerQ::JOBMODE:  {                  // change log 24
00367         std::string* jobMode_p =
00368                 static_cast<std::string*>(operand);
00369         JobMode jm = MessageLoggerDefaults::mode(*jobMode_p);
00370         messageLoggerDefaults = 
00371           value_ptr<MessageLoggerDefaults>(new MessageLoggerDefaults(jm));
00372                 // Note - since messageLoggerDefaults is a value_ptr, 
00373                 //        there is no concern about deleting here.
00374         delete jobMode_p;  // dispose of the message text
00375         break;
00376       }
00377       case MessageLoggerQ::SHUT_UP:  {
00378         assert( operand == 0 );
00379         active = false;
00380         break;
00381       }
00382       case MessageLoggerQ::FLUSH_LOG_Q:  {                      // changelog 26
00383         ConfigurationHandshake * h_p = 
00384                 static_cast<ConfigurationHandshake *>(operand);
00385         job_pset_p = static_cast<ParameterSet *>(h_p->p);
00386         boost::mutex::scoped_lock sl(h_p->m);   // get lock
00387         h_p->c.notify_all();  // Signal to MessageLoggerQ that we are done
00388         // finally, release the scoped lock by letting it go out of scope 
00389         break;
00390       }
00391       case MessageLoggerQ::GROUP_STATS:  {                      // change log 27
00392         std::string* cat_p =
00393                 static_cast<std::string*>(operand);
00394         ELstatistics::noteGroupedCategory(*cat_p);
00395         delete cat_p;  // dispose of the message text
00396         break;
00397       }
00398       case MessageLoggerQ::FJR_SUMMARY:  {                      // changelog 29
00399         ConfigurationHandshake * h_p = 
00400                 static_cast<ConfigurationHandshake *>(operand);
00401         boost::mutex::scoped_lock sl(h_p->m);   // get lock
00402         std::map<std::string, double> * smp = 
00403                 static_cast<std::map<std::string, double> *>(h_p->p);
00404         triggerFJRmessageSummary(*smp);
00405         h_p->c.notify_all();  // Signal to MessageLoggerQ that we are done
00406         // finally, release the scoped lock by letting it go out of scope 
00407         break;
00408       }
00409     }  // switch
00410 
00411   } while(! done);
00412 
00413 }  // MessageLoggerScribe::run()
00414 
00415 void MessageLoggerScribe::log ( ErrorObj *  errorobj_p ) {
00416   ELcontextSupplier& cs =
00417     const_cast<ELcontextSupplier&>(admin_p->getContextSupplier());
00418   MsgContext& mc = dynamic_cast<MsgContext&>(cs);
00419   mc.setContext(errorobj_p->context());
00420   std::vector<std::string> categories;
00421   parseCategories(errorobj_p->xid().id, categories);
00422   for (unsigned int icat = 0; icat < categories.size(); ++icat) {
00423     errorobj_p->setID(categories[icat]);
00424     (*errorlog_p)( *errorobj_p );  // route the message text
00425   } 
00426 }
00427 
00428 void
00429   MessageLoggerScribe::configure_errorlog()
00430 {
00431   vString  empty_vString;
00432   String   empty_String;
00433   PSet     empty_PSet;
00434   
00435   // The following is present to test pre-configuration message handling:
00436   String preconfiguration_message 
00437        = getAparameter<String>
00438         (job_pset_p, "generate_preconfiguration_message", empty_String);
00439   if (preconfiguration_message != empty_String) {
00440     // To test a preconfiguration message without first going thru the 
00441     // configuration we are about to do, we issue the message (so it sits
00442     // on the queue), then copy the processing that the LOG_A_MESSAGE case
00443     // does.  We suppress the timestamp to allow for automated unit testing.
00444     early_dest.suppressTime();
00445     LogError ("preconfiguration") << preconfiguration_message;
00446     MessageLoggerQ::OpCode  opcode;
00447     void *                  operand;
00448     MessageLoggerQ::consume(opcode, operand);  // grab next work item from Q
00449     assert (opcode == MessageLoggerQ::LOG_A_MESSAGE);
00450     ErrorObj *  errorobj_p = static_cast<ErrorObj *>(operand);
00451     log (errorobj_p);        
00452     delete errorobj_p;  // dispose of the message text
00453   }
00454 
00455   if ( !stream_ps.empty() ) {
00456     LogWarning ("multiLogConfig") 
00457         << "The message logger has been configured multiple times"; 
00458     clean_slate_configuration = false;                          // Change Log 22
00459   }
00460   configure_fwkJobReports();                                    // Change Log 16
00461   configure_ordinary_destinations();                            // Change Log 16
00462   configure_statistics();                                       // Change Log 16
00463 
00464   configure_external_dests();
00465 
00466 }  // MessageLoggerScribe::configure_errorlog()
00467 
00468 
00469 void
00470   MessageLoggerScribe::configure_dest( ELdestControl & dest_ctrl
00471                                      , String const &  filename
00472                                      )
00473 {
00474   static const int NO_VALUE_SET = -45654;                       // change log 2
00475   vString  empty_vString;
00476   PSet     empty_PSet;
00477   String   empty_String;
00478 
00479   // Defaults:                                                  // change log 3a
00480   const std::string COMMON_DEFAULT_THRESHOLD = "INFO";
00481   const         int COMMON_DEFAULT_LIMIT     = NO_VALUE_SET; 
00482   const         int COMMON_DEFAULT_INTERVAL  = NO_VALUE_SET;    // change log 6
00483   const         int COMMON_DEFAULT_TIMESPAN  = NO_VALUE_SET; 
00484 
00485   char *  severity_array[] = {"WARNING", "INFO", "ERROR", "DEBUG"};
00486   vString const  severities(severity_array+0, severity_array+4);
00487 
00488   // grab list of categories
00489   vString  categories
00490      = getAparameter<vString>(job_pset_p,"categories", empty_vString);
00491 
00492   // grab list of messageIDs -- these are a synonym for categories
00493   // Note -- the use of messageIDs is deprecated in favor of categories
00494   {
00495     vString  messageIDs
00496       = getAparameter<vString>(job_pset_p,"messageIDs", empty_vString);
00497 
00498   // combine the lists, not caring about possible duplicates (for now)
00499     copy_all( messageIDs, std::back_inserter(categories) );
00500   }  // no longer need messageIDs
00501 
00502   // grab list of hardwired categories (hardcats) -- these are to be added
00503   // to the list of categories -- change log 24
00504   {
00505     std::vector<std::string> hardcats = messageLoggerDefaults->categories;
00506   // combine the lists, not caring about possible duplicates (for now)
00507     copy_all( hardcats, std::back_inserter(categories) );
00508   }  // no longer need hardcats
00509 
00510   // grab default threshold common to all destinations
00511   String default_threshold
00512      = getAparameter<String>(job_pset_p,"threshold",empty_String);
00513                                                 // change log 3a
00514                                                 // change log 24
00515 
00516   // grab default limit/interval/timespan common to all destinations/categories:
00517   PSet  default_pset
00518      = getAparameter<PSet>(job_pset_p,"default", empty_PSet);
00519   int  default_limit
00520     = getAparameter<int>(&default_pset,"limit", COMMON_DEFAULT_LIMIT);
00521   int  default_interval
00522     = getAparameter<int>(&default_pset,"reportEvery", COMMON_DEFAULT_INTERVAL);
00523                                                 // change log 6, 10
00524   int  default_timespan
00525     = getAparameter<int>(&default_pset,"timespan", COMMON_DEFAULT_TIMESPAN);
00526                                                 // change log 2a
00527                                                 // change log 3a
00528                                         
00529   // grab all of this destination's parameters:
00530   PSet  dest_pset = getAparameter<PSet>(job_pset_p,filename,empty_PSet);
00531 
00532   // See if this is just a placeholder                  // change log 9
00533   bool is_placeholder 
00534       = getAparameter<bool>(&dest_pset,"placeholder", false);
00535   if (is_placeholder) return;
00536   
00537   // grab this destination's default limit/interval/timespan:
00538   PSet  dest_default_pset
00539      = getAparameter<PSet>(&dest_pset,"default", empty_PSet);
00540   int  dest_default_limit
00541     = getAparameter<int>(&dest_default_pset,"limit", default_limit);
00542   int  dest_default_interval
00543     = getAparameter<int>(&dest_default_pset,"reportEvery", default_interval);
00544                                                 // change log 6
00545   int  dest_default_timespan
00546     = getAparameter<int>(&dest_default_pset,"timespan", default_timespan);
00547                                                 // change log 1a
00548   if ( dest_default_limit != NO_VALUE_SET ) {
00549     if ( dest_default_limit < 0 ) dest_default_limit = 2000000000;
00550     dest_ctrl.setLimit("*", dest_default_limit );
00551   }                                             // change log 1b, 2a, 2b
00552   if ( dest_default_interval != NO_VALUE_SET ) {  // change log 6
00553     dest_ctrl.setInterval("*", dest_default_interval );
00554   }                                             
00555   if ( dest_default_timespan != NO_VALUE_SET ) {
00556     if ( dest_default_timespan < 0 ) dest_default_timespan = 2000000000;
00557     dest_ctrl.setTimespan("*", dest_default_timespan );
00558   }                                             // change log 1b, 2a, 2b
00559                                                   
00560   // establish this destination's threshold:
00561   String dest_threshold
00562      = getAparameter<String>(&dest_pset,"threshold", default_threshold);
00563   if (dest_threshold == empty_String) {
00564     dest_threshold = messageLoggerDefaults->threshold(filename);
00565   }
00566   if (dest_threshold == empty_String) dest_threshold = COMMON_DEFAULT_THRESHOLD;
00567   ELseverityLevel  threshold_sev(dest_threshold);
00568   dest_ctrl.setThreshold(threshold_sev);
00569 
00570   // establish this destination's limit/interval/timespan for each category:
00571   for( vString::const_iterator id_it = categories.begin()
00572      ; id_it != categories.end()
00573      ; ++id_it
00574      )
00575   {
00576     String  msgID = *id_it;
00577     PSet default_category_pset 
00578        = getAparameter<PSet>(&default_pset,msgID, empty_PSet);  // change log 5
00579     PSet  category_pset
00580        = getAparameter<PSet>(&dest_pset,msgID, default_category_pset);
00581 
00582     int  category_default_limit 
00583        = getAparameter<int>(&default_category_pset,"limit",NO_VALUE_SET);
00584     int  limit
00585       = getAparameter<int>(&category_pset,"limit", category_default_limit);
00586     if (limit == NO_VALUE_SET) limit = dest_default_limit;
00587                                                                 // change log 7 
00588     int  category_default_interval 
00589        = getAparameter<int>(&default_category_pset,"reportEvery",NO_VALUE_SET);
00590     int  interval
00591       = getAparameter<int>(&category_pset,"reportEvery",category_default_interval);
00592     if (interval == NO_VALUE_SET) interval = dest_default_interval;
00593                                                 // change log 6  and then 7
00594     int  category_default_timespan 
00595        = getAparameter<int>(&default_category_pset,"timespan",NO_VALUE_SET);
00596     int  timespan
00597       = getAparameter<int>(&category_pset,"timespan",category_default_timespan);
00598     if (timespan == NO_VALUE_SET) timespan = dest_default_timespan;
00599                                                                 // change log 7 
00600 
00601     std::string category = msgID;
00602     if ( limit     == NO_VALUE_SET )  {                         // change log 24
00603        limit = messageLoggerDefaults->limit(filename,category);
00604     }  
00605     if ( interval     == NO_VALUE_SET )  {                      // change log 24
00606        interval = messageLoggerDefaults->reportEvery(filename,category);
00607     }  
00608     if ( timespan     == NO_VALUE_SET )  {                      // change log 24
00609        timespan = messageLoggerDefaults->timespan(filename,category);
00610     }  
00611      
00612     if( limit     != NO_VALUE_SET )  {
00613       if ( limit < 0 ) limit = 2000000000;  
00614       dest_ctrl.setLimit(msgID, limit);
00615     }                                           // change log 2a, 2b
00616     if( interval  != NO_VALUE_SET )  {
00617       dest_ctrl.setInterval(msgID, interval);
00618     }                                           // change log 6
00619     if( timespan  != NO_VALUE_SET )  {
00620       if ( timespan < 0 ) timespan = 2000000000;  
00621       dest_ctrl.setTimespan(msgID, timespan);
00622     }                                           // change log 2a, 2b
00623                                                 
00624   }  // for
00625 
00626   // establish this destination's limit for each severity:
00627   for( vString::const_iterator sev_it = severities.begin()
00628      ; sev_it != severities.end()
00629      ; ++sev_it
00630      )
00631   {
00632     String  sevID = *sev_it;
00633     ELseverityLevel  severity(sevID);
00634     PSet  default_sev_pset 
00635         = getAparameter<PSet>(&default_pset,sevID, empty_PSet);
00636     PSet  sev_pset 
00637         = getAparameter<PSet>(&dest_pset,sevID, default_sev_pset);
00638                                                 // change log 5
00639     int  limit     = getAparameter<int>(&sev_pset,"limit",    NO_VALUE_SET);
00640     if ( limit     == NO_VALUE_SET )  {                         // change log 24
00641        limit = messageLoggerDefaults->sev_limit(filename,sevID);
00642     }  
00643     if( limit    != NO_VALUE_SET )  dest_ctrl.setLimit(severity, limit   );
00644     int  interval  = getAparameter<int>(&sev_pset,"reportEvery", NO_VALUE_SET);
00645     if ( interval     == NO_VALUE_SET )  {                      // change log 24
00646        interval = messageLoggerDefaults->sev_reportEvery(filename,sevID);
00647     }  
00648     if( interval != NO_VALUE_SET )  dest_ctrl.setInterval(severity, interval);
00649                                                 // change log 2
00650     int  timespan  = getAparameter<int>(&sev_pset,"timespan", NO_VALUE_SET);
00651     if ( timespan     == NO_VALUE_SET )  {                      // change log 24
00652        timespan = messageLoggerDefaults->sev_timespan(filename,sevID);
00653     }  
00654     if( timespan != NO_VALUE_SET )  dest_ctrl.setTimespan(severity, timespan   );
00655                                                 // change log 6
00656   }  // for
00657 
00658   // establish this destination's linebreak policy:
00659   bool noLineBreaks_default 
00660         = getAparameter<bool> (&default_pset,"noLineBreaks",false);
00661                                                 // change log 5
00662   bool noLineBreaks 
00663         = getAparameter<bool> (&dest_pset,"noLineBreaks",noLineBreaks_default);
00664   if (noLineBreaks) {
00665     dest_ctrl.setLineLength(32000);
00666   }
00667   else {
00668     int  lenDef = 80;
00669     int  lineLen_default
00670          = getAparameter<int> (&default_pset,"lineLength",lenDef);
00671                                                 // change log 5
00672     int  lineLen = getAparameter<int> (&dest_pset,"lineLength",lineLen_default);
00673     if (lineLen != lenDef) {
00674       dest_ctrl.setLineLength(lineLen);
00675     }
00676   }
00677 
00678   // if indicated, suppress time stamps in this destination's output
00679   bool suppressTime_default 
00680         = getAparameter<bool> (&default_pset,"noTimeStamps",false);
00681   bool suppressTime 
00682         = getAparameter<bool> (&dest_pset,"noTimeStamps",suppressTime_default);
00683   if (suppressTime) {
00684     dest_ctrl.suppressTime();
00685   }
00686 
00687 }  // MessageLoggerScribe::configure_dest()
00688 
00689 void
00690   MessageLoggerScribe::configure_default_fwkJobReport 
00691                                 ( ELdestControl & dest_ctrl ) 
00692 {
00693  
00694   dest_ctrl.setLimit("*", 0 );
00695   String  msgID = "FwkJob";
00696   int FwkJob_limit = 10000000;
00697   dest_ctrl.setLimit(msgID, FwkJob_limit);
00698   dest_ctrl.setLineLength(32000);
00699   dest_ctrl.suppressTime();
00700  
00701 }  // MessageLoggerScribe::configure_default_fwkJobReport()
00702 
00703 
00704 void
00705   MessageLoggerScribe::configure_fwkJobReports()                // Changelog 16
00706 {
00707   vString  empty_vString;
00708   String   empty_String;
00709   PSet     empty_PSet;
00710   
00711   // decide whether to configure any job reports at all         // Changelog 19
00712   bool jobReportExists  = false;
00713   bool enableJobReports = false;
00714   #ifdef DEFINE_THIS_TO_MAKE_REPORTS_THE_DEFAULT
00715   enableJobReports = true;
00716   #endif
00717   if (jobReportOption != empty_String) enableJobReports = true;
00718   if (jobReportOption == "~") enableJobReports = false; //  --nojobReport
00719   if (!enableJobReports) return;
00720    
00721   if ((jobReportOption != "*") && (jobReportOption != empty_String)) {
00722     const std::string::size_type npos = std::string::npos;
00723     if ( jobReportOption.find('.') == npos ) {
00724       jobReportOption += ".xml";
00725     }  
00726   }
00727 
00728   // grab list of fwkJobReports:
00729   vString  fwkJobReports
00730      = getAparameter<vString>(job_pset_p, "fwkJobReports", empty_vString);
00731 
00732   // Use the default list of fwkJobReports if and only if the grabbed list is
00733   // empty                                                      // change log 24
00734   if (fwkJobReports.empty()) {
00735     fwkJobReports = messageLoggerDefaults->fwkJobReports;
00736   }
00737   
00738   // establish each fwkJobReports destination:
00739   for( vString::const_iterator it = fwkJobReports.begin()
00740      ; it != fwkJobReports.end()
00741      ; ++it
00742      )
00743   {
00744     String filename = *it;
00745     String psetname = filename;
00746 
00747     // check that this destination is not just a placeholder // change log 20
00748     PSet  fjr_pset = getAparameter<PSet>(job_pset_p,psetname,empty_PSet);
00749     bool is_placeholder 
00750         = getAparameter<bool>(&fjr_pset,"placeholder", false);
00751     if (is_placeholder) continue;
00752 
00753     // Modify the file name if extension or name is explicitly specified
00754     // change log 14 
00755     String explicit_filename 
00756         = getAparameter<String>(&fjr_pset,"filename",empty_String);
00757     if (explicit_filename != empty_String) filename = explicit_filename;
00758     String explicit_extension 
00759         = getAparameter<String>(&fjr_pset,"extension",empty_String);
00760     if (explicit_extension != empty_String) {
00761       if (explicit_extension[0] == '.') {
00762         filename += explicit_extension;             
00763       } else {
00764         filename = filename + "." + explicit_extension;   
00765       }
00766     }
00767 
00768     // Attach a default extension of .xml if there is no extension on a file
00769     std::string actual_filename = filename;                     // change log 4
00770     const std::string::size_type npos = std::string::npos;
00771     if ( filename.find('.') == npos ) {
00772       actual_filename += ".xml";
00773     }  
00774 
00775      // Check that this is not a duplicate name                 // change log 18
00776     if ( stream_ps.find(actual_filename)!=stream_ps.end() ) {        
00777       if (clean_slate_configuration) {                          // change log 22
00778        throw edm::Exception ( edm::errors::Configuration ) 
00779        <<"Duplicate name for a MessageLogger Framework Job Report Destination: " 
00780        << actual_filename
00781        << "\n";
00782       } else {
00783        LogWarning("duplicateDestination")
00784        <<"Duplicate name for a MessageLogger Framework Job Report Destination: " 
00785        << actual_filename
00786        << "\n" << "Only original configuration instructions are used";
00787        continue;
00788       }
00789      } 
00790     
00791     jobReportExists = true;                                     // Changelog 19
00792     if ( actual_filename == jobReportOption ) jobReportOption = empty_String;   
00793     
00794     std::ofstream * os_p = new std::ofstream(actual_filename.c_str());
00795     file_ps.push_back(os_p);
00796     ELdestControl dest_ctrl;
00797     dest_ctrl = admin_p->attach( ELfwkJobReport(*os_p) );
00798     stream_ps[actual_filename] = os_p;
00799 
00800     // now configure this destination:
00801     configure_dest(dest_ctrl, psetname);        
00802 
00803   }  // for [it = fwkJobReports.begin() to end()]
00804 
00805   // Now possibly add the file specified by --jobReport         // Changelog 19
00806   if (jobReportOption==empty_String) return;
00807   if (jobReportExists && ( jobReportOption=="*" )) return;
00808   if (jobReportOption=="*") jobReportOption = "FrameworkJobReport.xml";
00809   // Check that this report is not already on order -- here the duplicate
00810   // name would not be a configuration error, but we shouldn't do it twice                      
00811   std::string actual_filename = jobReportOption;
00812   if ( stream_ps.find(actual_filename)!=stream_ps.end() ) return;
00813 
00814   std::ofstream * os_p = new std::ofstream(actual_filename.c_str());
00815   file_ps.push_back(os_p);
00816   ELdestControl dest_ctrl;
00817   dest_ctrl = admin_p->attach( ELfwkJobReport(*os_p) );
00818   stream_ps[actual_filename] = os_p;
00819 
00820   // now configure this destination, in the jobreport default manner:
00821   configure_default_fwkJobReport (dest_ctrl);   
00822 
00823 }
00824 
00825 void
00826   MessageLoggerScribe::configure_ordinary_destinations()        // Changelog 16
00827 {
00828   vString  empty_vString;
00829   String   empty_String;
00830   PSet     empty_PSet;
00831 
00832   // grab list of destinations:
00833   vString  destinations
00834      = getAparameter<vString>(job_pset_p, "destinations", empty_vString);
00835 
00836   // Use the default list of destinations if and only if the grabbed list is
00837   // empty                                                      // change log 24
00838   if (destinations.empty()) {
00839     destinations = messageLoggerDefaults->destinations;
00840   }
00841   
00842   // dial down the early destination if other dest's are supplied:
00843   if( ! destinations.empty() )
00844     early_dest.setThreshold(ELhighestSeverity);
00845 
00846   // establish each destination:
00847   for( vString::const_iterator it = destinations.begin()
00848      ; it != destinations.end()
00849      ; ++it
00850      )
00851   {
00852     String filename = *it;
00853     String psetname = filename;
00854     
00855     // check that this destination is not just a placeholder // change log 11
00856     PSet  dest_pset = getAparameter<PSet>(job_pset_p,psetname,empty_PSet);
00857     bool is_placeholder 
00858         = getAparameter<bool>(&dest_pset,"placeholder", false);
00859     if (is_placeholder) continue;
00860 
00861     // Modify the file name if extension or name is explicitly specified
00862     // change log 14 
00863 
00864     // Although for an ordinary destination there is no output attribute
00865     // for the cfg (you can use filename instead) we provide output() for
00866     // uniformity with the statistics destinations.  The "right way" to
00867     // work this would have been to provide a filename() method, along with 
00868     // an extension() method.  We recognize the potential name confusion here
00869     // (filename(filename))!
00870     
00871     // Determine the destination file name to use if no explicit filename is
00872     // supplied in the cfg.
00873     String filename_default 
00874         = getAparameter<String>(&dest_pset,"output",empty_String);
00875     if ( filename_default == empty_String ) {
00876       filename_default = messageLoggerDefaults->output(psetname); // change log 31
00877       if (filename_default  == empty_String) {
00878         filename_default  = filename;
00879       }        
00880     }
00881 
00882     String explicit_filename 
00883         = getAparameter<String>(&dest_pset,"filename",filename_default);
00884     if (explicit_filename != empty_String) filename = explicit_filename;
00885     String explicit_extension 
00886         = getAparameter<String>(&dest_pset,"extension",empty_String);
00887     if (explicit_extension != empty_String) {
00888       if (explicit_extension[0] == '.') {
00889         filename += explicit_extension;             
00890       } else {
00891         filename = filename + "." + explicit_extension;   
00892       }
00893     }
00894 
00895     // Attach a default extension of .log if there is no extension on a file
00896     // change log 18 - this had been done in concert with attaching destination
00897     
00898     std::string actual_filename = filename;                     // change log 4
00899     if ( (filename != "cout") && (filename != "cerr") )  {
00900       const std::string::size_type npos = std::string::npos;
00901       if ( filename.find('.') == npos ) {
00902         actual_filename += ".log";
00903       }  
00904     }
00905 
00906      // Check that this is not a duplicate name                 // change log 18
00907     if ( stream_ps.find(actual_filename)!=stream_ps.end() ) {        
00908       if (clean_slate_configuration) {                          // change log 22
00909         throw edm::Exception ( edm::errors::Configuration ) 
00910         <<"Duplicate name for a MessageLogger Destination: " 
00911         << actual_filename
00912         << "\n";
00913       } else {
00914         LogWarning("duplicateDestination")
00915         <<"Duplicate name for a MessageLogger Destination: " 
00916         << actual_filename
00917         << "\n" << "Only original configuration instructions are used";
00918         continue;
00919       }
00920     } 
00921     
00922     ordinary_destination_filenames.push_back(actual_filename);
00923 
00924     // attach the current destination, keeping a control handle to it:
00925     ELdestControl dest_ctrl;
00926     if( actual_filename == "cout" )  {
00927       dest_ctrl = admin_p->attach( ELoutput(std::cout) );
00928       stream_ps["cout"] = &std::cout;
00929     }
00930     else if( actual_filename == "cerr" )  {
00931       early_dest.setThreshold(ELzeroSeverity); 
00932       dest_ctrl = early_dest;
00933       stream_ps["cerr"] = &std::cerr;
00934     }
00935     else  {
00936       std::ofstream * os_p = new std::ofstream(actual_filename.c_str());
00937       file_ps.push_back(os_p);
00938       dest_ctrl = admin_p->attach( ELoutput(*os_p) );
00939       stream_ps[actual_filename] = os_p;
00940     }
00941     //(*errorlog_p)( ELinfo, "added_dest") << filename << endmsg;
00942 
00943     // now configure this destination:
00944     configure_dest(dest_ctrl, psetname);
00945 
00946   }  // for [it = destinations.begin() to end()]
00947 
00948 } // configure_ordinary_destinations
00949 
00950 
00951 void
00952   MessageLoggerScribe::configure_statistics()
00953 {
00954   vString  empty_vString;
00955   String   empty_String;
00956   PSet     empty_PSet;
00957 
00958   // grab list of statistics destinations:
00959   vString  statistics 
00960      = getAparameter<vString>(job_pset_p,"statistics", empty_vString);
00961   
00962   bool no_statistics_configured = statistics.empty();           // change log 24
00963   
00964   if ( no_statistics_configured ) {
00965     // Read the list of staistics destinations from hardwired defaults,
00966     // but only if there is also no list of ordinary destinations.
00967     // (If a cfg specifies destinations, and no statistics, assume that
00968     // is what the user wants.)
00969     vString  destinations
00970      = getAparameter<vString>(job_pset_p, "destinations", empty_vString);
00971     if (destinations.empty()) { 
00972       statistics = messageLoggerDefaults->statistics;
00973       no_statistics_configured = statistics.empty();
00974     }
00975   }
00976 
00977    // establish each statistics destination:
00978   for( vString::const_iterator it = statistics.begin()
00979      ; it != statistics.end()
00980      ; ++it
00981      )
00982   {
00983     String statname = *it;
00984     String psetname = statname;
00985 
00986     // check that this destination is not just a placeholder // change log 20
00987     PSet  stat_pset = getAparameter<PSet>(job_pset_p,psetname,empty_PSet);
00988     bool is_placeholder 
00989         = getAparameter<bool>(&stat_pset,"placeholder", false);
00990     if (is_placeholder) continue;
00991 
00992     // Determine the destination file name
00993     String filename 
00994         = getAparameter<String>(&stat_pset,"output",empty_String);
00995     if ( filename == empty_String ) {
00996       filename = messageLoggerDefaults->output(psetname);       // change log 31
00997       if (filename == empty_String) {
00998         filename = statname;
00999       }        
01000     }
01001 
01002     // Modify the file name if extension or name is explicitly specified
01003     // change log 14 -- probably suspenders and a belt, because ouput option
01004     // is present, but uniformity is nice.
01005                                         
01006     String explicit_filename 
01007         = getAparameter<String>(&stat_pset,"filename",filename);
01008     if (explicit_filename != empty_String) filename = explicit_filename;
01009     String explicit_extension 
01010         = getAparameter<String>(&stat_pset,"extension",empty_String);
01011     if (explicit_extension != empty_String) {
01012       if (explicit_extension[0] == '.') {
01013         filename += explicit_extension;             
01014       } else {
01015         filename = filename + "." + explicit_extension;   
01016       }
01017     }
01018 
01019     // Attach a default extension of .log if there is no extension on a file
01020     // change log 18 - this had been done in concert with attaching destination
01021     
01022     std::string actual_filename = filename;                     // change log 4
01023     if ( (filename != "cout") && (filename != "cerr") )  {      // change log 23
01024       const std::string::size_type npos = std::string::npos;
01025       if ( filename.find('.') == npos ) {
01026         actual_filename += ".log";
01027       }  
01028     }
01029 
01030     // Check that this is not a duplicate name - 
01031     // unless it is an ordinary destination (which stats can share)
01032     if ( !search_all(ordinary_destination_filenames, actual_filename) ) {
01033       if ( stream_ps.find(actual_filename)!=stream_ps.end() ) {        
01034         if (clean_slate_configuration) {                        // change log 22
01035           throw edm::Exception ( edm::errors::Configuration ) 
01036           <<"Duplicate name for a MessageLogger Statistics Destination: " 
01037           << actual_filename
01038           << "\n";
01039         } else {
01040           LogWarning("duplicateDestination")
01041           <<"Duplicate name for a MessageLogger Statistics Destination: " 
01042           << actual_filename
01043           << "\n" << "Only original configuration instructions are used";
01044           continue;
01045         } 
01046       }
01047     }
01048     
01049     // create (if statistics file does not match any destination file name)
01050     // or note (if statistics file matches a destination file name) the ostream.
01051     // But if no statistics destinations were provided in the config, do not
01052     // create a new destination for this hardwired statistics - only act if
01053     // it is matches a destination.  (shange log 24)
01054     bool statistics_destination_is_real = !no_statistics_configured;
01055     std::ostream * os_p;
01056     if ( stream_ps.find(actual_filename) == stream_ps.end() ) {
01057       if ( actual_filename == "cout" ) {
01058         os_p = &std::cout;
01059       } else if ( actual_filename == "cerr" ) {
01060         os_p = &std::cerr;
01061       } else {
01062         std::ofstream * osf_p = new std::ofstream(actual_filename.c_str());
01063         os_p = osf_p;
01064         file_ps.push_back(osf_p);
01065       }
01066       stream_ps[actual_filename] = os_p;
01067     } else { 
01068       statistics_destination_is_real = true;                    // change log 24
01069       os_p = stream_ps[actual_filename];
01070     }
01071        
01072     if (statistics_destination_is_real) {                       // change log 24
01073       // attach the statistics destination, keeping a control handle to it:
01074       ELdestControl dest_ctrl;
01075       dest_ctrl = admin_p->attach( ELstatistics(*os_p) );
01076       statisticsDestControls.push_back(dest_ctrl);
01077       bool reset = getAparameter<bool>(&stat_pset,"reset",false);
01078       statisticsResets.push_back(reset);
01079     
01080       // now configure this destination:
01081       configure_dest(dest_ctrl, psetname);
01082 
01083       // and suppress the desire to do an extra termination summary just because
01084       // of end-of-job info messages
01085       dest_ctrl.noTerminationSummary();
01086     }
01087      
01088   }  // for [it = statistics.begin() to end()]
01089 
01090 } // configure_statistics
01091 
01092 void
01093   MessageLoggerScribe::configure_external_dests()
01094 {
01095   if( ! job_pset_p )  
01096   {
01097 //  extern_dests.clear();                               
01098 //  change log 12, removed by change log 13
01099     return;
01100   }
01101 
01102   for( std::vector<NamedDestination*>::const_iterator it = extern_dests.begin()
01103      ; it != extern_dests.end()
01104      ;  ++it
01105      )
01106   {
01107     ELdestination *  dest_p = (*it)->dest_p().get();
01108     ELdestControl  dest_ctrl = admin_p->attach( *dest_p );
01109 
01110     // configure the newly-attached destination:
01111     configure_dest( dest_ctrl, (*it)->name() );
01112     delete *it;  // dispose of our (copy of the) NamedDestination
01113   }
01114   extern_dests.clear();
01115  
01116 }  // MessageLoggerScribe::configure_external_dests
01117 
01118 void
01119   MessageLoggerScribe::parseCategories (std::string const & s,
01120                                         std::vector<std::string> & cats)
01121 {
01122   const std::string::size_type npos = std::string::npos;
01123         std::string::size_type i    = 0;
01124   while ( i != npos ) {    
01125     std::string::size_type j = s.find('|',i);   
01126     cats.push_back (s.substr(i,j-i));
01127     i = j;
01128     while ( (i != npos) && (s[i] == '|') ) ++i; 
01129     // the above handles cases of || and also | at end of string
01130   } 
01131   // Note:  This algorithm assigns, as desired, one null category if it
01132   //        encounters an empty categories string
01133 }
01134 
01135 void
01136   MessageLoggerScribe::triggerStatisticsSummaries() {
01137     assert (statisticsDestControls.size() == statisticsResets.size());
01138     for (unsigned int i = 0; i != statisticsDestControls.size(); ++i) {
01139       statisticsDestControls[i].summary( );
01140       if (statisticsResets[i]) statisticsDestControls[i].wipe( );
01141     }
01142 }
01143 
01144 void
01145   MessageLoggerScribe::
01146   triggerFJRmessageSummary(std::map<std::string, double> & sm)  // ChangeLog 29
01147 {
01148   if (statisticsDestControls.empty()) {
01149     sm["NoStatisticsDestinationsConfigured"] = 0.0;
01150   } else {
01151     statisticsDestControls[0].summaryForJobReport(sm);
01152   }
01153 }
01154 
01155 ErrorLog * MessageLoggerScribe::static_errorlog_p;
01156 
01157 
01158 } // end of namespace service  
01159 } // end of namespace edm  
01160 

Generated on Tue Jun 9 17:36:18 2009 for CMSSW by  doxygen 1.5.4