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.
275 lines
9.1 KiB
275 lines
9.1 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.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 {
|
||
|
|
||
|
/** @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;
|
||
|
};
|
||
|
//@}
|
||
|
}
|
||
|
#endif
|