#include "stdafx.h" #ifdef _WINDOWS64 #include "Windows64_Log.h" #include #include #include namespace LceLog { static FILE* s_logFile = nullptr; static char s_logPath[MAX_PATH] = {}; static char s_prevLogPath[MAX_PATH] = {}; static void BuildLogPaths() { char exePath[MAX_PATH] = {}; GetModuleFileNameA(nullptr, exePath, MAX_PATH); char* lastSlash = strrchr(exePath, '\\'); if (lastSlash) { *(lastSlash + 1) = '\0'; } char logsDir[MAX_PATH] = {}; _snprintf_s(logsDir, sizeof(logsDir), _TRUNCATE, "%slogs", exePath); // Ensure logs folder exists; ignore failure when it already exists. CreateDirectoryA(logsDir, nullptr); _snprintf_s(s_logPath, sizeof(s_logPath), _TRUNCATE, "%s\\lcelive.log", logsDir); _snprintf_s(s_prevLogPath, sizeof(s_prevLogPath), _TRUNCATE, "%s\\lcelive.previous.log", logsDir); } // --------------------------------------------------------------------------- // Init — open logs\lcelive.log (rotating the previous one). // --------------------------------------------------------------------------- void Init() { BuildLogPaths(); // Rotate: lcelive.log -> lcelive.previous.log if (s_logPath[0] != '\0' && s_prevLogPath[0] != '\0') { remove(s_prevLogPath); rename(s_logPath, s_prevLogPath); } if (fopen_s(&s_logFile, s_logPath, "w") != 0 || !s_logFile) { s_logFile = nullptr; OutputDebugStringA("[LceLog] Failed to open logs\\lcelive.log\n"); return; } // Write header so it's easy to tell sessions apart. SYSTEMTIME st = {}; GetLocalTime(&st); char header[128]; snprintf(header, sizeof(header), "=== LCELive session started %04d-%02d-%02d %02d:%02d:%02d ===\n", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); fputs(header, s_logFile); fflush(s_logFile); } // --------------------------------------------------------------------------- // Shutdown — flush and close. // --------------------------------------------------------------------------- void Shutdown() { if (!s_logFile) return; fputs("=== session ended ===\n", s_logFile); fflush(s_logFile); fclose(s_logFile); s_logFile = nullptr; } // --------------------------------------------------------------------------- // Write — timestamped log entry. Safe to call before Init (silently skipped) // and from any thread (FILE* writes are internally serialised on MSVC CRT). // --------------------------------------------------------------------------- void Write(const char* fmt, ...) { if (!s_logFile && !IsDebuggerPresent()) return; // Build timestamp SYSTEMTIME st = {}; GetLocalTime(&st); char timeBuf[24]; snprintf(timeBuf, sizeof(timeBuf), "%02d:%02d:%02d.%03d", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); // Format the caller's message char msgBuf[2048]; va_list args; va_start(args, fmt); vsnprintf(msgBuf, sizeof(msgBuf) - 1, fmt, args); va_end(args); msgBuf[sizeof(msgBuf) - 1] = '\0'; // Full line: "[HH:MM:SS.mmm] message\n" char line[2048 + 32]; snprintf(line, sizeof(line), "[%s] %s\n", timeBuf, msgBuf); if (s_logFile) { fputs(line, s_logFile); fflush(s_logFile); // flush every write — we want to see crashes } // Also send to VS Output window when a debugger is attached. OutputDebugStringA(line); } } // namespace LceLog #endif // _WINDOWS64