initial version
This commit is contained in:
		
							
								
								
									
										239
									
								
								mrw/autofunctiontracelog4cxx.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								mrw/autofunctiontracelog4cxx.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,239 @@
 | 
				
			|||||||
 | 
					/** @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 __GNUG__
 | 
				
			||||||
 | 
					#error GNU C++ Compiler is required for automatical function trace
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <mrw/string.hpp>
 | 
				
			||||||
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					#include <iomanip>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <mrw/stacktrace.hpp>
 | 
				
			||||||
 | 
					#include <log4cxx/logger.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// these are special built in functions of GNU Compiler Collection
 | 
				
			||||||
 | 
					extern "C" void __cyg_profile_func_enter (void *, void *) __attribute__((no_instrument_function));
 | 
				
			||||||
 | 
					extern "C" void __cyg_profile_func_exit (void *, void *) __attribute__((no_instrument_function));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace mrw {
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  struct ThreadInfo {
 | 
				
			||||||
 | 
					      int level;
 | 
				
			||||||
 | 
					      bool recurse;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _REENTRANT
 | 
				
			||||||
 | 
					  static __thread ThreadInfo info = {0, false};
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					  static ThreadInfo info = {0, false};
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static bool mainPassed(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  class Lock {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					      Lock() __attribute__((no_instrument_function));
 | 
				
			||||||
 | 
					      ~Lock() __attribute__((no_instrument_function));
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  Lock::Lock() {
 | 
				
			||||||
 | 
					    info.recurse = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  Lock::~Lock() {
 | 
				
			||||||
 | 
					    info.recurse = false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" int main(int, char**);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @addtogroup FunctionTrace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @note There is also a fully automagic function trace, similar to
 | 
				
			||||||
 | 
					          @ref AutoTrace. It is described in @ref AutoFunctionTrace
 | 
				
			||||||
 | 
					          and requires the GNU Compiler Collection gcc, because it
 | 
				
			||||||
 | 
					          makes use of a proprietary compiler feature. */
 | 
				
			||||||
 | 
					//@{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @defgroup AutoFunctionTrace Automatic Function Trace for GNU g++
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    If you compile your program with GNU g++ / gcc, and you want
 | 
				
			||||||
 | 
					    to add function tracing without changing a single line of your
 | 
				
			||||||
 | 
					    code, here's the solution:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    If you link to the library @c libmrwautofunctiontracelog4cxx using
 | 
				
			||||||
 | 
					    a linker option such as: @c -lmrwautofunctiontracelog4cxx and you
 | 
				
			||||||
 | 
					    must enable the GNU Compiler Collection specific function trace
 | 
				
			||||||
 | 
					    feature with compile and link option @c -finstrument-functions
 | 
				
			||||||
 | 
					    then you get an automatical function trace, that traces to level
 | 
				
			||||||
 | 
					    @c DEBUG using the log4cxx library. You don't need to change a single
 | 
				
			||||||
 | 
					    line in your code!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This feature depends on:
 | 
				
			||||||
 | 
					     - the GNU C++ compiler gcc
 | 
				
			||||||
 | 
					     - @ref mrw::StackTrace
 | 
				
			||||||
 | 
					     - log4cxx http://logging.apache.org/log4cxx
 | 
				
			||||||
 | 
					     - optional: boost for thread support http://boost.org
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    The logger hiararchy name is: @c
 | 
				
			||||||
 | 
					    "mrw.gccfunctiontrace.<full-method-name>" where @c
 | 
				
			||||||
 | 
					    <full-method-name> is the full name of the method, including
 | 
				
			||||||
 | 
					    namespace and class name, seperated not by double colon @c :: but
 | 
				
			||||||
 | 
					    by single dots @c . as it is common use in log4cxx. This way, you
 | 
				
			||||||
 | 
					    can enable or disable the function trace per namespace, per class
 | 
				
			||||||
 | 
					    or even per method.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    The function trace does not start, before the program @c main is
 | 
				
			||||||
 | 
					    reached! Only the calls within the @c main are traced, but not during
 | 
				
			||||||
 | 
					    the initialisation and destruction of static members. This is
 | 
				
			||||||
 | 
					    necessary, because otherwise access the incompletely initialized
 | 
				
			||||||
 | 
					    MRW-C++ library itself may cause a crash.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    I use the following log4cxx @c log4cxx::PropertyConfigurator
 | 
				
			||||||
 | 
					    configuration in the test program to enable all function traces,
 | 
				
			||||||
 | 
					    except from some third party and standard libraries:
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    @verbatim
 | 
				
			||||||
 | 
					log4j.rootLogger                            = OFF, A1
 | 
				
			||||||
 | 
					log4j.logger.mrw.gccfunctiontrace           = DEBUG
 | 
				
			||||||
 | 
					log4j.logger.mrw.gccfunctiontrace.log4cxx   = OFF
 | 
				
			||||||
 | 
					log4j.logger.mrw.gccfunctiontrace.boost     = OFF
 | 
				
			||||||
 | 
					log4j.logger.mrw.gccfunctiontrace.Thread    = OFF
 | 
				
			||||||
 | 
					log4j.logger.mrw.gccfunctiontrace.mrw       = OFF
 | 
				
			||||||
 | 
					log4j.logger.mrw.gccfunctiontrace.std       = OFF
 | 
				
			||||||
 | 
					log4j.logger.mrw.gccfunctiontrace.new       = OFF
 | 
				
			||||||
 | 
					log4j.logger.mrw.gccfunctiontrace.CppUnit   = OFF
 | 
				
			||||||
 | 
					log4j.logger.mrw.gccfunctiontrace.__gnu_cxx = OFF
 | 
				
			||||||
 | 
					log4j.appender.A1                           = org.apache.log4j.FileAppender
 | 
				
			||||||
 | 
					log4j.appender.A1.layout                    = org.apache.log4j.PatternLayout
 | 
				
			||||||
 | 
					log4j.appender.A1.layout.ConversionPattern  = %t-%-41c%m%n
 | 
				
			||||||
 | 
					log4j.appender.A1.filename                  = filename.log
 | 
				
			||||||
 | 
					    @endverbatim
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Depending on your log4cxx configuration, a function trace may look
 | 
				
			||||||
 | 
					    e.g. like this (very simple configuration with very few additional
 | 
				
			||||||
 | 
					    information):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @verbatim
 | 
				
			||||||
 | 
					mrw.gccfunctiontrace.anotherFunction        \ anotherFunction()
 | 
				
			||||||
 | 
					mrw.gccfunctiontrace.HalloWelt.fn1           \ HalloWelt::fn1()
 | 
				
			||||||
 | 
					mrw.gccfunctiontrace.HalloWelt.fn             \ HalloWelt::fn()
 | 
				
			||||||
 | 
					mrw.gccfunctiontrace.HalloWelt.A.method        \ HalloWelt::A::method()
 | 
				
			||||||
 | 
					mrw.gccfunctiontrace.HalloWelt.A.method        / HalloWelt::A::method()
 | 
				
			||||||
 | 
					mrw.gccfunctiontrace.HalloWelt.A.method        \ HalloWelt::A::method()
 | 
				
			||||||
 | 
					mrw.gccfunctiontrace.HalloWelt.A.method        / HalloWelt::A::method()
 | 
				
			||||||
 | 
					mrw.gccfunctiontrace.HalloWelt.fn             / HalloWelt::fn()
 | 
				
			||||||
 | 
					mrw.gccfunctiontrace.HalloWelt.fn             \ HalloWelt::fn()
 | 
				
			||||||
 | 
					mrw.gccfunctiontrace.HalloWelt.A.method        \ HalloWelt::A::method()
 | 
				
			||||||
 | 
					mrw.gccfunctiontrace.HalloWelt.A.method        / HalloWelt::A::method()
 | 
				
			||||||
 | 
					mrw.gccfunctiontrace.HalloWelt.A.method        \ HalloWelt::A::method()
 | 
				
			||||||
 | 
					mrw.gccfunctiontrace.HalloWelt.A.method        / HalloWelt::A::method()
 | 
				
			||||||
 | 
					mrw.gccfunctiontrace.HalloWelt.fn             / HalloWelt::fn()
 | 
				
			||||||
 | 
					mrw.gccfunctiontrace.HalloWelt.fn1           / HalloWelt::fn1()
 | 
				
			||||||
 | 
					mrw.gccfunctiontrace.anotherFunction        / anotherFunction()
 | 
				
			||||||
 | 
					    @endverbatim
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @note The configurator is not installed automatically. If you
 | 
				
			||||||
 | 
					          want to trace e.g. on the console, you have to call @c
 | 
				
			||||||
 | 
					          log4cxx::BasicConfigurator::configure(); as first statement
 | 
				
			||||||
 | 
					          in your @c main().
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @section AutoFunctionTraceThread Multithreading
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Multithreading is also supported, then you need to link to the
 | 
				
			||||||
 | 
					    thread safe compilat of the library @c
 | 
				
			||||||
 | 
					    libmrwautofunctiontracelog4cxx-mt with option @c
 | 
				
			||||||
 | 
					    -libmrwautofunctiontracelog4cxx-mt and you need the option @c
 | 
				
			||||||
 | 
					    -pthread in addition to @c -finstrument-functions which is still
 | 
				
			||||||
 | 
					    required.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Thread support requires the boost thread library. See
 | 
				
			||||||
 | 
					    http://boost.org for details.
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					//@{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" void __cyg_profile_func_enter(void *this_fn, void*) {
 | 
				
			||||||
 | 
					  if (!mrw::mainPassed)
 | 
				
			||||||
 | 
					    if (this_fn == (void*)&::main) // not ANSI C++ conform...
 | 
				
			||||||
 | 
					      mrw::mainPassed=true;
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    if (mrw::info.recurse) return;
 | 
				
			||||||
 | 
					    mrw::Lock lock;
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      static bool init(mrw::StackTrace::createSymtable());
 | 
				
			||||||
 | 
					      if (!init) return;
 | 
				
			||||||
 | 
					      mrw::StackTrace::CodePos pos(mrw::StackTrace::translate(this_fn));
 | 
				
			||||||
 | 
					      std::string hierarchy(pos.function);
 | 
				
			||||||
 | 
					      for (std::string::size_type p(0);
 | 
				
			||||||
 | 
					           (p=hierarchy.find("::", p))!=std::string::npos;
 | 
				
			||||||
 | 
					           hierarchy.replace(p, 2, "."));
 | 
				
			||||||
 | 
					      hierarchy.erase(hierarchy.rfind('('));
 | 
				
			||||||
 | 
					      std::string::size_type p(hierarchy.rfind(' ', hierarchy.find('<')));
 | 
				
			||||||
 | 
					      if (p!=std::string::npos) hierarchy.erase(0, p+1);
 | 
				
			||||||
 | 
					      log4cxx::Logger* logger
 | 
				
			||||||
 | 
					        (log4cxx::Logger::getLogger(_T("mrw.gccfunctiontrace.")+hierarchy));
 | 
				
			||||||
 | 
					      if (logger->isDebugEnabled()) {
 | 
				
			||||||
 | 
					        std::stringstream ss;
 | 
				
			||||||
 | 
					        ss<<std::setw(2+mrw::info.level++)<<std::setfill(' ')
 | 
				
			||||||
 | 
					          <<"\\ "<<pos.function;
 | 
				
			||||||
 | 
					        logger->forcedLog(::log4cxx::Level::DEBUG, ss.str(),
 | 
				
			||||||
 | 
					                          pos.file.c_str(), pos.line);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  } catch (...) {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" void __cyg_profile_func_exit(void *this_fn, void*) {
 | 
				
			||||||
 | 
					  if (!mrw::mainPassed)
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    if (this_fn == (void*)&::main) { // not ANSI C++ conform...
 | 
				
			||||||
 | 
					      mrw::mainPassed=false;
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    if (mrw::info.recurse || mrw::info.level==0) return;
 | 
				
			||||||
 | 
					    mrw::Lock lock;
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      mrw::StackTrace::CodePos pos(mrw::StackTrace::translate(this_fn));
 | 
				
			||||||
 | 
					      std::string hierarchy(pos.function);
 | 
				
			||||||
 | 
					      for (std::string::size_type p(0);
 | 
				
			||||||
 | 
					           (p=hierarchy.find("::", p))!=std::string::npos;
 | 
				
			||||||
 | 
					           hierarchy.replace(p, 2, "."));
 | 
				
			||||||
 | 
					      hierarchy.erase(hierarchy.find('('));
 | 
				
			||||||
 | 
					      std::string::size_type p(hierarchy.rfind(' ', hierarchy.find('<')));
 | 
				
			||||||
 | 
					      if (p!=std::string::npos) hierarchy.erase(0, p+1);
 | 
				
			||||||
 | 
					      log4cxx::Logger* logger
 | 
				
			||||||
 | 
					        (log4cxx::Logger::getLogger(_T("mrw.gccfunctiontrace.")+hierarchy));
 | 
				
			||||||
 | 
					      if (logger->isDebugEnabled()) {
 | 
				
			||||||
 | 
					        std::stringstream ss;
 | 
				
			||||||
 | 
					        ss<<std::setw(2+--mrw::info.level)<<std::setfill(' ')
 | 
				
			||||||
 | 
					          <<"/ "<<pos.function;
 | 
				
			||||||
 | 
					        logger->forcedLog(::log4cxx::Level::DEBUG, ss.str(),
 | 
				
			||||||
 | 
					                          pos.file.c_str(), pos.line);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  } catch (...) {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//@}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//@}
 | 
				
			||||||
							
								
								
									
										22
									
								
								mrw/functiontrace.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								mrw/functiontrace.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					/** @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
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <mrw/functiontrace.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsigned int mrw::FnTrace::_level(0);
 | 
				
			||||||
							
								
								
									
										274
									
								
								mrw/functiontrace.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										274
									
								
								mrw/functiontrace.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,274 @@
 | 
				
			|||||||
 | 
					/** @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
 | 
				
			||||||
							
								
								
									
										116
									
								
								mrw/functiontrace_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								mrw/functiontrace_test.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,116 @@
 | 
				
			|||||||
 | 
					/** @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:55  marc
 | 
				
			||||||
 | 
					    initial version
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         1         2         3         4         5         6         7         8
 | 
				
			||||||
 | 
					    5678901234567890123456789012345678901234567890123456789012345678901234567890
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <mrw/functiontrace.hpp>
 | 
				
			||||||
 | 
					#include <mrw/regexp.hpp>
 | 
				
			||||||
 | 
					#include <mrw/file.hpp>
 | 
				
			||||||
 | 
					#include <log4cxx/propertyconfigurator.h>
 | 
				
			||||||
 | 
					#include <log4cxx/helpers/properties.h>
 | 
				
			||||||
 | 
					#include <cppunit/TestFixture.h>
 | 
				
			||||||
 | 
					#include <cppunit/ui/text/TestRunner.h>
 | 
				
			||||||
 | 
					#include <cppunit/extensions/HelperMacros.h>
 | 
				
			||||||
 | 
					#include <cppunit/extensions/TestFactoryRegistry.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class A {
 | 
				
			||||||
 | 
					  public:
 | 
				
			||||||
 | 
					    A() {
 | 
				
			||||||
 | 
					      METHOD("A::A()");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ~A() {
 | 
				
			||||||
 | 
					      METHOD("A::~A()");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    void fn1() {
 | 
				
			||||||
 | 
					      METHOD("A::fn1()");
 | 
				
			||||||
 | 
					      fn2();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    void fn2() {
 | 
				
			||||||
 | 
					      METHOD("A::fn2()");
 | 
				
			||||||
 | 
					      fn3();
 | 
				
			||||||
 | 
					      fn4();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    void fn3() {
 | 
				
			||||||
 | 
					      METHOD("A::fn3()");
 | 
				
			||||||
 | 
					      fn4();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    void fn4(bool flag=true) {
 | 
				
			||||||
 | 
					      METHOD("A::fn4()");
 | 
				
			||||||
 | 
					      if (flag) fn4(false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void fn(A a) {
 | 
				
			||||||
 | 
					  FUNCTION("fn(A)");
 | 
				
			||||||
 | 
					  a.fn1();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FunctionTraceTest: public CppUnit::TestFixture { 
 | 
				
			||||||
 | 
					  public:
 | 
				
			||||||
 | 
					    void Init() {
 | 
				
			||||||
 | 
					      try {mrw::File::remove("functiontrace_test.log");} catch (...) {}
 | 
				
			||||||
 | 
					      log4cxx::helpers::Properties properties;
 | 
				
			||||||
 | 
					      properties.setProperty("log4j.rootLogger",
 | 
				
			||||||
 | 
					                             "DEBUG, A1");
 | 
				
			||||||
 | 
					      properties.setProperty("log4j.appender.A1",
 | 
				
			||||||
 | 
					                             "org.apache.log4j.FileAppender");
 | 
				
			||||||
 | 
					      properties.setProperty("log4j.appender.A1.layout",
 | 
				
			||||||
 | 
					                             "org.apache.log4j.PatternLayout");
 | 
				
			||||||
 | 
					      properties.setProperty("log4j.appender.A1.layout.ConversionPattern",
 | 
				
			||||||
 | 
					                             "%F:%L - %m%n");
 | 
				
			||||||
 | 
					      properties.setProperty("log4j.appender.A1.filename",
 | 
				
			||||||
 | 
					                             "functiontrace_test.log");
 | 
				
			||||||
 | 
					      log4cxx::PropertyConfigurator::configure(properties);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    void Calls() {
 | 
				
			||||||
 | 
					      fn(A());
 | 
				
			||||||
 | 
					      mrw::RegExp match
 | 
				
			||||||
 | 
					        ("functiontrace_test.cpp:30 - *0x[0-9a-fA-F]+: \\\\ A::A\\(\\)\n"
 | 
				
			||||||
 | 
					         "functiontrace_test.cpp:30 - *0x[0-9a-fA-F]+: / A::A\\(\\)\n"
 | 
				
			||||||
 | 
					         "functiontrace_test.cpp:55 -                  \\\\ fn\\(A\\)\n"
 | 
				
			||||||
 | 
					         "functiontrace_test.cpp:36 - *0x[0-9a-fA-F]+:  \\\\ A::fn1\\(\\)\n"
 | 
				
			||||||
 | 
					         "functiontrace_test.cpp:40 - *0x[0-9a-fA-F]+:   \\\\ A::fn2\\(\\)\n"
 | 
				
			||||||
 | 
					         "functiontrace_test.cpp:45 - *0x[0-9a-fA-F]+:    \\\\ A::fn3\\(\\)\n"
 | 
				
			||||||
 | 
					         "functiontrace_test.cpp:49 - *0x[0-9a-fA-F]+:     \\\\ A::fn4\\(\\)\n"
 | 
				
			||||||
 | 
					         "functiontrace_test.cpp:49 - *0x[0-9a-fA-F]+:      \\\\ A::fn4\\(\\)\n"
 | 
				
			||||||
 | 
					         "functiontrace_test.cpp:49 - *0x[0-9a-fA-F]+:      / A::fn4\\(\\)\n"
 | 
				
			||||||
 | 
					         "functiontrace_test.cpp:49 - *0x[0-9a-fA-F]+:     / A::fn4\\(\\)\n"
 | 
				
			||||||
 | 
					         "functiontrace_test.cpp:45 - *0x[0-9a-fA-F]+:    / A::fn3\\(\\)\n"
 | 
				
			||||||
 | 
					         "functiontrace_test.cpp:49 - *0x[0-9a-fA-F]+:    \\\\ A::fn4\\(\\)\n"
 | 
				
			||||||
 | 
					         "functiontrace_test.cpp:49 - *0x[0-9a-fA-F]+:     \\\\ A::fn4\\(\\)\n"
 | 
				
			||||||
 | 
					         "functiontrace_test.cpp:49 - *0x[0-9a-fA-F]+:     / A::fn4\\(\\)\n"
 | 
				
			||||||
 | 
					         "functiontrace_test.cpp:49 - *0x[0-9a-fA-F]+:    / A::fn4\\(\\)\n"
 | 
				
			||||||
 | 
					         "functiontrace_test.cpp:40 - *0x[0-9a-fA-F]+:   / A::fn2\\(\\)\n"
 | 
				
			||||||
 | 
					         "functiontrace_test.cpp:36 - *0x[0-9a-fA-F]+:  / A::fn1\\(\\)\n"
 | 
				
			||||||
 | 
					         "functiontrace_test.cpp:55 -                  / fn\\(A\\)\n"
 | 
				
			||||||
 | 
					         "functiontrace_test.cpp:33 - *0x[0-9a-fA-F]+: \\\\ A::~A\\(\\)\n"
 | 
				
			||||||
 | 
					         "functiontrace_test.cpp:33 - *0x[0-9a-fA-F]+: / A::~A\\(\\)\n");
 | 
				
			||||||
 | 
					      CPPUNIT_ASSERT(match(mrw::File::read("functiontrace_test.log")));
 | 
				
			||||||
 | 
					      mrw::File::remove("functiontrace_test.log");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    CPPUNIT_TEST_SUITE(FunctionTraceTest);
 | 
				
			||||||
 | 
					    CPPUNIT_TEST(Init);
 | 
				
			||||||
 | 
					    CPPUNIT_TEST(Calls);
 | 
				
			||||||
 | 
					    CPPUNIT_TEST_SUITE_END();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					CPPUNIT_TEST_SUITE_REGISTRATION(FunctionTraceTest);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main() {
 | 
				
			||||||
 | 
					  CppUnit::TextUi::TestRunner runner;
 | 
				
			||||||
 | 
					  runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
 | 
				
			||||||
 | 
					  return runner.run() ? 0 : 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										179
									
								
								mrw/mrwautofunctiontracelog4cxx_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								mrw/mrwautofunctiontracelog4cxx_test.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,179 @@
 | 
				
			|||||||
 | 
					/** @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:55  marc
 | 
				
			||||||
 | 
					    initial version
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         1         2         3         4         5         6         7         8
 | 
				
			||||||
 | 
					    5678901234567890123456789012345678901234567890123456789012345678901234567890
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <log4cxx/propertyconfigurator.h>
 | 
				
			||||||
 | 
					#include <log4cxx/helpers/properties.h>
 | 
				
			||||||
 | 
					#include <cppunit/TestFixture.h>
 | 
				
			||||||
 | 
					#include <cppunit/ui/text/TestRunner.h>
 | 
				
			||||||
 | 
					#include <cppunit/extensions/HelperMacros.h>
 | 
				
			||||||
 | 
					#include <cppunit/extensions/TestFactoryRegistry.h>
 | 
				
			||||||
 | 
					#include <mrw/file.hpp>
 | 
				
			||||||
 | 
					#include <mrw/regexp.hpp>
 | 
				
			||||||
 | 
					#include <mrw/string.hpp>
 | 
				
			||||||
 | 
					#include <mrw/stacktrace.hpp>
 | 
				
			||||||
 | 
					#include <map>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace HalloWelt {
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  class A {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					      void method() {
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void fn() {
 | 
				
			||||||
 | 
					    A().method();
 | 
				
			||||||
 | 
					    A().method();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void fn1() {
 | 
				
			||||||
 | 
					    fn();
 | 
				
			||||||
 | 
					    fn();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void anotherFunction() {
 | 
				
			||||||
 | 
					  HalloWelt::fn1();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _REENTRANT
 | 
				
			||||||
 | 
					#include <boost/thread/thread.hpp>
 | 
				
			||||||
 | 
					//#include <unistd.h> // sleep, the one from boost::thread does not work!
 | 
				
			||||||
 | 
					class Thread {
 | 
				
			||||||
 | 
					  public:
 | 
				
			||||||
 | 
					    void operator()() {
 | 
				
			||||||
 | 
					      anotherFunction();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace mrw {
 | 
				
			||||||
 | 
					  class AutoFunctionTraceLog4CxxTest: public CppUnit::TestFixture {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					      void testcase() {
 | 
				
			||||||
 | 
					        mrw::StackTrace::createSymtable();
 | 
				
			||||||
 | 
					#ifdef _REENTRANT
 | 
				
			||||||
 | 
					        try {mrw::File::remove("mrwautofunctiontracelog4cxx_test-mt.log");}
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        try {mrw::File::remove("mrwautofunctiontracelog4cxx_test.log");}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					        catch (...) {}
 | 
				
			||||||
 | 
					        log4cxx::helpers::Properties properties;
 | 
				
			||||||
 | 
					        properties.setProperty("log4j.rootLogger",
 | 
				
			||||||
 | 
					                               "OFF, A1");
 | 
				
			||||||
 | 
					        properties.setProperty("log4j.logger.mrw.gccfunctiontrace",
 | 
				
			||||||
 | 
					                               "DEBUG");
 | 
				
			||||||
 | 
					        properties.setProperty("log4j.logger.mrw.gccfunctiontrace.log4cxx",
 | 
				
			||||||
 | 
					                               "OFF");
 | 
				
			||||||
 | 
					        properties.setProperty("log4j.logger.mrw.gccfunctiontrace.boost",
 | 
				
			||||||
 | 
					                               "OFF");
 | 
				
			||||||
 | 
					        properties.setProperty("log4j.logger.mrw.gccfunctiontrace.Thread",
 | 
				
			||||||
 | 
					                               "OFF");
 | 
				
			||||||
 | 
					        properties.setProperty("log4j.logger.mrw.gccfunctiontrace.mrw",
 | 
				
			||||||
 | 
					                               "OFF");
 | 
				
			||||||
 | 
					        properties.setProperty("log4j.logger.mrw.gccfunctiontrace.std",
 | 
				
			||||||
 | 
					                               "OFF");
 | 
				
			||||||
 | 
					        properties.setProperty("log4j.logger.mrw.gccfunctiontrace.new",
 | 
				
			||||||
 | 
					                               "OFF");
 | 
				
			||||||
 | 
					        properties.setProperty("log4j.logger.mrw.gccfunctiontrace.CppUnit",
 | 
				
			||||||
 | 
					                               "OFF");
 | 
				
			||||||
 | 
					        properties.setProperty("log4j.logger.mrw.gccfunctiontrace.__gnu_cxx",
 | 
				
			||||||
 | 
					                               "OFF");
 | 
				
			||||||
 | 
					        properties.setProperty("log4j.appender.A1",
 | 
				
			||||||
 | 
					                               "org.apache.log4j.FileAppender");
 | 
				
			||||||
 | 
					        properties.setProperty("log4j.appender.A1.layout",
 | 
				
			||||||
 | 
					                               "org.apache.log4j.PatternLayout");
 | 
				
			||||||
 | 
					#ifdef _REENTRANT
 | 
				
			||||||
 | 
					        properties.setProperty("log4j.appender.A1.layout.ConversionPattern",
 | 
				
			||||||
 | 
					                               "%t-%-41c%m%n");
 | 
				
			||||||
 | 
					        properties.setProperty("log4j.appender.A1.filename",
 | 
				
			||||||
 | 
					                               "mrwautofunctiontracelog4cxx_test-mt.log");
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        properties.setProperty("log4j.appender.A1.layout.ConversionPattern",
 | 
				
			||||||
 | 
					                               "%-41c%m%n");
 | 
				
			||||||
 | 
					        properties.setProperty("log4j.appender.A1.filename",
 | 
				
			||||||
 | 
					                               "mrwautofunctiontracelog4cxx_test.log");
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					        log4cxx::PropertyConfigurator::configure(properties);
 | 
				
			||||||
 | 
					#ifdef _REENTRANT
 | 
				
			||||||
 | 
					        // sleep(4); // to be reproducable, wait for "main" flag
 | 
				
			||||||
 | 
					        Thread threadFunction;
 | 
				
			||||||
 | 
					        boost::thread::thread thread1(threadFunction);
 | 
				
			||||||
 | 
					        boost::thread::thread thread2(threadFunction);
 | 
				
			||||||
 | 
					        boost::thread::thread thread3(threadFunction);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					        anotherFunction();
 | 
				
			||||||
 | 
					#ifdef _REENTRANT
 | 
				
			||||||
 | 
					        thread1.join();
 | 
				
			||||||
 | 
					        thread2.join();
 | 
				
			||||||
 | 
					        thread3.join();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void checkfile() {
 | 
				
			||||||
 | 
					        mrw::RegExp match
 | 
				
			||||||
 | 
					          ("^mrw\\.gccfunctiontrace\\.anotherFunction     ( ? ? ?)\\\\ anotherFunction\\(\\)\n"
 | 
				
			||||||
 | 
					           "mrw\\.gccfunctiontrace\\.HalloWelt\\.fn1       \\1 \\\\ HalloWelt::fn1\\(\\)\n"
 | 
				
			||||||
 | 
					           "mrw\\.gccfunctiontrace\\.HalloWelt\\.fn        \\1  \\\\ HalloWelt::fn\\(\\)\n"
 | 
				
			||||||
 | 
					           "mrw\\.gccfunctiontrace\\.HalloWelt\\.A\\.method  \\1   \\\\ HalloWelt::A::method\\(\\)\n"
 | 
				
			||||||
 | 
					           "mrw\\.gccfunctiontrace\\.HalloWelt\\.A\\.method  \\1   / HalloWelt::A::method\\(\\)\n"
 | 
				
			||||||
 | 
					           "mrw\\.gccfunctiontrace\\.HalloWelt\\.A\\.method  \\1   \\\\ HalloWelt::A::method\\(\\)\n"
 | 
				
			||||||
 | 
					           "mrw\\.gccfunctiontrace\\.HalloWelt\\.A\\.method  \\1   / HalloWelt::A::method\\(\\)\n"
 | 
				
			||||||
 | 
					           "mrw\\.gccfunctiontrace\\.HalloWelt\\.fn        \\1  / HalloWelt::fn\\(\\)\n"
 | 
				
			||||||
 | 
					           "mrw\\.gccfunctiontrace\\.HalloWelt\\.fn        \\1  \\\\ HalloWelt::fn\\(\\)\n"
 | 
				
			||||||
 | 
					           "mrw\\.gccfunctiontrace\\.HalloWelt\\.A\\.method  \\1   \\\\ HalloWelt::A::method\\(\\)\n"
 | 
				
			||||||
 | 
					           "mrw\\.gccfunctiontrace\\.HalloWelt\\.A\\.method  \\1   / HalloWelt::A::method\\(\\)\n"
 | 
				
			||||||
 | 
					           "mrw\\.gccfunctiontrace\\.HalloWelt\\.A\\.method  \\1   \\\\ HalloWelt::A::method\\(\\)\n"
 | 
				
			||||||
 | 
					           "mrw\\.gccfunctiontrace\\.HalloWelt\\.A\\.method  \\1   / HalloWelt::A::method\\(\\)\n"
 | 
				
			||||||
 | 
					           "mrw\\.gccfunctiontrace\\.HalloWelt\\.fn        \\1  / HalloWelt::fn\\(\\)\n"
 | 
				
			||||||
 | 
					           "mrw\\.gccfunctiontrace\\.HalloWelt\\.fn1       \\1 / HalloWelt::fn1\\(\\)\n"
 | 
				
			||||||
 | 
					           "mrw\\.gccfunctiontrace\\.anotherFunction     \\1/ anotherFunction\\(\\)\n$");
 | 
				
			||||||
 | 
					#ifdef _REENTRANT
 | 
				
			||||||
 | 
					        std::string log(mrw::File::read("mrwautofunctiontracelog4cxx_test-mt.log"));
 | 
				
			||||||
 | 
					        std::map<unsigned long, std::string> logs;
 | 
				
			||||||
 | 
					        for (std::string::size_type pos(0), last(0);
 | 
				
			||||||
 | 
					             (pos=log.find('\n', pos+1))!=std::string::npos; last=pos) {
 | 
				
			||||||
 | 
					          std::string::size_type dash(log.find('-', last));
 | 
				
			||||||
 | 
					          CPPUNIT_ASSERT(dash!=std::string::npos);
 | 
				
			||||||
 | 
					          logs[mrw::to<unsigned long>(log.substr(last, dash-last))] +=
 | 
				
			||||||
 | 
					            log.substr(dash+1, pos-dash);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        CPPUNIT_ASSERT(logs.size()==4); // 4 threads
 | 
				
			||||||
 | 
					        for (std::map<unsigned long, std::string>::iterator it(logs.begin());
 | 
				
			||||||
 | 
					             it!=logs.end(); ++it)
 | 
				
			||||||
 | 
					          CPPUNIT_ASSERT(match(it->second));
 | 
				
			||||||
 | 
					        mrw::File::remove("mrwautofunctiontracelog4cxx_test-mt.log");
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        CPPUNIT_ASSERT(match(mrw::File::read("mrwautofunctiontracelog4cxx_test.log")));
 | 
				
			||||||
 | 
					        mrw::File::remove("mrwautofunctiontracelog4cxx_test.log");
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      CPPUNIT_TEST_SUITE(AutoFunctionTraceLog4CxxTest);
 | 
				
			||||||
 | 
					      CPPUNIT_TEST(testcase);
 | 
				
			||||||
 | 
					      CPPUNIT_TEST(checkfile);
 | 
				
			||||||
 | 
					      CPPUNIT_TEST_SUITE_END();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  CPPUNIT_TEST_SUITE_REGISTRATION(AutoFunctionTraceLog4CxxTest);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main() {
 | 
				
			||||||
 | 
					  CppUnit::TextUi::TestRunner runner;
 | 
				
			||||||
 | 
					  runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
 | 
				
			||||||
 | 
					  return runner.run() ? 0 : 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user