////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 1997-2000 Microsoft Corporation // // Module Name: // LogSrc.cpp // // Description: // Logging utilities. // // Documentation: // Spec\Admin\Debugging.ppt // // Maintained By: // Galen Barbee (GalenB) 05-DEC-2000 // ////////////////////////////////////////////////////////////////////////////// #include #include #include "Common.h" //**************************************************************************** //**************************************************************************** // // Logging Functions // // These are in both DEBUG and RETAIL. // //**************************************************************************** //**************************************************************************** // // Constants // static const int LOG_OUTPUT_BUFFER_SIZE = 512; // // Globals // CRITICAL_SECTION * g_pcsLogging = NULL; HANDLE g_hLogFile = INVALID_HANDLE_VALUE; ////////////////////////////////////////////////////////////////////////////// //++ // // HRESULT // HrLogOpen( void ) // // Description: // This function: // - initializes the log critical section // - enters the log critical section assuring only one thread is // writing to the log at a time // - creates the directory tree to the log file (if needed) // - initializes the log file by: // - creating a new log file if one doesn't exist. // - opens an existing log file (for append) // - appends a time/date stamp that the log was (re)opened. // // Use LogClose() to exit the log critical section. // // If there is a failure inside this function, the log critical // section will be released before returning. // // Arguments: // None. // // Return Values: // S_OK - log critical section held and log open successfully // Otherwize HRESULT error code. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT HrLogOpen( void ) { TCHAR szFilePath[ MAX_PATH ]; TCHAR szModulePath[ MAX_PATH ]; CHAR szBuffer[ LOG_OUTPUT_BUFFER_SIZE ]; DWORD dwWritten; HANDLE hTemp; BOOL fReturn; HRESULT hr; SYSTEMTIME SystemTime; // // Create a critical section to prevent lines from being fragmented. // if ( g_pcsLogging == NULL ) { PCRITICAL_SECTION pNewCritSect = (PCRITICAL_SECTION) HeapAlloc( GetProcessHeap(), 0, sizeof( CRITICAL_SECTION ) ); if ( pNewCritSect == NULL ) { DebugMsg( "DEBUG: Out of Memory. Logging disabled." ); hr = E_OUTOFMEMORY; goto Cleanup; } // if: creation failed InitializeCriticalSection( pNewCritSect ); // Make sure we only have one log critical section InterlockedCompareExchangePointer( (PVOID *) &g_pcsLogging, pNewCritSect, 0 ); if ( g_pcsLogging != pNewCritSect ) { DebugMsg( "DEBUG: Another thread already created the CS. Deleting this one." ); DeleteCriticalSection( pNewCritSect ); HeapFree( GetProcessHeap(), 0, pNewCritSect ); } // if: already have another critical section } // if: no critical section created yet Assert( g_pcsLogging != NULL ); EnterCriticalSection( g_pcsLogging ); // // Make sure the log file is open // if ( g_hLogFile == INVALID_HANDLE_VALUE ) { DWORD dwLen; LPTSTR psz; // // Create the directory tree // // TODO: 12-DEC-2000 DavidP // Change this to be more generic. This shouldn't be specific // to clustering. // ExpandEnvironmentStrings( TEXT("%windir%\\system32\\LogFiles\\Cluster"), szFilePath, MAX_PATH ); hr = HrCreateDirectoryPath( szFilePath ); if ( FAILED( hr ) ) { #if defined( DEBUG ) if ( !( g_tfModule & mtfOUTPUTTODISK ) ) { DebugMsg( "*ERROR* Failed to create directory tree %s", szFilePath ); } // if: not logging to disk #endif goto Error; } // if: failed // // Add filename // dwLen = GetModuleFileName( g_hInstance, szModulePath, sizeof( szModulePath ) / sizeof( szModulePath[ 0 ] ) ); Assert( dwLen != 0 ); _tcscpy( &szModulePath[ dwLen - 3 ], TEXT("log") ); psz = _tcsrchr( szModulePath, TEXT('\\') ); Assert( psz != NULL ); if ( psz == NULL ) { hr = E_POINTER; goto Error; } _tcscat( szFilePath, psz ); // // Create it // g_hLogFile = CreateFile( szFilePath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL ); if ( g_hLogFile == INVALID_HANDLE_VALUE ) { #if defined( DEBUG ) if ( !( g_tfModule & mtfOUTPUTTODISK ) ) { DebugMsg( "*ERROR* Failed to create log at %s", szFilePath ); } // if: not logging to disk #endif hr = THR( HRESULT_FROM_WIN32( GetLastError() ) ); goto Error; } // if: failed // Seek to the end SetFilePointer( g_hLogFile, 0, NULL, FILE_END ); // // Write the time/date the log was (re)openned. // GetLocalTime( &SystemTime ); _snprintf( szBuffer, sizeof( szBuffer ), "*" ASZ_NEWLINE "* %04u-%02u-%02u %02u:%02u:%02u.%03u" ASZ_NEWLINE "*" ASZ_NEWLINE, SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, SystemTime.wMilliseconds ); fReturn = WriteFile( g_hLogFile, szBuffer, strlen(szBuffer), &dwWritten, NULL ); if ( ! fReturn ) { hr = THR( HRESULT_FROM_WIN32( GetLastError() ) ); goto Error; } // if: failed DebugMsg( "DEBUG: Created log at %s", szFilePath ); } // if: file not already openned hr = S_OK; Cleanup: return hr; Error: DebugMsg( "LogOpen: Failed hr = 0x%08x", hr ); if ( g_hLogFile != INVALID_HANDLE_VALUE ) { CloseHandle( g_hLogFile ); g_hLogFile = INVALID_HANDLE_VALUE; } // if: handle was open LeaveCriticalSection( g_pcsLogging ); goto Cleanup; } //*** HrLogOpen() ////////////////////////////////////////////////////////////////////////////// //++ // // HRESULT // HrLogRelease( void ) // // Description: // This actually just leaves the log critical section. // // Arguments: // None. // // Return Values: // S_OK always. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT HrLogRelease( void ) { Assert( g_pcsLogging != NULL ); LeaveCriticalSection( g_pcsLogging ); return S_OK; } //*** HrLogRelease() ////////////////////////////////////////////////////////////////////////////// //++ // // HRESULT // HrLogClose( void ) // // Description: // Close the file. This function expects the critical section to have // already been released. // // Arguments: // None. // // Return Values: // S_OK always. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT HrLogClose( void ) { TraceFunc( "" ); HRESULT hr = S_OK; if ( g_hLogFile != INVALID_HANDLE_VALUE ) { CloseHandle( g_hLogFile ); g_hLogFile = INVALID_HANDLE_VALUE; } // if: handle was open return hr; } //*** HrLogClose() ////////////////////////////////////////////////////////////////////////////// //++ // // ASCII // // void // LogMsgNoNewline( // LPCSTR pszFormat, // ... // ) // // Description: // Logs a message to the log file without adding a newline. // // Arguments: // pszFormat - A printf format string to be printed. // ,,, - Arguments for the printf string. // // Return Values: // None. // //-- ////////////////////////////////////////////////////////////////////////////// void __cdecl LogMsgNoNewline( LPCSTR pszFormat, ... ) { va_list valist; CHAR szBuf[ LOG_OUTPUT_BUFFER_SIZE ]; DWORD dwWritten; HRESULT hr; #ifdef UNICODE WCHAR szFormat[ LOG_OUTPUT_BUFFER_SIZE ]; WCHAR szTmpBuf[ LOG_OUTPUT_BUFFER_SIZE ]; mbstowcs( szFormat, pszFormat, strlen( pszFormat ) + 1 ); va_start( valist, pszFormat ); wvsprintf( szTmpBuf, szFormat, valist ); va_end( valist ); dwWritten = wcstombs( szBuf, szTmpBuf, wcslen( szTmpBuf ) + 1 ); if ( dwWritten == - 1 ) { dwWritten = strlen( szBuf ); } // if: bad character found #else va_start( valist, pszFormat ); dwWritten = wvsprintf( szBuf, pszFormat, valist ); va_end( valist ); #endif // UNICODE hr = HrLogOpen(); if ( hr != S_OK ) { return; } // if: failed // LogDateTime(); WriteFile( g_hLogFile, szBuf, dwWritten, &dwWritten, NULL ); HrLogRelease(); } //*** LogMsgNoNewline() ASCII ////////////////////////////////////////////////////////////////////////////// //++ // // UNICODE // // void // LogMsgNoNewline( // LPCWSTR pszFormat, // ... // ) // // Description: // Logs a message to the log file without adding a newline. // // Arguments: // pszFormat - A printf format string to be printed. // ,,, - Arguments for the printf string. // // Return Values: // None. // //-- ////////////////////////////////////////////////////////////////////////////// void __cdecl LogMsgNoNewline( LPCWSTR pszFormat, ... ) { va_list valist; CHAR szBuf[ LOG_OUTPUT_BUFFER_SIZE ]; DWORD dwWritten; HRESULT hr; #ifdef UNICODE WCHAR szTmpBuf[ LOG_OUTPUT_BUFFER_SIZE ]; va_start( valist, pszFormat ); wvsprintf( szTmpBuf, pszFormat, valist); va_end( valist ); dwWritten = wcstombs( szBuf, szTmpBuf, wcslen( szTmpBuf ) + 1 ); if ( dwWritten == -1 ) { dwWritten = strlen( szBuf ); } // if: bad character found #else CHAR szFormat[ LOG_OUTPUT_BUFFER_SIZE ]; wcstombs( szFormat, pszFormat, wcslen( pszFormat ) + 1 ); va_start( valist, pszFormat ); dwWritten = wvsprintf( szBuf, szFormat, valist); va_end( valist ); #endif // UNICODE hr = HrLogOpen(); if ( hr != S_OK ) { return; } // if: failed // LogDateTime(); WriteFile( g_hLogFile, szBuf, dwWritten, &dwWritten, NULL ); HrLogRelease(); } //*** LogMsgNoNewline() UNICODE ////////////////////////////////////////////////////////////////////////////// //++ // // void // LogFormatStatusReport( // CHAR ** ppaszBuffer, // int iFirstArg, // ... // ) // // Description: // Formats a status report for writing to the log file. // // Arugments: // // Return Values: // None. // //-- ////////////////////////////////////////////////////////////////////////////// DWORD LogFormatStatusReport( CHAR ** ppaszBuffer, int iFirstArg, ... ) { va_list valist; va_start( valist, iFirstArg ); DWORD dw; dw = FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING, "%2!02u!/%3!02u!/%4!04u!-%5!02u!:%6!02u!:%7!02u!.%8!02u! - %9!02u!/%10!02u!/%11!04u!-%12!02u!:%13!02u!:%14!02u!.%15!02u! {%16!08X!-%17!04X!-%18!04X!-%19!02X!%20!02X!-%21!02X!%22!02X!%23!02X!%24!02X!%25!02X!%26!02X!}, {%27!08X!-%28!04X!-%29!04X!-%30!02X!%31!02X!-%32!02X!%33!02X!%34!02X!%35!02X!%36!02X!%37!02X!} (%38!2d! / %39!2d! .. %40!2d! ) <%41!ws!> hr=%42!08X! %43!ws! %44!ws!" ASZ_NEWLINE, 0, 0, (LPSTR) ppaszBuffer, 256, &valist ); return dw; } //*** LogFormatStatusReport() ////////////////////////////////////////////////////////////////////////////// //++ // // void // LogDateTime( void ) // // Description: // Adds date/time stamp to the log without a CR. This should be done // while holding the Logging critical section which is done by calling // HrLogOpen(). // // Arguments: // None. // // Return Values: // None. // //-- ////////////////////////////////////////////////////////////////////////////// void LogDateTime( void ) { static CHAR szBuffer[ 25 ]; static SYSTEMTIME OldSystemTime = { 0 }; static DWORD dwWritten; SYSTEMTIME SystemTime; DWORD dwWhoCares; int iCmp; GetLocalTime( &SystemTime ); // // Avoid expensive printf by comparing times // iCmp = memcmp( (PVOID) &SystemTime, (PVOID) &OldSystemTime, sizeof( SYSTEMTIME ) ); if ( iCmp != 0 ) { dwWritten = _snprintf( szBuffer, sizeof( szBuffer ), "%04u-%02u-%02u %02u:%02u:%02u.%03u ", SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, SystemTime.wMilliseconds ); Assert( dwWritten < 25 && dwWritten != -1 ); CopyMemory( (PVOID) &OldSystemTime, (PVOID) &SystemTime, sizeof( SYSTEMTIME ) ); } // if: time last different from this time WriteFile( g_hLogFile, szBuffer, dwWritten, &dwWhoCares, NULL ); } //*** LogDateTime() ////////////////////////////////////////////////////////////////////////////// //++ // // void // LogSystemTime( SYSTEMTIME stSystemTimeIn ) // // Description: // Adds date/time stamp to the log without a CR. This should be done // while holding the Logging critical section which is done by calling // HrLogOpen(). // // Arguments: // None. // // Return Values: // None. // //-- ////////////////////////////////////////////////////////////////////////////// void LogSystemTime( SYSTEMTIME * stSystemTimeIn ) { static CHAR szBuffer[ 25 ]; DWORD dwWhoCares; DWORD dwWritten; dwWritten = _snprintf( szBuffer, sizeof( szBuffer ), "%04u-%02u-%02u %02u:%02u:%02u.%03u ", stSystemTimeIn->wYear, stSystemTimeIn->wMonth, stSystemTimeIn->wDay, stSystemTimeIn->wHour, stSystemTimeIn->wMinute, stSystemTimeIn->wSecond, stSystemTimeIn->wMilliseconds ); Assert( dwWritten < 25 && dwWritten != -1 ); WriteFile( g_hLogFile, szBuffer, dwWritten, &dwWhoCares, NULL ); } //*** LogSystemTime() ////////////////////////////////////////////////////////////////////////////// //++ // // ASCII // // void // LogMsg( // LPCSTR pszFormat, // ... // ) // // Description: // Logs a message to the log file and adds a newline. // // Arguments: // pszFormat - A printf format string to be printed. // ,,, - Arguments for the printf string. // // Return Values: // None. // //-- ////////////////////////////////////////////////////////////////////////////// void __cdecl LogMsg( LPCSTR pszFormat, ... ) { va_list valist; CHAR szBuf[ LOG_OUTPUT_BUFFER_SIZE ]; DWORD dwWritten; HRESULT hr; #ifdef UNICODE WCHAR szFormat[ LOG_OUTPUT_BUFFER_SIZE ]; WCHAR szTmpBuf[ LOG_OUTPUT_BUFFER_SIZE ]; mbstowcs( szFormat, pszFormat, strlen( pszFormat ) + 1 ); va_start( valist, pszFormat ); wvsprintf( szTmpBuf, szFormat, valist); va_end( valist ); dwWritten = wcstombs( szBuf, szTmpBuf, wcslen( szTmpBuf ) + 1 ); if ( dwWritten == - 1 ) { dwWritten = strlen( szBuf ); } // if: bad character found #else va_start( valist, pszFormat ); dwWritten = wvsprintf( szBuf, pszFormat, valist); va_end( valist ); #endif // UNICODE hr = HrLogOpen(); if ( FAILED( hr ) ) goto Cleanup; LogDateTime(); WriteFile( g_hLogFile, szBuf, dwWritten, &dwWritten, NULL ); WriteFile( g_hLogFile, ASZ_NEWLINE, SIZEOF_ASZ_NEWLINE, &dwWritten, NULL ); HrLogRelease(); Cleanup: return; } //*** LogMsg() ASCII ////////////////////////////////////////////////////////////////////////////// //++ // // UNICODE // // void // LogMsg( // LPCWSTR pszFormat, // ... // ) // // Description: // Logs a message to the log file and adds a newline. // // Arguments: // pszFormat - A printf format string to be printed. // ,,, - Arguments for the printf string. // // Return Values: // None. // //-- ////////////////////////////////////////////////////////////////////////////// void __cdecl LogMsg( LPCWSTR pszFormat, ... ) { va_list valist; CHAR szBuf[ LOG_OUTPUT_BUFFER_SIZE ]; DWORD dwWritten; HRESULT hr; #ifdef UNICODE WCHAR szTmpBuf[ LOG_OUTPUT_BUFFER_SIZE ]; va_start( valist, pszFormat ); wvsprintf( szTmpBuf, pszFormat, valist); va_end( valist ); dwWritten = wcstombs( szBuf, szTmpBuf, wcslen( szTmpBuf ) + 1 ); if ( dwWritten == -1 ) { dwWritten = strlen( szBuf ); } // if: bad character found #else CHAR szFormat[ LOG_OUTPUT_BUFFER_SIZE ]; wcstombs( szFormat, pszFormat, wcslen( pszFormat ) + 1 ); va_start( valist, pszFormat ); dwWritten = wvsprintf( szBuf, szFormat, valist); va_end( valist ); #endif // UNICODE hr = HrLogOpen(); if ( FAILED( hr ) ) goto Cleanup; LogDateTime(); WriteFile( g_hLogFile, szBuf, dwWritten, &dwWritten, NULL ); WriteFile( g_hLogFile, ASZ_NEWLINE, SIZEOF_ASZ_NEWLINE, &dwWritten, NULL ); HrLogRelease(); Cleanup: return; } //*** LogMsg() UNICODE ////////////////////////////////////////////////////////////////////////////// //++ // // void // LogStatusReport( // SYSTEMTIME * pstTimeIn, // const WCHAR * pcszNodeNameIn, // CLSID clsidTaskMajorIn, // CLSID clsidTaskMinorIn, // ULONG ulMinIn, // ULONG ulMaxIn, // ULONG ulCurrentIn, // HRESULT hrStatusIn, // const WCHAR * pcszDescriptionIn, // const WCHAR * pcszUrlIn // ) // // Description: // Writes a status report to the log file. // // Arugments: // // Return Values: // None. // //-- ////////////////////////////////////////////////////////////////////////////// void LogStatusReport( SYSTEMTIME * pstTimeIn, const WCHAR * pcszNodeNameIn, CLSID clsidTaskMajorIn, CLSID clsidTaskMinorIn, ULONG ulMinIn, ULONG ulMaxIn, ULONG ulCurrentIn, HRESULT hrStatusIn, const WCHAR * pcszDescriptionIn, const WCHAR * pcszUrlIn ) { HRESULT hr; DWORD dw; DWORD dwWritten; unsigned long dwArray[50]; CHAR * paszBuffer = NULL; SYSTEMTIME SystemTime; SYSTEMTIME SystemTime2; GetLocalTime( &SystemTime ); if ( pstTimeIn ) { memcpy( &SystemTime2, pstTimeIn, sizeof( SYSTEMTIME ) ); } else { memset( &SystemTime2, 0, sizeof( SYSTEMTIME) ); } dw = LogFormatStatusReport( &paszBuffer, 0, 0, // Time One. SystemTime.wMonth, //1 SystemTime.wDay, //2 SystemTime.wYear, //3 SystemTime.wHour, //4 SystemTime.wMinute, //5 SystemTime.wSecond, //6 SystemTime.wMilliseconds, //7 // Time Two SystemTime2.wMonth, SystemTime2.wDay, SystemTime2.wYear, SystemTime2.wHour, SystemTime2.wMinute, SystemTime2.wSecond, SystemTime2.wMilliseconds, // GUID One clsidTaskMajorIn.Data1, clsidTaskMajorIn.Data2, clsidTaskMajorIn.Data3, clsidTaskMajorIn.Data4[0], clsidTaskMajorIn.Data4[1], clsidTaskMajorIn.Data4[2], clsidTaskMajorIn.Data4[3], clsidTaskMajorIn.Data4[4], clsidTaskMajorIn.Data4[5], clsidTaskMajorIn.Data4[6], clsidTaskMajorIn.Data4[7], // GUID Two clsidTaskMinorIn.Data1, clsidTaskMinorIn.Data2, clsidTaskMinorIn.Data3, clsidTaskMinorIn.Data4[0], clsidTaskMinorIn.Data4[1], clsidTaskMinorIn.Data4[2], clsidTaskMinorIn.Data4[3], clsidTaskMinorIn.Data4[4], clsidTaskMinorIn.Data4[5], clsidTaskMinorIn.Data4[6], clsidTaskMinorIn.Data4[7], // Other... ulCurrentIn, ulMinIn, ulMaxIn, pcszNodeNameIn, hrStatusIn, pcszDescriptionIn, pcszUrlIn, 0, 0 ); // Open the log file. hr = HrLogOpen(); if ( hr != S_OK ) { return; } // if: failed // Write the initial output. WriteFile( g_hLogFile, paszBuffer, dw, &dwWritten, NULL ); HrLogRelease(); LocalFree( paszBuffer ); } //*** LogStatusReport ////////////////////////////////////////////////////////////////////////////// //++ // // void // LogTerminateProcess( void ) // // Description: // Cleans up anything the logging routines may have created or // initialized. Typical called from the TraceTerminateProcess() macro. // // Arugments: // None. // // Return Values: // None. // //-- ////////////////////////////////////////////////////////////////////////////// void LogTerminateProcess( void ) { } //*** LogTerminateProcess()