ciderpress/util/MyDebug.cpp

119 lines
3.8 KiB
C++

/*
* CiderPress
* Copyright (C) 2014 by CiderPress authors. All Rights Reserved.
* See the file LICENSE for distribution terms.
*/
/*
* Debug log support.
*/
#include "stdafx.h"
DebugLog::DebugLog(const WCHAR* logFile)
: fLogFp(NULL)
{
fPid = getpid();
if (logFile == NULL) {
return;
}
PathName debugPath(logFile);
time_t now = time(NULL);
time_t when = debugPath.GetModWhen();
if (when > 0 && now - when > kStaleLog) {
/* log file is more than 8 hours old, remove it */
/* [consider opening it and truncating with chsize() instead, so we
don't hose somebody's custom access permissions. ++ATM 20041015] */
_wunlink(logFile);
}
fLogFp = _wfopen(logFile, L"a");
if (fLogFp == NULL) {
#ifdef _DEBUG
_CrtDbgReport(_CRT_WARN, __FILE__, __LINE__, NULL,
"Unable to open %ls: %d\n", logFile, errno);
#endif
} else {
// disable buffering so we don't lose anything if app crashes
setvbuf(fLogFp, NULL, _IONBF, 0);
fprintf(fLogFp, "\n");
if (when > 0) {
fprintf(fLogFp,
"(Log file was %.3f hours old; logs are reset after %.3f)\n",
(now - when) / 3600.0, kStaleLog / 3600.0);
}
}
}
DebugLog::~DebugLog() {
if (fLogFp != NULL) {
fclose(fLogFp);
}
}
void DebugLog::Log(LogSeverity severity, const char* file, int line,
_Printf_format_string_ const char* format, ...)
{
#ifndef _DEBUG
if (fLogFp == NULL) {
// nothing to do, don't waste time formatting the string
return;
}
#endif
static const char kSeverityChars[] = "?VDIWE";
if (severity < 0 || severity > sizeof(kSeverityChars) - 1) {
severity = LOG_UNKNOWN;
}
if (severity == LOG_VERBOSE) {
// Globally disable. They still get compiled, which helps to
// prevent bit-rot. TODO: be fancier and have LOGV map to
// a do-nothing inline function that the compiler will effectively
// eliminate.
return;
}
va_list argptr;
char textBuf[4096];
// TODO: _vsnprintf() doesn't deal with "%ls" well. If it encounters a
// character it can't translate, it stops and returns -1. This is
// very annoying if you're trying to print a wide-char filename that
// includes characters that aren't in CP-1252.
//
// We can probably fix this by converting "format" to a wide string,
// printing with _vsnwprintf(), and then converting the output back
// to narrow manually (selecting options that prevent it from stopping
// mid-string on failure). As an optimization, we only need to do this
// if the format string includes a "%ls" specifier.
//
// The interpretation of plain "%s" will change if we use a wide printf
// function (it's a Microsoft extension, not ANSI behavior), so we'd also
// want to check for "%s" and complain if we see it. All callers must
// use explicit "%hs" or "%ls".
va_start(argptr, format);
(void) _vsnprintf(textBuf, NELEM(textBuf) - 1, format, argptr);
va_end(argptr);
textBuf[NELEM(textBuf) - 1] = '\0';
if (fLogFp) {
struct tm tmbuf;
time_t now = time(NULL);
localtime_s(&tmbuf, &now);
// The pid is useful when we spawn a new instance of CiderPress
// to handle a disk image or NuFX archive inside an archive. The
// file is opened in "append" mode, so we shouldn't collide.
fprintf(fLogFp, "%02d:%02d:%02d %05u %c %s\n", tmbuf.tm_hour,
tmbuf.tm_min, tmbuf.tm_sec, fPid, kSeverityChars[severity],
textBuf);
}
#ifdef _DEBUG
if (_CrtDbgReport(_CRT_WARN, file, line, NULL, "%s\n", textBuf) == 1) {
// "retry" button causes a debugger break
_CrtDbgBreak();
}
#endif
}