/** @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(std::string(name.begin(), name.end()))); static const std::string txt("Unexpected Exception"); logger->fatal(std::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(std::string(txt.begin(), txt.end())); } catch (const std::exception& x) { std::string txt(std::string("Reason:\n")+x.what() +"\nStack:\n"+st); logger->fatal(std::string(txt.begin(), txt.end())); } catch (...) { std::string txt(std::string("Reason: **** not available ****") +"\nStack:\n"+st); logger->fatal(std::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(std::string(name.begin(), name.end()))); static const std::string txt("Uncaught Exception"); logger->fatal(std::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(std::string(txt.begin(), txt.end())); } catch (const std::exception& x) { std::string txt(std::string("Reason:\n")+x.what() +"\nStack:\n"+st); logger->fatal(std::string(txt.begin(), txt.end())); } catch (...) { std::string txt(std::string("Reason: **** not available ****") +"\nStack:\n"+st); logger->fatal(std::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(std::string(name.begin(), name.end()))); std::string errtxt("Aborted by signal: "+txt+"\nStack:\n"+st); logger->fatal(std::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; }