Skip to content
Snippets Groups Projects

Use MessageSvc to handle ROOT messages

Merged Marco Clemencic requested to merge use-messagesvc-for-root-messages into master
Files
15
/***********************************************************************************\
* (c) Copyright 1998-2019 CERN for the benefit of the LHCb and ATLAS collaborations *
* (c) Copyright 1998-2023 CERN for the benefit of the LHCb and ATLAS collaborations *
* *
* This software is distributed under the terms of the Apache version 2 licence, *
* copied verbatim in the file "LICENSE". *
@@ -9,44 +9,73 @@
* or submit itself to any jurisdiction. *
\***********************************************************************************/
// Include files
#include "ApplicationMgr.h"
#include "AlgorithmManager.h"
#include "DLLClassManager.h"
#include "ServiceManager.h"
#include "GaudiKernel/IMessageSvc.h"
#include "GaudiKernel/IRunable.h"
#include "GaudiKernel/IService.h"
#include "GaudiKernel/TypeNameString.h"
#include "GaudiKernel/MsgStream.h"
#include "GaudiKernel/ObjectFactory.h"
#include "GaudiKernel/SmartIF.h"
#include "GaudiKernel/GaudiException.h"
#include "GaudiKernel/StatusCode.h"
#include "GaudiKernel/System.h"
#include "GaudiKernel/Time.h"
#include "GAUDI_VERSION.h"
using System::getEnv;
using System::isEnvSet;
#include <GAUDI_VERSION.h>
#include <GaudiKernel/GaudiException.h>
#include <GaudiKernel/IMessageSvc.h>
#include <GaudiKernel/IRunable.h>
#include <GaudiKernel/IService.h>
#include <GaudiKernel/Message.h>
#include <GaudiKernel/MsgStream.h>
#include <GaudiKernel/ObjectFactory.h>
#include <GaudiKernel/SmartIF.h>
#include <GaudiKernel/StatusCode.h>
#include <GaudiKernel/System.h>
#include <GaudiKernel/Time.h>
#include <GaudiKernel/TypeNameString.h>
#include <TError.h>
#include <TROOT.h>
#include <algorithm>
#include <cassert>
#include <ctime>
#include <limits>
#include <sstream>
using System::getEnv;
using System::isEnvSet;
#define ON_DEBUG if ( m_outputLevel <= MSG::DEBUG )
#define ON_VERBOSE if ( m_outputLevel <= MSG::VERBOSE )
DECLARE_OBJECT_FACTORY( ApplicationMgr )
namespace {
/// Pointer to the IMessageSvc instance used by ROOTErrorHandlerAdapter.
static IMessageSvc* s_messageSvcInstance{ nullptr };
/// Pointer to the ROOT error handler registered before we replaced it with ROOTErrorHandlerAdapter.
static ErrorHandlerFunc_t s_originalRootErrorHandler{ nullptr };
/// @brief Adapter to forward ROOT messages to a MessageSvc.
void ROOTErrorHandlerAdapter( int level, Bool_t abort, const char* location, const char* msg ) {
if ( s_messageSvcInstance ) {
// we pass the message to MessageSvc only if it is not suppressed by ROOT itself
if ( level >= gErrorIgnoreLevel ) {
// # Map ROOT level to Gaudi level:
// ROOT levels go from 0 to 6000 in step of 1000,
// kInfo is 1000 while MSG::INFO is 3, so we aim for `level / 1000 + 2`,
// but we have to put a cap at MSG::FATAL.
int msgLevel = std::min<int>( level / 1000 + 2, MSG::FATAL );
if ( msgLevel >= s_messageSvcInstance->outputLevel( location ) ) {
s_messageSvcInstance->reportMessage( Message{ location, msgLevel, msg }, msgLevel );
}
}
} else {
// If a message is sent when we do not have an IMessageSvc, let's use something else
if ( s_originalRootErrorHandler ) {
// either the original handler (if any)
s_originalRootErrorHandler( level, abort, location, msg );
} else {
// or some minimalistic implementation from ROOT (just not to loose the message)
ROOT::Internal::MinimalErrorHandler( level, abort, location, msg );
}
}
+3
}
} // namespace
// Implementation class for the Application Manager. In this way the
// ApplicationMgr class is a fully insulated concrete class. Clients
// (main programs) will not need to re-compile if there are changes
@@ -145,6 +174,18 @@ StatusCode ApplicationMgr::i_startup() {
log << MSG::FATAL << "Error setting OutputLevel option of MessageSvc" << endmsg;
return sc;
}
if ( m_useMessageSvcForROOTMessages ) {
if ( gROOT ) {
// if ROOT is already initialized (usually it is the case) we redirect messages to MessageSvc.
s_messageSvcInstance = m_messageSvc.get();
s_originalRootErrorHandler = SetErrorHandler( ROOTErrorHandlerAdapter );
} else {
log << MSG::WARNING
<< "ROOT not yet initialized, we cannot override the error handler are requested "
"(UseMessageSvcForROOTMessages==true)"
<< endmsg;
}
}
auto jobsvc = svcManager()->createService( Gaudi::Utils::TypeNameString( "JobOptionsSvc", m_jobOptionsSvcType ) );
// Create the Job Options service
@@ -620,6 +661,13 @@ StatusCode ApplicationMgr::terminate() {
opts.set( "JobOptionsSvc.AuditFinalize", "false" );
}
// if we have overriden it, restore the original ROOT error handler
if ( s_originalRootErrorHandler ) {
SetErrorHandler( s_originalRootErrorHandler );
s_originalRootErrorHandler = nullptr;
}
// make sure ROOTErrorHandlerAdapter (if in use) does not try to use the MessageSvc we are about to delete
s_messageSvcInstance = nullptr;
// finalize MessageSvc
auto svc = m_messageSvc.as<IService>();
if ( !svc ) {
Loading