252 lines
7.3 KiB
C++
252 lines
7.3 KiB
C++
/*
|
|
* This is a part of the BugTrap package.
|
|
* Copyright (c) 2005-2009 IntelleSoft.
|
|
* All rights reserved.
|
|
*
|
|
* Description: Base class for custom log file.
|
|
* Author: Maksim Pyatkovskiy.
|
|
*
|
|
* This source code is only intended as a supplement to the
|
|
* BugTrap package reference and related electronic documentation
|
|
* provided with the product. See these sources for detailed
|
|
* information regarding the BugTrap package.
|
|
*/
|
|
|
|
#include "StdAfx.h"
|
|
#include "LogFile.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#endif
|
|
|
|
/**
|
|
* @param dwInitialLogSizeInBytes - initial log file size.
|
|
*/
|
|
CLogFile::CLogFile(void) : m_StrStream(1024)
|
|
{
|
|
*m_szLogFileName = _T('\0');
|
|
m_dwLogEchoMode = BTLE_NONE;
|
|
m_dwLogFlags = BTLF_NONE;
|
|
m_eLogLevel = BTLL_ALL;
|
|
InitializeCriticalSection(&m_csLogFile);
|
|
}
|
|
|
|
/**
|
|
* @return pointer to custom log file name.
|
|
*/
|
|
PCTSTR CLogFile::GetLogFileName(void)
|
|
{
|
|
if (*m_szLogFileName == _T('\0'))
|
|
CompleteLogFileName(NULL);
|
|
return m_szLogFileName;
|
|
}
|
|
|
|
/**
|
|
* @param eLogLevel - log level number.
|
|
* @return log level prefix.
|
|
*/
|
|
PCTSTR CLogFile::GetLogLevelPrefix(BUGTRAP_LOGLEVEL eLogLevel)
|
|
{
|
|
switch (eLogLevel)
|
|
{
|
|
case BTLL_ERROR: return _T("ERROR");
|
|
case BTLL_WARNING: return _T("WARNING");
|
|
case BTLL_IMPORTANT: return _T("IMPORTANT");
|
|
case BTLL_INFO: return _T("INFO");
|
|
case BTLL_VERBOSE: return _T("VERBOSE");
|
|
default: return NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return output console handle.
|
|
*/
|
|
HANDLE CLogFile::GetConsoleHandle(void) const
|
|
{
|
|
HANDLE hConsole;
|
|
if (m_dwLogEchoMode & BTLE_STDOUT)
|
|
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
else if (m_dwLogEchoMode & BTLE_STDERR)
|
|
hConsole = GetStdHandle(STD_ERROR_HANDLE);
|
|
else
|
|
hConsole = NULL;
|
|
return hConsole;
|
|
}
|
|
|
|
/**
|
|
* @param hConsole - console handle.
|
|
*/
|
|
void CLogFile::WriteTextToConsole(HANDLE hConsole)
|
|
{
|
|
DWORD dwTextLength, dwWritten;
|
|
PCTSTR pszText = m_StrStream;
|
|
#ifndef _UNICODE
|
|
UINT uConsoleCP = GetConsoleOutputCP();
|
|
if (uConsoleCP != CP_ACP)
|
|
{
|
|
DWORD dwTextSizeW = MultiByteToWideChar(CP_ACP, 0, pszText, -1, NULL, 0);
|
|
if (m_ConsoleBufferW.GetSize() < dwTextSizeW)
|
|
{
|
|
dwTextSizeW *= 2;
|
|
if (! m_ConsoleBufferW.SetSize(dwTextSizeW))
|
|
return;
|
|
}
|
|
MultiByteToWideChar(CP_ACP, 0, pszText, -1, m_ConsoleBufferW.GetData(), dwTextSizeW);
|
|
DWORD dwTextSizeA = WideCharToMultiByte(uConsoleCP, 0, m_ConsoleBufferW.GetData(), -1, NULL, 0, NULL, NULL);
|
|
if (m_ConsoleBufferA.GetSize() < dwTextSizeA)
|
|
{
|
|
dwTextSizeA *= 2;
|
|
if (! m_ConsoleBufferA.SetSize(dwTextSizeA))
|
|
return;
|
|
}
|
|
dwTextLength = WideCharToMultiByte(uConsoleCP, 0, m_ConsoleBufferW.GetData(), -1, m_ConsoleBufferA.GetData(), dwTextSizeA, NULL, NULL);
|
|
WriteConsoleA(hConsole, m_ConsoleBufferA.GetData(), dwTextLength - 1, &dwWritten, NULL);
|
|
}
|
|
else
|
|
{
|
|
dwTextLength = (DWORD)m_StrStream.GetLength();
|
|
WriteConsoleA(hConsole, pszText, dwTextLength, &dwWritten, NULL);
|
|
}
|
|
#else
|
|
dwTextLength = (DWORD)m_StrStream.GetLength();
|
|
WriteConsole(hConsole, pszText, dwTextLength, &dwWritten, NULL);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @param pSystemTime - pointer to system time.
|
|
* @param pszTimeStatistics - time statistics buffer.
|
|
* @param dwTimeStatisticsSize - size of time statistics buffer.
|
|
*/
|
|
void CLogFile::GetTimeStatistics(const SYSTEMTIME* pSystemTime, PTSTR pszTimeStatistics, DWORD dwTimeStatisticsSize)
|
|
{
|
|
_stprintf_s(pszTimeStatistics, dwTimeStatisticsSize,
|
|
_T("%04d/%02d/%02d %02d:%02d:%02d"),
|
|
pSystemTime->wYear, pSystemTime->wMonth, pSystemTime->wDay, pSystemTime->wHour, pSystemTime->wMinute, pSystemTime->wSecond);
|
|
}
|
|
|
|
/**
|
|
* @param pSystemTime - pointer to system time.
|
|
* @param eLogLevel - log level number.
|
|
* @param pszEntry - log entry text.
|
|
*/
|
|
void CLogFile::FillEntryText(BUGTRAP_LOGLEVEL eLogLevel, const SYSTEMTIME* pSystemTime, PCTSTR pszEntry)
|
|
{
|
|
_ASSERTE(pszEntry != NULL);
|
|
m_StrStream.Reset();
|
|
if (m_dwLogFlags & BTLF_SHOWTIMESTAMP)
|
|
{
|
|
TCHAR szTimeStatistics[32];
|
|
GetTimeStatistics(pSystemTime, szTimeStatistics, countof(szTimeStatistics));
|
|
m_StrStream << _T('[') << szTimeStatistics << _T("] ");
|
|
}
|
|
if (m_dwLogFlags & BTLF_SHOWLOGLEVEL)
|
|
{
|
|
PCTSTR pszLogLevelPrefix = GetLogLevelPrefix(eLogLevel);
|
|
if (pszLogLevelPrefix)
|
|
m_StrStream << pszLogLevelPrefix << _T(": ");
|
|
}
|
|
m_StrStream << pszEntry << _T("\r\n");
|
|
}
|
|
|
|
/**
|
|
* @param pszFormat - format expression.
|
|
* @param argList - variable argument list.
|
|
* @return true if string was formatted.
|
|
*/
|
|
BOOL CLogFile::FormatBufferV(PCTSTR pszFormat, va_list argList)
|
|
{
|
|
DWORD dwFormatBufferSize = m_FormatBuffer.GetSize();
|
|
if (dwFormatBufferSize == 0)
|
|
{
|
|
dwFormatBufferSize = 256;
|
|
if (! m_FormatBuffer.SetSize(dwFormatBufferSize))
|
|
return FALSE;
|
|
}
|
|
for (;;)
|
|
{
|
|
int iResult = _vsntprintf_s(m_FormatBuffer.GetData(), dwFormatBufferSize, _TRUNCATE, pszFormat, argList);
|
|
if (iResult >= 0)
|
|
return TRUE;
|
|
dwFormatBufferSize *= 2;
|
|
if (! m_FormatBuffer.SetSize(dwFormatBufferSize))
|
|
return FALSE;
|
|
_ASSERTE(m_FormatBuffer.GetSize() >= dwFormatBufferSize);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param pszFormat - format expression.
|
|
* @param argList - variable argument list.
|
|
* @return true if string was formatted.
|
|
*/
|
|
BOOL CLogFile::FormatBufferF(PCTSTR pszFormat, ...)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, pszFormat);
|
|
BOOL bResult = FormatBufferV(pszFormat, argList);
|
|
va_end(argList);
|
|
return bResult;
|
|
}
|
|
|
|
/**
|
|
* @param eLogLevel - log level number.
|
|
* @param eEntryMode - entry mode.
|
|
* @param rcsConsoleAccess - provides synchronous access to the console.
|
|
* @param pszFormat - format string.
|
|
* @return true if operation was completed successfully.
|
|
*/
|
|
BOOL CLogFile::WriteLogEntryF(BUGTRAP_LOGLEVEL eLogLevel, ENTRY_MODE eEntryMode, CRITICAL_SECTION& rcsConsoleAccess, PCTSTR pszFormat, ...)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, pszFormat);
|
|
BOOL bResult = WriteLogEntryV(eLogLevel, eEntryMode, rcsConsoleAccess, pszFormat, argList);
|
|
va_end(argList);
|
|
return bResult;
|
|
}
|
|
|
|
/**
|
|
* @param eLogLevel - log level number.
|
|
* @param eEntryMode - entry mode.
|
|
* @param rcsConsoleAccess - provides synchronous access to the console.
|
|
* @param pszFormat - format string.
|
|
* @param argList - variable argument list.
|
|
* @return true if operation was completed successfully.
|
|
*/
|
|
BOOL CLogFile::WriteLogEntryV(BUGTRAP_LOGLEVEL eLogLevel, ENTRY_MODE eEntryMode, CRITICAL_SECTION& rcsConsoleAccess, PCTSTR pszFormat, va_list argList)
|
|
{
|
|
BUGTRAP_LOGLEVEL eLogFileLevel = GetLogLevel();
|
|
if (eLogLevel > eLogFileLevel)
|
|
return TRUE;
|
|
BOOL bResult = FormatBufferV(pszFormat, argList);
|
|
if (bResult)
|
|
bResult = WriteLogEntry(eLogLevel, eEntryMode, rcsConsoleAccess, m_FormatBuffer.GetData());
|
|
return bResult;
|
|
}
|
|
|
|
/**
|
|
* @param eLogLevel - log level number.
|
|
* @param pSystemTime - system time.
|
|
* @param rcsConsoleAccess - provides synchronous access to the console.
|
|
* @param pszEntry - log entry text.
|
|
* @return true if text was written to console.
|
|
*/
|
|
BOOL CLogFile::WriteLogEntryToConsole(BUGTRAP_LOGLEVEL eLogLevel, const SYSTEMTIME* pSystemTime, CRITICAL_SECTION& rcsConsoleAccess, PCTSTR pszEntry)
|
|
{
|
|
DWORD dwLogEchoMode = GetLogEchoMode();
|
|
HANDLE hConsole = GetConsoleHandle();
|
|
BOOL bLogEcho = (dwLogEchoMode & BTLE_DBGOUT) != 0;
|
|
if (hConsole || bLogEcho)
|
|
{
|
|
FillEntryText(eLogLevel, pSystemTime, pszEntry);
|
|
EnterCriticalSection(&rcsConsoleAccess);
|
|
if (hConsole)
|
|
WriteTextToConsole(hConsole);
|
|
if (bLogEcho)
|
|
WriteTextToDebugConsole();
|
|
LeaveCriticalSection(&rcsConsoleAccess);
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|