windows-nt/Source/XPSP1/NT/admin/burnslib/inc/log.hpp

517 lines
13 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
// 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