Commit 6a8a85e2 authored by Rosen Matev's avatar Rosen Matev Committed by Charles Leggett
Browse files

Capture and print exception backtrace

parent 24d8ee5d
......@@ -37,6 +37,9 @@ StatusCode TestToolAlgFailure::initialize()
warning() << "Got exception '" << e.what() << "'" << endmsg;
} else {
error() << "Got exception '" << e.what() << "'" << endmsg;
if ( m_throwException ) {
throw;
}
return StatusCode::FAILURE;
}
}
......
......@@ -29,6 +29,7 @@ public:
private:
Gaudi::Property<std::vector<std::string>> m_tools{this, "Tools", {}, "list of tools to test"};
Gaudi::Property<bool> m_ignoreFailure{this, "IgnoreFailure", false};
Gaudi::Property<bool> m_throwException{this, "ThrowException", false};
};
#endif // TESTTOOLALG_H
<?xml version="1.0" ?>
<!DOCTYPE extension PUBLIC '-//QM/2.3/Extension//EN' 'http://www.codesourcery.com/qm/dtds/2.3/-//qm/2.3/extension//en.dtd'>
<extension class="GaudiTest.GaudiExeTest" kind="test">
<argument name="program"><text>gaudirun.py</text></argument>
<argument name="args"><set><text>-v</text></set></argument>
<argument name="options"><text>
from Gaudi.Configuration import *
from Configurables import TestToolFailing, TestToolAlgFailure
alg = TestToolAlgFailure(Tools=[TestToolFailing("Tool")],
IgnoreFailure=False,
ThrowException=True)
ApplicationMgr(TopAlg=[alg], EvtSel="NONE", EvtMax=1)
</text></argument>
<argument name="environment"><set>
<text>ENABLE_BACKTRACE=1</text>
</set></argument>
<argument name="use_temp_dir"><enumeral>true</enumeral></argument>
<argument name="reference"><text>refs/backtrace.ref</text></argument>
<argument name="exit_code"><integer>1</integer></argument>
<argument name="validator"><text>
preprocessor = (
normalizeEOL +
RegexpReplacer(r"#\d+ +0(x[0-9a-fA-F]{4,16})? +.* +\[.*\]", r"#N 0xffffffff signature() [/path/to/libLibrary.so]")
)
with open(self._expandReferenceFileName("refs/backtrace.ref")) as f:
findReferenceBlock(f.read(), stdout=preprocessor(stdout))
</text></argument>
</extension>
TestToolAlgFailure ERROR Exception stack trace
#N 0xffffffff signature() [/path/to/libLibrary.so]
#N 0xffffffff signature() [/path/to/libLibrary.so]
#N 0xffffffff signature() [/path/to/libLibrary.so]
......@@ -5,7 +5,6 @@
#include "GaudiKernel/Kernel.h"
#include "GaudiKernel/MsgStream.h"
#include "GaudiKernel/StatusCode.h"
#include "GaudiKernel/System.h"
#include <exception>
#include <iostream>
......@@ -21,11 +20,6 @@
*/
class GAUDI_API GaudiException : virtual public std::exception
{
// friends
friend inline std::ostream& operator<<( std::ostream& os, const GaudiException& ge );
friend inline std::ostream& operator<<( std::ostream& os, const GaudiException* pge );
friend inline MsgStream& operator<<( MsgStream& os, const GaudiException& ge );
friend inline MsgStream& operator<<( MsgStream& os, const GaudiException* pge );
friend class StatusCode;
public:
......@@ -34,11 +28,7 @@ public:
@param Tag "name tag", or exeption type
@param Code status code
*/
GaudiException( std::string Message, std::string Tag, StatusCode Code )
: m_message( std::move( Message ) ), m_tag( std::move( Tag ) ), m_code( std::move( Code ) )
{
s_proc = true;
}
GaudiException( std::string Message, std::string Tag, StatusCode Code );
/** Constructor (2)
@param Message error message
......@@ -46,13 +36,7 @@ public:
@param Code status code
@param Exception "previous" exception
*/
GaudiException( std::string Message, std::string Tag, StatusCode Code, const GaudiException& Exception )
: m_message( std::move( Message ) )
, m_tag( std::move( Tag ) )
, m_code( std::move( Code ) )
, m_previous( Exception.clone() )
{
}
GaudiException( std::string Message, std::string Tag, StatusCode Code, const GaudiException& Exception );
/** Constructor (3)
@param Message error message
......@@ -60,40 +44,16 @@ public:
@param Code status code
@param Exception "previous" exception (used to improve the error message)
*/
GaudiException( std::string Message, std::string Tag, StatusCode Code, const std::exception& Exception )
: m_message( std::move( Message ) ), m_tag( std::move( Tag ) ), m_code( std::move( Code ) )
{
s_proc = true;
m_message += ": " + System::typeinfoName( typeid( Exception ) ) + ", " + Exception.what();
}
GaudiException( std::string Message, std::string Tag, StatusCode Code, const std::exception& Exception );
/// Copy constructor (deep copying!)
GaudiException( const GaudiException& Exception )
: std::exception( Exception )
, m_message{Exception.message()}
, m_tag{Exception.tag()}
, m_code{Exception.code()}
, m_previous{Exception.previous() ? Exception.previous()->clone() : nullptr}
{
s_proc = true;
}
GaudiException( const GaudiException& Exception );
/// destructor (perform the deletion of "previous" field!)
virtual ~GaudiException() throw()
{
m_code.setChecked();
s_proc = false;
}
virtual ~GaudiException() throw();
/// assignment operator
GaudiException& operator=( const GaudiException& Exception )
{
m_message = Exception.message();
m_tag = Exception.tag();
m_code = Exception.code();
m_previous.reset( Exception.previous() ? Exception.previous()->clone() : nullptr );
return *this;
}
GaudiException& operator=( const GaudiException& Exception );
/// error message to be printed
virtual const std::string& message() const { return m_message; }
......@@ -128,19 +88,14 @@ public:
/// get the previous exception ( "previous" element in the linked list)
virtual GaudiException* previous() const { return m_previous.get(); }
/// return the stack trace at instantiation
virtual const std::string& backTrace() const { return m_backTrace; }
/// methods for overloaded printout to std::ostream& and MsgStream&
virtual std::ostream& printOut( std::ostream& os = std::cerr ) const
{
os << tag() << " \t " << message() << "\t StatusCode=" << code();
return ( 0 != previous() ) ? previous()->printOut( os << std::endl ) : os;
}
virtual std::ostream& printOut( std::ostream& os = std::cerr ) const;
/// Output the exception to the Gaudi MsgStream
virtual MsgStream& printOut( MsgStream& os ) const
{
os << tag() << " \t " << message() << "\t StatusCode=" << code();
return ( 0 != previous() ) ? previous()->printOut( os << endmsg ) : os;
}
virtual MsgStream& printOut( MsgStream& os ) const;
/// clone operation
virtual GaudiException* clone() const { return new GaudiException( *this ); }
......@@ -149,26 +104,24 @@ public:
const char* what() const throw() override { return message().c_str(); }
protected:
mutable std::string m_message; /// error message
mutable std::string m_tag; /// exception tag
mutable StatusCode m_code; /// status code for exception
mutable std::unique_ptr<GaudiException> m_previous; /// "previous" element in the linked list
static bool s_proc;
std::string m_message; /// error message
std::string m_tag; /// exception tag
StatusCode m_code; /// status code for exception
std::string m_backTrace; /// stack trace at instantiation
std::unique_ptr<GaudiException> m_previous; /// "previous" element in the linked list
static bool s_proc;
};
/// overloaded printout to std::ostream
std::ostream& operator<<( std::ostream& os, const GaudiException& ge ) { return ge.printOut( os ); }
std::ostream& operator<<( std::ostream& os, const GaudiException* pge )
{
return ( 0 == pge ) ? ( os << " GaudiException* points to NULL!" ) : ( os << *pge );
}
std::ostream& operator<<( std::ostream& os, const GaudiException& ge );
/// overloaded printout to std::ostream
std::ostream& operator<<( std::ostream& os, const GaudiException* pge );
/// overloaded printout to MsgStream
MsgStream& operator<<( MsgStream& os, const GaudiException& ge ) { return ge.printOut( os ); }
MsgStream& operator<<( MsgStream& os, const GaudiException& ge );
/// overloaded printout to MsgStream
MsgStream& operator<<( MsgStream& os, const GaudiException* pge )
{
return ( 0 == pge ) ? ( os << " GaudiException* points to NULL!" ) : ( os << *pge );
}
MsgStream& operator<<( MsgStream& os, const GaudiException* pge );
#endif // GAUDIKERNEL_GAUDIEXCEPTION_H
#include "GaudiKernel/GaudiException.h"
bool GaudiException::s_proc( false );
#include "GaudiKernel/System.h"
bool GaudiException::s_proc( false );
static const bool enableBacktrace = System::isEnvSet( "ENABLE_BACKTRACE" );
namespace
{
inline std::string captureBacktrace( const StatusCode& code )
{
std::string backtrace;
if ( enableBacktrace && !code.isSuccess() ) System::backTrace( backtrace, 100, 1 );
return backtrace;
}
}
GaudiException::GaudiException( std::string Message, std::string Tag, StatusCode Code )
: m_message( std::move( Message ) ), m_tag( std::move( Tag ) ), m_code( std::move( Code ) )
{
s_proc = true;
m_backTrace = captureBacktrace( Code );
}
GaudiException::GaudiException( std::string Message, std::string Tag, StatusCode Code, const GaudiException& Exception )
: m_message( std::move( Message ) )
, m_tag( std::move( Tag ) )
, m_code( std::move( Code ) )
, m_previous( Exception.clone() )
{
// Do not capture backtrace in outer chained exceptions, so only innermost exception is printed
}
GaudiException::GaudiException( std::string Message, std::string Tag, StatusCode Code, const std::exception& Exception )
: m_message( std::move( Message ) ), m_tag( std::move( Tag ) ), m_code( std::move( Code ) )
{
s_proc = true;
m_message += ": " + System::typeinfoName( typeid( Exception ) ) + ", " + Exception.what();
m_backTrace = captureBacktrace( Code );
}
GaudiException::GaudiException( const GaudiException& Exception )
: std::exception( Exception )
, m_message{Exception.message()}
, m_tag{Exception.tag()}
, m_code{Exception.code()}
, m_backTrace{Exception.backTrace()}
, m_previous{Exception.previous() ? Exception.previous()->clone() : nullptr}
{
s_proc = true;
}
GaudiException::~GaudiException() throw()
{
m_code.setChecked();
s_proc = false;
}
GaudiException& GaudiException::operator=( const GaudiException& Exception )
{
m_message = Exception.message();
m_tag = Exception.tag();
m_code = Exception.code();
m_backTrace = Exception.backTrace();
m_previous.reset( Exception.previous() ? Exception.previous()->clone() : nullptr );
return *this;
}
std::ostream& GaudiException::printOut( std::ostream& os ) const
{
os << tag() << " \t " << message() << "\t StatusCode=" << code();
if ( !backTrace().empty() ) os << std::endl << "Exception stack trace\n" << backTrace();
return ( 0 != previous() ) ? previous()->printOut( os << std::endl ) : os;
}
MsgStream& GaudiException::printOut( MsgStream& os ) const
{
os << tag() << " \t " << message() << "\t StatusCode=" << code();
if ( !backTrace().empty() ) os << endmsg << "Exception stack trace\n" << backTrace();
return ( 0 != previous() ) ? previous()->printOut( os << endmsg ) : os;
}
std::ostream& operator<<( std::ostream& os, const GaudiException& ge ) { return ge.printOut( os ); }
std::ostream& operator<<( std::ostream& os, const GaudiException* pge )
{
return ( 0 == pge ) ? ( os << " GaudiException* points to NULL!" ) : ( os << *pge );
}
MsgStream& operator<<( MsgStream& os, const GaudiException& ge ) { return ge.printOut( os ); }
MsgStream& operator<<( MsgStream& os, const GaudiException* pge )
{
return ( 0 == pge ) ? ( os << " GaudiException* points to NULL!" ) : ( os << *pge );
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment