C++ Library containing a lot of needful things: Stack Trace, Command Line Parser, Resource Handling, Configuration Files, Unix Command Execution, Directories, Regular Expressions, Tokenizer, Function Trace, Standard Extensions.
281 lines
9.2 KiB
281 lines
9.2 KiB
/** @file |
|
|
|
$Id$ |
|
|
|
$Date$ |
|
$Author$ |
|
|
|
@copy © Marc Wäckerlin |
|
@license LGPL, see file <a href="license.html">COPYING</a> |
|
|
|
$Log$ |
|
Revision 1.2 2005/04/07 20:50:13 marc |
|
docu: new doxygen, new grouping |
|
|
|
Revision 1.1 2005/03/11 21:07:54 marc |
|
initial version |
|
|
|
|
|
1 2 3 4 5 6 7 8 |
|
5678901234567890123456789012345678901234567890123456789012345678901234567890 |
|
*/ |
|
|
|
#ifndef __MRW_FUNCTIONTRACE_HPP__ |
|
#define __MRW_FUNCTIONTRACE_HPP__ |
|
|
|
#include <log4cxx/logger.h> |
|
#include <sstream> |
|
#include <iomanip> |
|
#include <string> |
|
|
|
namespace mrw { |
|
|
|
/** @addtogroup debug */ |
|
//@{ |
|
|
|
/** @defgroup FunctionTrace Function Tracing (using log4cxx) |
|
@pre #include <mrw/functiontrace.hpp> |
|
|
|
Place the macro @ref METHOD as first line of all methods you want to |
|
trace, and macro @ref FUNCTION as first line of all functions to be |
|
traced. |
|
|
|
There are alternative macros @ref METHOD2 and @ref FUNCTION2, |
|
that allow you to also specify the logging hierarchy. The |
|
default for the hierarchy string is @c "mrw.fntrace". The |
|
logging level is always @c DEBUG and cannot be changed. |
|
|
|
@attention Be careful when you copy paste the declarations from |
|
one method to the other! Don't forget to correctly change the |
|
method's name! I recommend to use a tool like OpenC++ |
|
(http://opencxx.sf.net) to automatically place function trace |
|
statements into classes, so that the coder does not have to care |
|
about. I have already partly written such a module and I will |
|
provide it for free (GPL) when it is good enough. |
|
|
|
The trace of the following code: |
|
|
|
@code |
|
#include <mrw/functiontrace.hpp> |
|
#include <log4cxx/basicconfigurator.h> |
|
void fn(int i=0) { |
|
FUNCTION("fn(int)"); // trace entry and exit |
|
if (i<4) fn(++i); |
|
} |
|
class A { |
|
public: |
|
A() { // not traced |
|
method(); |
|
} |
|
void method() { |
|
METHOD("A::method()"); // trace entry and exit |
|
fn(); |
|
} |
|
}; |
|
int main(int, char**) { |
|
log4cxx::BasicConfigurator::configure(); |
|
FUNCTION("main(int, char**)"); |
|
A().method(); |
|
return 0; |
|
} |
|
@endcode |
|
|
|
Produces this output: |
|
|
|
@verbatim |
|
1 [1078671488] DEBUG mrw.fntrace - \ main(int, char**) |
|
1 [1078671488] DEBUG mrw.fntrace - 0xbfffef3f: \ A::method() |
|
1 [1078671488] DEBUG mrw.fntrace - \ fn(int) |
|
2 [1078671488] DEBUG mrw.fntrace - \ fn(int) |
|
2 [1078671488] DEBUG mrw.fntrace - \ fn(int) |
|
2 [1078671488] DEBUG mrw.fntrace - \ fn(int) |
|
2 [1078671488] DEBUG mrw.fntrace - \ fn(int) |
|
2 [1078671488] DEBUG mrw.fntrace - / fn(int) |
|
2 [1078671488] DEBUG mrw.fntrace - / fn(int) |
|
2 [1078671488] DEBUG mrw.fntrace - / fn(int) |
|
3 [1078671488] DEBUG mrw.fntrace - / fn(int) |
|
3 [1078671488] DEBUG mrw.fntrace - / fn(int) |
|
3 [1078671488] DEBUG mrw.fntrace - 0xbfffef3f: / A::method() |
|
3 [1078671488] DEBUG mrw.fntrace - 0xbfffef3f: \ A::method() |
|
3 [1078671488] DEBUG mrw.fntrace - \ fn(int) |
|
3 [1078671488] DEBUG mrw.fntrace - \ fn(int) |
|
3 [1078671488] DEBUG mrw.fntrace - \ fn(int) |
|
4 [1078671488] DEBUG mrw.fntrace - \ fn(int) |
|
4 [1078671488] DEBUG mrw.fntrace - \ fn(int) |
|
4 [1078671488] DEBUG mrw.fntrace - / fn(int) |
|
4 [1078671488] DEBUG mrw.fntrace - / fn(int) |
|
4 [1078671488] DEBUG mrw.fntrace - / fn(int) |
|
4 [1078671488] DEBUG mrw.fntrace - / fn(int) |
|
4 [1078671488] DEBUG mrw.fntrace - / fn(int) |
|
4 [1078671488] DEBUG mrw.fntrace - 0xbfffef3f: / A::method() |
|
5 [1078671488] DEBUG mrw.fntrace - / main(int, char**) |
|
@endverbatim |
|
|
|
The indentation is according to the call stack depth level, the |
|
name is preceded by a @c \\ on entry and by a @c / on exit. The |
|
methods are preceded by the address of @c this, so that |
|
different instances can be distinguished. All before and |
|
including the dash @c - is configurable through the normal |
|
log4cxx trace patterns. |
|
*/ |
|
//@{ |
|
|
|
/** @brief Declare method entrance, place as first line in method. |
|
|
|
Place this macro as first statement in each method that should |
|
write a function trace. |
|
|
|
Example: |
|
|
|
@code |
|
namespace xxx { |
|
namespace yyy { |
|
class Zzz { |
|
public: void doIt(int, char) { |
|
METHOD("xxx::yyy::Zzz::doIt(int, char)"); |
|
[...] |
|
} |
|
}; |
|
} |
|
} |
|
@endcode |
|
|
|
@param name the full name of the method, including namespaces |
|
and class name |
|
*/ |
|
#define METHOD(name) mrw::FnTrace fnTrace(this, name, __FILE__, __LINE__) |
|
|
|
/** @brief Declare function entrance, place as first line in functions. |
|
|
|
Place this macro as first statement in each function that should |
|
write a function trace. |
|
|
|
Example: |
|
|
|
@code |
|
namespace xxx { |
|
namespace yyy { |
|
void doIt(int, char) { |
|
FUNCTION("xxx::yyy::doIt(int, char)"); |
|
[...] |
|
} |
|
} |
|
} |
|
@endcode |
|
|
|
@param name the full name of the function, including namespaces |
|
*/ |
|
#define FUNCTION(name) mrw::FnTrace fnTrace(name, __FILE__, __LINE__) |
|
|
|
/** @brief Declare method entrance, place as first line in method. |
|
|
|
Place this macro as first statement in each method that should |
|
write a function trace. |
|
|
|
This macro allows you to define a logging hierarchy string. |
|
|
|
Example: |
|
|
|
@code |
|
namespace xxx { |
|
namespace yyy { |
|
class Zzz { |
|
public: void doIt(int, char) { |
|
METHOD2("xxx::yyy::Zzz::doIt(int, char)", "fn.xxx.yyy.Zzz"); |
|
[...] |
|
} |
|
}; |
|
} |
|
} |
|
@endcode |
|
|
|
@param name the full name of the method, including namespaces |
|
and class name |
|
@param tracer the tracer hierarchy |
|
*/ |
|
#define METHOD2(name, tracer) \ |
|
mrw::FnTrace fnTrace(this, name, __FILE__, __LINE__, tracer) |
|
|
|
/** @brief Declare function entrance, place as first line in functions. |
|
|
|
Place this macro as first statement in each function that should |
|
write a function trace. |
|
|
|
This macro allows you to define a logging hierarchy string. |
|
|
|
Example: |
|
|
|
@code |
|
namespace xxx { |
|
namespace yyy { |
|
void doIt(int, char) { |
|
FUNCTION2("xxx::yyy::doIt(int, char)", "fn.xxx.yyy"); |
|
[...] |
|
} |
|
} |
|
} |
|
@endcode |
|
|
|
@param name the full name of the function, including namespaces |
|
@param tracer the tracer hierarchy |
|
*/ |
|
#define FUNCTION2(name, tracer) \ |
|
mrw::FnTrace fnTrace(name, __FILE__, __LINE__, tracer) |
|
|
|
class FnTrace { |
|
public: |
|
FnTrace(const void* addr, const std::string& name, |
|
const std::string& file, unsigned long line, |
|
const std::string& tracer = "mrw.fntrace") throw(): |
|
_addr(addr), _name(name), _file(file), _line(line), _tracer(tracer) { |
|
log4cxx::Logger* logger(log4cxx::Logger::getLogger(_tracer)); |
|
if (logger->isDebugEnabled()) { |
|
std::stringstream oss; |
|
oss<<std::hex<<std::setw(15)<<_addr<<": "<<std::dec |
|
<<std::setw(2+_level)<<std::setfill(' ')<<"\\ "<<_name; |
|
logger->forcedLog(log4cxx::Level::DEBUG, oss.str(), |
|
_file.c_str(), _line); |
|
++_level; |
|
} |
|
} |
|
FnTrace(const std::string& name, |
|
const std::string& file, unsigned long line, |
|
const std::string& tracer = "mrw.fntrace") throw(): |
|
_addr(0), _name(name), _file(file), _line(line), _tracer(tracer) { |
|
log4cxx::Logger* logger(log4cxx::Logger::getLogger(_tracer)); |
|
if (logger->isDebugEnabled()) { |
|
std::stringstream oss; |
|
oss<<std::setw(17)<<' ' |
|
<<std::setw(2+_level)<<std::setfill(' ')<<"\\ "<<_name; |
|
logger->forcedLog(log4cxx::Level::DEBUG, oss.str(), |
|
_file.c_str(), _line); |
|
++_level; |
|
} |
|
} |
|
~FnTrace() throw() { |
|
log4cxx::Logger* logger(log4cxx::Logger::getLogger(_tracer)); |
|
if (logger->isDebugEnabled()) { |
|
--_level; |
|
std::stringstream oss; |
|
if (_addr) |
|
oss<<std::hex<<std::setw(15)<<_addr<<": "<<std::dec; |
|
else |
|
oss<<std::setw(17)<<' '; |
|
oss<<std::setw(2+_level)<<std::setfill(' ')<<"/ "<<_name; |
|
logger->forcedLog(log4cxx::Level::DEBUG, oss.str(), |
|
_file.c_str(), _line); |
|
} |
|
} |
|
private: |
|
const void* _addr; |
|
const std::string _name; |
|
const std::string _file; |
|
unsigned long _line; |
|
const std::string _tracer; |
|
/** @todo for multithreading, use thread specific storage */ |
|
static unsigned int _level; |
|
}; |
|
//@} |
|
//@} |
|
} |
|
#endif
|
|
|