2004-08-28 16:21:25 +00:00
|
|
|
/** @file
|
|
|
|
|
|
|
|
$Id$
|
|
|
|
|
|
|
|
$Date$
|
|
|
|
$Author$
|
|
|
|
|
|
|
|
@copy © Marc Wäckerlin
|
|
|
|
@license LGPL, see file <a href="license.html">COPYING</a>
|
|
|
|
|
|
|
|
*/
|
2004-04-23 16:03:29 +00:00
|
|
|
#include <mrw/stacktrace.hpp>
|
|
|
|
#include <mrw/exception.hpp>
|
2007-08-16 07:43:56 +00:00
|
|
|
#include <csignal>
|
2004-04-23 16:03:29 +00:00
|
|
|
#include <exception>
|
|
|
|
#include <log4cxx/logger.h>
|
|
|
|
|
2007-08-16 07:43:56 +00:00
|
|
|
|
|
|
|
// 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()
|
2005-11-29 12:42:01 +00:00
|
|
|
#endif
|
|
|
|
|
2004-04-23 16:03:29 +00:00
|
|
|
namespace mrw {
|
|
|
|
|
|
|
|
/** @addtogroup AutoTrace
|
|
|
|
|
|
|
|
@section trclog4cxx Trace using the log4cxx Library
|
|
|
|
|
|
|
|
If you link to the library @c libmrwexclog4cxx using a linker
|
2005-01-28 07:42:23 +00:00
|
|
|
option such as: @c -lmrwexclog4cxx, then an unexpected and a
|
|
|
|
terminate handler are registered, that trace a fatal error using
|
2007-08-16 07:43:56 +00:00
|
|
|
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!
|
2004-04-23 16:03:29 +00:00
|
|
|
|
|
|
|
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
|
2005-04-07 20:43:50 +00:00
|
|
|
your @c main(). @see @ref AutoInitLog4cxx if you also want to
|
|
|
|
automatically configure @c log4cxx.
|
2004-04-23 16:03:29 +00:00
|
|
|
*/
|
|
|
|
//@{
|
|
|
|
|
|
|
|
/** @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() {
|
2007-08-16 07:43:56 +00:00
|
|
|
log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("mrw.stacktrace"));
|
2004-04-23 16:03:29 +00:00
|
|
|
logger->fatal("Unexpected Exception", __FILE__, __LINE__);
|
2004-08-28 16:21:25 +00:00
|
|
|
StackTrace::createSymtable();
|
|
|
|
std::string st((std::string)StackTrace());
|
2004-04-23 16:03:29 +00:00
|
|
|
try {
|
|
|
|
throw;
|
|
|
|
} catch (const mrw::exception& x) {
|
|
|
|
logger->fatal(std::string("Reason:\n")+x.what()
|
2004-08-28 16:21:25 +00:00
|
|
|
+"\nStack:+\n"+x.stacktrace());
|
2004-04-23 16:03:29 +00:00
|
|
|
} catch (const std::exception& x) {
|
|
|
|
logger->fatal(std::string("Reason:\n")+x.what()
|
2004-08-28 16:21:25 +00:00
|
|
|
+"\nStack:\n"+st);
|
2004-04-23 16:03:29 +00:00
|
|
|
} catch (...) {
|
2004-08-28 16:21:25 +00:00
|
|
|
logger->fatal(std::string("Reason: **** not available ****")
|
|
|
|
+"\nStack:\n"+st);
|
2004-04-23 16:03:29 +00:00
|
|
|
}
|
|
|
|
throw std::bad_exception();
|
|
|
|
}
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
*/
|
|
|
|
void unexpected_log4cxx() {
|
2007-08-16 07:43:56 +00:00
|
|
|
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);
|
2004-08-28 16:21:25 +00:00
|
|
|
StackTrace::createSymtable();
|
|
|
|
std::string st((std::string)StackTrace());
|
2004-04-23 16:03:29 +00:00
|
|
|
try {
|
|
|
|
throw;
|
|
|
|
} catch (const mrw::exception& x) {
|
2007-08-16 07:43:56 +00:00
|
|
|
std::string txt(std::string("Reason:\n")+x.what()
|
|
|
|
+"\nStack:\n"+x.stacktrace());
|
|
|
|
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
|
2004-04-23 16:03:29 +00:00
|
|
|
} catch (const std::exception& x) {
|
2007-08-16 07:43:56 +00:00
|
|
|
std::string txt(std::string("Reason:\n")+x.what()
|
|
|
|
+"\nStack:\n"+st);
|
|
|
|
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
|
2004-04-23 16:03:29 +00:00
|
|
|
} catch (...) {
|
2007-08-16 07:43:56 +00:00
|
|
|
std::string txt(std::string("Reason: **** not available ****")
|
|
|
|
+"\nStack:\n"+st);
|
|
|
|
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
|
2004-04-23 16:03:29 +00:00
|
|
|
}
|
|
|
|
throw std::bad_exception();
|
|
|
|
}
|
|
|
|
|
2005-01-28 07:42:23 +00:00
|
|
|
/** @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() {
|
2007-08-16 07:43:56 +00:00
|
|
|
log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("mrw.stacktrace"));
|
2005-01-28 07:42:23 +00:00
|
|
|
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() {
|
2007-08-16 07:43:56 +00:00
|
|
|
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);
|
2005-01-28 07:42:23 +00:00
|
|
|
StackTrace::createSymtable();
|
|
|
|
std::string st((std::string)StackTrace());
|
|
|
|
try {
|
|
|
|
throw;
|
|
|
|
} catch (const mrw::exception& x) {
|
2007-08-16 07:43:56 +00:00
|
|
|
std::string txt(std::string("Reason:\n")+x.what()
|
|
|
|
+"\nStack:\n"+x.stacktrace());
|
|
|
|
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
|
2005-01-28 07:42:23 +00:00
|
|
|
} catch (const std::exception& x) {
|
2007-08-16 07:43:56 +00:00
|
|
|
std::string txt(std::string("Reason:\n")+x.what()
|
|
|
|
+"\nStack:\n"+st);
|
|
|
|
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
|
2005-01-28 07:42:23 +00:00
|
|
|
} catch (...) {
|
2007-08-16 07:43:56 +00:00
|
|
|
std::string txt(std::string("Reason: **** not available ****")
|
|
|
|
+"\nStack:\n"+st);
|
|
|
|
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
|
2005-01-28 07:42:23 +00:00
|
|
|
}
|
|
|
|
exit(1);
|
|
|
|
}
|
2007-08-16 07:43:56 +00:00
|
|
|
|
|
|
|
/** @brief segmentation-fault handler, that traces using log4cxx
|
2005-01-28 07:42:23 +00:00
|
|
|
|
2007-08-16 07:43:56 +00:00
|
|
|
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);
|
|
|
|
}
|
2004-04-23 16:03:29 +00:00
|
|
|
|
|
|
|
class AutoStackTrace {
|
|
|
|
public:
|
|
|
|
AutoStackTrace() {
|
|
|
|
std::set_unexpected(&mrw::unexpected_log4cxx);
|
2005-01-28 07:42:23 +00:00
|
|
|
std::set_terminate(&mrw::terminate_log4cxx);
|
2007-08-16 07:43:56 +00:00
|
|
|
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);
|
2004-04-23 16:03:29 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2007-08-16 07:43:56 +00:00
|
|
|
//@}
|
|
|
|
|
2004-04-23 16:03:29 +00:00
|
|
|
// initialize stack traces (load symbols)
|
|
|
|
static AutoStackTrace _autoStackTrace;
|
|
|
|
|
|
|
|
}
|