|
|
#ifndef _TRACER_H_
#define _TRACER_H_
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <stdarg.h>
//
// global defines.
//
#define MAX_FLAG_NAME 32
#define MAX_TAG_NAME 64
#define DEVICE_FLAG 0
#define ERROR_LEVEL_FLAG 1
#define ASSERT_LEVEL_FLAG 2
#define PRINT_LOCATION 3
#define PRINT_PROGRAM_NAME 4
#define PRINT_TIME 5
#define PRINT_THREAD_ID 6
#define PRINT_ERROR_LEVEL 7
#define PRINT_TAG_ID 8
#define PRINT_TAG_NAME 9
#define PRINT_PROCESS_ID 10
#define LAST_FLAG 11
#define TRACER_DEVICE_FLAG_FILE 0x00000001L
#define TRACER_DEVICE_FLAG_DEBUGOUT 0x00000002L
#define TRACER_DEVICE_FLAG_STDOUT 0x00000004L
#define TRACER_DEVICE_FLAG_STDERR 0x00000008L
//
// basic classes
//
typedef enum _ERROR_LEVEL { elFirst = 0, elCrash, elError, elWarning, elInfo, elVerbose, elLast } ERROR_LEVEL;
typedef ULONG TAG;
///////////////////////////////////////////////////////////////////////////////
// CTracerTagEntry
///////////////////////////////////////////////////////////////////////////////
class CTracerTagEntry { public: CTracerTagEntry() : m_TagErrLevel(elFirst) { m_pszTagName[0] = '\0'; }
public: ERROR_LEVEL m_TagErrLevel; char m_pszTagName[MAX_TAG_NAME];
};
///////////////////////////////////////////////////////////////////////////////
// CTracerFlagEntry
///////////////////////////////////////////////////////////////////////////////
class CTracerFlagEntry { public: CTracerFlagEntry() : m_ulFlagValue(0) { m_pszName[0] = '\0'; }
public: ULONG m_ulFlagValue; char m_pszName[MAX_FLAG_NAME]; };
///////////////////////////////////////////////////////////////////////////////
// CTracer
///////////////////////////////////////////////////////////////////////////////
typedef enum { logUseLogName, logUseAppName } LogState;
class CTracer { public:
// The virtual distructor is here to allow derived classes to
// define distructors
virtual ~CTracer();
// This function deallocates the tracer! it calls the Function pointer
// passed in the constructor or if not given - the default
// delete operator for the dll.
virtual void Free();
// The TraceSZ function output is defined by the tags and error level mode.
// The control of this mode is via the registry.
// (Default LOCAL_MACHINE\SOFTWARE\Microsoft\Tracer)
// TraceSZ gets the mode by calling IsEnabled.
//-------------------------------------------------------------------------
// accepts printf format for traces
virtual void TraceSZ(DWORD, LPCSTR, int, ERROR_LEVEL, TAG, LPCSTR, ...); virtual void TraceSZ(DWORD, LPCSTR, int, ERROR_LEVEL, TAG, PCWSTR, ...);
// Prints the implements the TraceSZ function.
virtual void VaTraceSZ(DWORD, LPCSTR, int, ERROR_LEVEL, TAG, LPCSTR, va_list); virtual void VaTraceSZ(DWORD, LPCSTR, int, ERROR_LEVEL, TAG, PCWSTR, va_list);
// Raw output functions
virtual void RawVaTraceSZ(LPCSTR, va_list); virtual void RawVaTraceSZ(PCWSTR, va_list);
// Create or open a new tag for tracing
virtual HRESULT RegisterTagSZ(LPCSTR, TAG&);
// Two Assert functions one allows attaching a string.
//-------------------------------------------------------------------------
// assert, different implementations possible - gui or text
virtual void TraceAssertSZ(LPCSTR, LPCSTR, LPCSTR, int);
// assert, different implementations possible - gui or text
virtual void TraceAssert(LPCSTR, LPCSTR, int);
// The following function are used to check return values and validity of
// pointers and handles. If the item checked is bad the function will
// return TRUE and a trace will be made for that.
//-------------------------------------------------------------------------
// Verify a boolean function return code
virtual BOOL IsFailure(BOOL, LPCSTR, int);
// verify allocation
virtual BOOL IsBadAlloc(void*, LPCSTR, int);
// Verify a Handle
virtual BOOL IsBadHandle(HANDLE, LPCSTR, int);
// Verify an OLE hresult function
virtual BOOL IsBadResult(HRESULT, LPCSTR, int);
public:
TAG* m_ptagNextTagId; // A array of tags.
CTracerTagEntry* m_aTags;
// Contains the flags that control wich output devices are used.
ULONG* m_pulNumOfFlagEntries; CTracerFlagEntry* m_aFlags;
// log file
LogState m_LogState; char* m_pszLogName; };
extern "C" CTracer* g_pTracer;
class CSetLogFile { public: CSetLogFile() { g_pTracer->m_LogState = logUseAppName; }
CSetLogFile(char* pszName) { g_pTracer->m_LogState = logUseLogName; g_pTracer->m_pszLogName = pszName; }
}; ///////////////////////////////////////////////////////////////////////////////
// CTempTrace
///////////////////////////////////////////////////////////////////////////////
class CTempTrace { public: CTempTrace(LPCSTR pszFile, int iLine);
void TraceSZ(ERROR_LEVEL, ULONG, LPCSTR, ...); void TraceSZ(ERROR_LEVEL, ULONG, DWORD dwError, LPCSTR, ...);
void TraceSZ(ERROR_LEVEL, ULONG, PCWSTR, ...); void TraceSZ(ERROR_LEVEL, ULONG, DWORD dwError, PCWSTR, ...);
private:
LPCSTR m_pszFile; int m_iLine;
};
///////////////////////////////////////////////////////////////////////////////
// CTempTrace1
///////////////////////////////////////////////////////////////////////////////
class CTempTrace1 { public: CTempTrace1(LPCSTR pszFile, int iLine, TAG tag, ERROR_LEVEL el);
void TraceSZ(LPCSTR, ...); void TraceSZ(DWORD dwError, LPCSTR, ...);
void TraceSZ(PCWSTR, ...); void TraceSZ(DWORD dwError, PCWSTR, ...);
private:
LPCSTR m_pszFile; int m_iLine; TAG m_ulTag; ERROR_LEVEL m_el;
};
///////////////////////////////////////////////////////////////////////////////
// CLongTrace
///////////////////////////////////////////////////////////////////////////////
class CLongTrace { public: CLongTrace(LPCSTR pszFile, int iLine); ~CLongTrace(); BOOL Init(ERROR_LEVEL, TAG);
private: BOOL m_fRelease; LPCSTR m_pszFile; int m_iLine; };
///////////////////////////////////////////////////////////////////////////////
// CLongTraceOutput
///////////////////////////////////////////////////////////////////////////////
class CLongTraceOutput { public: CLongTraceOutput(LPCSTR pszFile, int iLine);
void TraceSZ(LPCSTR, ...); void TraceSZ(PCWSTR, ...);
private: LPCSTR m_pszFile; int m_iLine; };
///////////////////////////////////////////////////////////////////////////////
// CTracerTag
///////////////////////////////////////////////////////////////////////////////
class CTracerTag { #if (defined (DEBUG) && !defined(_NO_TRACER)) || defined(USE_TRACER)
public:
CTracerTag(PSZ pszTagName) { HRESULT hrTagRegistrationResult;
hrTagRegistrationResult = g_pTracer->RegisterTagSZ(pszTagName, m_ulTag);
if(FAILED(hrTagRegistrationResult)) throw "Tag could not be registered";
}
operator TAG() { return m_ulTag; }
public: TAG m_ulTag; #else /* DEBUG */
public: CTracerTag(PSZ){} #endif /* DEBUG */
};
extern CTracerTag tagError; extern CTracerTag tagWarning; extern CTracerTag tagInformation; extern CTracerTag tagVerbose; extern CTracerTag tagGeneral; //
// global defines
//
#define BAD_POINTER(ptr) (NULL == (ptr))
#define BAD_HANDLE(h) ((0 == ((HANDLE)h))|| \
(INVALID_HANDLE_VALUE == ((HANDLE)h))) #define BAD_RESULT(hr) (FAILED(hr))
#if (defined (DEBUG) && !defined(_NO_TRACER)) || defined(USE_TRACER)
#ifdef __cplusplus
#define CheckTraceRestrictions(el, tag) \
((g_pTracer->m_aTags[tag].m_TagErrLevel >= el) && \ (g_pTracer->m_aFlags[ERROR_LEVEL_FLAG].m_ulFlagValue >= (ULONG)el) && \ g_pTracer->m_aFlags[DEVICE_FLAG].m_ulFlagValue)
#define Trace(x) \
{CTempTrace tmp(__FILE__, __LINE__);tmp.TraceSZ x;}
#define Trace1(el, tag, x) \
{ \ if (CheckTraceRestrictions(el, tag.m_ulTag)) \ { \ CTempTrace1 tmp(__FILE__, __LINE__, tag.m_ulTag, el); \ tmp.TraceSZ x; \ } \ }
#define BeginLongTrace(x) {CLongTrace tmp(__FILE__, __LINE__);if (tmp.Init x) {
#define LongTrace(x) {CLongTraceOutput tmp(__FILE__, __LINE__);tmp.TraceSZ x;}
#define EndLongTrace }}
#define RegisterTag(psz, tag) g_pTracer->RegisterTagSZ((psz), tag)
#define IS_FAILURE(x) g_pTracer->IsFailure((x), __FILE__, __LINE__)
#define IS_BAD_ALLOC(x) g_pTracer->IsBadAlloc((void*)(x), __FILE__, __LINE__)
#define IS_BAD_HANDLE(x) g_pTracer->IsBadHandle((HANDLE)(x), __FILE__, __LINE__)
#define IS_BAD_RESULT(x) g_pTracer->IsBadResult((x), __FILE__, __LINE__)
#define Assert(x) {if (!(x)) {g_pTracer->TraceAssert(#x, __FILE__, __LINE__);}}
#define AssertSZ(x, psz) {if (!(x)) {g_pTracer->TraceAssertSZ(#x, (PSZ)(psz),__FILE__, __LINE__);}}
#define SET_TRACER(x) SetTracer(x)
#define SET_TRACER_LOGGING_TO_FILE_OFF g_pTracer->m_aFlags[DEVICE_FLAG].m_ulFlagValue &= ~TRACER_DEVICE_FLAG_FILE;
#define USE_COMMON_LOG_FILE(name) CSetLogFile SetLogFile(name);
#else /* __cplusplus */
#define IS_FAILURE(x) IsFailure((x), __FILE__, __LINE__)
#define IS_BAD_ALLOC(x) IsBadAlloc((void*)(x), __FILE__, __LINE__)
#define IS_BAD_HANDLE(x) IsBadHandle((HANDLE)(x), __FILE__, __LINE__)
#define IS_BAD_RESULT(x) IsBadResult((x), __FILE__, __LINE__)
#define Assert(x) {if (!(x)) {TraceAssert(#x,__FILE__, __LINE__);}}
#ifdef UNICODE
#define AssertSZ(x, psz) {if (!(x)) {TraceAssertWSZ(#x, (pwsz), __FILE__, __LINE__);}}
#define Trace(x) TraceWSZ x
#else
#define AssertSZ(x, psz) {if (!(x)) {TraceAssertSZ(#x, (psz),__FILE__, __LINE__);}}
#define Trace(x) TraceSZ x
#endif
#define RegisterTag(psz, tag) RegisterTagSZ((psz), &(tag))
#endif /* __cplusplus */
#define GIS_FAILURE(x) IsFailure((x), __FILE__, __LINE__)
#define GIS_BAD_ALLOC(x) IsBadAlloc((void*)(x), __FILE__, __LINE__)
#define GIS_BAD_HANDLE(x) IsBadHandle((HANDLE)(x), __FILE__, __LINE__)
#define GIS_BAD_RESULT(x) IsBadResult((x), __FILE__, __LINE__)
#define GAssert(x) {if (!(x)) {TraceAssert(#x, __FILE__, __LINE__);}}
#define GAssertSZ(x, psz) {if (!(x)) {TraceAssertSZ(#x, (PSZ)(psz), __FILE__, __LINE__);}}
#define GTrace(x) TraceSZ x
#define DECLARE_TAG(name, psz) static CTracerTag name(psz);
#define DECLARE_GLOBAL_TAG(name, psz) CTracerTag name(psz);
#define USES_TAG(name) extern CTracerTag name;
#else // DEBUG
#define IS_FAILURE(x) (!(x))
#define IS_BAD_ALLOC(x) BAD_POINTER((void*)(x))
#define IS_BAD_HANDLE(x) BAD_HANDLE((HANDLE)(x))
#define IS_BAD_RESULT(x) BAD_RESULT(x)
#define Assert(x)
#define AssertSZ(x, psz)
#define Trace(x)
#define Trace1(el,tag,x)
#define BeginLongTrace(x) {if (0) {
#define LongTrace(x) ;
#define EndLongTrace }}
#define RegisterTag(psz, tag)
#define SET_TRACER(x)
#define SET_TRACER_LOGGING_TO_FILE_OFF
#define USE_COMMON_LOG_FILE(name)
#define GIS_FAILURE(x) IS_FAILURE(x)
#define GIS_BAD_ALLOC(x) IS_BAD_ALLOC(x)
#define GIS_BAD_HANDLE(x) IS_BAD_HANDLE(x)
#define GIS_BAD_RESULT(x) IS_BAD_RESULT(x)
#define GAssert(x) Assert(x)
#define GAssertSZ(x, psz) AssertSZ(x, psz)
#define GTrace(x)
#define DECLARE_TAG(name, psz)
#define DECLARE_GLOBAL_TAG(name, psz)
#define USES_TAG(name)
#endif // DEBUG
//
// Turn off Asserts for retail, even if USE_TRACER is specified
//
#if (!defined(DEBUG))
#ifdef Assert
#undef Assert
#define Assert(x)
#endif // Assert
#ifdef AssertSZ
#undef AssertSZ
#define AssertSZ(x, psz)
#endif // AssertSZ
#ifdef GAssert
#undef GAssert
#define GAssert(x)
#endif // GAssert
#ifdef GAssertSZ
#undef GAssertSZ
#define GAssertSZ(x, psz)
#endif // GAssertSZ
#endif // DEBUG
#ifndef PQS_CODE
#undef _ASSERTE
#if (defined (DEBUG) && !defined(_NO_TRACER))
#define _ASSERTE(x) Assert(x)
#else
#define _ASSERTE(x) 0
#endif
#endif // PQS_CODE
////////////////////////////////////////////////////////////////////////////////
//
// Define this to export the classes
//
////////////////////////////////////////////////////////////////////////////////
#ifdef TRACER_EXPORT
#define TracerExported __declspec( dllexport )
#else
#define TracerExported
#endif
////////////////////////////////////////////////////////////////////////////////
//
// class CTraced definition + implementation
//
// pupose : A base class for every class who wants to use a special.
//
//
////////////////////////////////////////////////////////////////////////////////
#if (defined (DEBUG) && !defined(_NO_TRACER)) || defined(USE_TRACER)
void __cdecl ShutdownTracer();
class TracerExported CTraced { public: // A Constructor - sets a default Tracer. replace it by calling SetTracer
// in the derived class constructor.
CTraced() { m_pTracer = NULL; }
// The destructor deletes the existing tracer.
~CTraced() { if (m_pTracer) m_pTracer->Free(); }
// replace the current tracer while erasing it.
BOOL SetTracer(CTracer* pTracer) { CTracer* pTempTracer = m_pTracer; m_pTracer = pTracer;
if (pTempTracer) pTempTracer->Free();
return TRUE; }
// Return a pointer to the tracer this function is called by the macro's so
// if one wants to supply a different mechanism he can override it.
virtual CTracer* GetTracer() { if(m_pTracer) return m_pTracer; else return g_pTracer; }
protected: // A pointer to the tracer.
CTracer *m_pTracer; };
#else /* DEBUG */
class TracerExported CTraced {}; #endif /* DEBUG */
////////////////////////////////////////////////////////////////////////////////
//
// The C interface prototypes. The macros calls them.
//
////////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
extern "C" { #endif /* __cplusplus */
void TraceAssert( PSZ, PSZ, int); void TraceAssertSZ( PSZ, PSZ, PSZ, int); void TraceAssertWSZ(PSZ, PWSTR, PSZ, int);
BOOL IsFailure (BOOL , PSZ, int); BOOL IsBadAlloc (void* , PSZ, int); BOOL IsBadHandle(HANDLE , PSZ, int); BOOL IsBadResult(HRESULT, PSZ, int);
void TraceSZ(ERROR_LEVEL, TAG, PSZ, ...); void TraceWSZ(ERROR_LEVEL, TAG, PWSTR, ...);
HRESULT RegisterTagSZ(PSZ, TAG*);
#ifdef __cplusplus
} #endif /* __cplusplus */
#ifdef __cplusplus
////////////////////////////////////////////////////////////////////////////////
//
// Some extra classes.
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// An accumulating timer. Use it to define accuulator.
// (See cpptest.cpp in the Sample)
//
// It is be used to compute average times of function etc.
//
// timer - the vaiable name
// tag - the tag to trace to
// string - a prefix
//
////////////////////////////////////////////////////////////////////////////////
#if (defined (DEBUG) && !defined(_NO_TRACER)) || defined(USE_TRACER)
#define AccumulatingTimer(timer, tag, string, actimer) \
CTracerAccumulatingTimer timer(tag, string, actimer) #else
#define AccumulatingTimer(timer, tag, string, actimer)
#endif
#if (defined (DEBUG) && !defined(_NO_TRACER)) || defined(USE_TRACER)
class CTracerAccumulatingTimer { public: CTracerAccumulatingTimer( TAG tag, PSZ pszSomeText = NULL, CTracerAccumulatingTimer *pTimer = NULL) :m_ulAccumulatedTimeInMiliseconds(0) ,m_ulEventNumber(0) ,m_tagTheTagToTraceTo(tag) ,m_pAccumulator(pTimer) { if (pszSomeText) strncpy(m_rchText, pszSomeText, MAX_PATH); else m_rchText[0] = '\0'; }
operator TAG(){return m_tagTheTagToTraceTo;}
void AddEvent(ULONG ulEventDurationInMiliseconds, PSZ pszSomeText) { m_ulAccumulatedTimeInMiliseconds += ulEventDurationInMiliseconds; m_ulEventNumber++;
Trace(( elInfo, m_tagTheTagToTraceTo, "%s%s took %d miliseconds," " average is %d miliseconds," " accumulated %d miliseconds," " op# %d", m_rchText, pszSomeText, ulEventDurationInMiliseconds, m_ulAccumulatedTimeInMiliseconds/m_ulEventNumber, m_ulAccumulatedTimeInMiliseconds, m_ulEventNumber));
if(m_pAccumulator) m_pAccumulator->AddEvent( ulEventDurationInMiliseconds, m_rchText); }
protected: // The time
ULONG m_ulAccumulatedTimeInMiliseconds;
// The event counter
ULONG m_ulEventNumber;
// The tag the trace will use.
TAG m_tagTheTagToTraceTo;
// some text to specify which scope or code block is it
char m_rchText[MAX_PATH + 1];
// pointer to accumulating time
CTracerAccumulatingTimer *m_pAccumulator; }; #endif
////////////////////////////////////////////////////////////////////////////////
//
// A scope timer. It will trace the time that passed from the instanciation
// to the end of the scope.
// (See cpptest.cpp in the Sample)
//
// It is be used to compute times of function etc.
//
// tag - the tag to trace to
// string - a prefix
//
////////////////////////////////////////////////////////////////////////////////
#if (defined (DEBUG) && !defined(_NO_TRACER)) || defined(USE_TRACER)
#define ScopeTimer(tag, string) CTracerScopeTimer __scopetimer(tag, string)
#else
#define ScopeTimer(tag, string)
#endif
////////////////////////////////////////////////////////////////////////////////
//
// A scope timer that uses and updates an accumulator timer.
// It will trace the time that passed from the instanciation
// to the end of the scope and tell this time to the accumulator as well.
// (See cpptest.cpp in the Sample)
//
// tag - the tag to trace to
// string - a prefix
// actimer - an AccumulatingTimer object.
//
// comment - if both the scope timer and the accumulating timer has the
// same tags - the scope timer will not trace.
//
////////////////////////////////////////////////////////////////////////////////
#if (defined (DEBUG) && !defined(_NO_TRACER)) || defined(USE_TRACER)
#define ScopeAccumulatingTimer(tag, string, actimer) \
CTracerScopeTimer __scopetimer(tag, string, actimer) #else
#define ScopeAccumulatingTimer(tag, string, actimer)
#endif
#if (defined (DEBUG) && !defined(_NO_TRACER)) || defined(USE_TRACER)
class CTracerScopeTimer { public: CTracerScopeTimer( TAG tag, PSZ pszSomeText = NULL, CTracerAccumulatingTimer *pTimer = NULL) :m_ulStartTimeInMiliseconds(GetTickCount()) ,m_tagTheTagToTraceTo(tag) ,m_pAccumulator(pTimer) { if (pszSomeText) strncpy(m_rchText, pszSomeText, MAX_PATH); else m_rchText[0] = '\0'; }
~CTracerScopeTimer() { ULONG ulFinishTimeInMiliseconds = GetTickCount(); ULONG ulStartToFinishTimeInMiliseconds;
if (ulFinishTimeInMiliseconds > m_ulStartTimeInMiliseconds) ulStartToFinishTimeInMiliseconds = ulFinishTimeInMiliseconds - m_ulStartTimeInMiliseconds; else ulStartToFinishTimeInMiliseconds = ulFinishTimeInMiliseconds + 1 + (0xffffffff - m_ulStartTimeInMiliseconds);
if(!m_pAccumulator || (m_tagTheTagToTraceTo != (ULONG)(*m_pAccumulator))) Trace(( elInfo, m_tagTheTagToTraceTo, "%s took %d miliseconds", m_rchText, ulStartToFinishTimeInMiliseconds));
if(m_pAccumulator) m_pAccumulator->AddEvent( ulStartToFinishTimeInMiliseconds, m_rchText); }
protected: // The counter
ULONG m_ulStartTimeInMiliseconds;
// The tag the trace will use.
TAG m_tagTheTagToTraceTo;
// some text to specify which scope or code block is it
char m_rchText[MAX_PATH + 1];
// pointer to accumulating time
CTracerAccumulatingTimer *m_pAccumulator; }; #endif
#endif /* __cplusplus */
#endif // _TRACER_H_
|