This commit is contained in:
Ahmed Hani 2025-02-22 17:25:04 +00:00 committed by GitHub
commit fbe03cbf1e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 169 additions and 10 deletions

View File

@ -0,0 +1,100 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "base/commandlineflags.h"
#include "glog/logging.h"
#include "glog/raw_logging.h"
#include "googletest.h"
#ifdef GLOG_USE_GFLAGS
# include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE;
#endif
#ifdef HAVE_LIB_GMOCK
# include <gmock/gmock.h>
# include "mock-log.h"
// Introduce several symbols from gmock.
using google::glog_testing::ScopedMockLog;
using testing::_;
using testing::AllOf;
using testing::AnyNumber;
using testing::HasSubstr;
using testing::InitGoogleMock;
using testing::StrictMock;
using testing::StrNe;
#endif
using namespace google;
TEST(CleanDeferred, logging) {
using namespace std::chrono_literals;
const string dest =
FLAGS_test_tmpdir + "/test_cleanup_enable_generic_logs";
google::EnableLogCleanerForGenericLogs(1h);
google::SetLogDestination(GLOG_INFO, dest.c_str());
for (unsigned i = 0; i < 10; ++i) {
LOG(INFO) << "cleanup test";
}
google::DisableLogCleanerForGenericLogs();
// delete the file
CHECK(unlink(dest.c_str()) == 0) << ": " << strerror(errno);
}
int main(int argc, char** argv) {
FLAGS_colorlogtostderr = false;
FLAGS_timestamp_in_logfile_name = false;
FLAGS_logcleansecs = 1;
#ifdef GLOG_USE_GFLAGS
ParseCommandLineFlags(&argc, &argv, true);
#endif
// Make sure stderr is not buffered as stderr seems to be buffered
// on recent windows.
setbuf(stderr, nullptr);
// Test some basics before InitGoogleLogging:
CaptureTestStderr();
const string early_stderr = GetCapturedTestStderr();
EXPECT_FALSE(IsGoogleLoggingInitialized());
InitGoogleLogging(argv[0]);
EXPECT_TRUE(IsGoogleLoggingInitialized());
InitGoogleTest(&argc, argv);
#ifdef HAVE_LIB_GMOCK
InitGoogleMock(&argc, argv);
#endif
// so that death tests run before we use threads
CHECK_EQ(RUN_ALL_TESTS(), 0);
}

View File

@ -485,6 +485,10 @@ InstallFailureFunction(logging_fail_func_t fail_func);
GLOG_EXPORT void EnableLogCleaner(const std::chrono::minutes& overdue);
GLOG_EXPORT void DisableLogCleaner();
GLOG_EXPORT void SetApplicationFingerprint(const std::string& fingerprint);
GLOG_EXPORT void EnableLogCleaner(LogSeverity severity, const std::chrono::minutes& overdue);
GLOG_EXPORT void DisableLogCleaner(LogSeverity severity);
GLOG_EXPORT void EnableLogCleanerForGenericLogs(const std::chrono::minutes& overdue);
GLOG_EXPORT void DisableLogCleanerForGenericLogs();
class LogSink; // defined below

View File

