forked from aya/aya
Initial commit
This commit is contained in:
635
client/common/CrashManager.cpp
Normal file
635
client/common/CrashManager.cpp
Normal file
@@ -0,0 +1,635 @@
|
||||
#ifndef AYA_STUDIO
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
#include "format_string.hpp"
|
||||
#include "AyaFormat.hpp"
|
||||
#include "Debug.hpp"
|
||||
#include "boost.hpp"
|
||||
#include "Utility/StandardOut.hpp"
|
||||
#include "Utility/FileSystem.hpp"
|
||||
#include "Utility/Guid.hpp"
|
||||
#include "Utility/Http.hpp"
|
||||
#include "Utility/Statistics.hpp"
|
||||
|
||||
#include "debugAssert.hpp"
|
||||
#include <direct.h>
|
||||
|
||||
#include "atltime.h"
|
||||
#include "atlfile.h"
|
||||
|
||||
#include "TaskScheduler.hpp"
|
||||
#include "DumpErrorUploader.hpp"
|
||||
#include "Log.hpp"
|
||||
#include "FastLog.hpp"
|
||||
#include <Windows.h>
|
||||
#include <DbgHelp.h>
|
||||
#include <string.h>
|
||||
#include <atlbase.h>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
LOGGROUP(CrashReporterInit)
|
||||
|
||||
bool LogManager::logsEnabled = false; // to be honest we only really need crash dmps & the logs outputted are not working
|
||||
|
||||
MainLogManager* LogManager::mainLogManager = NULL;
|
||||
|
||||
Aya::mutex MainLogManager::fastLogChannelsLock;
|
||||
|
||||
static const ATL::CPath& DoGetPath()
|
||||
{
|
||||
static ATL::CPath path(CString(Aya::FileSystem::getUserDirectory(true, Aya::DirAppData, "logs").native().c_str()));
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
void InitPath()
|
||||
{
|
||||
DoGetPath();
|
||||
}
|
||||
|
||||
std::string GetAppVersion()
|
||||
{
|
||||
CVersionInfo vi;
|
||||
FASTLOG1(FLog::CrashReporterInit, "Getting app version, module handle: %p", _AtlBaseModule.m_hInst);
|
||||
vi.Load(_AtlBaseModule.m_hInst);
|
||||
return vi.GetFileVersionAsString();
|
||||
}
|
||||
|
||||
const ATL::CPath& LogManager::GetLogPath() const
|
||||
{
|
||||
static boost::once_flag flag = BOOST_ONCE_INIT;
|
||||
boost::call_once(&InitPath, flag);
|
||||
return DoGetPath();
|
||||
}
|
||||
|
||||
const std::string LogManager::GetLogPathString() const
|
||||
{
|
||||
CStringA path = (LPCTSTR)GetLogPath();
|
||||
return std::string(path.GetString());
|
||||
}
|
||||
|
||||
void MainLogManager::fastLogMessage(FLog::Channel id, const char* message)
|
||||
{
|
||||
Aya::mutex::scoped_lock lock(fastLogChannelsLock);
|
||||
|
||||
if (mainLogManager)
|
||||
{
|
||||
if (id >= mainLogManager->fastLogChannels.size())
|
||||
mainLogManager->fastLogChannels.resize(id + 1, NULL);
|
||||
|
||||
if (mainLogManager->fastLogChannels[id] == NULL)
|
||||
{
|
||||
|
||||
mainLogManager->fastLogChannels[id] = new Aya::Log(mainLogManager->getFastLogFileName(id).c_str(), "Log Channel");
|
||||
}
|
||||
|
||||
mainLogManager->fastLogChannels[id]->writeEntry(Aya::Log::Information, message);
|
||||
}
|
||||
}
|
||||
|
||||
std::string MainLogManager::getSessionId()
|
||||
{
|
||||
std::string id = guid;
|
||||
return id;
|
||||
}
|
||||
|
||||
std::string MainLogManager::getCrashEventName()
|
||||
{
|
||||
#ifdef WIN32
|
||||
FASTLOG(FLog::CrashReporterInit, "Getting crash event name");
|
||||
std::string path = GetLogPathString();
|
||||
|
||||
std::string fileName = "log_";
|
||||
fileName += getSessionId();
|
||||
fileName += " ";
|
||||
|
||||
fileName += GetAppVersion();
|
||||
fileName += crashEventExtention;
|
||||
|
||||
path.append(fileName);
|
||||
|
||||
return path;
|
||||
#endif
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string MainLogManager::getLogFileName()
|
||||
{
|
||||
#ifdef WIN32
|
||||
std::string path = GetLogPathString();
|
||||
|
||||
std::string fileName = "log_";
|
||||
fileName += getSessionId();
|
||||
fileName += ".txt";
|
||||
|
||||
path.append(fileName);
|
||||
|
||||
return path;
|
||||
#endif
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string MainLogManager::getFastLogFileName(FLog::Channel channelId)
|
||||
{
|
||||
#ifdef WIN32
|
||||
std::string path = GetLogPathString();
|
||||
std::string filename = Aya::format("log_%s_%d.txt", getSessionId().c_str(), channelId);
|
||||
|
||||
path.append(filename);
|
||||
|
||||
return path;
|
||||
#endif
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
std::string MainLogManager::MakeLogFileName(const char* postfix)
|
||||
{
|
||||
#ifdef WIN32
|
||||
std::string path = GetLogPathString();
|
||||
|
||||
std::string fileName = "log_";
|
||||
fileName += getSessionId();
|
||||
fileName += postfix;
|
||||
fileName += ".txt";
|
||||
|
||||
path.append(fileName);
|
||||
|
||||
return path;
|
||||
#endif
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string ThreadLogManager::getLogFileName()
|
||||
{
|
||||
#ifdef WIN32
|
||||
std::string fileName = mainLogManager->getLogFileName();
|
||||
std::string id = Aya::format("_%s_%d", name.c_str(), threadID);
|
||||
fileName.insert(fileName.size() - 4, id);
|
||||
return fileName;
|
||||
#endif
|
||||
return "";
|
||||
}
|
||||
|
||||
Aya::Log* LogManager::getLog()
|
||||
{
|
||||
if (!logsEnabled)
|
||||
return NULL;
|
||||
if (log == NULL)
|
||||
{
|
||||
log = new Aya::Log(getLogFileName().c_str(), name.c_str());
|
||||
// TODO: delete an old log that isn't in use
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
|
||||
Aya::Log* MainLogManager::provideLog()
|
||||
{
|
||||
if (GetCurrentThreadId() == threadID)
|
||||
return this->getLog();
|
||||
|
||||
return ThreadLogManager::getCurrent()->getLog();
|
||||
}
|
||||
|
||||
|
||||
#include <process.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
|
||||
#define MAX_CONSOLE_LINES 250;
|
||||
|
||||
HANDLE g_hConsoleOut; // Handle to debug console
|
||||
|
||||
|
||||
|
||||
RobloxCrashReporter::RobloxCrashReporter(const char* outputPath, const char* appName, const char* crashExtention)
|
||||
{
|
||||
controls.minidumpType = MiniDumpWithDataSegs;
|
||||
|
||||
controls.minidumpType |= MiniDumpWithIndirectlyReferencedMemory;
|
||||
|
||||
// null terminate just in case long paths & make safe
|
||||
strncpy(controls.pathToMinidump, outputPath, sizeof(controls.pathToMinidump) - 1);
|
||||
controls.pathToMinidump[sizeof(controls.pathToMinidump) - 1] = '\0';
|
||||
|
||||
strncpy(controls.appName, appName, sizeof(controls.appName) - 1);
|
||||
controls.appName[sizeof(controls.appName) - 1] = '\0';
|
||||
|
||||
strncpy(controls.appVersion, GetAppVersion().c_str(), sizeof(controls.appVersion) - 1);
|
||||
controls.appVersion[sizeof(controls.appVersion) - 1] = '\0';
|
||||
|
||||
strncpy(controls.crashExtention, crashExtention, sizeof(controls.crashExtention) - 1);
|
||||
controls.crashExtention[sizeof(controls.crashExtention) - 1] = '\0';
|
||||
}
|
||||
|
||||
bool RobloxCrashReporter::silent;
|
||||
|
||||
LONG RobloxCrashReporter::ProcessException(struct _EXCEPTION_POINTERS* info, bool noMsg)
|
||||
{
|
||||
LogManager::ReportEvent(EVENTLOG_INFORMATION_TYPE, "StartProcessException...");
|
||||
|
||||
LONG result = __super::ProcessException(info, noMsg);
|
||||
static bool showedMessage = silent;
|
||||
if (!showedMessage && !noMsg)
|
||||
{
|
||||
showedMessage = true;
|
||||
::MessageBoxA(NULL, "An unexpected error occurred and " AYA_PROJECT_NAME " needs to quit. We're sorry!", AYA_PROJECT_NAME " Crash", MB_OK);
|
||||
}
|
||||
|
||||
LogManager::ReportEvent(EVENTLOG_INFORMATION_TYPE, "DoneProcessException");
|
||||
|
||||
LogManager::ReportEvent(EVENTLOG_INFORMATION_TYPE, "Uploading .crashevent...");
|
||||
DumpErrorUploader::UploadCrashEventFile(info);
|
||||
LogManager::ReportEvent(EVENTLOG_INFORMATION_TYPE, "Done uploading .crashevent...");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void RobloxCrashReporter::logEvent(const char* msg)
|
||||
{
|
||||
LogManager::ReportEvent(EVENTLOG_INFORMATION_TYPE, msg);
|
||||
}
|
||||
|
||||
void MainLogManager::WriteCrashDump()
|
||||
{
|
||||
std::string appName = "log_";
|
||||
appName += getSessionId();
|
||||
crashReporter.reset(new RobloxCrashReporter(GetLogPathString().c_str(), appName.c_str(), crashExtention));
|
||||
crashReporter->Start();
|
||||
};
|
||||
|
||||
bool MainLogManager::CreateFakeCrashDump()
|
||||
{
|
||||
if (!crashReporter)
|
||||
{
|
||||
// start the service if not started.
|
||||
WriteCrashDump();
|
||||
}
|
||||
|
||||
// First, write FastLog
|
||||
char dumpFilepath[_MAX_PATH];
|
||||
if (FAILED(crashReporter->GenerateDmpFileName(dumpFilepath, _MAX_PATH, true)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FLog::WriteFastLogDump(dumpFilepath, 2000);
|
||||
|
||||
if (FAILED(crashReporter->GenerateDmpFileName(dumpFilepath, _MAX_PATH)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
HANDLE hFile = CreateFileA(dumpFilepath, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD cb;
|
||||
WriteFile(hFile, "Fake", 5, &cb, NULL);
|
||||
|
||||
CloseHandle(hFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainLogManager::EnableImmediateCrashUpload(bool enabled)
|
||||
{
|
||||
if (crashReporter)
|
||||
{
|
||||
crashReporter->EnableImmediateUpload(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void MainLogManager::DisableHangReporting()
|
||||
{
|
||||
if (crashReporter)
|
||||
{
|
||||
crashReporter->DisableHangReporting();
|
||||
}
|
||||
}
|
||||
|
||||
void MainLogManager::NotifyFGThreadAlive()
|
||||
{
|
||||
if (crashReporter)
|
||||
{
|
||||
#if 0
|
||||
// for debugging only:
|
||||
static int alivecount = 0;
|
||||
if(alivecount++ % 60 == 0)
|
||||
{
|
||||
CString eventMessage;
|
||||
eventMessage.Format("FGAlive %d", alivecount);
|
||||
LogManager::ReportEvent(EVENTLOG_INFORMATION_TYPE, eventMessage);
|
||||
}
|
||||
#endif
|
||||
|
||||
crashReporter->NotifyAlive();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void purecallHandler(void)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
_CrtDbgBreak();
|
||||
#endif
|
||||
// Cause a crash
|
||||
AYACRASH();
|
||||
}
|
||||
|
||||
MainLogManager::MainLogManager(LPCTSTR productName, const char* crashExtention, const char* crashEventExtention)
|
||||
: LogManager("Aya")
|
||||
, crashExtention(crashExtention)
|
||||
, crashEventExtention(crashEventExtention)
|
||||
, gameState(MainLogManager::GameState::UN_INITIALIZED)
|
||||
{
|
||||
Aya::Guid::generateRBXGUID(guid);
|
||||
|
||||
AYAASSERT(mainLogManager == NULL);
|
||||
mainLogManager = this;
|
||||
|
||||
Aya::Log::setLogProvider(this);
|
||||
|
||||
Aya::setAssertionHook(&MainLogManager::handleDebugAssert);
|
||||
Aya::setFailureHook(&MainLogManager::handleFailure);
|
||||
|
||||
_set_purecall_handler(purecallHandler);
|
||||
|
||||
FLog::SetExternalLogFunc(fastLogMessage);
|
||||
}
|
||||
|
||||
MainLogManager* LogManager::getMainLogManager()
|
||||
{
|
||||
return mainLogManager;
|
||||
}
|
||||
|
||||
|
||||
ThreadLogManager::ThreadLogManager()
|
||||
: LogManager(Aya::get_thread_name())
|
||||
{
|
||||
}
|
||||
|
||||
ThreadLogManager::~ThreadLogManager() {}
|
||||
|
||||
static float getThisYearTimeInMinutes(SYSTEMTIME time)
|
||||
{
|
||||
return (time.wMonth * 43829.0639f) + (time.wDay * 1440) + (time.wHour * 60) + time.wMinute;
|
||||
}
|
||||
|
||||
MainLogManager::~MainLogManager()
|
||||
{
|
||||
Aya::mutex::scoped_lock lock(fastLogChannelsLock);
|
||||
|
||||
FLog::SetExternalLogFunc(NULL);
|
||||
|
||||
for (std::size_t i = 0; i < fastLogChannels.size(); i++)
|
||||
delete fastLogChannels[i];
|
||||
|
||||
mainLogManager = NULL;
|
||||
}
|
||||
|
||||
|
||||
LogManager::~LogManager()
|
||||
{
|
||||
if (log != NULL)
|
||||
{
|
||||
std::string logFile = log->logFile;
|
||||
delete log; // this will close the file so that we can move it
|
||||
log = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
inline HRESULT WINAPI RbxReportError(
|
||||
const CLSID& clsid, LPCSTR lpszDesc, DWORD dwHelpID, LPCSTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0)
|
||||
{
|
||||
ATLASSERT(lpszDesc != NULL);
|
||||
if (lpszDesc == NULL)
|
||||
return E_POINTER;
|
||||
|
||||
USES_CONVERSION_EX;
|
||||
CString strDesc(lpszDesc);
|
||||
CComBSTR desc = strDesc.AllocSysString(); // Convert CString to BSTR
|
||||
if (desc == NULL)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
CComBSTR helpFile = NULL;
|
||||
if (lpszHelpFile != NULL)
|
||||
{
|
||||
CString strHelpFile(lpszHelpFile);
|
||||
helpFile = strHelpFile.AllocSysString(); // Convert CString to BSTR
|
||||
if (helpFile == NULL)
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
return AtlSetErrorInfo(clsid, desc.Detach(), dwHelpID, helpFile.Detach(), iid, hRes, NULL);
|
||||
}
|
||||
|
||||
inline HRESULT WINAPI RbxReportError(
|
||||
const CLSID& clsid, UINT nID, const IID& iid = GUID_NULL, HRESULT hRes = 0, HINSTANCE hInst = _AtlBaseModule.GetResourceInstance())
|
||||
{
|
||||
return AtlSetErrorInfo(clsid, (LPCOLESTR)MAKEINTRESOURCE(nID), 0, NULL, iid, hRes, hInst);
|
||||
}
|
||||
|
||||
inline HRESULT WINAPI RbxReportError(const CLSID& clsid, UINT nID, DWORD dwHelpID, LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL,
|
||||
HRESULT hRes = 0, HINSTANCE hInst = _AtlBaseModule.GetResourceInstance())
|
||||
{
|
||||
return AtlSetErrorInfo(clsid, (LPCOLESTR)MAKEINTRESOURCE(nID), dwHelpID, lpszHelpFile, iid, hRes, hInst);
|
||||
}
|
||||
|
||||
inline HRESULT WINAPI RbxReportError(const CLSID& clsid, LPCSTR lpszDesc, const IID& iid = GUID_NULL, HRESULT hRes = 0)
|
||||
{
|
||||
return RbxReportError(clsid, lpszDesc, 0, NULL, iid, hRes);
|
||||
}
|
||||
|
||||
inline HRESULT WINAPI RbxReportError(const CLSID& clsid, LPCOLESTR lpszDesc, const IID& iid = GUID_NULL, HRESULT hRes = 0)
|
||||
{
|
||||
return AtlSetErrorInfo(clsid, lpszDesc, 0, NULL, iid, hRes, NULL);
|
||||
}
|
||||
|
||||
inline HRESULT WINAPI RbxReportError(
|
||||
const CLSID& clsid, LPCOLESTR lpszDesc, DWORD dwHelpID, LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0)
|
||||
{
|
||||
return AtlSetErrorInfo(clsid, lpszDesc, dwHelpID, lpszHelpFile, iid, hRes, NULL);
|
||||
}
|
||||
|
||||
HRESULT LogManager::ReportCOMError(const CLSID& clsid, LPCOLESTR lpszDesc, HRESULT hRes)
|
||||
{
|
||||
return RbxReportError(clsid, lpszDesc, GUID_NULL, hRes);
|
||||
}
|
||||
|
||||
HRESULT LogManager::ReportCOMError(const CLSID& clsid, LPCSTR lpszDesc, HRESULT hRes)
|
||||
{
|
||||
return RbxReportError(clsid, lpszDesc, GUID_NULL, hRes);
|
||||
}
|
||||
|
||||
HRESULT LogManager::ReportCOMError(const CLSID& clsid, HRESULT hRes)
|
||||
{
|
||||
std::string message = Aya::format("HRESULT 0x%X", hRes);
|
||||
LogManager::ReportEvent(EVENTLOG_ERROR_TYPE, message.c_str());
|
||||
return RbxReportError(clsid, message.c_str(), GUID_NULL, hRes);
|
||||
}
|
||||
|
||||
#ifdef _MFC_VER
|
||||
HRESULT LogManager::ReportCOMError(const CLSID& clsid, CException* exception)
|
||||
{
|
||||
CString fullError;
|
||||
HRESULT hr = COleException::Process(exception);
|
||||
CString sError;
|
||||
if (exception->GetErrorMessage(sError.GetBuffer(1024), 1023))
|
||||
{
|
||||
sError.ReleaseBuffer();
|
||||
fullError.Format("%s (0x%X)", sError, hr);
|
||||
}
|
||||
else
|
||||
fullError.Format("Error 0x%X", hr);
|
||||
|
||||
LogManager::ReportEvent(EVENTLOG_ERROR_TYPE, fullError);
|
||||
return RbxReportError(clsid, fullError, GUID_NULL, hr);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool MainLogManager::handleG3DDebugAssert(
|
||||
const char* _expression, const std::string& message, const char* filename, int lineNumber, bool useGuiPrompt)
|
||||
{
|
||||
return handleDebugAssert(_expression, filename, lineNumber);
|
||||
}
|
||||
|
||||
bool MainLogManager::handleDebugAssert(const char* expression, const char* filename, int lineNumber)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
LogManager::ReportEvent(EVENTLOG_WARNING_TYPE,
|
||||
std::string("Assertion failed: " + std::string(expression) + "\n" + std::string(filename) + "(" + std::to_string(lineNumber) + ")").c_str());
|
||||
AYACRASH();
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool MainLogManager::handleG3DFailure(const char* _expression, const std::string& message, const char* filename, int lineNumber, bool useGuiPrompt)
|
||||
{
|
||||
return handleFailure(_expression, filename, lineNumber);
|
||||
}
|
||||
bool MainLogManager::handleFailure(const char* expression, const char* filename, int lineNumber)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
_CrtDbgBreak();
|
||||
#endif
|
||||
// Cause a crash
|
||||
AYACRASH();
|
||||
return false;
|
||||
}
|
||||
|
||||
HRESULT LogManager::ReportExceptionAsCOMError(const CLSID& clsid, std::exception const& exp)
|
||||
{
|
||||
return ReportCOMError(clsid, exp.what());
|
||||
}
|
||||
|
||||
void LogManager::ReportException(std::exception const& exp)
|
||||
{
|
||||
Aya::StandardOut::singleton()->print(Aya::MESSAGE_ERROR, exp);
|
||||
}
|
||||
|
||||
void LogManager::ReportLastError(LPCSTR message)
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
Aya::StandardOut::singleton()->printf(Aya::MESSAGE_ERROR, "%s, GetLastError=%d", message, error);
|
||||
}
|
||||
|
||||
void LogManager::ReportEvent(WORD type, LPCSTR message)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case EVENTLOG_SUCCESS:
|
||||
Aya::StandardOut::singleton()->printf(Aya::MESSAGE_INFO, "%s", message);
|
||||
break;
|
||||
case EVENTLOG_ERROR_TYPE:
|
||||
Aya::StandardOut::singleton()->printf(Aya::MESSAGE_ERROR, "%s", message);
|
||||
break;
|
||||
case EVENTLOG_INFORMATION_TYPE:
|
||||
Aya::StandardOut::singleton()->printf(Aya::MESSAGE_INFO, "%s", message);
|
||||
break;
|
||||
case EVENTLOG_AUDIT_SUCCESS:
|
||||
Aya::StandardOut::singleton()->printf(Aya::MESSAGE_INFO, "%s", message);
|
||||
break;
|
||||
case EVENTLOG_AUDIT_FAILURE:
|
||||
Aya::StandardOut::singleton()->printf(Aya::MESSAGE_ERROR, "%s", message);
|
||||
break;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
switch (type)
|
||||
{
|
||||
case EVENTLOG_SUCCESS:
|
||||
ATLTRACE("EVENTLOG_SUCCESS %s\n", message);
|
||||
break;
|
||||
case EVENTLOG_ERROR_TYPE:
|
||||
ATLTRACE("EVENTLOG_ERROR_TYPE %s\n", message);
|
||||
break;
|
||||
case EVENTLOG_INFORMATION_TYPE:
|
||||
ATLTRACE("EVENTLOG_INFORMATION_TYPE %s\n", message);
|
||||
break;
|
||||
case EVENTLOG_AUDIT_SUCCESS:
|
||||
ATLTRACE("EVENTLOG_AUDIT_SUCCESS %s\n", message);
|
||||
break;
|
||||
case EVENTLOG_AUDIT_FAILURE:
|
||||
ATLTRACE("EVENTLOG_AUDIT_FAILURE %s\n", message);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LogManager::ReportEvent(WORD type, LPCSTR message, LPCSTR fileName, int lineNumber)
|
||||
{
|
||||
// CString m;
|
||||
// m.Format(convert_s2w("%s\n%s(%d)"), message, fileName, lineNumber);
|
||||
// LogManager::ReportEvent(type, m);
|
||||
}
|
||||
|
||||
#ifdef _MFC_VER
|
||||
void LogManager::ReportEvent(WORD type, HRESULT hr, LPCSTR fileName, int lineNumber)
|
||||
{
|
||||
COleException e;
|
||||
e.m_sc = hr;
|
||||
TCHAR s[1024];
|
||||
e.GetErrorMessage(s, 1024);
|
||||
|
||||
CString m;
|
||||
m.Format("HRESULT = %d: %s\n%s(%d)", hr, s, fileName, lineNumber);
|
||||
LogManager::ReportEvent(type, m);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace log_detail
|
||||
{
|
||||
boost::once_flag once_init = BOOST_ONCE_INIT;
|
||||
static boost::thread_specific_ptr<ThreadLogManager>* ts;
|
||||
void init(void)
|
||||
{
|
||||
static boost::thread_specific_ptr<ThreadLogManager> value;
|
||||
ts = &value;
|
||||
}
|
||||
} // namespace log_detail
|
||||
|
||||
ThreadLogManager* ThreadLogManager::getCurrent()
|
||||
{
|
||||
boost::call_once(log_detail::init, log_detail::once_init);
|
||||
ThreadLogManager* logManager = log_detail::ts->get();
|
||||
if (!logManager)
|
||||
{
|
||||
logManager = new ThreadLogManager();
|
||||
log_detail::ts->reset(logManager);
|
||||
}
|
||||
return logManager;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user