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

/** @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