/** @file
$Id$
$Date$
$Author$
@copy © Marc Wäckerlin
@license LGPL, see file COPYING
*/
#include
#include
#include
#include
#include
// support for log4cxx 0.9.7 and for new CVS version
#ifndef LOG4CXX_LOCATION
# define MRW_LOG4CXX_LOCATION __FILE__, __LINE__
#define MRW_LEVEL_DEBUG ::log4cxx::Level::DEBUG
#define MRW_LEVEL_INFO ::log4cxx::Level::INFO
#define MRW_LEVEL_WARN ::log4cxx::Level::WARN
#define MRW_LEVEL_ERROR ::log4cxx::Level::ERROR
#define MRW_LEVEL_FATAL ::log4cxx::Level::FATAL
#else
# define LOG4CXX_CVS
# define MRW_LOG4CXX_LOCATION \
::log4cxx::spi::LocationInfo(__FILE__, __FUNCTION__, __LINE__)
#define MRW_LEVEL_DEBUG ::log4cxx::Level::getDebug()
#define MRW_LEVEL_INFO ::log4cxx::Level::getInfo()
#define MRW_LEVEL_WARN ::log4cxx::Level::getWarn()
#define MRW_LEVEL_ERROR ::log4cxx::Level::getError()
#define MRW_LEVEL_FATAL ::log4cxx::Level::getFatal()
#endif
namespace mrw {
/** @addtogroup AutoTrace
@section trclog4cxx Trace using the log4cxx Library
If you link to the library @c libmrwexclog4cxx using a linker
option such as: @c -lmrwexclog4cxx, then an unexpected and a
terminate handler are registered, that trace a fatal error using
the log4cxx library. Also for all know signals there's a signal
handler to trace the stack before termination (except in case of
a @c SIGTRAP, wehere the program is not terminated). You don't
need to change a single line in your code!
The log4cxx library is located at:
- http://logging.apache.org/log4cxx
@note The configurator is not installed automatically. If you
want to trace e.g. on the console, you have to call @c
log4cxx::BasicConfigurator::configure(); as first statement in
your @c main(). @see @ref AutoInitLog4cxx if you also want to
automatically configure @c log4cxx.
*/
//@{
/** @brief unexpected handler, that traces using log4cxx
The unexpected handler is installed automatically when you link
to @c -lmrwexclog4cxx. The implementation of this unexpected
handler is as follows:
@code
void unexpected_log4cxx() {
log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("mrw.stacktrace"));
logger->fatal("Unexpected Exception", __FILE__, __LINE__);
StackTrace::createSymtable();
std::string st((std::string)StackTrace());
try {
throw;
} catch (const mrw::exception& x) {
logger->fatal(std::string("Reason:\n")+x.what()
+"\nStack:+\n"+x.stacktrace());
} catch (const std::exception& x) {
logger->fatal(std::string("Reason:\n")+x.what()
+"\nStack:\n"+st);
} catch (...) {
logger->fatal(std::string("Reason: **** not available ****")
+"\nStack:\n"+st);
}
throw std::bad_exception();
}
@endcode
*/
void unexpected_log4cxx() {
static const std::string name("mrw.stacktrace");
log4cxx::LoggerPtr logger
(log4cxx::Logger::getLogger(log4cxx::String(name.begin(), name.end())));
static const std::string txt("Unexpected Exception");
logger->fatal(log4cxx::String(txt.begin(), txt.end()), MRW_LOG4CXX_LOCATION);
StackTrace::createSymtable();
std::string st((std::string)StackTrace());
try {
throw;
} catch (const mrw::exception& x) {
std::string txt(std::string("Reason:\n")+x.what()
+"\nStack:\n"+x.stacktrace());
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
} catch (const std::exception& x) {
std::string txt(std::string("Reason:\n")+x.what()
+"\nStack:\n"+st);
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
} catch (...) {
std::string txt(std::string("Reason: **** not available ****")
+"\nStack:\n"+st);
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
}
throw std::bad_exception();
}
/** @brief terminate handler, that traces using log4cxx
The terminate handler is installed automatically when you link
to @c -lmrwexclog4cxx. The implementation of this terminate
handler is as follows:
@code
void terminate_log4cxx() {
log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("mrw.stacktrace"));
logger->fatal("Uncaught Exception", __FILE__, __LINE__);
StackTrace::createSymtable();
std::string st((std::string)StackTrace());
try {
throw;
exit(0);
} catch (const mrw::exception& x) {
logger->fatal(std::string("Reason:\n")+x.what()
+"\nStack:+\n"+x.stacktrace());
} catch (const std::exception& x) {
logger->fatal(std::string("Reason:\n")+x.what()
+"\nStack:\n"+st);
} catch (...) {
logger->fatal(std::string("Reason: **** not available ****")
+"\nStack:\n"+st);
}
exit(1);
}
@endcode
*/
void terminate_log4cxx() {
static const std::string name("mrw.stacktrace");
log4cxx::LoggerPtr logger
(log4cxx::Logger::getLogger(log4cxx::String(name.begin(), name.end())));
static const std::string txt("Uncaught Exception");
logger->fatal(log4cxx::String(txt.begin(), txt.end()), MRW_LOG4CXX_LOCATION);
StackTrace::createSymtable();
std::string st((std::string)StackTrace());
try {
throw;
} catch (const mrw::exception& x) {
std::string txt(std::string("Reason:\n")+x.what()
+"\nStack:\n"+x.stacktrace());
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
} catch (const std::exception& x) {
std::string txt(std::string("Reason:\n")+x.what()
+"\nStack:\n"+st);
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
} catch (...) {
std::string txt(std::string("Reason: **** not available ****")
+"\nStack:\n"+st);
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
}
exit(1);
}
/** @brief segmentation-fault handler, that traces using log4cxx
The segmentation-fault handler is installed automatically when you link
to @c -lmrwexclog4cxx. The implementation of this handler is as follows:
@code
void signal_log4cxx(int sig) {
std::string txt;
bool abort(true);
switch sig {
case SIGFPE: txt="SIGFPE: Arithmetic error."; break;
case SIGILL: txt="SIGILL: Illegal instruction."; break;
case SIGSEGV: txt="SIGSEGV: Segmentation fault"
" (invalid access to valid memory)."; break;
case SIGBUS: txt="SIGBUS: Invalid pointer dereference"
" (access to an invalid memory address)."; break;
case SIGABRT: txt="SIGABRT: Funktion 'abort' was called."; break;
case SIGIOT: txt="SIGIOT: PDP-11 'iot' instruction"; break;
case SIGTRAP: txt="SIGTRAP: Breakpoint instruction."; abort=false; break;
case SIGEMT: txt="SIGEMT: Emulator trap."; break;
case SIGSYS: txt="SIGSYS: Bad system call."; break;
default: txt="Unknown Signal Nr. "+sig; break;
}
StackTrace::createSymtable();
std::string st((std::string)StackTrace());
log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("mrw.stacktrace"));
logger->fatal("Aborted by signal: "+txt+"\nStack:\n"+st);
if (abort) exit(1);
}
@endcode
*/
void signal_log4cxx(int sig) {
std::string txt;
bool abort(true);
switch (sig) {
case SIGFPE: txt="SIGFPE: Arithmetic error."; break;
case SIGILL: txt="SIGILL: Illegal instruction."; break;
case SIGSEGV: txt="SIGSEGV: Segmentation fault"
" (invalid access to valid memory)."; break;
case SIGBUS: txt="SIGBUS: Invalid pointer dereference"
" (access to an invalid memory address)."; break;
case SIGABRT: txt="SIGABRT: Funktion 'abort' was called."; break;
case SIGTRAP: txt="SIGTRAP: Breakpoint instruction."; abort=false; break;
case SIGSYS: txt="SIGSYS: Bad system call."; break;
default: txt="Unknown Signal Nr. "+sig; break;
}
StackTrace::createSymtable();
std::string st((std::string)StackTrace());
static const std::string name("mrw.stacktrace");
log4cxx::LoggerPtr logger
(log4cxx::Logger::getLogger(log4cxx::String(name.begin(), name.end())));
std::string errtxt("Aborted by signal: "+txt+"\nStack:\n"+st);
logger->fatal(log4cxx::String(errtxt.begin(), errtxt.end()));
if (abort) exit(1);
}
class AutoStackTrace {
public:
AutoStackTrace() {
std::set_unexpected(&mrw::unexpected_log4cxx);
std::set_terminate(&mrw::terminate_log4cxx);
std::signal(SIGFPE, &mrw::signal_log4cxx);
std::signal(SIGILL, &mrw::signal_log4cxx);
std::signal(SIGSEGV, &mrw::signal_log4cxx);
std::signal(SIGBUS, &mrw::signal_log4cxx);
std::signal(SIGTRAP, &mrw::signal_log4cxx);
std::signal(SIGSYS, &mrw::signal_log4cxx);
}
};
//@}
// initialize stack traces (load symbols)
static AutoStackTrace _autoStackTrace;
}