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.
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
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
|
|
|