From 4f007d96212d3dfd11dfaaf9ed7758fd1ea37a25 Mon Sep 17 00:00:00 2001 From: Ahmed Hani Date: Thu, 20 Feb 2025 18:49:33 +0200 Subject: [PATCH] fix: truncate single log file upon reopening (#1143) --- src/logging.cc | 15 ++++++++++++++ src/logging_unittest.cc | 43 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/src/logging.cc b/src/logging.cc index 08b2ab3..a452cff 100644 --- a/src/logging.cc +++ b/src/logging.cc @@ -995,7 +995,22 @@ bool LogFileObject::CreateLogfile(const string& time_pid_string) { if (FLAGS_timestamp_in_logfile_name) { // demand that the file is unique for our timestamp (fail if it exists). flags = flags | O_EXCL; + } else { + // logs are written to a single file, where: a log file is created for the + // the first time or a file is being recreated due to exceeding max size + + struct stat statbuf; + if (stat(filename, &statbuf) == 0) { + // truncate the file if it exceeds the max size + if ((static_cast(statbuf.st_size) >> 20U) >= MaxLogSize()) { + flags |= O_TRUNC; + } + + // update file length to sync file size + file_length_ = static_cast(statbuf.st_size); + } } + FileDescriptor fd{ open(filename, flags, static_cast(FLAGS_logfile_mode))}; if (!fd) return false; diff --git a/src/logging_unittest.cc b/src/logging_unittest.cc index 321f38f..65c28ee 100644 --- a/src/logging_unittest.cc +++ b/src/logging_unittest.cc @@ -110,6 +110,7 @@ static void TestLogSinkWaitTillSent(); static void TestCHECK(); static void TestDCHECK(); static void TestSTREQ(); +static void TestMaxLogSizeWhenNoTimestamp(); static void TestBasename(); static void TestBasenameAppendWhenNoTimestamp(); static void TestTwoProcessesWrite(); @@ -288,6 +289,7 @@ int main(int argc, char** argv) { MungeAndDiffTestStdout(FLAGS_test_srcdir + "/src/logging_unittest.out")); FLAGS_logtostdout = false; + TestMaxLogSizeWhenNoTimestamp(); TestBasename(); TestBasenameAppendWhenNoTimestamp(); TestTwoProcessesWrite(); @@ -806,6 +808,47 @@ static void CheckFile(const string& name, const string& expected_string, << expected_string << " in " << files[0]; } +static void TestMaxLogSizeWhenNoTimestamp() { + fprintf(stderr, "==== Test setting max log size without timestamp\n"); + const string dest = FLAGS_test_tmpdir + "/logging_test_max_log_size"; + DeleteFiles(dest + "*"); + + auto original_max_log_size = FLAGS_max_log_size; + auto original_timestamp_in_logfile_name = FLAGS_timestamp_in_logfile_name; + + FLAGS_max_log_size = 1; // Set max log size to 1MB + FLAGS_timestamp_in_logfile_name = false; + + // Set log destination + SetLogDestination(GLOG_INFO, dest.c_str()); + + // 1e4 info logs -> is about 772 KB in size + // 2e4 info logs -> is around 1500 KB in size -> 1.5MB + // If our max_log_size constraint is respected, it will truncate earlier logs + // and the file size will be lesser than 1MB (around 0.5MB) + const int num_logs = 2e4; + for (int i = 0; i < num_logs; i++) { + LOG(INFO) << "Hello world"; + } + FlushLogFiles(GLOG_INFO); + + // Check log file size + struct stat statbuf; + stat(dest.c_str(), &statbuf); + + // Verify file size is less than the max log size limit + CHECK_LT(static_cast(statbuf.st_size), + FLAGS_max_log_size << 20U); + + // Reset flag values to their original values + FLAGS_max_log_size = original_max_log_size; + FLAGS_timestamp_in_logfile_name = original_timestamp_in_logfile_name; + + // Release file handle for the destination file to unlock the file in Windows. + LogToStderr(); + DeleteFiles(dest + "*"); +} + static void TestBasename() { fprintf(stderr, "==== Test setting log file basename\n"); const string dest = FLAGS_test_tmpdir + "/logging_test_basename";