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.
308 lines
10 KiB
308 lines
10 KiB
/** @file |
|
|
|
$Id$ |
|
|
|
$Date$ |
|
$Author$ |
|
|
|
@copy © Marc Wäckerlin |
|
@license LGPL, see file <a href="license.html">COPYING</a> |
|
|
|
$Log$ |
|
Revision 1.3 2005/11/29 12:39:42 marc |
|
make it compilable with gcc 4.0.2 and newer doxygen |
|
|
|
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> |
|
|
|
// support for log4cxx 0.9.7 and for new CVS version |
|
#ifndef LOG4CXX_LOCATION |
|
# define MRW_LOG4CXX_LOCATION _file.c_str(), _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.c_str(), _name.c_str(), _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 debug */ |
|
//@{ |
|
|
|
/** @defgroup FunctionTrace Function Tracing (using log4cxx) |
|
@pre \#include <mrw/functiontrace.hpp> |
|
|
|
Place the macro @ref MRW_METHOD as first line of all methods you want to |
|
trace, and macro @ref MRW_FUNCTION as first line of all functions to be |
|
traced. |
|
|
|
There are alternative macros @ref MRW_METHOD2 and @ref MRW_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) { |
|
MRW_FUNCTION("fn(int)"); // trace entry and exit |
|
if (i<4) fn(++i); |
|
} |
|
class A { |
|
public: |
|
A() { // not traced |
|
method(); |
|
} |
|
void method() { |
|
MRW_METHOD("A::method()"); // trace entry and exit |
|
fn(); |
|
} |
|
}; |
|
int main(int, char**) { |
|
log4cxx::BasicConfigurator::configure(); |
|
MRW_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) { |
|
MRW_METHOD("xxx::yyy::Zzz::doIt(int, char)"); |
|
[...] |
|
} |
|
}; |
|
} |
|
} |
|
@endcode |
|
|
|
@param name the full name of the method, including namespaces |
|
and class name |
|
*/ |
|
#define MRW_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) { |
|
MRW_FUNCTION("xxx::yyy::doIt(int, char)"); |
|
[...] |
|
} |
|
} |
|
} |
|
@endcode |
|
|
|
@param name the full name of the function, including namespaces |
|
*/ |
|
#define MRW_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) { |
|
MRW_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 MRW_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) { |
|
MRW_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 MRW_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.begin(), name.end()), _file(file), _line(line), |
|
_tracer(tracer.begin(), tracer.end()) { |
|
log4cxx::Logger* logger(log4cxx::Logger::getLogger(_tracer)); |
|
if (logger->isDebugEnabled()) { |
|
std::basic_stringstream<log4cxx::String::value_type> oss; |
|
oss<<std::hex<<std::setw(15)<<_addr<<": " |
|
<<std::dec<<std::setw(2+_level) |
|
<<std::setfill(log4cxx::String::value_type(' '))<<"\\ "<<_name; |
|
logger->forcedLog(MRW_LEVEL_DEBUG, oss.str(), |
|
MRW_LOG4CXX_LOCATION); |
|
++_level; |
|
} |
|
} |
|
FnTrace(const std::string& name, |
|
const std::string& file, unsigned long line, |
|
const std::string& tracer = "mrw.fntrace") throw(): |
|
_addr(0), _name(name.begin(), name.end()), _file(file), _line(line), |
|
_tracer(tracer.begin(), tracer.end()) { |
|
log4cxx::Logger* logger(log4cxx::Logger::getLogger(_tracer)); |
|
if (logger->isDebugEnabled()) { |
|
std::basic_stringstream<log4cxx::String::value_type> oss; |
|
oss<<std::setw(17)<<' ' |
|
<<std::setw(2+_level)<<std::setfill(log4cxx::String::value_type(' ')) |
|
<<"\\ "<<_name; |
|
logger->forcedLog(MRW_LEVEL_DEBUG, oss.str(), |
|
MRW_LOG4CXX_LOCATION); |
|
++_level; |
|
} |
|
} |
|
~FnTrace() throw() { |
|
log4cxx::Logger* logger(log4cxx::Logger::getLogger(_tracer)); |
|
if (logger->isDebugEnabled()) { |
|
--_level; |
|
std::basic_stringstream<log4cxx::String::value_type> oss; |
|
if (_addr) |
|
oss<<std::hex<<std::setw(15)<<_addr<<": "<<std::dec; |
|
else |
|
oss<<std::setw(17)<<' '; |
|
oss<<std::setw(2+_level)<<std::setfill(log4cxx::String::value_type(' ')) |
|
<<"/ "<<_name; |
|
logger->forcedLog(MRW_LEVEL_DEBUG, oss.str(), |
|
MRW_LOG4CXX_LOCATION); |
|
} |
|
} |
|
private: |
|
const void* _addr; |
|
const log4cxx::String _name; |
|
const std::string _file; |
|
unsigned long _line; |
|
const log4cxx::String _tracer; |
|
/** @todo for multithreading, use thread specific storage */ |
|
static unsigned int _level; |
|
}; |
|
//@} |
|
//@} |
|
} |
|
#endif
|
|
|