/***************************************************************************** * Project: RooFit * * Package: RooFitCore * * @(#)root/roofitcore:$Id$ * Authors: * * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu * * DK, David Kirkby, UC Irvine, dkirkby@uci.edu * * * * Copyright (c) 2000-2005, Regents of the University of California * * and Stanford University. All rights reserved. * * * * Redistribution and use in source and binary forms, * * with or without modification, are permitted according to the terms * * listed in LICENSE (http://roofit.sourceforge.net/license.txt) * *****************************************************************************/ ////////////////////////////////////////////////////////////////////////////// // // BEGIN_HTML // // The RooMsgService class is a singleton class that organizes informational, debugging, // warning and errors messages generated by the RooFit core code. //

// Each message generated by the core // has a message level (DEBUG,INFO,PROGRESS,WARNING,ERROR or FATAL), an originating object, // and a 'topic'. Currently implemented topics are "Generation","Plotting", // "Integration", "Minimization" and "Workspace" and "ChangeTracking". //

// The RooMsgService class allows to filter and redirect messages into 'streams' // according to message level, topic, (base) class of originating object, name of originating // object and based on attribute labels attached to individual objects. //

// The current default configuration creates streams for all messages at WARNING level // or higher (e.g. ERROR and FATAL) and for all INFO message on topics Generation,Plotting, // Integration and Minimization and redirects them to stdout. Users can create additional streams // for logging of e.g. DEBUG messages on particular topics or objects and or redirect streams to // C++ streams or files. //

