Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

truncate single file upon creation #1143

Merged
merged 1 commit into from
Feb 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/logging.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint32>(statbuf.st_size) >> 20U) >= MaxLogSize()) {
flags |= O_TRUNC;
}

// update file length to sync file size
file_length_ = static_cast<uint32>(statbuf.st_size);
}
}

FileDescriptor fd{
open(filename, flags, static_cast<mode_t>(FLAGS_logfile_mode))};
if (!fd) return false;
Expand Down
43 changes: 43 additions & 0 deletions src/logging_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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<unsigned int>(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";
Expand Down
Loading