Back to home page

Project CMSSW displayed by LXR

 
 

    


Warning, /FWCore/MessageLogger/doc/MessageLoggerDesign.txt is written in an unsupported language. File is not indexed.

0001                         MessageLogger Design
0002                         --------------------
0003 Glossary
0004 --------
0005 
0006 KitchenSink             Initializes certain static-lifetime entities
0007                         which need to be around before any subtantive
0008                         code in main() is done.  Instantiated at the
0009                         begining of main(); goes out of scope only when
0010                         main() terminates.  We rely on precisely one
0011                         KitchenSink to be instantiated.
0012 
0013 MessageLoggerSpigot     Owns the messageLoggerScribe thread -- it starts it,
0014                         it makes it (tells it to) go away.  Concpetually
0015                         a destructible singleton:  We rely on the fact that
0016                         the dtor is invoked at the end of the job, to
0017                         cleanly terminate the messageLoggerScribe thread.
0018                         Instantiated early in instantiation of a KitchenSink.
0019                         We do not use the DestructibleSingleton pattern
0020                         because we want to keep the code reuired in
0021                         KitchenSink as trivial as possible.
0022 
0023 MessageLoggerQ          Interthread communication buffer of MessageLoggerSlot
0024                         blocks.  Handles all the locking, blocking, sleeping,
0025                         waking, etc.  Singleton.  Makes use of framework's
0026                         Interthread communication buffer mechanism.
0027 
0028 MessageLoggerScribe     Singleton, responsible for creating, owning, and
0029                         managing the (single) ErrorLog and for consuming
0030                         MessageLoggerSlot blocks from the MessageLoggerQ.
0031 
0032 MessageSender           Primary interface between the user composing a
0033                         message (by invoking LogWarning or the like) and
0034                         the MessageLoggerQ, for which it acts as a producer.
0035 
0036 MessageLogger           A framework service, which when started up (and
0037                         possibly at other times) passes parameter-set
0038                         or other information via the  MessageLoggerQ
0039                         for purpose of configuring the behavior of the
0040                         ErrorLog owned by MessageLoggerScribe.
0041 
0042 ===========================================================================
0043 int
0044 main() {
0045  KitchenSink ks;
0046  .
0047  .
0048  .
0049 }
0050 
0051 struct
0052 KitchenSink {
0053  KitchenSink() : theMessageLoggerSpigot(),      // The order is chosen carefully
0054                  theAccountingSpigot(),
0055                  ... {}
0056  private:
0057  MessageLoggerSpigot theMessageLoggerSpigot;   // If we want everything else
0058                                                // to be MessageLogger ready,
0059                                                // then this spigot goes first
0060  // ...
0061 };
0062 
0063 MessageLoggerQ * messageLoggerQ() {
0064   static MessageLoggerQ q(500,sizeof(MessageLoggerSlot));
0065   return &q;
0066 }
0067 
0068 
0069 // The purpose of MessageLoggerSpigot is to own the messageLoggerScribe
0070 // thread -- it starts it, it makes it (tells it to) go away.
0071 
0072 // This should be a singleton in fact.
0073 
0074 struct
0075 MessageLoggerSpigot {
0076  MessageLoggerSpigot() {
0077    startAthread (messageLoggerScribe);
0078  }
0079  ~MessageLoggerSpigot() {
0080   UnstructuredQslot * s = messageLoggerQ()->getSlot();
0081   MessageLoggerSlotRaw * mx = static_cast<MessageLoggerSlotRaw *> (s);
0082   mx->command = DIE;
0083   s->commmit();
0084  }
0085 };
0086 
0087 
0088 void messageLoggerScribe() {
0089  MessageLoggerScribe m;
0090  m.activate();
0091 }
0092 
0093 struct MessageLoggerScribe {
0094  MessageLoggerScribe() {
0095   logger = ELadministrator::instance();
0096   earlyOutput = logger->attach(ELoutput ( cerr ));
0097   // possibly modify some behaviors of logger or earlyOutput here
0098   errlogp = new ErrorLog();
0099  }
0100  void activate() {
0101   bool dontDie = true;
0102   while (dontDie) {
0103    ProducerBuffer b ( messageLoggerQ() );
0104    MessageLoggerSlotRaw * mx = static_cast<MessageLoggerSlotRaw*>(b.buffer());
0105    switch (mx.command) {
0106     case LOG:
0107     {
0108      MessageLoggerSlot m = static_cast<MessageLoggerSlot> m;
0109      unique_ptr<ErrorObj> ep (m->ep);
0110      (*errlogp) << *ep;
0111     } break;
0112     case SETUP_USING_PARAMETERS:
0113     {
0114       edm::ParameterSet * params (mx-> params);
0115       logger->detach(earlyOutput);
0116       setupErrorLogger ( logger, params );
0117     } break;
0118     case STATISTICS:
0119     {
0120     } break;
0121     case OTHER_TYPE_OF_CONTROL:
0122     {
0123     } break;
0124     case DIE:
0125     {
0126      dontDie = false;
0127     } break;
0128    }
0129   // I think the buffer should be put back into the pool here.
0130   }
0131  }
0132  ~MessageLoggerScribe() {
0133   errlogp->emit_statistics();
0134   delete errlogp;
0135  }
0136  ErrorLog * errlogp;
0137  ELadministrator * logger;
0138  ELdestControl earlyOutput;
0139 };
0140 
0141 
0142 class MessageLoggerQ /* not written by us, part of framework */ {
0143 public:
0144   MessageLoggerQ(int howManySlots, size_t sizeOfEachSlot);
0145   UnstructuredQSlot * getSlot();
0146 
0147 };
0148 
0149 
0150 struct MessageSender {
0151   MessageSender(sev,id) : ep(new ErrorObj(sev,id)) {}
0152   template <typename T>
0153   operator<<(const T& t) { *ep << t; }
0154   ~MessageSender() {
0155     UnstructuredQslot * s = messageLoggerQ()->getSlot();
0156     MessageLoggerSlot * m = static_cast<MessageLoggerSlot *> (s);
0157     m->command = LOG;
0158     m->Object = ep;
0159     s->commit();
0160   }
0161   std::shared_ptr<ErrorObj> ep;
0162 };
0163 
0164 MessageLogger::MessageLogger ( const edm::parameter_set & p, ... ) {
0165   UnstructuredQslot * s = messageLoggerQ()->getSlot();
0166   MessageLoggerSetupSlot * ms = static_cast<MessageLoggerSetupSlot *> (s);
0167   ms.params = p;
0168   ms.command = SETUP_USING_PARAMETERS;
0169   s->commit();
0170 }
0171 
0172 MessageSender LogWarning (const char* id)
0173 {
0174   return MessageSender (ELwarning, id);
0175 }
0176 
0177 1) a pre-services activity issues a LogError("id"):
0178 
0179   a) Because the first thing main does ins instantiate a KitchenSink,
0180      and the first thing the ctor of KitchenSink does is instnatiate
0181      a (default) MessageLoggerSpigot, the ctor of MessageLoggerSpigot
0182      has already been called.
0183 
0184   b) The ctor of MessageLoggerSpigot starts a thread, running
0185      messageLoggerScribe, which instantiates a MessageLoggerScribe
0186      and calls its activate() method.  So this will already have been done.
0187 
0188   c) The ctor of MessageLoggerScribe has already attached an ELoutput (using
0189      cerr) to the error logger.  So the errorLogger does have one sensible
0190      destination.
0191 
0192   d) The activate() member function is in a loop, getting a buffer from
0193      the queue, which is found by invokiing messageLoggerQ(). messageLoggerQ()
0194      has a function-level static MessageLoggerQ, so even if this was not
0195      in place before, that queue certainly exists by the time activate()
0196      tries to get a buffer.
0197 
0198   d*)If the queue is empty, activate() sleeps at that point.  Eventually
0199      somebody -- in fact, somebody we will encounter next in this story-line,
0200      will obtain a buffer from the queue, fill it, and commit.  That will
0201      cause the buffer() method to wake up, in possesion of a committed buffer.
0202 
0203   e) One of the pre-services activities decides, for some reason, to issue
0204      a message via (say) LogWarning.  The syntax of the statement issuing
0205      the message is
0206      LogWarning("myid") << a << b;
0207 
0208   f) LogWarning is a free function, returning a MessageSender which it
0209      constructs.  The MessageSender class contains an ErrorObj*, which
0210      the ctor initializes to point to an ErrorObj on the heap, constructed
0211      from ELwarning and myid.  This ErrorObj, though allocated via new,
0212      will not be deleted explicitly by MessageSender - instead, a unique_ptr
0213      will be formed to pass that duty onward.
0214 
0215   g) The messageSender now has a couple of invocations of operator<<().  It
0216      passes a and b on to its internal ErrorObj in the obvious manner.
0217 
0218   h) At the end of the statement issuing the message, the MessageSender
0219      returned by LogWarning goes out of scope and is destructed.
0220 
0221   i) The dtor of MessageSender obtains a slot in the queue obtained by
0222      messageLoggerQ().  It casts this unstructured slot into form for taking
0223      a command and a unique_ptr to an ErrorObj.  It then fills that structure
0224      with the command LOG and a unique_ptr to the on-the-heap ErrorObj
0225      (at this point, it is relieved of responsibility for deleting the
0226      ErrorObj).
0227 
0228   j) The last act of the MessageSender dtor is to call the commit() member
0229      function of the slot obtained.  Now we resolve the hanging execution
0230      issue that we left at steps d and d*:  activate() has obtained a buffer.
0231 
0232   k) The unstructured buffer is cast into a raw MessageLoggerSlot, and the
0233      command member of that struct is examined and found (in this case) to
0234      be LOG.
0235 
0236   l) An unique_ptr<ErrorObj> is formed from the pointer sitting in the
0237      raw slot.  This is done by casting the raw memory into its Message
0238      SenderSlot form.  This is crucial because we had "lost" the unique_ptr
0239      nature of that pointer.
0240 
0241   m) The activate() is a member function of MessageLoggerScribe; it has
0242      the class variable errlogp in scope.  *ep is sent (<<) to that
0243      error logger.  Thus the message is formated and comes out in all
0244      the destinations -- in this case just cerr -- attached to the logger.
0245 
0246   n) At the end of the LOG case, the unique_ptr goes out of scope, thus deleting
0247      the ErrorObj so that the memory on the heap is properly freed.
0248 
0249   o) At the end of the switch on command, the buffer is replaced into the pool.
0250      Since dontDie remains true, the loop continues -- and the
0251      messageLoggerScribe thread immediately sleeps since now the queue is empty.
0252      It is waiting for a new message or other command.
0253 
0254 2) a post-services activity issues a LogError("id"):
0255 
0256 
0257 
0258 3) end of job is reached (MessageLoggerSpigot is destructed):
0259 
0260 ===========================================================================
0261 
0262 Design of interface to configure the MessageLogger service
0263 via a ParameterSet:
0264 
0265 Features wanted:
0266   create an ELoutput destination
0267   attaching an ELoutput destination
0268   detaching an ELoutput destination
0269   attaching a statistics destination
0270 
0271   controlling a particular destination (ELunspecified == unrecognized sevLevel)
0272     setLimit(ID,n)
0273     setLimit(severity,n)
0274     setLimit("*",n)
0275     setThreshold(severity)
0276     setTimespan(ID,sec)
0277     setTimespan(severity,sec)
0278     setTimespan("*",sec)
0279 
0280 ===========================================================================
0281 
0282 Features not wanted:
0283   ELcollected
0284 
0285 ===========================================================================
0286 
0287 Future features?
0288   contextSupplier
0289   moduleName
0290   processName (threadID?)