517 lines
13 KiB
C++
517 lines
13 KiB
C++
|
// Copyright (c) 1997-1999 Microsoft Corporation
|
||
|
//
|
||
|
// debug logging tools
|
||
|
//
|
||
|
// 8-13-97 sburns
|
||
|
|
||
|
|
||
|
|
||
|
#ifndef LOG_HPP_INCLUDED
|
||
|
#define LOG_HPP_INCLUDED
|
||
|
|
||
|
|
||
|
|
||
|
// Log provides an interface to a singleton application logging facility.
|
||
|
|
||
|
namespace Burnslib
|
||
|
{
|
||
|
|
||
|
class Log
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
// use these to set DEFAULT_LOGGING_OPTIONS
|
||
|
//
|
||
|
// During CRT startup of our module (i.e. before main, WinMain, or
|
||
|
// DllMain), the debug code examines the DWORD LogFlags value under the
|
||
|
// registry key named by REG_ADMIN_RUNTIME_OPTIONS\LOGFILE_NAME. If the
|
||
|
// value is not present, it is created and DEFAULT_LOGGING_OPTIONS is
|
||
|
// written there. If the value is present, it is read.
|
||
|
//
|
||
|
// The HIWORD is a bit mask specifying the destination of the logging
|
||
|
// output.
|
||
|
//
|
||
|
// The LOWORD of that value contains a bitmask of the various debug
|
||
|
// message types to be output:
|
||
|
|
||
|
|
||
|
// cause LOG output to go to a log file named RUNTIME_NAME.log
|
||
|
|
||
|
static const DWORD OUTPUT_TO_FILE = (1 << 16);
|
||
|
|
||
|
// cause LOG output to go to OutputDebugString
|
||
|
|
||
|
static const DWORD OUTPUT_TO_DEBUGGER = (1 << 17);
|
||
|
|
||
|
// cause LOG output to go to SpewView application
|
||
|
|
||
|
static const DWORD OUTPUT_TO_SPEWVIEW = (1 << 18);
|
||
|
|
||
|
// cause LOG output to be appended to a log file named RUNTIME_NAME.log
|
||
|
|
||
|
static const DWORD OUTPUT_APPEND_TO_FILE = (1 << 19);
|
||
|
|
||
|
|
||
|
// output object construction/destruction
|
||
|
|
||
|
static const DWORD OUTPUT_CTORS = (1 << 0);
|
||
|
|
||
|
// output calls to AddRef/Release
|
||
|
|
||
|
static const DWORD OUTPUT_ADDREFS = (1 << 1);
|
||
|
|
||
|
// output function call entry
|
||
|
|
||
|
static const DWORD OUTPUT_FUNCCALLS = (1 << 2);
|
||
|
|
||
|
// output trace messages
|
||
|
|
||
|
static const DWORD OUTPUT_LOGS = (1 << 3);
|
||
|
|
||
|
// output log header
|
||
|
|
||
|
static const DWORD OUTPUT_HEADER = (1 << 4);
|
||
|
|
||
|
// output error messages
|
||
|
|
||
|
static const DWORD OUTPUT_ERRORS = (1 << 5);
|
||
|
|
||
|
// output time-of-day on each log line
|
||
|
|
||
|
static const DWORD OUTPUT_TIME_OF_DAY = (1 << 6);
|
||
|
|
||
|
// output time-since-start on each log line
|
||
|
|
||
|
static const DWORD OUTPUT_RUN_TIME = (1 << 7);
|
||
|
|
||
|
// output function/scope exits
|
||
|
|
||
|
static const DWORD OUTPUT_SCOPE_EXIT = (1 << 8);
|
||
|
|
||
|
|
||
|
|
||
|
static const DWORD OUTPUT_MUTE = 0;
|
||
|
|
||
|
static const DWORD OUTPUT_FULL_VOLUME =
|
||
|
Log::OUTPUT_TO_FILE
|
||
|
| Log::OUTPUT_TO_DEBUGGER
|
||
|
| Log::OUTPUT_TO_SPEWVIEW
|
||
|
| Log::OUTPUT_CTORS
|
||
|
| Log::OUTPUT_ADDREFS
|
||
|
| Log::OUTPUT_FUNCCALLS
|
||
|
| Log::OUTPUT_LOGS
|
||
|
| Log::OUTPUT_HEADER
|
||
|
| Log::OUTPUT_ERRORS
|
||
|
| Log::OUTPUT_TIME_OF_DAY
|
||
|
| Log::OUTPUT_RUN_TIME
|
||
|
| Log::OUTPUT_SCOPE_EXIT;
|
||
|
|
||
|
static const DWORD OUTPUT_TYPICAL =
|
||
|
Log::OUTPUT_TO_FILE
|
||
|
| Log::OUTPUT_TO_DEBUGGER
|
||
|
| Log::OUTPUT_FUNCCALLS
|
||
|
| Log::OUTPUT_LOGS
|
||
|
| Log::OUTPUT_HEADER
|
||
|
| Log::OUTPUT_ERRORS;
|
||
|
|
||
|
|
||
|
// Returns a pointer to the single Burnslib::Log instance.
|
||
|
|
||
|
static
|
||
|
Log*
|
||
|
GetInstance();
|
||
|
|
||
|
|
||
|
|
||
|
// Called by the initialization machinery to tear down the debugging setup.
|
||
|
// This takes place during static de-initialization, after
|
||
|
// main/WinMain/DllMain(DLL_PROCESS_DETACH) has returned.
|
||
|
|
||
|
static
|
||
|
void
|
||
|
Cleanup();
|
||
|
|
||
|
|
||
|
|
||
|
// Dumps text to the log for the given logging type.
|
||
|
//
|
||
|
// type - log type of text.
|
||
|
//
|
||
|
// text - text to dump.
|
||
|
//
|
||
|
// file - filename of source file producing text.
|
||
|
//
|
||
|
// line - line number in source file producing text.
|
||
|
|
||
|
void
|
||
|
WriteLn(
|
||
|
WORD type,
|
||
|
const String& text);
|
||
|
// const String& file,
|
||
|
// unsigned line);
|
||
|
|
||
|
|
||
|
|
||
|
// A ScopeTracer object emits text to the log upon construction and
|
||
|
// destruction. Place one at the beggining of a lexical scope, and it
|
||
|
// will log when the scope is entered and exited.
|
||
|
|
||
|
// See LOG_SCOPE, LOG_CTOR, LOG_DTOR, LOG_FUNCTION,
|
||
|
// LOG_FUNCTION2
|
||
|
|
||
|
class ScopeTracer
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
// Constructs a new instance, and logs it's creation.
|
||
|
//
|
||
|
// type - the logging type for the log output
|
||
|
//
|
||
|
// message - the text to be emited on construction and destruction
|
||
|
|
||
|
ScopeTracer(
|
||
|
DWORD type,
|
||
|
const String& message);
|
||
|
|
||
|
~ScopeTracer();
|
||
|
|
||
|
private:
|
||
|
|
||
|
String message;
|
||
|
DWORD type;
|
||
|
};
|
||
|
|
||
|
|
||
|
friend class ScopeTracer;
|
||
|
|
||
|
|
||
|
|
||
|
private:
|
||
|
|
||
|
|
||
|
|
||
|
explicit Log(const String& logBaseName);
|
||
|
~Log();
|
||
|
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
AdjustLogMargin(int delta);
|
||
|
|
||
|
|
||
|
|
||
|
String
|
||
|
ComposeSpewLine(const String& text);
|
||
|
|
||
|
|
||
|
|
||
|
// Closes and deletes the single Burnslib::Log instance. If GetInstance
|
||
|
// is called after this point, then a new instance will be created.
|
||
|
|
||
|
static
|
||
|
void
|
||
|
KillInstance();
|
||
|
|
||
|
|
||
|
|
||
|
size_t
|
||
|
GetLogMargin();
|
||
|
|
||
|
|
||
|
|
||
|
void
|
||
|
Indent();
|
||
|
|
||
|
|
||
|
|
||
|
// Returns true if the log file is open, false if not.
|
||
|
|
||
|
bool
|
||
|
IsOpen() const
|
||
|
{
|
||
|
return fileHandle != INVALID_HANDLE_VALUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void
|
||
|
Outdent();
|
||
|
|
||
|
|
||
|
|
||
|
void
|
||
|
ReadLogFlags();
|
||
|
|
||
|
|
||
|
|
||
|
// This does all the work, really.
|
||
|
|
||
|
void
|
||
|
UnguardedWriteLn(DWORD type, const String& text);
|
||
|
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
DebugType()
|
||
|
{
|
||
|
// mask off the HIWORD for now.
|
||
|
|
||
|
return LOWORD(flags);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
bool
|
||
|
ShouldLogToFile()
|
||
|
{
|
||
|
return (flags & OUTPUT_TO_FILE) ? true : false;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool
|
||
|
ShouldAppendLogToFile()
|
||
|
{
|
||
|
return (flags & OUTPUT_APPEND_TO_FILE) ? true : false;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
ShouldLogToDebugger()
|
||
|
{
|
||
|
return (flags & OUTPUT_TO_DEBUGGER) ? true : false;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
bool
|
||
|
ShouldLogToSpewView()
|
||
|
{
|
||
|
return (flags & OUTPUT_TO_SPEWVIEW) ? true : false;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
bool
|
||
|
ShouldLogTimeOfDay()
|
||
|
{
|
||
|
return (flags & OUTPUT_TIME_OF_DAY) ? true : false;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
bool
|
||
|
ShouldLogRunTime()
|
||
|
{
|
||
|
return (flags & OUTPUT_RUN_TIME) ? true : false;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void
|
||
|
WriteHeader();
|
||
|
|
||
|
|
||
|
void
|
||
|
WriteHeaderModule(HMODULE moduleHandle);
|
||
|
|
||
|
|
||
|
|
||
|
String baseName;
|
||
|
HANDLE fileHandle;
|
||
|
DWORD flags;
|
||
|
HANDLE spewviewHandle;
|
||
|
String spewviewPipeName;
|
||
|
unsigned traceLineNumber;
|
||
|
CRITICAL_SECTION critsec;
|
||
|
DWORD logfileMarginTlsIndex;
|
||
|
|
||
|
// not implemented; no instance copying allowed.
|
||
|
Log(const Log&);
|
||
|
const Log& operator=(const Log&);
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
// CODEWORK: purge these aliases
|
||
|
|
||
|
const DWORD OUTPUT_MUTE = Log::OUTPUT_MUTE;
|
||
|
|
||
|
const DWORD OUTPUT_FULL_VOLUME = Log::OUTPUT_FULL_VOLUME;
|
||
|
|
||
|
const DWORD OUTPUT_TYPICAL = Log::OUTPUT_TYPICAL;
|
||
|
|
||
|
|
||
|
|
||
|
} // namespace Burnslib
|
||
|
|
||
|
|
||
|
|
||
|
#ifdef LOGGING_BUILD
|
||
|
|
||
|
|
||
|
// The logging feature offers the ability to cause output spew at the opening
|
||
|
// and closing of a lexical scope. This can be done at arbitrary scope with
|
||
|
// the LOG_SCOPE macro, or (more commonly) at function scope with the
|
||
|
// LOG_FUNCTION/2 macros. Specializations of LOG_FUNCTION include LOG_CTOR/2,
|
||
|
// LOG_DTOR/2, LOG_ADDREF, and LOG_RELEASE. Refer to the following table:
|
||
|
//
|
||
|
// Spew macro Output spewed (spewn?) when this flag is set
|
||
|
//
|
||
|
// LOG_SCOPE OUTPUT_LOGS
|
||
|
// LOG_FUNCTION OUTPUT_FUNCCALLS
|
||
|
// LOG_FUNCTION2 OUTPUT_FUNCCALLS
|
||
|
// LOG_CTOR OUTPUT_CTORS
|
||
|
// LOG_CTOR2 OUTPUT_CTORS
|
||
|
// LOG_DTOR OUTPUT_CTORS
|
||
|
// LOG_DTOR2 OUTPUT_CTORS
|
||
|
// LOG_ADDREF OUTPUT_ADDREFS
|
||
|
// LOG_RELEASE OUTPUT_ADDREFS
|
||
|
// LOG_LOG_EGGS_AND_SPAM_LOG To be implemented
|
||
|
//
|
||
|
// At the point where the LOG macro is executed, if the corresponding flag
|
||
|
// is set, a line starting with "Enter " is output. Subsequent output is then
|
||
|
// indented. At the point where the lexical scope enclosing the macro ends,
|
||
|
// if the OUTPUT_SCOPE_EXIT flag is set, a line starting with "Exit" is
|
||
|
// output. Subsequent output is aligned with the next most recent Enter, i.e.
|
||
|
// outdented.
|
||
|
//
|
||
|
// If the flag corresponding to a LOG macro is not set, then no "Enter" or
|
||
|
// "Exit" lines are output.
|
||
|
|
||
|
|
||
|
#define LOGT(type, msg) \
|
||
|
{ /* open scope */ \
|
||
|
Burnslib::Log* _dlog = Burnslib::Log::GetInstance(); \
|
||
|
if (_dlog) \
|
||
|
{ \
|
||
|
_dlog->WriteLn(type, msg); \
|
||
|
} \
|
||
|
} /* close scope */ \
|
||
|
|
||
|
|
||
|
|
||
|
#define LOG(msg) LOGT(Burnslib::Log::OUTPUT_LOGS, msg)
|
||
|
|
||
|
|
||
|
|
||
|
#define LOG_LAST_WINERROR() \
|
||
|
LOGT( \
|
||
|
Burnslib::Log::OUTPUT_ERRORS, \
|
||
|
String::format( \
|
||
|
L"GetLastError = 0x%1!08X!", \
|
||
|
::GetLastError())) \
|
||
|
\
|
||
|
|
||
|
|
||
|
#define LOG_SCOPET(type, msg) \
|
||
|
Burnslib::Log::ScopeTracer __tracer(type, msg)
|
||
|
|
||
|
|
||
|
|
||
|
#define LOG_SCOPE(msg) \
|
||
|
LOG_SCOPET( \
|
||
|
Burnslib::Log::OUTPUT_LOGS, \
|
||
|
msg)
|
||
|
|
||
|
|
||
|
|
||
|
#define LOG_CTOR(classname) \
|
||
|
LOG_SCOPET(Burnslib::Log::OUTPUT_CTORS, L"ctor: " TEXT(#classname))
|
||
|
|
||
|
|
||
|
|
||
|
#define LOG_CTOR2(classname, msg) \
|
||
|
LOG_SCOPET( \
|
||
|
Burnslib::Log::OUTPUT_CTORS, \
|
||
|
String(L"ctor: " TEXT(#classname) L" ") \
|
||
|
+ String(msg))
|
||
|
|
||
|
|
||
|
|
||
|
#define LOG_DTOR(classname) \
|
||
|
LOG_SCOPET(Burnslib::Log::OUTPUT_CTORS, L"dtor: " TEXT(#classname))
|
||
|
|
||
|
|
||
|
|
||
|
#define LOG_DTOR2(classname, msg) \
|
||
|
LOG_SCOPET( \
|
||
|
Burnslib::Log::OUTPUT_CTORS, \
|
||
|
String(L"dtor: " TEXT(#classname) L" ") \
|
||
|
+ String(msg))
|
||
|
|
||
|
|
||
|
|
||
|
#define LOG_ADDREF(classname) \
|
||
|
LOGT( \
|
||
|
Burnslib::Log::OUTPUT_ADDREFS, \
|
||
|
L"AddRef: " TEXT(#classname))
|
||
|
|
||
|
|
||
|
|
||
|
#define LOG_RELEASE(classname) \
|
||
|
LOGT( \
|
||
|
Burnslib::Log::OUTPUT_ADDREFS, \
|
||
|
L"Release: " TEXT(#classname))
|
||
|
|
||
|
|
||
|
|
||
|
#define LOG_FUNCTION(func) \
|
||
|
LOG_SCOPET( \
|
||
|
Burnslib::Log::OUTPUT_FUNCCALLS, \
|
||
|
TEXT(#func))
|
||
|
|
||
|
|
||
|
|
||
|
#define LOG_FUNCTION2(func, s) \
|
||
|
LOG_SCOPET( \
|
||
|
Burnslib::Log::OUTPUT_FUNCCALLS, \
|
||
|
String(TEXT(#func) L" ").append(s))
|
||
|
|
||
|
|
||
|
|
||
|
#define LOG_HRESULT(hr) \
|
||
|
LOGT( \
|
||
|
Burnslib::Log::OUTPUT_ERRORS, \
|
||
|
String::format(L"HRESULT = 0x%1!08X!", hr))
|
||
|
|
||
|
|
||
|
|
||
|
#define LOG_BOOL(boolexpr) \
|
||
|
LOGT( \
|
||
|
Burnslib::Log::OUTPUT_LOGS, \
|
||
|
String::format( \
|
||
|
L"%1 = %2", \
|
||
|
TEXT(#boolexpr), \
|
||
|
(boolexpr) ? L"true" : L"false"))
|
||
|
|
||
|
|
||
|
|
||
|
#else // LOGGING_BUILD
|
||
|
|
||
|
#define LOGL(type, msg)
|
||
|
#define LOG(msg)
|
||
|
#define LOG_LAST_WINERROR()
|
||
|
|
||
|
#define LOG_SCOPEL(type, msg)
|
||
|
#define LOG_SCOPE(msg)
|
||
|
|
||
|
#define LOG_CTOR(classname)
|
||
|
#define LOG_CTOR2(classname, msg)
|
||
|
#define LOG_DTOR(classname)
|
||
|
#define LOG_DTOR2(classname, msg)
|
||
|
|
||
|
#define LOG_ADDREF(classname)
|
||
|
#define LOG_RELEASE(classname)
|
||
|
|
||
|
#define LOG_FUNCTION(func)
|
||
|
|
||
|
#define LOG_FUNCTION2(func, s)
|
||
|
|
||
|
#define LOG_HRESULT(hr)
|
||
|
#define LOG_BOOL(boolexpr)
|
||
|
|
||
|
#endif // LOGGING_BUILD
|
||
|
|
||
|
|
||
|
|
||
|
#endif // LOG_HPP_INCLUDED
|