Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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
23Singleton class that organizes messages generated in RooFit.
24Each message has a message level RooFit::MsgLevel (DEBUG,INFO,PROGRESS,WARNING,ERROR or FATAL),
25an source object, and a RooFit::MsgTopic.
26RooMsgService allows to filter and redirect messages into streams
27according to message level, topic, (base) class of originating object, name of originating
28object and based on attribute labels attached to individual objects.
29The current default configuration creates streams for all messages at WARNING level
30or higher (e.g. ERROR and FATAL) and for all INFO message on topics Generation,Plotting,
31Integration and Minimization and redirects them to stdout. Users can create additional streams
32for logging of e.g. DEBUG messages on particular topics or objects and/or redirect streams to
33C++ streams or files.
34
35The singleton instance is accessible through RooMsgService::instance().
36
37### Temporarily change the message level
38There is a helper, RooHelpers::LocalChangeMsgLevel, that overrides the default message levels as
39long as it is alive. To suppress everything below WARNING:
40~~~{.cpp}
41RooHelpers::LocalChangeMessageLevel changeMsgLvl(RooFit::WARNING);
42[ statements that normally generate a lot of output ]
43~~~
44
45#### Temporarily capture a message stream
46RooHelpers::HijackMessageStream allows to fully capture a message stream in a std::stringstream. With this,
47RooFit messages can be evaluated or suppressed.
48**/
49
50
51#include "RooMsgService.h"
52
53#include <sys/types.h>
54#include "RooAbsArg.h"
55#include "RooCmdArg.h"
56#include "RooCmdConfig.h"
57#include "RooGlobalFunc.h"
58#include "RooWorkspace.h"
59#include "RooHelpers.h"
60
61#include "TClass.h"
62#include "TSystem.h"
63
64#include <fstream>
65#include <iomanip>
66
67using std::cout, std::endl, std::ofstream, std::ostream, std::string, std::vector, std::map;
68using namespace RooFit;
69
71
73
74
75////////////////////////////////////////////////////////////////////////////////
76/// Constructor. Defines names of message levels
77/// and mapping of topic codes to topic names
78/// Install default message streams.
79
81{
82 _devnull = std::make_unique<ofstream>("/dev/null") ;
83
84 _levelNames[DEBUG]="DEBUG" ;
85 _levelNames[INFO]="INFO" ;
86 _levelNames[PROGRESS]="PROGRESS" ;
87 _levelNames[WARNING]="WARNING" ;
88 _levelNames[ERROR]="ERROR" ;
89 _levelNames[FATAL]="FATAL" ;
90
91 _topicNames[Generation]="Generation" ;
92 _topicNames[Minimization]="Minimization" ;
93 _topicNames[Plotting]="Plotting" ;
94 _topicNames[Fitting]="Fitting" ;
95 _topicNames[Integration]="Integration" ;
96 _topicNames[LinkStateMgmt]="LinkStateMgmt" ;
97 _topicNames[Eval]="Eval" ;
98 _topicNames[Caching]="Caching" ;
99 _topicNames[Optimization]="Optimization" ;
100 _topicNames[ObjectHandling]="ObjectHandling" ;
101 _topicNames[InputArguments]="InputArguments" ;
102 _topicNames[Tracing]="Tracing" ;
103 _topicNames[Contents]="Contents" ;
104 _topicNames[DataHandling]="DataHandling" ;
105 _topicNames[NumIntegration]="NumericIntegration" ;
106 _topicNames[FastEvaluations] = "FastEvaluations";
107 _topicNames[HistFactory]="HistFactory";
108
109 reset();
110}
111
112
114 _silentMode = false ;
115 _showPid = false ;
118
119 _debugWorkspace = nullptr;
120 _debugCode = 0 ;
121
122 _files.clear();
123
124 // Old-style streams
125 _streams.clear();
126 addStream(RooFit::PROGRESS, Topic(RooFit::HistFactory - 1));//All before HistFactory
129}
130
131
133
134
135////////////////////////////////////////////////////////////////////////////////
136/// Returns true if any debug level stream is active
137
139{
140 return instance()._debugCount>0 ;
141}
142
143
144
145////////////////////////////////////////////////////////////////////////////////
146
148{
149 if (!_debugWorkspace) {
150 _debugWorkspace = std::make_unique<RooWorkspace>("wdebug") ;
151 }
152 return _debugWorkspace.get();
153}
154
155
156
157////////////////////////////////////////////////////////////////////////////////
158/// Add a message logging stream for message with given RooFit::MsgLevel or higher.
159/// Higher means that messages with higher priority/severity are issued.
160///
161/// This method accepts the following arguments to configure the stream:
162/// <table>
163/// <tr><th> Output Style options <th>
164/// <tr><td> Prefix(bool flag=true) <td> Prefix all messages in this stream with Topic/Originator information
165/// <tr><th> Filtering options <th>
166/// <tr><td> Topic() <td> Restrict stream to messages on given topic
167/// <tr><td> ObjectName(const char*) <td> Restrict stream to messages from object with given name
168/// <tr><td> ClassName(const char*) <td> Restrict stream to messages from objects with given class name
169/// <tr><td> BaseClassName(const char*)<td> Restrict stream to messages from objects with given base class name
170/// <tr><td> LabelName(const chat*) <td> Restrict stream to messages from objects setAttribute(const char*) tag with given name
171/// <tr><th> Output redirection options <th>
172/// <tr><td> OutputFile(const char*) <td> Send output to file with given name. Multiple streams can write to same file.
173/// <tr><td> OutputStream(ostream&) <td> Send output to given C++ stream. Multiple message streams can write to same c++ stream
174/// </table>
175/// The return value is the unique ID of the defined stream.
176
177Int_t RooMsgService::addStream(RooFit::MsgLevel level, const RooCmdArg& arg1, const RooCmdArg& arg2, const RooCmdArg& arg3,
178 const RooCmdArg& arg4, const RooCmdArg& arg5, const RooCmdArg& arg6)
179{
180
181 // Aggregate all arguments in a list
183 l.Add((TObject*)&arg1) ; l.Add((TObject*)&arg2) ;
184 l.Add((TObject*)&arg3) ; l.Add((TObject*)&arg4) ;
185 l.Add((TObject*)&arg5) ; l.Add((TObject*)&arg6) ;
186
187 // Define configuration for this method
188 RooCmdConfig pc("RooMsgService::addReportingStream(" + std::string(GetName()) + ")") ;
189 pc.defineInt("prefix","Prefix",0,true) ;
190 pc.defineInt("color","Color",0,static_cast<Int_t>(kBlack)) ;
191 pc.defineInt("topic","Topic",0,0xFFFFF) ;
192 pc.defineString("objName","ObjectName",0,"") ;
193 pc.defineString("className","ClassName",0,"") ;
194 pc.defineString("baseClassName","BaseClassName",0,"") ;
195 pc.defineString("tagName","LabelName",0,"") ;
196 pc.defineString("outFile","OutputFile",0,"") ;
197 pc.defineObject("outStream","OutputStream",0,nullptr) ;
198 pc.defineMutex("OutputFile","OutputStream") ;
199
200 // Process & check varargs
201 pc.process(l) ;
202 if (!pc.ok(true)) {
203 return -1 ;
204 }
205
206 // Extract values from named arguments
207 RooFit::MsgTopic topic = (RooFit::MsgTopic) pc.getInt("topic") ;
208 const char* objName = pc.getString("objName") ;
209 const char* className = pc.getString("className") ;
210 const char* baseClassName = pc.getString("baseClassName") ;
211 const char* tagName = pc.getString("tagName") ;
212 const char* outFile = pc.getString("outFile") ;
213 bool prefix = pc.getInt("prefix") ;
214 Color_t color = static_cast<Color_t>(pc.getInt("color")) ;
215 auto wrapper = static_cast<RooHelpers::WrapIntoTObject<ostream>*>(pc.getObject("outStream"));
216 ostream* os = nullptr;
217 if (wrapper) {
218 os = wrapper->_payload;
219 delete wrapper;
220 wrapper = nullptr;
221 }
222
223 // Create new stream object
224 StreamConfig newStream ;
225
226 // Store configuration info
227 newStream.active = true ;
228 newStream.minLevel = level ;
229 newStream.topic = topic ;
230 newStream.objectName = (objName ? objName : "" ) ;
231 newStream.className = (className ? className : "" ) ;
232 newStream.baseClassName = (baseClassName ? baseClassName : "" ) ;
233 newStream.tagName = (tagName ? tagName : "" ) ;
234 newStream.color = color ;
235 newStream.prefix = prefix ;
236 newStream.universal = (newStream.objectName.empty() && newStream.className.empty() && newStream.baseClassName.empty() && newStream.tagName.empty()) ;
237
238 // Update debug stream count
239 if (level==DEBUG) {
240 _debugCount++ ;
241 }
242
243 // Configure output
244 if (os) {
245
246 // To given non-owned stream
247 newStream.os = os ;
248
249 } else if (!string(outFile).empty()) {
250
251 // See if we already opened the file
252 ostream* os2 = _files["outFile"].get();
253
254 if (!os2) {
255
256 // To given file name, create owned stream for it
257 os2 = new ofstream(outFile) ;
258
259 if (!*os2) {
260 cout << "RooMsgService::addReportingStream ERROR: cannot open output log file " << outFile << " reverting stream to stdout" << endl ;
261 delete os2 ;
262 newStream.os = &cout ;
263 } else {
264 newStream.os = os2 ;
265 }
266
267 } else {
268 newStream.os = os2 ;
269 _files["outFile"] = std::unique_ptr<std::ostream>{os2};
270 }
271
272
273 } else {
274
275 // To stdout
276 newStream.os = &cout ;
277
278 }
279
280
281 // Add it to list of active streams ;
282 _streams.push_back(newStream) ;
283
284 // Return stream identifier
285 return _streams.size()-1 ;
286}
287
288
289
290////////////////////////////////////////////////////////////////////////////////
291/// Delete stream with given unique ID code
292
294{
295 vector<StreamConfig>::iterator iter = _streams.begin() ;
296 iter += id ;
297
298 // Update debug stream count
299 if (iter->minLevel==DEBUG) {
300 _debugCount-- ;
301 }
302
303 _streams.erase(iter) ;
304}
305
306
307
308////////////////////////////////////////////////////////////////////////////////
309/// (De)Activate stream with given unique ID
310
312{
313 if (id<0 || id>=static_cast<Int_t>(_streams.size())) {
314 cout << "RooMsgService::setStreamStatus() ERROR: invalid stream ID " << id << endl ;
315 return ;
316 }
317
318 // Update debug stream count
319 if (_streams[id].minLevel==DEBUG) {
320 _debugCount += flag ? 1 : -1 ;
321 }
322
323 _streams[id].active = flag ;
324}
325
326
327
328////////////////////////////////////////////////////////////////////////////////
329/// Get activation status of stream with given unique ID
330
332{
333 if (id<0 || id>= static_cast<Int_t>(_streams.size())) {
334 cout << "RooMsgService::getStreamStatus() ERROR: invalid stream ID " << id << endl ;
335 return false ;
336 }
337 return _streams[id].active ;
338}
339
340
341
342////////////////////////////////////////////////////////////////////////////////
343/// Return reference to singleton instance
344
346{
347 static RooMsgService instance;
348 return instance;
349}
350
351
352
353////////////////////////////////////////////////////////////////////////////////
354/// Save current state of message service
355
357{
358 _streamsSaved.push(_streams) ;
359}
360
361
362
363////////////////////////////////////////////////////////////////////////////////
364/// Restore last saved state of message service
365
367{
368 _streams = _streamsSaved.top() ;
369 _streamsSaved.pop() ;
370}
371
372
373////////////////////////////////////////////////////////////////////////////////
374/// Determine if message from given object at given level on given topic is logged
375
377{
378 if (!active) return false ;
379 if (level<minLevel) return false ;
380 if (!(topic&top)) return false ;
381
382 if (universal) return true ;
383
384 if (!obj) return false;
385 if (!objectName.empty() && objectName != obj->GetName()) return false ;
386 if (!className.empty() && className != obj->ClassName()) return false ;
387 if (!baseClassName.empty() && !obj->IsA()->InheritsFrom(baseClassName.c_str())) return false ;
388 if (!tagName.empty() && !obj->getAttribute(tagName.c_str())) return false ;
389
390 return true ;
391}
392
393
394////////////////////////////////////////////////////////////////////////////////
395/// Determine if message from given object at given level on given topic is logged
396
398{
399 if (!active) return false ;
400 if (level<minLevel) return false ;
401 if (!(topic&top)) return false ;
402
403 if (universal) return true ;
404
405 if (!obj) return false;
406 if (!objectName.empty() && objectName != obj->GetName()) return false ;
407 if (!className.empty() && className != obj->ClassName()) return false ;
408 if (!baseClassName.empty() && !obj->IsA()->InheritsFrom(baseClassName.c_str())) return false ;
409
410 return true ;
411}
412
413
414
415////////////////////////////////////////////////////////////////////////////////
416/// Log error message associated with RooAbsArg object self at given level and topic. If skipPrefix
417/// is true the standard RooMsgService prefix is not added.
418
419ostream& RooMsgService::log(const RooAbsArg* self, RooFit::MsgLevel level, RooFit::MsgTopic topic, bool skipPrefix)
420{
421 if (level>=ERROR) {
422 _errorCount++ ;
423 }
424
425 // Return C++ ostream associated with given message configuration
426 Int_t as = activeStream(self,topic,level) ;
427
428 if (as==-1) {
429 return *_devnull ;
430 }
431
432 // Flush any previous messages
433 (*_streams[as].os).flush() ;
434
435 // Insert an endl if we switch from progress to another level
436 if (_lastMsgLevel==PROGRESS && level!=PROGRESS) {
437 (*_streams[as].os) << endl ;
438 }
439 _lastMsgLevel=level ;
440
441 if (_streams[as].prefix && !skipPrefix) {
442 if (_showPid) {
443 (*_streams[as].os) << "pid" << gSystem->GetPid() << " " ;
444 }
445 (*_streams[as].os) << "[#" << as << "] " << _levelNames[level] << ":" << _topicNames[topic] << " -- " ;
446 }
447 return (*_streams[as].os) ;
448}
449
450
451
452////////////////////////////////////////////////////////////////////////////////
453/// Log error message associated with TObject object self at given level and topic. If skipPrefix
454/// is true the standard RooMsgService prefix is not added.
455
456ostream& RooMsgService::log(const TObject* self, RooFit::MsgLevel level, RooFit::MsgTopic topic, bool skipPrefix)
457{
458 if (level>=ERROR) {
459 _errorCount++ ;
460 }
461
462 // Return C++ ostream associated with given message configuration
463 Int_t as = activeStream(self,topic,level) ;
464 if (as==-1) {
465 return *_devnull ;
466 }
467
468 // Flush any previous messages
469 (*_streams[as].os).flush() ;
470
471 if (_streams[as].prefix && !skipPrefix) {
472 if (_showPid) {
473 (*_streams[as].os) << "pid" << gSystem->GetPid() << " " ;
474 }
475 (*_streams[as].os) << "[#" << as << "] " << _levelNames[level] << ":" << _topicNames[topic] << " -- " ;
476 }
477 return (*_streams[as].os) ;
478}
479
480
481
482////////////////////////////////////////////////////////////////////////////////
483/// Print configuration of message service. If "v" option is given also
484/// inactive streams are listed
485
486void RooMsgService::Print(Option_t *options) const
487{
488 bool activeOnly = true ;
489 if (TString(options).Contains("V") || TString(options).Contains("v")) {
490 activeOnly = false ;
491 }
492
493 cout << (activeOnly?"Active Message streams":"All Message streams") << endl ;
494 for (UInt_t i=0 ; i<_streams.size() ; i++) {
495
496 // Skip passive streams in active only mode
497 if (activeOnly && !_streams[i].active) {
498 continue ;
499 }
500
501
502 map<int,string>::const_iterator is = _levelNames.find(_streams[i].minLevel) ;
503 cout << "[" << i << "] MinLevel = " << is->second ;
504
505 cout << " Topic = " ;
506 if (_streams[i].topic != 0xFFFFF) {
507 map<int,string>::const_iterator iter = _topicNames.begin() ;
508 while(iter!=_topicNames.end()) {
509 if (iter->first & _streams[i].topic) {
510 cout << iter->second << " " ;
511 }
512 ++iter ;
513 }
514 } else {
515 cout << " Any " ;
516 }
517
518
519 if (!_streams[i].objectName.empty()) {
520 cout << " ObjectName = " << _streams[i].objectName ;
521 }
522 if (!_streams[i].className.empty()) {
523 cout << " ClassName = " << _streams[i].className ;
524 }
525 if (!_streams[i].baseClassName.empty()) {
526 cout << " BaseClassName = " << _streams[i].baseClassName ;
527 }
528 if (!_streams[i].tagName.empty()) {
529 cout << " TagLabel = " << _streams[i].tagName ;
530 }
531
532 // Postfix status when printing all
533 if (!activeOnly && !_streams[i].active) {
534 cout << " (NOT ACTIVE)" ;
535 }
536
537 cout << endl ;
538 }
539
540}
#define DEBUG
int Int_t
Definition RtypesCore.h:45
short Color_t
Definition RtypesCore.h:92
const char Option_t
Definition RtypesCore.h:66
#define ClassImp(name)
Definition Rtypes.h:377
@ kBlack
Definition Rtypes.h:65
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize id
R__EXTERN TSystem * gSystem
Definition TSystem.h:555
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:77
bool getAttribute(const Text_t *name) const
Check if a named attribute is set. By default, all attributes are unset.
Named container for two doubles, two integers two object points and three string pointers that can be...
Definition RooCmdArg.h:26
Configurable parser for RooCmdArg named arguments.
void defineMutex(const char *head, Args_t &&... tail)
Define arguments where any pair is mutually exclusive.
bool process(const RooCmdArg &arg)
Process given RooCmdArg.
bool ok(bool verbose) const
Return true of parsing was successful.
bool defineObject(const char *name, const char *argName, int setNum, const TObject *obj=nullptr, bool isArray=false)
Define TObject property name 'name' mapped to object in slot 'setNum' in RooCmdArg with name argName ...
const char * getString(const char *name, const char *defaultValue="", bool convEmptyToNull=false) const
Return string property registered with name 'name'.
bool defineString(const char *name, const char *argName, int stringNum, const char *defValue="", bool appendMode=false)
Define double property name 'name' mapped to double in slot 'stringNum' in RooCmdArg with name argNam...
bool defineInt(const char *name, const char *argName, int intNum, int defValue=0)
Define integer property name 'name' mapped to integer in slot 'intNum' in RooCmdArg with name argName...
int getInt(const char *name, int defaultValue=0) const
Return integer property registered with name 'name'.
TObject * getObject(const char *name, TObject *obj=nullptr) const
Return TObject property registered with name 'name'.
Collection class for internal use, storing a collection of RooAbsArg pointers in a doubly linked list...
Singleton class that organizes messages generated in RooFit.
std::vector< StreamConfig > _streams
void restoreState()
Restore last saved state of message service.
std::ostream & log(const RooAbsArg *self, RooFit::MsgLevel level, RooFit::MsgTopic facility, bool forceSkipPrefix=false)
Log error message associated with RooAbsArg object self at given level and topic.
Int_t activeStream(T self, RooFit::MsgTopic topic, RooFit::MsgLevel level)
Find appropriate logging stream for message from given object with given topic and message level.
static RooMsgService & instance()
Return reference to singleton instance.
static Int_t _debugCount
std::unique_ptr< RooWorkspace > _debugWorkspace
static bool anyDebug()
Returns true if any debug level stream is active.
RooFit::MsgLevel _globMinLevel
std::stack< std::vector< StreamConfig > > _streamsSaved
RooMsgService()
Constructor.
RooWorkspace * debugWorkspace()
void Print(Option_t *options=nullptr) const override
Print configuration of message service.
void setStreamStatus(Int_t id, bool active)
(De)Activate stream with given unique ID
void saveState()
Save current state of message service.
Int_t addStream(RooFit::MsgLevel level, const RooCmdArg &arg1={}, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={})
Add a message logging stream for message with given RooFit::MsgLevel or higher.
std::map< int, std::string > _topicNames
~RooMsgService() override
std::map< std::string, std::unique_ptr< std::ostream > > _files
bool getStreamStatus(Int_t id) const
Get activation status of stream with given unique ID.
void deleteStream(Int_t id)
Delete stream with given unique ID code.
std::unique_ptr< std::ofstream > _devnull
std::map< int, std::string > _levelNames
RooFit::MsgLevel _lastMsgLevel
Persistable container for RooFit projects.
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
Definition TClass.cxx:4874
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
TClass * IsA() const override
Definition TNamed.h:58
Mother of all ROOT objects.
Definition TObject.h:41
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:439
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:207
virtual TClass * IsA() const
Definition TObject.h:243
Basic string class.
Definition TString.h:139
virtual int GetPid()
Get process id.
Definition TSystem.cxx:707
RooCmdArg Topic(Int_t topic)
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
Definition JSONIO.h:26
MsgLevel
Verbosity level for RooMsgService::StreamConfig in RooMsgService.
MsgTopic
Topics for a RooMsgService::StreamConfig in RooMsgService.
@ FastEvaluations
@ NumIntegration
@ InputArguments
@ ObjectHandling
@ LinkStateMgmt
Wrap an object into a TObject. Sometimes needed to avoid reinterpret_cast or enable RTTI.
Definition RooHelpers.h:57
bool match(RooFit::MsgLevel level, RooFit::MsgTopic facility, const RooAbsArg *obj)
Determine if message from given object at given level on given topic is logged.
TLine l
Definition textangle.C:4