middle of porting; unstable, don't checkout; refs #1
This commit is contained in:
262
src/mrw/autofunctiontracelog4cxx.cpp
Normal file
262
src/mrw/autofunctiontracelog4cxx.cpp
Normal file
@@ -0,0 +1,262 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wäckerlin
|
||||
@license LGPL, see file <a href="license.html">COPYING</a>
|
||||
|
||||
1 2 3 4 5 6 7 8
|
||||
5678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
*/
|
||||
|
||||
#ifndef __GNUG__
|
||||
#error GNU C++ Compiler is required for automatical function trace
|
||||
#endif
|
||||
|
||||
#include <mrw/string.hpp>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include <mrw/stacktrace.hpp>
|
||||
#include <log4cxx/logger.h>
|
||||
|
||||
#if (__GNUC__==3 && __GNUC_MINOR__<4 || __GNUC__<3) \
|
||||
&& defined(_REENTRANT) && !defined(_MT)
|
||||
#define _MT
|
||||
#endif
|
||||
|
||||
// these are special built in functions of GNU Compiler Collection
|
||||
extern "C" void __cyg_profile_func_enter (void *, void *) __attribute__((no_instrument_function));
|
||||
extern "C" void __cyg_profile_func_exit (void *, void *) __attribute__((no_instrument_function));
|
||||
|
||||
|
||||
// support for log4cxx 0.9.7 and for new CVS version
|
||||
#ifndef LOG4CXX_LOCATION
|
||||
# define MRW_LOG4CXX_LOCATION pos.file.c_str(), pos.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(pos.file.c_str(), pos.function.c_str(), pos.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 {
|
||||
|
||||
struct ThreadInfo {
|
||||
int level;
|
||||
bool recurse;
|
||||
};
|
||||
|
||||
#ifdef _MT
|
||||
static __thread ThreadInfo info = {0, false};
|
||||
#else
|
||||
static ThreadInfo info = {0, false};
|
||||
#endif
|
||||
|
||||
static bool mainPassed(false);
|
||||
|
||||
class Lock {
|
||||
public:
|
||||
Lock() __attribute__((no_instrument_function));
|
||||
~Lock() __attribute__((no_instrument_function));
|
||||
};
|
||||
// workaround doxygen problem:
|
||||
// - the C++ compiler compiles the following code
|
||||
// - doxygen ignores it
|
||||
#ifndef LET_DOXYGEN_IGNORE_THIS // doxygen can't match with __attribute__ above
|
||||
Lock::Lock() {
|
||||
info.recurse = true;
|
||||
}
|
||||
Lock::~Lock() {
|
||||
info.recurse = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" int main(int, char**);
|
||||
|
||||
/** @addtogroup FunctionTrace
|
||||
|
||||
@note There is also a fully automagic function trace, similar to
|
||||
@ref AutoTrace. It is described in @ref AutoFunctionTrace
|
||||
and requires the GNU Compiler Collection gcc, because it
|
||||
makes use of a proprietary compiler feature. */
|
||||
//@{
|
||||
|
||||
/** @defgroup AutoFunctionTrace Automatic Function Trace for GNU g++
|
||||
|
||||
If you compile your program with GNU g++ / gcc, and you want
|
||||
to add function tracing without changing a single line of your
|
||||
code, here's the solution:
|
||||
|
||||
If you link to the library @c libmrwautofunctiontracelog4cxx using
|
||||
a linker option such as: @c -lmrwautofunctiontracelog4cxx and you
|
||||
must enable the GNU Compiler Collection specific function trace
|
||||
feature with compile and link option @c -finstrument-functions
|
||||
then you get an automatical function trace, that traces to level
|
||||
@c DEBUG using the log4cxx library. You don't need to change a single
|
||||
line in your code!
|
||||
|
||||
This feature depends on:
|
||||
- the GNU C++ compiler gcc
|
||||
- @ref mrw::StackTrace
|
||||
- log4cxx http://logging.apache.org/log4cxx
|
||||
- optional: boost for thread support http://boost.org
|
||||
|
||||
The logger hiararchy name is: @c
|
||||
"mrw.fn.<full-method-name>" where @c
|
||||
<full-method-name> is the full name of the method, including
|
||||
namespace and class name, seperated not by double colon @c :: but
|
||||
by single dots @c . as it is common use in log4cxx. This way, you
|
||||
can enable or disable the function trace per namespace, per class
|
||||
or even per method.
|
||||
|
||||
The function trace does not start, before the program @c main is
|
||||
reached! Only the calls within the @c main are traced, but not during
|
||||
the initialisation and destruction of static members. This is
|
||||
necessary, because otherwise access the incompletely initialized
|
||||
MRW-C++ library itself may cause a crash.
|
||||
|
||||
A good default configuration is given in @ref AutoInitLog4cxx.
|
||||
Depending on your log4cxx configuration, a function trace may look
|
||||
e.g. like this (very simple configuration with very few additional
|
||||
information):
|
||||
|
||||
@verbatim
|
||||
mrw.fn.anotherFunction \ anotherFunction()
|
||||
mrw.fn.HalloWelt.fn1 \ HalloWelt::fn1()
|
||||
mrw.fn.HalloWelt.fn \ HalloWelt::fn()
|
||||
mrw.fn.HalloWelt.A.method \ HalloWelt::A::method()
|
||||
mrw.fn.HalloWelt.A.method / HalloWelt::A::method()
|
||||
mrw.fn.HalloWelt.A.method \ HalloWelt::A::method()
|
||||
mrw.fn.HalloWelt.A.method / HalloWelt::A::method()
|
||||
mrw.fn.HalloWelt.fn / HalloWelt::fn()
|
||||
mrw.fn.HalloWelt.fn \ HalloWelt::fn()
|
||||
mrw.fn.HalloWelt.A.method \ HalloWelt::A::method()
|
||||
mrw.fn.HalloWelt.A.method / HalloWelt::A::method()
|
||||
mrw.fn.HalloWelt.A.method \ HalloWelt::A::method()
|
||||
mrw.fn.HalloWelt.A.method / HalloWelt::A::method()
|
||||
mrw.fn.HalloWelt.fn / HalloWelt::fn()
|
||||
mrw.fn.HalloWelt.fn1 / HalloWelt::fn1()
|
||||
mrw.fn.anotherFunction / anotherFunction()
|
||||
@endverbatim
|
||||
|
||||
@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.
|
||||
|
||||
@section AutoFunctionTraceThread Multithreading
|
||||
|
||||
Multithreading is also supported, then you need to link to the
|
||||
thread safe compilat of the library @c
|
||||
libmrwautofunctiontracelog4cxx-mt with option @c
|
||||
-libmrwautofunctiontracelog4cxx-mt and you need the option @c
|
||||
-pthread in addition to @c -finstrument-functions which is still
|
||||
required.
|
||||
|
||||
Thread support requires the boost thread library. See
|
||||
http://boost.org for details.
|
||||
*/
|
||||
//@{
|
||||
|
||||
extern "C" void __cyg_profile_func_enter(void *this_fn, void*) {
|
||||
if (!mrw::mainPassed)
|
||||
if (this_fn == (void*)&::main) // not ANSI C++ conform...
|
||||
mrw::mainPassed=true;
|
||||
else
|
||||
return;
|
||||
try {
|
||||
if (mrw::info.recurse) return;
|
||||
mrw::Lock lock;
|
||||
{
|
||||
static bool init(mrw::StackTrace::createSymtable());
|
||||
if (!init) return;
|
||||
const mrw::StackTrace::CodePos& pos(mrw::StackTrace::translate(this_fn));
|
||||
std::string hierarchy(pos.function);
|
||||
for (std::string::size_type p(0);
|
||||
(p=hierarchy.find("::", p))!=std::string::npos;
|
||||
hierarchy.replace(p, 2, "."));
|
||||
hierarchy.erase(hierarchy.rfind('('));
|
||||
std::string::size_type p
|
||||
(hierarchy.rfind(' ', std::min(hierarchy.find('<'),
|
||||
hierarchy.find("operator"))));
|
||||
if (p!=std::string::npos) hierarchy.erase(0, p+1);
|
||||
// hierarchy.erase
|
||||
// (hierarchy.find_first_not_of
|
||||
// ("qwertzuiopasdfghjklyxcvbnmQWERTZUIOPASDFGHJKLYXCVBNM1234567890_."));
|
||||
if (hierarchy=="") hierarchy = "global";
|
||||
std::string name("mrw.fn."+hierarchy);
|
||||
log4cxx::Logger* logger
|
||||
(log4cxx::Logger::getLogger(log4cxx::String(name.begin(), name.end())));
|
||||
if (logger->isDebugEnabled()) {
|
||||
std::basic_ostringstream<log4cxx::String::value_type> ss;
|
||||
ss<<std::setw(2+mrw::info.level++)
|
||||
<<std::setfill(log4cxx::String::value_type(' '))
|
||||
<<"\\ "<<log4cxx::String(pos.function.begin(), pos.function.end());
|
||||
logger->forcedLog(MRW_LEVEL_DEBUG, ss.str(),
|
||||
MRW_LOG4CXX_LOCATION);
|
||||
}
|
||||
}
|
||||
} catch (...) {}
|
||||
}
|
||||
|
||||
extern "C" void __cyg_profile_func_exit(void *this_fn, void*) {
|
||||
if (!mrw::mainPassed)
|
||||
return;
|
||||
else
|
||||
if (this_fn == (void*)&::main) { // not ANSI C++ conform...
|
||||
mrw::mainPassed=false;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (mrw::info.recurse || mrw::info.level==0) return;
|
||||
mrw::Lock lock;
|
||||
{
|
||||
const mrw::StackTrace::CodePos& pos(mrw::StackTrace::translate(this_fn));
|
||||
std::string hierarchy(pos.function);
|
||||
for (std::string::size_type p(0);
|
||||
(p=hierarchy.find("::", p))!=std::string::npos;
|
||||
hierarchy.replace(p, 2, "."));
|
||||
hierarchy.erase(hierarchy.rfind('('));
|
||||
std::string::size_type p
|
||||
(hierarchy.rfind(' ', std::min(hierarchy.find('<'),
|
||||
hierarchy.find("operator"))));
|
||||
if (p!=std::string::npos) hierarchy.erase(0, p+1);
|
||||
// hierarchy.erase
|
||||
// (hierarchy.find_first_not_of
|
||||
// ("qwertzuiopasdfghjklyxcvbnmQWERTZUIOPASDFGHJKLYXCVBNM1234567890_."));
|
||||
if (hierarchy=="") hierarchy = "global";
|
||||
std::string name("mrw.fn."+hierarchy);
|
||||
log4cxx::Logger* logger
|
||||
(log4cxx::Logger::getLogger(log4cxx::String(name.begin(), name.end())));
|
||||
if (logger->isDebugEnabled()) {
|
||||
std::basic_ostringstream<log4cxx::String::value_type> ss;
|
||||
ss<<std::setw(2+--mrw::info.level)
|
||||
<<std::setfill(log4cxx::String::value_type(' '))
|
||||
<<"/ "<<log4cxx::String(pos.function.begin(), pos.function.end());
|
||||
logger->forcedLog(MRW_LEVEL_DEBUG, ss.str(),
|
||||
MRW_LOG4CXX_LOCATION);
|
||||
}
|
||||
}
|
||||
} catch (...) {}
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
//@}
|
Reference in New Issue
Block a user