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?)