Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RooMsgService.cxx
Go to the documentation of this file.
1 /*****************************************************************************
2  * Project: RooFit *
3  * Package: RooFitCore *
4  * @(#)root/roofitcore:$Id$
5  * Authors: *
6  * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
7  * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
8  * *
9  * Copyright (c) 2000-2005, Regents of the University of California *
10  * and Stanford University. All rights reserved. *
11  * *
12  * Redistribution and use in source and binary forms, *
13  * with or without modification, are permitted according to the terms *
14  * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
15  *****************************************************************************/
16 
17 /**
18 \file RooMsgService.cxx
19 \class RooMsgService
20 \ingroup Roofitcore
21 
22 
23 The RooMsgService class is a singleton class that organizes informational, debugging,
24 warning and errors messages generated by the RooFit core code.
25 Each message generated by the core
26 has a message level RooFit::MsgLevel (DEBUG,INFO,PROGRESS,WARNING,ERROR or FATAL), an originating object,
27 and a 'topic'. Currently implemented topics are "Generation","Plotting",
28 "Integration", "Minimization" and "Workspace" and "ChangeTracking".
29 The RooMsgService class allows to filter and redirect messages into 'streams'
30 according to message level, topic, (base) class of originating object, name of originating
31 object and based on attribute labels attached to individual objects.
32 The current default configuration creates streams for all messages at WARNING level
33 or higher (e.g. ERROR and FATAL) and for all INFO message on topics Generation,Plotting,
34 Integration and Minimization and redirects them to stdout. Users can create additional streams
35 for logging of e.g. DEBUG messages on particular topics or objects and or redirect streams to
36 C++ streams or files.
37 The singleton instance is accessible through RooMsgService::instance() ;
38 
39 **/
40 
41 
42 #include <sys/types.h>
43 
44 #include "RooFit.h"
45 #include "RooAbsArg.h"
46 #include "TClass.h"
47 #include "TROOT.h"
48 
49 #include "RooMsgService.h"
50 #include "RooCmdArg.h"
51 #include "RooCmdConfig.h"
52 #include "RooGlobalFunc.h"
53 #include "RooWorkspace.h"
54 
55 #include "TSystem.h"
56 #include "Riostream.h"
57 #include <iomanip>
58 using namespace std ;
59 using namespace RooFit ;
60 
61 ClassImp(RooMsgService);
62 
63 Int_t RooMsgService::_debugCount = 0 ;
64 
65 
66 ////////////////////////////////////////////////////////////////////////////////
67 /// Constructor. Defines names of message levels
68 /// and mapping of topic codes to topic names
69 /// Install default message streams.
70 
71 RooMsgService::RooMsgService()
72 {
73  _devnull = new ofstream("/dev/null") ;
74 
75  _levelNames[DEBUG]="DEBUG" ;
76  _levelNames[INFO]="INFO" ;
77  _levelNames[PROGRESS]="PROGRESS" ;
78  _levelNames[WARNING]="WARNING" ;
79  _levelNames[ERROR]="ERROR" ;
80  _levelNames[FATAL]="FATAL" ;
81 
82  _topicNames[Generation]="Generation" ;
83  _topicNames[Minimization]="Minization" ;
84  _topicNames[Plotting]="Plotting" ;
85  _topicNames[Fitting]="Fitting" ;
86  _topicNames[Integration]="Integration" ;
87  _topicNames[LinkStateMgmt]="LinkStateMgmt" ;
88  _topicNames[Eval]="Eval" ;
89  _topicNames[Caching]="Caching" ;
90  _topicNames[Optimization]="Optimization" ;
91  _topicNames[ObjectHandling]="ObjectHandling" ;
92  _topicNames[InputArguments]="InputArguments" ;
93  _topicNames[Tracing]="Tracing" ;
94  _topicNames[Contents]="Contents" ;
95  _topicNames[DataHandling]="DataHandling" ;
96  _topicNames[NumIntegration]="NumericIntegration" ;
97 
98  reset();
99 }
100 
101 
102 void RooMsgService::reset() {
103  _silentMode = kFALSE ;
104  _showPid = kFALSE ;
105  _globMinLevel = DEBUG ;
106  _lastMsgLevel = DEBUG ;
107 
108  delete _debugWorkspace;
109  _debugWorkspace = nullptr;
110  _debugCode = 0 ;
111 
112  for (auto item : _files) {
113  delete item.second;
114  }
115  _files.clear();
116 
117  // Old-style streams
118  _streams.clear();
119  addStream(RooFit::PROGRESS) ;
120  addStream(RooFit::INFO,Topic(RooFit::Eval|RooFit::Plotting|RooFit::Fitting|RooFit::Minimization|RooFit::Caching|RooFit::ObjectHandling|RooFit::NumIntegration|RooFit::InputArguments|RooFit::DataHandling)) ;
121 }
122 
123 
124 ////////////////////////////////////////////////////////////////////////////////
125 /// Destructor
126 
127 RooMsgService::~RooMsgService()
128 {
129  // Delete all ostreams we own ;
130  map<string,ostream*>::iterator iter = _files.begin() ;
131  for (; iter != _files.end() ; ++iter) {
132  delete iter->second ;
133  }
134 
135  if (_debugWorkspace) {
136  delete _debugWorkspace ;
137  }
138 
139  delete _devnull ;
140 }
141 
142 
143 
144 ////////////////////////////////////////////////////////////////////////////////
145 /// Returns true if any debug level stream is active
146 
147 Bool_t RooMsgService::anyDebug()
148 {
149  return instance()._debugCount>0 ;
150 }
151 
152 
153 
154 ////////////////////////////////////////////////////////////////////////////////
155 
156 RooWorkspace* RooMsgService::debugWorkspace()
157 {
158  if (!_debugWorkspace) {
159  _debugWorkspace = new RooWorkspace("wdebug") ;
160  }
161  return _debugWorkspace ;
162 }
163 
164 
165 
166 ////////////////////////////////////////////////////////////////////////////////
167 /// Add a message logging stream for message with given RooFit::MsgLevel or higher (i.e. more severe)
168 /// This method accepts the following arguments to configure the stream
169 ///
170 /// Output Style options
171 /// --------------------
172 /// Prefix(Bool_t flag=kTRUE) -- Prefix all messages in this stream with Topic/Originator information
173 ///
174 /// Filtering options
175 /// -----------------
176 /// Topic(const char*) -- Restrict stream to messages on given topic
177 /// ObjectName(const char*) -- Restrict stream to messages from object with given name
178 /// ClassName(const char*) -- Restrict stream to messages from objects with given class name
179 /// BaseClassName(const char*)-- Restrict stream to messages from objects with given base class name
180 /// LabelName(const chat*) -- Restrict stream to messages from objects setAtrribute(const char*) tag with given name
181 ///
182 /// Output redirection options
183 /// --------------------------
184 /// OutputFile(const char*) -- Send output to file with given name. Multiple streams can write to same file.
185 /// OutputStream(ostream&) -- Send output to given C++ stream. Multiple message streams can write to same c++ stream
186 ///
187 /// The return value is the unique ID code of the defined stream
188 
189 Int_t RooMsgService::addStream(RooFit::MsgLevel level, const RooCmdArg& arg1, const RooCmdArg& arg2, const RooCmdArg& arg3,
190  const RooCmdArg& arg4, const RooCmdArg& arg5, const RooCmdArg& arg6)
191 {
192 
193  // Aggregate all arguments in a list
194  RooLinkedList l ;
195  l.Add((TObject*)&arg1) ; l.Add((TObject*)&arg2) ;
196  l.Add((TObject*)&arg3) ; l.Add((TObject*)&arg4) ;
197  l.Add((TObject*)&arg5) ; l.Add((TObject*)&arg6) ;
198 
199  // Define configuration for this method
200  RooCmdConfig pc(Form("RooMsgService::addReportingStream(%s)",GetName())) ;
201  pc.defineInt("prefix","Prefix",0,kTRUE) ;
202  pc.defineInt("color","Color",0,static_cast<Int_t>(kBlack)) ;
203  pc.defineInt("topic","Topic",0,0xFFFFF) ;
204  pc.defineString("objName","ObjectName",0,"") ;
205  pc.defineString("className","ClassName",0,"") ;
206  pc.defineString("baseClassName","BaseClassName",0,"") ;
207  pc.defineString("tagName","LabelName",0,"") ;
208  pc.defineString("outFile","OutputFile",0,"") ;
209  pc.defineObject("outStream","OutputStream",0,0) ;
210  pc.defineMutex("OutputFile","OutputStream") ;
211 
212  // Process & check varargs
213  pc.process(l) ;
214  if (!pc.ok(kTRUE)) {
215  return -1 ;
216  }
217 
218  // Extract values from named arguments
219  RooFit::MsgTopic topic = (RooFit::MsgTopic) pc.getInt("topic") ;
220  const char* objName = pc.getString("objName") ;
221  const char* className = pc.getString("className") ;
222  const char* baseClassName = pc.getString("baseClassName") ;
223  const char* tagName = pc.getString("tagName") ;
224  const char* outFile = pc.getString("outFile") ;
225  Bool_t prefix = pc.getInt("prefix") ;
226  Color_t color = static_cast<Color_t>(pc.getInt("color")) ;
227  ostream* os = reinterpret_cast<ostream*>(pc.getObject("outStream")) ;
228 
229  // Create new stream object
230  StreamConfig newStream ;
231 
232  // Store configuration info
233  newStream.active = kTRUE ;
234  newStream.minLevel = level ;
235  newStream.topic = topic ;
236  newStream.objectName = (objName ? objName : "" ) ;
237  newStream.className = (className ? className : "" ) ;
238  newStream.baseClassName = (baseClassName ? baseClassName : "" ) ;
239  newStream.tagName = (tagName ? tagName : "" ) ;
240  newStream.color = color ;
241  newStream.prefix = prefix ;
242  newStream.universal = (newStream.objectName=="" && newStream.className=="" && newStream.baseClassName=="" && newStream.tagName=="") ;
243 
244  // Update debug stream count
245  if (level==DEBUG) {
246  _debugCount++ ;
247  }
248 
249  // Configure output
250  if (os) {
251 
252  // To given non-owned stream
253  newStream.os = os ;
254 
255  } else if (string(outFile).size()>0) {
256 
257  // See if we already opened the file
258  ostream* os2 = _files["outFile"] ;
259 
260  if (!os2) {
261 
262  // To given file name, create owned stream for it
263  os2 = new ofstream(outFile) ;
264 
265  if (!*os2) {
266  cout << "RooMsgService::addReportingStream ERROR: cannot open output log file " << outFile << " reverting stream to stdout" << endl ;
267  delete os2 ;
268  newStream.os = &cout ;
269  } else {
270  newStream.os = os2 ;
271  }
272 
273  } else {
274  _files["outFile"] = os2 ;
275  newStream.os = os2 ;
276  }
277 
278 
279  } else {
280 
281  // To stdout
282  newStream.os = &cout ;
283 
284  }
285 
286 
287  // Add it to list of active streams ;
288  _streams.push_back(newStream) ;
289 
290  // Return stream identifier
291  return _streams.size()-1 ;
292 }
293 
294 
295 
296 ////////////////////////////////////////////////////////////////////////////////
297 /// Delete stream with given unique ID code
298 
299 void RooMsgService::deleteStream(Int_t id)
300 {
301  vector<StreamConfig>::iterator iter = _streams.begin() ;
302  iter += id ;
303 
304  // Update debug stream count
305  if (iter->minLevel==DEBUG) {
306  _debugCount-- ;
307  }
308 
309  _streams.erase(iter) ;
310 }
311 
312 
313 
314 ////////////////////////////////////////////////////////////////////////////////
315 /// (De)Activate stream with given unique ID
316 
317 void RooMsgService::setStreamStatus(Int_t id, Bool_t flag)
318 {
319  if (id<0 || id>=static_cast<Int_t>(_streams.size())) {
320  cout << "RooMsgService::setStreamStatus() ERROR: invalid stream ID " << id << endl ;
321  return ;
322  }
323 
324  // Update debug stream count
325  if (_streams[id].minLevel==DEBUG) {
326  _debugCount += flag ? 1 : -1 ;
327  }
328 
329  _streams[id].active = flag ;
330 }
331 
332 
333 
334 ////////////////////////////////////////////////////////////////////////////////
335 /// Get activation status of stream with given unique ID
336 
337 Bool_t RooMsgService::getStreamStatus(Int_t id) const
338 {
339  if (id<0 || id>= static_cast<Int_t>(_streams.size())) {
340  cout << "RooMsgService::getStreamStatus() ERROR: invalid stream ID " << id << endl ;
341  return kFALSE ;
342  }
343  return _streams[id].active ;
344 }
345 
346 
347 
348 ////////////////////////////////////////////////////////////////////////////////
349 /// Return reference to singleton instance
350 
351 RooMsgService& RooMsgService::instance()
352 {
353  static RooMsgService instance;
354  return instance;
355 }
356 
357 
358 
359 ////////////////////////////////////////////////////////////////////////////////
360 /// Save current state of message service
361 
362 void RooMsgService::saveState()
363 {
364  _streamsSaved.push(_streams) ;
365 }
366 
367 
368 
369 ////////////////////////////////////////////////////////////////////////////////
370 /// Restore last saved state of message service
371 
372 void RooMsgService::restoreState()
373 {
374  _streams = _streamsSaved.top() ;
375  _streamsSaved.pop() ;
376 }
377 
378 
379 
380 ////////////////////////////////////////////////////////////////////////////////
381 /// Check if logging is active for given object/topic/RooFit::MsgLevel combination
382 
383 Bool_t RooMsgService::isActive(const RooAbsArg* self, RooFit::MsgTopic topic, RooFit::MsgLevel level)
384 {
385  return (activeStream(self,topic,level)>=0) ;
386 }
387 
388 
389 ////////////////////////////////////////////////////////////////////////////////
390 /// Check if logging is active for given object/topic/RooFit::MsgLevel combination
391 
392 Bool_t RooMsgService::isActive(const TObject* self, RooFit::MsgTopic topic, RooFit::MsgLevel level)
393 {
394  return (activeStream(self,topic,level)>=0) ;
395 }
396 
397 
398 ////////////////////////////////////////////////////////////////////////////////
399 /// Find appropriate logging stream for message from given object with given topic and message level
400 
401 Int_t RooMsgService::activeStream(const RooAbsArg* self, RooFit::MsgTopic topic, RooFit::MsgLevel level)
402 {
403  if (level<_globMinLevel) return -1 ;
404  for (UInt_t i=0 ; i<_streams.size() ; i++) {
405  if (_streams[i].match(level,topic,self)) {
406  return i ;
407  }
408  }
409  return -1 ;
410 }
411 
412 
413 ////////////////////////////////////////////////////////////////////////////////
414 /// Find appropriate logging stream for message from given object with given topic and message level
415 
416 Int_t RooMsgService::activeStream(const TObject* self, RooFit::MsgTopic topic, RooFit::MsgLevel level)
417 {
418  if (level<_globMinLevel) return -1 ;
419  for (UInt_t i=0 ; i<_streams.size() ; i++) {
420  if (_streams[i].match(level,topic,self)) {
421  return i ;
422  }
423  }
424  return -1 ;
425 }
426 
427 
428 ////////////////////////////////////////////////////////////////////////////////
429 /// Determine if message from given object at given level on given topic is logged
430 
431 Bool_t RooMsgService::StreamConfig::match(RooFit::MsgLevel level, RooFit::MsgTopic top, const RooAbsArg* obj)
432 {
433  if (!active) return kFALSE ;
434  if (level<minLevel) return kFALSE ;
435  if (!(topic&top)) return kFALSE ;
436 
437  if (universal) return kTRUE ;
438 
439  if (objectName.size()>0 && objectName != obj->GetName()) return kFALSE ;
440  if (className.size()>0 && className != obj->IsA()->GetName()) return kFALSE ;
441  if (baseClassName.size()>0 && !obj->IsA()->InheritsFrom(baseClassName.c_str())) return kFALSE ;
442  if (tagName.size()>0 && !obj->getAttribute(tagName.c_str())) return kFALSE ;
443 
444  return kTRUE ;
445 }
446 
447 
448 ////////////////////////////////////////////////////////////////////////////////
449 /// Determine if message from given object at given level on given topic is logged
450 
451 Bool_t RooMsgService::StreamConfig::match(RooFit::MsgLevel level, RooFit::MsgTopic top, const TObject* obj)
452 {
453  if (!active) return kFALSE ;
454  if (level<minLevel) return kFALSE ;
455  if (!(topic&top)) return kFALSE ;
456 
457  if (universal) return kTRUE ;
458 
459  if (objectName.size()>0 && objectName != obj->GetName()) return kFALSE ;
460  if (className.size()>0 && className != obj->IsA()->GetName()) return kFALSE ;
461  if (baseClassName.size()>0 && !obj->IsA()->InheritsFrom(baseClassName.c_str())) return kFALSE ;
462 
463  return kTRUE ;
464 }
465 
466 
467 
468 ////////////////////////////////////////////////////////////////////////////////
469 /// Log error message associated with RooAbsArg object self at given level and topic. If skipPrefix
470 /// is true the standard RooMsgService prefix is not added.
471 
472 ostream& RooMsgService::log(const RooAbsArg* self, RooFit::MsgLevel level, RooFit::MsgTopic topic, Bool_t skipPrefix)
473 {
474  if (level>=ERROR) {
475  _errorCount++ ;
476  }
477 
478  // Return C++ ostream associated with given message configuration
479  Int_t as = activeStream(self,topic,level) ;
480 
481  if (as==-1) {
482  return *_devnull ;
483  }
484 
485  // Flush any previous messages
486  (*_streams[as].os).flush() ;
487 
488  // Insert an endl if we switch from progress to another level
489  if (_lastMsgLevel==PROGRESS && level!=PROGRESS) {
490  (*_streams[as].os) << endl ;
491  }
492  _lastMsgLevel=level ;
493 
494  if (_streams[as].prefix && !skipPrefix) {
495  if (_showPid) {
496  (*_streams[as].os) << "pid" << gSystem->GetPid() << " " ;
497  }
498  (*_streams[as].os) << "[#" << as << "] " << _levelNames[level] << ":" << _topicNames[topic] << " -- " ;
499  }
500  return (*_streams[as].os) ;
501 }
502 
503 
504 
505 ////////////////////////////////////////////////////////////////////////////////
506 /// Log error message associated with TObject object self at given level and topic. If skipPrefix
507 /// is true the standard RooMsgService prefix is not added.
508 
509 ostream& RooMsgService::log(const TObject* self, RooFit::MsgLevel level, RooFit::MsgTopic topic, Bool_t skipPrefix)
510 {
511  if (level>=ERROR) {
512  _errorCount++ ;
513  }
514 
515  // Return C++ ostream associated with given message configuration
516  Int_t as = activeStream(self,topic,level) ;
517  if (as==-1) {
518  return *_devnull ;
519  }
520 
521  // Flush any previous messages
522  (*_streams[as].os).flush() ;
523 
524  if (_streams[as].prefix && !skipPrefix) {
525  if (_showPid) {
526  (*_streams[as].os) << "pid" << gSystem->GetPid() << " " ;
527  }
528  (*_streams[as].os) << "[#" << as << "] " << _levelNames[level] << ":" << _topicNames[topic] << " -- " ;
529  }
530  return (*_streams[as].os) ;
531 }
532 
533 
534 
535 ////////////////////////////////////////////////////////////////////////////////
536 /// Print configuration of message service. If "v" option is given also
537 /// inactive streams are listed
538 
539 void RooMsgService::Print(Option_t *options) const
540 {
541  Bool_t activeOnly = kTRUE ;
542  if (TString(options).Contains("V") || TString(options).Contains("v")) {
543  activeOnly = kFALSE ;
544  }
545 
546  cout << (activeOnly?"Active Message streams":"All Message streams") << endl ;
547  for (UInt_t i=0 ; i<_streams.size() ; i++) {
548 
549  // Skip passive streams in active only mode
550  if (activeOnly && !_streams[i].active) {
551  continue ;
552  }
553 
554 
555  map<int,string>::const_iterator is = _levelNames.find(_streams[i].minLevel) ;
556  cout << "[" << i << "] MinLevel = " << is->second ;
557 
558  cout << " Topic = " ;
559  if (_streams[i].topic != 0xFFFFF) {
560  map<int,string>::const_iterator iter = _topicNames.begin() ;
561  while(iter!=_topicNames.end()) {
562  if (iter->first & _streams[i].topic) {
563  cout << iter->second << " " ;
564  }
565  ++iter ;
566  }
567  } else {
568  cout << " Any " ;
569  }
570 
571 
572  if (_streams[i].objectName.size()>0) {
573  cout << " ObjectName = " << _streams[i].objectName ;
574  }
575  if (_streams[i].className.size()>0) {
576  cout << " ClassName = " << _streams[i].className ;
577  }
578  if (_streams[i].baseClassName.size()>0) {
579  cout << " BaseClassName = " << _streams[i].baseClassName ;
580  }
581  if (_streams[i].tagName.size()>0) {
582  cout << " TagLabel = " << _streams[i].tagName ;
583  }
584 
585  // Postfix status when printing all
586  if (!activeOnly && !_streams[i].active) {
587  cout << " (NOT ACTIVE)" ;
588  }
589 
590  cout << endl ;
591  }
592 
593 }