middle of porting; unstable, don't checkout; refs #1
This commit is contained in:
308
src/mrw/functiontrace.hpp
Normal file
308
src/mrw/functiontrace.hpp
Normal file
@@ -0,0 +1,308 @@
|
||||
/** @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
|
Reference in New Issue
Block a user