@ -72,6 +72,7 @@
#include <regex>
#include <sstream>
#include <vector>
#include <unordered_map>
#ifdef HAVE__CHSIZE_S
# include <io.h> // for truncate log file
@ -337,6 +338,16 @@ const char* GetLogSeverityName(LogSeverity severity) {
return LogSeverityNames[severity];
}
int FindFilepathLogSeverity(const std::string& filepath) {
for (int i = GLOG_INFO; i < NUM_SEVERITIES; i++) {
if (filepath.rfind(GetLogSeverityName(static_cast<LogSeverity>(i))) != std::string::npos) {
return i;
}
}
return -1;
}
static bool SendEmailInternal(const char* dest, const char* subject,
const char* body, bool use_logging);
@ -345,7 +356,6 @@ base::Logger::~Logger() = default;
namespace {
constexpr std::intmax_t kSecondsInDay = 60 * 60 * 24;
constexpr std::intmax_t kSecondsInWeek = kSecondsInDay * 7;
// Optional user-configured callback to print custom prefixes.
class PrefixFormatter {
@ -437,13 +447,18 @@ class LogCleaner {
// Setting overdue to 0 days will delete all logs.
void Enable(const std::chrono::minutes& overdue);
void Enable(const LogSeverity severity, const std::chrono::minutes& overdue);
void Disable();
void Disable(const LogSeverity severity);
// For files with no severity in their names
void EnableForGenericLogs(const std::chrono::minutes& overdue);
void DisableForGenericLogs();
void Run(const std::chrono::system_clock::time_point& current_time,
bool base_filename_selected, const string& base_filename,
const string& filename_extension);
bool enabled() const { return enabled_; }
bool enabled() const { return !overdue_.empty(); }
private:
vector<string> GetOverdueLogNames(
@ -459,9 +474,7 @@ class LogCleaner {
const string& filepath,
const std::chrono::system_clock::time_point& current_time) const;
bool enabled_{false};
std::chrono::minutes overdue_{
std::chrono::duration<int, std::ratio<kSecondsInWeek>>{1}};
std::unordered_map<int, std::chrono::minutes> overdue_;
std::chrono::system_clock::time_point
next_cleanup_time_; // cycle count at which to clean overdue log
};
@ -1300,16 +1313,36 @@ void LogFileObject::Write(
LogCleaner::LogCleaner() = default;
void LogCleaner::Enable(const std::chrono::minutes& overdue) {
enabled_ = true;
overdue_ = overdue;
// For the files that have no severity specified, we use -1 as the key
EnableForGenericLogs(overdue);
// For backward compatability, set all severities to the same value
for (int i = GLOG_INFO; i < NUM_SEVERITIES; i++) {
Enable(static_cast<LogSeverity>(i), overdue);
}
}
void LogCleaner::Disable() { enabled_ = false; }
void LogCleaner::Enable(const LogSeverity severity, const std::chrono::minutes& overdue) {
overdue_[severity] = overdue;
}
void LogCleaner::Disable() { overdue_.clear(); }
void LogCleaner::Disable(const LogSeverity severity) {
overdue_.erase(severity);
}
void LogCleaner::EnableForGenericLogs(const std::chrono::minutes& overdue) {
overdue_[-1] = overdue;
}
void LogCleaner::DisableForGenericLogs() {
overdue_.erase(-1);
}
void LogCleaner::Run(const std::chrono::system_clock::time_point& current_time,
bool base_filename_selected, const string& base_filename,
const string& filename_extension) {
assert(enabled_);
assert(enabled());
assert(!base_filename_selected || !base_filename.empty());
// avoid scanning logs too frequently
@ -1486,7 +1519,13 @@ bool LogCleaner::IsLogLastModifiedOver(
const auto last_modified_time =
std::chrono::system_clock::from_time_t(file_stat.st_mtime);
const auto diff = current_time - last_modified_time;
return diff >= overdue_;
auto severity_it = overdue_.find(FindFilepathLogSeverity(filepath));
if (severity_it == overdue_.end()) {
return false;
}
return diff >= severity_it->second;
}
// If failed to get file stat, don't return true!
@ -2642,8 +2681,24 @@ void EnableLogCleaner(const std::chrono::minutes& overdue) {
log_cleaner.Enable(overdue);
}
void EnableLogCleaner(LogSeverity severity, const std::chrono::minutes& overdue) {
log_cleaner.Enable(severity, overdue);
}
void EnableLogCleanerForGenericLogs(const std::chrono::minutes& overdue) {
log_cleaner.EnableForGenericLogs(overdue);
}
void DisableLogCleaner() { log_cleaner.Disable(); }
void DisableLogCleaner(LogSeverity severity) {
log_cleaner.Disable(severity);
}
void DisableLogCleanerForGenericLogs() {
log_cleaner.DisableForGenericLogs();
}
LogMessageTime::LogMessageTime() = default;
namespace {