// 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