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.

309 lines
10 KiB

20 years ago
/** @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
20 years ago
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
20 years ago
namespace mrw {
/** @addtogroup debug */
//@{
20 years ago
/** @defgroup FunctionTrace Function Tracing (using log4cxx)
@pre \#include <mrw/functiontrace.hpp>
20 years ago
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
20 years ago
traced.
There are alternative macros @ref MRW_METHOD2 and @ref MRW_FUNCTION2,
20 years ago
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>
20 years ago
void fn(int i=0) {
MRW_FUNCTION("fn(int)"); // trace entry and exit
20 years ago
if (i<4) fn(++i);
}
class A {
public:
A() { // not traced
method();
}
void method() {
MRW_METHOD("A::method()"); // trace entry and exit
20 years ago
fn();
}
};
int main(int, char**) {
log4cxx::BasicConfigurator::configure();
MRW_FUNCTION("main(int, char**)");
20 years ago
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)");
20 years ago
[...]
}
};
}
}
@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__)
20 years ago
/** @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)");
20 years ago
[...]
}
}
}
@endcode
@param name the full name of the function, including namespaces
*/
#define MRW_FUNCTION(name) mrw::FnTrace fnTrace(name, __FILE__, __LINE__)
20 years ago
/** @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");
20 years ago
[...]
}
};
}
}
@endcode
@param name the full name of the method, including namespaces
and class name
@param tracer the tracer hierarchy
*/
#define MRW_METHOD2(name, tracer) \
20 years ago
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");
20 years ago
[...]
}
}
}
@endcode
@param name the full name of the function, including namespaces
@param tracer the tracer hierarchy
*/
#define MRW_FUNCTION2(name, tracer) \
20 years ago
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()) {
20 years ago
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);
20 years ago
++_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()) {
20 years ago
log4cxx::Logger* logger(log4cxx::Logger::getLogger(_tracer));
if (logger->isDebugEnabled()) {
std::basic_stringstream<log4cxx::String::value_type> oss;
20 years ago
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);
20 years ago
++_level;
}
}
~FnTrace() throw() {
log4cxx::Logger* logger(log4cxx::Logger::getLogger(_tracer));
if (logger->isDebugEnabled()) {
--_level;
std::basic_stringstream<log4cxx::String::value_type> oss;
20 years ago
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);
20 years ago
}
}
private:
const void* _addr;
const log4cxx::String _name;
20 years ago
const std::string _file;
unsigned long _line;
const log4cxx::String _tracer;
20 years ago
/** @todo for multithreading, use thread specific storage */
static unsigned int _level;
};
//@}
//@}
20 years ago
}
#endif