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.

282 lines
9.2 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.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>
namespace mrw {
/** @addtogroup debug */
//@{
20 years ago
/** @defgroup FunctionTrace Function Tracing (using log4cxx)
@pre #include <mrw/functiontrace.hpp>
Place the macro @ref METHOD as first line of all methods you want to
trace, and macro @ref FUNCTION as first line of all functions to be
traced.
There are alternative macros @ref METHOD2 and @ref 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) {
FUNCTION("fn(int)"); // trace entry and exit
if (i<4) fn(++i);
}
class A {
public:
A() { // not traced
method();
}
void method() {
METHOD("A::method()"); // trace entry and exit
fn();
}
};
int main(int, char**) {
log4cxx::BasicConfigurator::configure();
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) {
METHOD("xxx::yyy::Zzz::doIt(int, char)");
[...]
}
};
}
}
@endcode
@param name the full name of the method, including namespaces
and class name
*/
#define 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) {
FUNCTION("xxx::yyy::doIt(int, char)");
[...]
}
}
}
@endcode
@param name the full name of the function, including namespaces
*/
#define 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) {
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 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) {
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 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), _file(file), _line(line), _tracer(tracer) {
log4cxx::Logger* logger(log4cxx::Logger::getLogger(_tracer));
if (logger->isDebugEnabled()) {
std::stringstream oss;
oss<<std::hex<<std::setw(15)<<_addr<<": "<<std::dec
<<std::setw(2+_level)<<std::setfill(' ')<<"\\ "<<_name;
logger->forcedLog(log4cxx::Level::DEBUG, oss.str(),
_file.c_str(), _line);
++_level;
}
}
FnTrace(const std::string& name,
const std::string& file, unsigned long line,
const std::string& tracer = "mrw.fntrace") throw():
_addr(0), _name(name), _file(file), _line(line), _tracer(tracer) {
log4cxx::Logger* logger(log4cxx::Logger::getLogger(_tracer));
if (logger->isDebugEnabled()) {
std::stringstream oss;
oss<<std::setw(17)<<' '
<<std::setw(2+_level)<<std::setfill(' ')<<"\\ "<<_name;
logger->forcedLog(log4cxx::Level::DEBUG, oss.str(),
_file.c_str(), _line);
++_level;
}
}
~FnTrace() throw() {
log4cxx::Logger* logger(log4cxx::Logger::getLogger(_tracer));
if (logger->isDebugEnabled()) {
--_level;
std::stringstream oss;
if (_addr)
oss<<std::hex<<std::setw(15)<<_addr<<": "<<std::dec;
else
oss<<std::setw(17)<<' ';
oss<<std::setw(2+_level)<<std::setfill(' ')<<"/ "<<_name;
logger->forcedLog(log4cxx::Level::DEBUG, oss.str(),
_file.c_str(), _line);
}
}
private:
const void* _addr;
const std::string _name;
const std::string _file;
unsigned long _line;
const std::string _tracer;
/** @todo for multithreading, use thread specific storage */
static unsigned int _level;
};
//@}
//@}
20 years ago
}
#endif