diff --git a/include/logger.hpp b/include/logger.hpp index cf356019..08ac5cb9 100644 --- a/include/logger.hpp +++ b/include/logger.hpp @@ -36,6 +36,10 @@ void destroy(); Thread-safe, meaning messages cannot overlap each other in the log. */ void log(Level level, const char* filename, int line, const char* format, ...); +/** Returns whether the current log file failed to end properly, due to a possible crash. +Must be called *before* init(). +*/ +bool isTruncated(); } // namespace logger diff --git a/src/logger.cpp b/src/logger.cpp index 3ed88790..94d7c6af 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -18,17 +18,19 @@ void init() { startTime = system::getNanoseconds(); if (settings::devMode) { outputFile = stderr; - return; } - - outputFile = fopen(asset::logPath.c_str(), "w"); - if (!outputFile) { - fprintf(stderr, "Could not open log at %s\n", asset::logPath.c_str()); + else { + outputFile = fopen(asset::logPath.c_str(), "w"); + if (!outputFile) { + fprintf(stderr, "Could not open log at %s\n", asset::logPath.c_str()); + } } } void destroy() { - if (outputFile != stderr) { + if (outputFile && outputFile != stderr) { + // Print end token so we know if the logger exited cleanly. + fprintf(outputFile, "END"); fclose(outputFile); } } @@ -49,6 +51,8 @@ static const int levelColors[] = { static void logVa(Level level, const char* filename, int line, const char* format, va_list args) { std::lock_guard lock(logMutex); + if (!outputFile) + return; int64_t nowTime = system::getNanoseconds(); double duration = (nowTime - startTime) / 1e9; @@ -69,6 +73,27 @@ void log(Level level, const char* filename, int line, const char* format, ...) { va_end(args); } +bool isTruncated() { + if (settings::devMode) + return false; + + // Open existing log file + FILE* file = fopen(asset::logPath.c_str(), "r"); + if (!file) + return false; + DEFER({ + fclose(file); + }); + + // Seek to last 3 characters + fseek(file, -3, SEEK_END); + char str[4]; + if (fread(str, 1, 3, file) != 3) + return true; + if (memcmp(str, "END", 3) != 0) + return true; +} + } // namespace logger } // namespace rack