// The singleton instance is accessible through RooMsgService::instance() ; // // END_HTML // #define INST_MSG_SERVICE #include #include "RooFit.h" #include "RooAbsArg.h" #include "TClass.h" #include "TROOT.h" #include "RooMsgService.h" #include "RooCmdArg.h" #include "RooCmdConfig.h" #include "RooGlobalFunc.h" #include "RooSentinel.h" #include "RooWorkspace.h" #include "TSystem.h" #include "Riostream.h" #include #include using namespace std ; using namespace RooFit ; ClassImp(RooMsgService) ; RooMsgService* RooMsgService::_instance = 0 ; Int_t RooMsgService::_debugCount = 0 ; //_____________________________________________________________________________ void RooMsgService::cleanup() { // Cleanup function called by atexit() handler installed by RooSentinel // to delete all global object upon program termination if (_instance) { delete _instance ; _instance = 0 ; } } //_____________________________________________________________________________ RooMsgService::RooMsgService() { // Constructor. Defines names of message levels // and mapping of topic codes to topic names // Install default message streams. _silentMode = kFALSE ; _showPid = kFALSE ; _globMinLevel = DEBUG ; _lastMsgLevel = DEBUG ; _devnull = new ofstream("/dev/null") ; _levelNames[DEBUG]="DEBUG" ; _levelNames[INFO]="INFO" ; _levelNames[PROGRESS]="PROGRESS" ; _levelNames[WARNING]="WARNING" ; _levelNames[ERROR]="ERROR" ; _levelNames[FATAL]="FATAL" ; _topicNames[Generation]="Generation" ; _topicNames[Minimization]="Minization" ; _topicNames[Plotting]="Plotting" ; _topicNames[Fitting]="Fitting" ; _topicNames[Integration]="Integration" ; _topicNames[LinkStateMgmt]="LinkStateMgmt" ; _topicNames[Eval]="Eval" ; _topicNames[Caching]="Caching" ; _topicNames[Optimization]="Optimization" ; _topicNames[ObjectHandling]="ObjectHandling" ; _topicNames[InputArguments]="InputArguments" ; _topicNames[Tracing]="Tracing" ; _topicNames[Contents]="Contents" ; _topicNames[DataHandling]="DataHandling" ; _topicNames[NumIntegration]="NumericIntegration" ; _instance = this ; gMsgService = this ; _debugWorkspace = 0 ; _debugCode = 0 ; // Old-style streams addStream(RooFit::PROGRESS) ; addStream(RooFit::INFO,Topic(RooFit::Eval|RooFit::Plotting|RooFit::Fitting|RooFit::Minimization|RooFit::Caching|RooFit::ObjectHandling|RooFit::NumIntegration|RooFit::InputArguments|RooFit::DataHandling)) ; } //_____________________________________________________________________________ RooMsgService::~RooMsgService() { // Destructor // Delete all ostreams we own ; map::iterator iter = _files.begin() ; for (; iter != _files.end() ; ++iter) { delete iter->second ; } if (_debugWorkspace) { delete _debugWorkspace ; } delete _devnull ; } //_____________________________________________________________________________ Bool_t RooMsgService::anyDebug() { // Returns true if any debug level stream is active return instance()._debugCount>0 ; } //_____________________________________________________________________________ RooWorkspace* RooMsgService::debugWorkspace() { if (!_debugWorkspace) { _debugWorkspace = new RooWorkspace("wdebug") ; } return _debugWorkspace ; } //_____________________________________________________________________________ Int_t RooMsgService::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 (i.e. more severe) // This method accepts the following arguments to configure the stream // // Output Style options // -------------------- // Prefix(Bool_t flag=kTRUE) -- Prefix all messages in this stream with Topic/Originator information // // Filtering options // ----------------- // Topic(const char*) -- Restrict stream to messages on given topic // ObjectName(const char*) -- Restrict stream to messages from object with given name // ClassName(const char*) -- Restrict stream to messages from objects with given class name // BaseClassName(const char*)-- Restrict stream to messages from objects with given base class name // LabelName(const chat*) -- Restrict stream to messages from objects setAtrribute(const char*) tag with given name // // Output redirection options // -------------------------- // OutputFile(const char*) -- Send output to file with given name. Multiple streams can write to same file. // OutputStream(ostream&) -- Send output to given C++ stream. Multiple message streams can write to same c++ stream // // The return value is the unique ID code of the defined stream // Aggregate all arguments in a list RooLinkedList l ; l.Add((TObject*)&arg1) ; l.Add((TObject*)&arg2) ; l.Add((TObject*)&arg3) ; l.Add((TObject*)&arg4) ; l.Add((TObject*)&arg5) ; l.Add((TObject*)&arg6) ; // Define configuration for this method RooCmdConfig pc(Form("RooMsgService::addReportingStream(%s)",GetName())) ; pc.defineInt("prefix","Prefix",0,kTRUE) ; pc.defineInt("color","Color",0,static_cast(kBlack)) ; pc.defineInt("topic","Topic",0,0xFFFFF) ; pc.defineString("objName","ObjectName",0,"") ; pc.defineString("className","ClassName",0,"") ; pc.defineString("baseClassName","BaseClassName",0,"") ; pc.defineString("tagName","LabelName",0,"") ; pc.defineString("outFile","OutputFile",0,"") ; pc.defineObject("outStream","OutputStream",0,0) ; pc.defineMutex("OutputFile","OutputStream") ; // Process & check varargs pc.process(l) ; if (!pc.ok(kTRUE)) { return -1 ; } // Extract values from named arguments RooFit::MsgTopic topic = (RooFit::MsgTopic) pc.getInt("topic") ; const char* objName = pc.getString("objName") ; const char* className = pc.getString("className") ; const char* baseClassName = pc.getString("baseClassName") ; const char* tagName = pc.getString("tagName") ; const char* outFile = pc.getString("outFile") ; Bool_t prefix = pc.getInt("prefix") ; Color_t color = static_cast(pc.getInt("color")) ; ostream* os = reinterpret_cast(pc.getObject("outStream")) ; // Create new stream object StreamConfig newStream ; // Store configuration info newStream.active = kTRUE ; newStream.minLevel = level ; newStream.topic = topic ; newStream.objectName = (objName ? objName : "" ) ; newStream.className = (className ? className : "" ) ; newStream.baseClassName = (baseClassName ? baseClassName : "" ) ; newStream.tagName = (tagName ? tagName : "" ) ; newStream.color = color ; newStream.prefix = prefix ; newStream.universal = (newStream.objectName=="" && newStream.className=="" && newStream.baseClassName=="" && newStream.tagName=="") ; // Update debug stream count if (level==DEBUG) { _debugCount++ ; } // Configure output if (os) { // To given non-owned stream newStream.os = os ; } else if (string(outFile).size()>0) { // See if we already opened the file ostream* os2 = _files["outFile"] ; if (!os2) { // To given file name, create owned stream for it os2 = new ofstream(outFile) ; if (!*os2) { cout << "RooMsgService::addReportingStream ERROR: cannot open output log file " << outFile << " reverting stream to stdout" << endl ; delete os2 ; newStream.os = &cout ; } else { newStream.os = os2 ; } } else { _files["outFile"] = os2 ; newStream.os = os2 ; } } else { // To stdout newStream.os = &cout ; } // Add it to list of active streams ; _streams.push_back(newStream) ; // Return stream identifier return _streams.size()-1 ; } //_____________________________________________________________________________ void RooMsgService::deleteStream(Int_t id) { // Delete stream with given unique ID code vector::iterator iter = _streams.begin() ; iter += id ; // Update debug stream count if (iter->minLevel==DEBUG) { _debugCount-- ; } _streams.erase(iter) ; } //_____________________________________________________________________________ void RooMsgService::setStreamStatus(Int_t id, Bool_t flag) { // (De)Activate stream with given unique ID if (id<0 || id>=static_cast(_streams.size())) { cout << "RooMsgService::setStreamStatus() ERROR: invalid stream ID " << id << endl ; return ; } // Update debug stream count if (_streams[id].minLevel==DEBUG) { _debugCount += flag ? 1 : -1 ; } _streams[id].active = flag ; } //_____________________________________________________________________________ Bool_t RooMsgService::getStreamStatus(Int_t id) const { // Get activation status of stream with given unique ID if (id<0 || id>= static_cast(_streams.size())) { cout << "RooMsgService::getStreamStatus() ERROR: invalid stream ID " << id << endl ; return kFALSE ; } return _streams[id].active ; } //_____________________________________________________________________________ RooMsgService& RooMsgService::instance() { // Return reference to singleton instance if (!_instance) { new RooMsgService() ; RooSentinel::activate() ; } return *_instance ; } //_____________________________________________________________________________ void RooMsgService::saveState() { // Save current state of message service _streamsSaved.push(_streams) ; } //_____________________________________________________________________________ void RooMsgService::restoreState() { // Restore last saved state of message service _streams = _streamsSaved.top() ; _streamsSaved.pop() ; } //_____________________________________________________________________________ Bool_t RooMsgService::isActive(const RooAbsArg* self, RooFit::MsgTopic topic, RooFit::MsgLevel level) { // Check if logging is active for given object/topic/RooFit::MsgLevel combination return (activeStream(self,topic,level)>=0) ; } //_____________________________________________________________________________ Bool_t RooMsgService::isActive(const TObject* self, RooFit::MsgTopic topic, RooFit::MsgLevel level) { // Check if logging is active for given object/topic/RooFit::MsgLevel combination return (activeStream(self,topic,level)>=0) ; } //_____________________________________________________________________________ Int_t RooMsgService::activeStream(const RooAbsArg* self, RooFit::MsgTopic topic, RooFit::MsgLevel level) { // Find appropriate logging stream for message from given object with given topic and message level if (level<_globMinLevel) return -1 ; for (UInt_t i=0 ; i<_streams.size() ; i++) { if (_streams[i].match(level,topic,self)) { return i ; } } return -1 ; } //_____________________________________________________________________________ Int_t RooMsgService::activeStream(const TObject* self, RooFit::MsgTopic topic, RooFit::MsgLevel level) { // Find appropriate logging stream for message from given object with given topic and message level if (level<_globMinLevel) return -1 ; for (UInt_t i=0 ; i<_streams.size() ; i++) { if (_streams[i].match(level,topic,self)) { return i ; } } return -1 ; } //_____________________________________________________________________________ Bool_t RooMsgService::StreamConfig::match(RooFit::MsgLevel level, RooFit::MsgTopic top, const RooAbsArg* obj) { // Determine if message from given object at given level on given topic is logged if (!active) return kFALSE ; if (level0 && objectName != obj->GetName()) return kFALSE ; if (className.size()>0 && className != obj->IsA()->GetName()) return kFALSE ; if (baseClassName.size()>0 && !obj->IsA()->InheritsFrom(baseClassName.c_str())) return kFALSE ; if (tagName.size()>0 && !obj->getAttribute(tagName.c_str())) return kFALSE ; return kTRUE ; } //_____________________________________________________________________________ Bool_t RooMsgService::StreamConfig::match(RooFit::MsgLevel level, RooFit::MsgTopic top, const TObject* obj) { // Determine if message from given object at given level on given topic is logged if (!active) return kFALSE ; if (level0 && objectName != obj->GetName()) return kFALSE ; if (className.size()>0 && className != obj->IsA()->GetName()) return kFALSE ; if (baseClassName.size()>0 && !obj->IsA()->InheritsFrom(baseClassName.c_str())) return kFALSE ; return kTRUE ; } //_____________________________________________________________________________ ostream& RooMsgService::log(const RooAbsArg* self, RooFit::MsgLevel level, RooFit::MsgTopic topic, Bool_t skipPrefix) { // Log error message associated with RooAbsArg object self at given level and topic. If skipPrefix // is true the standard RooMsgService prefix is not added. if (level>=ERROR) { _errorCount++ ; } // Return C++ ostream associated with given message configuration Int_t as = activeStream(self,topic,level) ; if (as==-1) { return *_devnull ; } // Flush any previous messages (*_streams[as].os).flush() ; // Insert an endl if we switch from progress to another level if (_lastMsgLevel==PROGRESS && level!=PROGRESS) { (*_streams[as].os) << endl ; } _lastMsgLevel=level ; if (_streams[as].prefix && !skipPrefix) { if (_showPid) { (*_streams[as].os) << "pid" << gSystem->GetPid() << " " ; } (*_streams[as].os) << "[#" << as << "] " << _levelNames[level] << ":" << _topicNames[topic] << " -- " ; } return (*_streams[as].os) ; } //_____________________________________________________________________________ ostream& RooMsgService::log(const TObject* self, RooFit::MsgLevel level, RooFit::MsgTopic topic, Bool_t skipPrefix) { // Log error message associated with TObject object self at given level and topic. If skipPrefix // is true the standard RooMsgService prefix is not added. if (level>=ERROR) { _errorCount++ ; } // Return C++ ostream associated with given message configuration Int_t as = activeStream(self,topic,level) ; if (as==-1) { return *_devnull ; } // Flush any previous messages (*_streams[as].os).flush() ; if (_streams[as].prefix && !skipPrefix) { if (_showPid) { (*_streams[as].os) << "pid" << gSystem->GetPid() << " " ; } (*_streams[as].os) << "[#" << as << "] " << _levelNames[level] << ":" << _topicNames[topic] << " -- " ; } return (*_streams[as].os) ; } //_____________________________________________________________________________ void RooMsgService::Print(Option_t *options) const { // Print configuration of message service. If "v" option is given also // inactive streams are listed Bool_t activeOnly = kTRUE ; if (TString(options).Contains("V") || TString(options).Contains("v")) { activeOnly = kFALSE ; } cout << (activeOnly?"Active Message streams":"All Message streams") << endl ; for (UInt_t i=0 ; i<_streams.size() ; i++) { // Skip passive streams in active only mode if (activeOnly && !_streams[i].active) { continue ; } map::const_iterator is = _levelNames.find(_streams[i].minLevel) ; cout << "[" << i << "] MinLevel = " << is->second ; cout << " Topic = " ; if (_streams[i].topic != 0xFFFFF) { map::const_iterator iter = _topicNames.begin() ; while(iter!=_topicNames.end()) { if (iter->first & _streams[i].topic) { cout << iter->second << " " ; } ++iter ; } } else { cout << " Any " ; } if (_streams[i].objectName.size()>0) { cout << " ObjectName = " << _streams[i].objectName ; } if (_streams[i].className.size()>0) { cout << " ClassName = " << _streams[i].className ; } if (_streams[i].baseClassName.size()>0) { cout << " BaseClassName = " << _streams[i].baseClassName ; } if (_streams[i].tagName.size()>0) { cout << " TagLabel = " << _streams[i].tagName ; } // Postfix status when printing all if (!activeOnly && !_streams[i].active) { cout << " (NOT ACTIVE)" ; } cout << endl ; } }