2005-03-11 21:07:55 +00:00
|
|
|
/** @file
|
|
|
|
|
|
|
|
$Id$
|
|
|
|
|
|
|
|
$Date$
|
|
|
|
$Author$
|
|
|
|
|
|
|
|
@copy © Marc Wäckerlin
|
|
|
|
@license LGPL, see file <a href="license.html">COPYING</a>
|
|
|
|
|
|
|
|
$Log$
|
2005-11-29 12:42:01 +00:00
|
|
|
Revision 1.3 2005/11/29 12:39:42 marc
|
|
|
|
make it compilable with gcc 4.0.2 and newer doxygen
|
|
|
|
|
2005-04-07 20:51:30 +00:00
|
|
|
Revision 1.2 2005/04/07 20:50:13 marc
|
|
|
|
docu: new doxygen, new grouping
|
|
|
|
|
2005-03-11 21:07:55 +00:00
|
|
|
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>
|
|
|
|
|
2005-11-29 12:42:01 +00:00
|
|
|
// support for log4cxx 0.9.7 and for new CVS version
|
|
|
|
#ifndef LOG4CXX_LOCATION
|
|
|
|
# define MRW_LOG4CXX_LOCATION _file.c_str(), _line
|
2007-08-05 08:20:01 +00:00
|
|
|
#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
|
2005-11-29 12:42:01 +00:00
|
|
|
#else
|
|
|
|
# define LOG4CXX_CVS
|
|
|
|
# define MRW_LOG4CXX_LOCATION \
|
2007-08-05 08:20:01 +00:00
|
|
|
::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()
|
2005-11-29 12:42:01 +00:00
|
|
|
#endif
|
|
|
|
|
2005-03-11 21:07:55 +00:00
|
|
|
namespace mrw {
|
|
|
|
|
2005-04-07 20:51:30 +00:00
|
|
|
/** @addtogroup debug */
|
|
|
|
//@{
|
|
|
|
|
2005-03-11 21:07:55 +00:00
|
|
|
/** @defgroup FunctionTrace Function Tracing (using log4cxx)
|
2005-11-29 12:42:01 +00:00
|
|
|
@pre \#include <mrw/functiontrace.hpp>
|
2005-03-11 21:07:55 +00:00
|
|
|
|
2007-08-05 08:20:01 +00:00
|
|
|
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
|
2005-03-11 21:07:55 +00:00
|
|
|
traced.
|
|
|
|
|
2007-08-05 08:20:01 +00:00
|
|
|
There are alternative macros @ref MRW_METHOD2 and @ref MRW_FUNCTION2,
|
2005-03-11 21:07:55 +00:00
|
|
|
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
|
2005-11-29 12:42:01 +00:00
|
|
|
\#include <mrw/functiontrace.hpp>
|
|
|
|
\#include <log4cxx/basicconfigurator.h>
|
2005-03-11 21:07:55 +00:00
|
|
|
void fn(int i=0) {
|
2007-08-05 08:20:01 +00:00
|
|
|
MRW_FUNCTION("fn(int)"); // trace entry and exit
|
2005-03-11 21:07:55 +00:00
|
|
|
if (i<4) fn(++i);
|
|
|
|
}
|
|
|
|
class A {
|
|
|
|
public:
|
|
|
|
A() { // not traced
|
|
|
|
method();
|
|
|
|
}
|
|
|
|
void method() {
|
2007-08-05 08:20:01 +00:00
|
|
|
MRW_METHOD("A::method()"); // trace entry and exit
|
2005-03-11 21:07:55 +00:00
|
|
|
fn();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
int main(int, char**) {
|
|
|
|
log4cxx::BasicConfigurator::configure();
|
2007-08-05 08:20:01 +00:00
|
|
|
MRW_FUNCTION("main(int, char**)");
|
2005-03-11 21:07:55 +00:00
|
|
|
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) {
|
2007-08-05 08:20:01 +00:00
|
|
|
MRW_METHOD("xxx::yyy::Zzz::doIt(int, char)");
|
2005-03-11 21:07:55 +00:00
|
|
|
[...]
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
@param name the full name of the method, including namespaces
|
|
|
|
and class name
|
|
|
|
*/
|
2007-08-05 08:20:01 +00:00
|
|
|
#define MRW_METHOD(name) mrw::FnTrace fnTrace(this, name, __FILE__, __LINE__)
|
2005-03-11 21:07:55 +00:00
|
|
|
|
|
|
|
/** @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) {
|
2007-08-05 08:20:01 +00:00
|
|
|
MRW_FUNCTION("xxx::yyy::doIt(int, char)");
|
2005-03-11 21:07:55 +00:00
|
|
|
[...]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
@param name the full name of the function, including namespaces
|
|
|
|
*/
|
2007-08-05 08:20:01 +00:00
|
|
|
#define MRW_FUNCTION(name) mrw::FnTrace fnTrace(name, __FILE__, __LINE__)
|
2005-03-11 21:07:55 +00:00
|
|
|
|
|
|
|
/** @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) {
|
2007-08-05 08:20:01 +00:00
|
|
|
MRW_METHOD2("xxx::yyy::Zzz::doIt(int, char)", "fn.xxx.yyy.Zzz");
|
2005-03-11 21:07:55 +00:00
|
|
|
[...]
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
@param name the full name of the method, including namespaces
|
|
|
|
and class name
|
|
|
|
@param tracer the tracer hierarchy
|
|
|
|
*/
|
2007-08-05 08:20:01 +00:00
|
|
|
#define MRW_METHOD2(name, tracer) \
|
2005-03-11 21:07:55 +00:00
|
|
|
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) {
|
2007-08-05 08:20:01 +00:00
|
|
|
MRW_FUNCTION2("xxx::yyy::doIt(int, char)", "fn.xxx.yyy");
|
2005-03-11 21:07:55 +00:00
|
|
|
[...]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
@param name the full name of the function, including namespaces
|
|
|
|
@param tracer the tracer hierarchy
|
|
|
|
*/
|
2007-08-05 08:20:01 +00:00
|
|
|
#define MRW_FUNCTION2(name, tracer) \
|
2005-03-11 21:07:55 +00:00
|
|
|
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():
|
2007-08-05 08:20:01 +00:00
|
|
|
_addr(addr), _name(name.begin(), name.end()), _file(file), _line(line),
|
|
|
|
_tracer(tracer.begin(), tracer.end()) {
|
2005-03-11 21:07:55 +00:00
|
|
|
log4cxx::Logger* logger(log4cxx::Logger::getLogger(_tracer));
|
|
|
|
if (logger->isDebugEnabled()) {
|
2007-08-05 08:20:01 +00:00
|
|
|
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(),
|
2005-11-29 12:42:01 +00:00
|
|
|
MRW_LOG4CXX_LOCATION);
|
2005-03-11 21:07:55 +00:00
|
|
|
++_level;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FnTrace(const std::string& name,
|
|
|
|
const std::string& file, unsigned long line,
|
|
|
|
const std::string& tracer = "mrw.fntrace") throw():
|
2007-08-05 08:20:01 +00:00
|
|
|
_addr(0), _name(name.begin(), name.end()), _file(file), _line(line),
|
|
|
|
_tracer(tracer.begin(), tracer.end()) {
|
2005-03-11 21:07:55 +00:00
|
|
|
log4cxx::Logger* logger(log4cxx::Logger::getLogger(_tracer));
|
|
|
|
if (logger->isDebugEnabled()) {
|
2007-08-05 08:20:01 +00:00
|
|
|
std::basic_stringstream<log4cxx::String::value_type> oss;
|
2005-03-11 21:07:55 +00:00
|
|
|
oss<<std::setw(17)<<' '
|
2007-08-05 08:20:01 +00:00
|
|
|
<<std::setw(2+_level)<<std::setfill(log4cxx::String::value_type(' '))
|
|
|
|
<<"\\ "<<_name;
|
|
|
|
logger->forcedLog(MRW_LEVEL_DEBUG, oss.str(),
|
2005-11-29 12:42:01 +00:00
|
|
|
MRW_LOG4CXX_LOCATION);
|
2005-03-11 21:07:55 +00:00
|
|
|
++_level;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
~FnTrace() throw() {
|
|
|
|
log4cxx::Logger* logger(log4cxx::Logger::getLogger(_tracer));
|
|
|
|
if (logger->isDebugEnabled()) {
|
|
|
|
--_level;
|
2007-08-05 08:20:01 +00:00
|
|
|
std::basic_stringstream<log4cxx::String::value_type> oss;
|
2005-03-11 21:07:55 +00:00
|
|
|
if (_addr)
|
|
|
|
oss<<std::hex<<std::setw(15)<<_addr<<": "<<std::dec;
|
|
|
|
else
|
|
|
|
oss<<std::setw(17)<<' ';
|
2007-08-05 08:20:01 +00:00
|
|
|
oss<<std::setw(2+_level)<<std::setfill(log4cxx::String::value_type(' '))
|
|
|
|
<<"/ "<<_name;
|
|
|
|
logger->forcedLog(MRW_LEVEL_DEBUG, oss.str(),
|
2005-11-29 12:42:01 +00:00
|
|
|
MRW_LOG4CXX_LOCATION);
|
2005-03-11 21:07:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
const void* _addr;
|
2007-08-05 08:20:01 +00:00
|
|
|
const log4cxx::String _name;
|
2005-03-11 21:07:55 +00:00
|
|
|
const std::string _file;
|
|
|
|
unsigned long _line;
|
2007-08-05 08:20:01 +00:00
|
|
|
const log4cxx::String _tracer;
|
2005-03-11 21:07:55 +00:00
|
|
|
/** @todo for multithreading, use thread specific storage */
|
|
|
|
static unsigned int _level;
|
|
|
|
};
|
|
|
|
//@}
|
2005-04-07 20:51:30 +00:00
|
|
|
//@}
|
2005-03-11 21:07:55 +00:00
|
|
|
}
|
|
|
|
#endif
|