From 812d00012cca62ed0dc292b132dbef7bdf099201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Thanh=20Ch=C3=A2u?= <86813867+nuocbiendang12@users.noreply.github.com> Date: Fri, 26 Jun 2026 11:35:23 +0700 Subject: [PATCH 1/2] [core] Create event log files lazily to avoid stale/empty logs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #64153 Previously, LogEventReporter created event log files eagerly in its constructor, causing empty log files to appear on every Ray startup even when no events were ever written: - logs/events/event_CORE_WORKER_.log (always empty) - logs/events/event_GCS.log (usually empty) - logs/events/event_RAYLET.log (usually empty) - logs/export_events/*.log (empty when export framework enabled) This change defers log file creation to the first call to Report() or ReportExportEvent() via a new EnsureSinkInitialized() helper. If no events are written, no log file is created on disk. Changes: - Added EnsureSinkInitialized() private helper method that creates the spdlog rotating_logger_mt only on first use - Added log_sink_key_ member field to store the key for deferred init - Modified constructor to only compute and store the file name/path, without opening the file - Modified Flush() to safely handle an uninitialized (nullptr) sink - Modified Report() and ReportExportEvent() to call EnsureSinkInitialized() before writing All existing behavior is preserved when events are actually written. Signed-off-by: Lê Thanh Châu <19120463@student.hcmus.edu.vn> --- src/ray/util/event.cc | 34 ++++++++++++++++++++++++++++------ src/ray/util/event.h | 10 ++++++++++ 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/ray/util/event.cc b/src/ray/util/event.cc index efdd53ff8db4..df62e3180c11 100644 --- a/src/ray/util/event.cc +++ b/src/ray/util/event.cc @@ -72,13 +72,27 @@ LogEventReporter::LogEventReporter(SourceTypeVariant source_type, file_name_ = "event_" + source_type_name + (add_pid_to_file ? "_" + std::to_string(getpid()) : "") + ".log"; - std::string log_sink_key = GetReporterKey() + log_dir_ + file_name_; - log_sink_ = spdlog::get(log_sink_key); + // Store the sink key for lazy initialization. + // The log file will only be created on the first call to Report() or + // ReportExportEvent(), avoiding stale/empty log files at startup. + // See: https://github.com/ray-project/ray/issues/64153 + log_sink_key_ = GetReporterKey() + log_dir_ + file_name_; + // Do NOT initialize log_sink_ here. It is lazily initialized in + // EnsureSinkInitialized(), which is called on the first write. +} + +LogEventReporter::~LogEventReporter() { Flush(); } + +void LogEventReporter::EnsureSinkInitialized() { + if (log_sink_ != nullptr) { + return; + } + log_sink_ = spdlog::get(log_sink_key_); // If the file size is over {rotate_max_file_size_} MB, this file would be renamed // for example event_GCS.0.log, event_GCS.1.log, event_GCS.2.log ... // We allow to rotate for {rotate_max_file_num_} times. if (log_sink_ == nullptr) { - log_sink_ = spdlog::rotating_logger_mt(log_sink_key, + log_sink_ = spdlog::rotating_logger_mt(log_sink_key_, log_dir_ + file_name_, 1048576 * rotate_max_file_size_, rotate_max_file_num_); @@ -86,9 +100,13 @@ LogEventReporter::LogEventReporter(SourceTypeVariant source_type, log_sink_->set_pattern("%v"); } -LogEventReporter::~LogEventReporter() { Flush(); } - -void LogEventReporter::Flush() { log_sink_->flush(); } +void LogEventReporter::Flush() { + // Guard against an uninitialized sink (no events were ever written, + // so no log file was created). + if (log_sink_ != nullptr) { + log_sink_->flush(); + } +} std::string LogEventReporter::replaceLineFeed(std::string message) { std::stringstream ss; @@ -169,6 +187,8 @@ std::string LogEventReporter::ExportEventToString(const rpc::ExportEvent &export void LogEventReporter::Report(const rpc::Event &event, const json &custom_fields) { RAY_CHECK(Event_SourceType_IsValid(event.source_type())); RAY_CHECK(Event_Severity_IsValid(event.severity())); + // Lazily create the log file on the first write. + EnsureSinkInitialized(); std::string result = EventToString(event, custom_fields); log_sink_->info(result); @@ -179,6 +199,8 @@ void LogEventReporter::Report(const rpc::Event &event, const json &custom_fields void LogEventReporter::ReportExportEvent(const rpc::ExportEvent &export_event) { RAY_CHECK(ExportEvent_SourceType_IsValid(export_event.source_type())); + // Lazily create the log file on the first write. + EnsureSinkInitialized(); std::string result = ExportEventToString(export_event); log_sink_->info(result); diff --git a/src/ray/util/event.h b/src/ray/util/event.h index 4dc9371a8c5f..4ad88d3468ae 100644 --- a/src/ray/util/event.h +++ b/src/ray/util/event.h @@ -126,6 +126,11 @@ class LogEventReporter : public BaseEventReporter { virtual void Flush(); + // Lazily initializes log_sink_ on the first write, so that no log file + // is created on disk unless at least one event is actually written. + // Fixes: https://github.com/ray-project/ray/issues/64153 + void EnsureSinkInitialized(); + std::string GetReporterKey() override { return "log.event.reporter"; } protected: @@ -136,6 +141,11 @@ class LogEventReporter : public BaseEventReporter { std::string file_name_; + // The key used to look up / register the spdlog logger. Stored to enable + // lazy initialization of log_sink_ in EnsureSinkInitialized(). + std::string log_sink_key_; + + // The underlying spdlog logger. nullptr until the first event is written. std::shared_ptr log_sink_; }; From f680dafb3dcb40d731027e33e75df0b3fee3e12c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Thanh=20Ch=C3=A2u?= <86813867+nuocbiendang12@users.noreply.github.com> Date: Sun, 28 Jun 2026 11:09:42 +0700 Subject: [PATCH 2/2] fix: make lazy sink initialization thread-safe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lê Thanh Châu <19120463@student.hcmus.edu.vn> --- src/ray/util/event.cc | 27 +++++++++++++-------------- src/ray/util/event.h | 14 +++++++++++--- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/ray/util/event.cc b/src/ray/util/event.cc index df62e3180c11..63d3096c9f40 100644 --- a/src/ray/util/event.cc +++ b/src/ray/util/event.cc @@ -84,20 +84,19 @@ LogEventReporter::LogEventReporter(SourceTypeVariant source_type, LogEventReporter::~LogEventReporter() { Flush(); } void LogEventReporter::EnsureSinkInitialized() { - if (log_sink_ != nullptr) { - return; - } - log_sink_ = spdlog::get(log_sink_key_); - // If the file size is over {rotate_max_file_size_} MB, this file would be renamed - // for example event_GCS.0.log, event_GCS.1.log, event_GCS.2.log ... - // We allow to rotate for {rotate_max_file_num_} times. - if (log_sink_ == nullptr) { - log_sink_ = spdlog::rotating_logger_mt(log_sink_key_, - log_dir_ + file_name_, - 1048576 * rotate_max_file_size_, - rotate_max_file_num_); - } - log_sink_->set_pattern("%v"); + std::call_once(sink_init_once_, [this]() { + log_sink_ = spdlog::get(log_sink_key_); + // If the file size is over {rotate_max_file_size_} MB, this file would be renamed + // for example event_GCS.0.log, event_GCS.1.log, event_GCS.2.log ... + // We allow to rotate for {rotate_max_file_num_} times. + if (log_sink_ == nullptr) { + log_sink_ = spdlog::rotating_logger_mt(log_sink_key_, + log_dir_ + file_name_, + 1048576 * rotate_max_file_size_, + rotate_max_file_num_); + } + log_sink_->set_pattern("%v"); + }); } void LogEventReporter::Flush() { diff --git a/src/ray/util/event.h b/src/ray/util/event.h index 4ad88d3468ae..0f19e9d3984b 100644 --- a/src/ray/util/event.h +++ b/src/ray/util/event.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -126,9 +127,13 @@ class LogEventReporter : public BaseEventReporter { virtual void Flush(); - // Lazily initializes log_sink_ on the first write, so that no log file - // is created on disk unless at least one event is actually written. - // Fixes: https://github.com/ray-project/ray/issues/64153 + /** + * @brief Lazily initializes log_sink_ on the first write. + * + * Ensures that no log file is created on disk unless at least one event + * is actually written, avoiding stale/empty log files. + * Fixes: https://github.com/ray-project/ray/issues/64153 + */ void EnsureSinkInitialized(); std::string GetReporterKey() override { return "log.event.reporter"; } @@ -147,6 +152,9 @@ class LogEventReporter : public BaseEventReporter { // The underlying spdlog logger. nullptr until the first event is written. std::shared_ptr log_sink_; + + // Ensure thread-safe lazy initialization of log_sink_. + std::once_flag sink_init_once_; }; // store the reporters, add reporters and clean reporters