From 46249ed18042725d20fc9d7da862065fa4ca37bf Mon Sep 17 00:00:00 2001 From: Jiajun Yao Date: Wed, 3 Apr 2024 17:04:33 -0700 Subject: [PATCH 01/17] ray structured logging Signed-off-by: Jiajun Yao --- src/ray/raylet/main.cc | 2 +- src/ray/util/logging.cc | 10 ++++------ src/ray/util/logging.h | 12 ++++++++++-- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/ray/raylet/main.cc b/src/ray/raylet/main.cc index 1ceece83dbba..865972c5a7c9 100644 --- a/src/ray/raylet/main.cc +++ b/src/ray/raylet/main.cc @@ -173,7 +173,7 @@ int main(int argc, char *argv[]) { RAY_CHECK_NE(FLAGS_cluster_id, "") << "Expected cluster ID."; ray::ClusterID cluster_id = ray::ClusterID::FromHex(FLAGS_cluster_id); - RAY_LOG(INFO) << "Setting cluster ID to: " << cluster_id; + RAY_LOG(INFO, "cluster_id", cluster_id) << "Setting cluster ID to: " << cluster_id; gflags::ShutDownCommandLineFlags(); // Configuration for the node manager. diff --git a/src/ray/util/logging.cc b/src/ray/util/logging.cc index 8e9f45d4b865..9a65d8a5c0ee 100644 --- a/src/ray/util/logging.cc +++ b/src/ray/util/logging.cc @@ -52,7 +52,8 @@ std::string RayLog::app_name_ = ""; std::string RayLog::log_dir_ = ""; // Format pattern is 2020-08-21 17:00:00,000 I 100 1001 msg. // %L is loglevel, %P is process id, %t for thread id. -std::string RayLog::log_format_pattern_ = "[%Y-%m-%d %H:%M:%S,%e %L %P %t] %v"; +std::string RayLog::log_format_pattern_ = + "{\"ts\":\"%Y-%m-%d %H:%M:%S,%e\", \"level\": \"%l\", %v"; std::string RayLog::logger_name_ = "ray_log_sink"; long RayLog::log_rotation_max_size_ = 1 << 29; long RayLog::log_rotation_file_num_ = 10; @@ -148,9 +149,7 @@ class SpdLogMessage final { int line, int loglevel, std::shared_ptr expose_osstream) - : loglevel_(loglevel), expose_osstream_(expose_osstream) { - stream() << ConstBasename(file) << ":" << line << ": "; - } + : loglevel_(loglevel), expose_osstream_(expose_osstream) {} inline void Flush() { auto logger = spdlog::get(RayLog::GetLoggerName()); @@ -164,6 +163,7 @@ class SpdLogMessage final { if (expose_osstream_) { *expose_osstream_ << "\n*** StackTrace Information ***\n" << ray::StackTrace(); } + stream() << "\"}"; // NOTE(lingxuan.zlx): See more fmt by visiting https://github.com/fmtlib/fmt. logger->log( static_cast(loglevel_), /*fmt*/ "{}", str_.str()); @@ -293,8 +293,6 @@ void RayLog::StartRayLog(const std::string &app_name, } else { // Format pattern is 2020-08-21 17:00:00,000 I 100 1001 msg. // %L is loglevel, %P is process id, %t for thread id. - log_format_pattern_ = - "[%Y-%m-%d %H:%M:%S,%e %L %P %t] (" + app_name_without_path + ") %v"; auto console_sink = std::make_shared(); console_sink->set_pattern(log_format_pattern_); console_sink->set_level(level); diff --git a/src/ray/util/logging.h b/src/ray/util/logging.h index 2adf4b26f617..bb911c9aef05 100644 --- a/src/ray/util/logging.h +++ b/src/ray/util/logging.h @@ -103,9 +103,17 @@ enum class RayLogLevel { #define RAY_LOG_ENABLED(level) ray::RayLog::IsLevelEnabled(ray::RayLogLevel::level) -#define RAY_LOG(level) \ +#define GET_MACRO(_1, _2, _3, NAME, ...) NAME +#define RAY_LOG(...) GET_MACRO(__VA_ARGS__, RAY_LOG3, RAY_LOG2, RAY_LOG1)(__VA_ARGS__) + +#define RAY_LOG1(level) \ if (ray::RayLog::IsLevelEnabled(ray::RayLogLevel::level)) \ - RAY_LOG_INTERNAL(ray::RayLogLevel::level) + RAY_LOG_INTERNAL(ray::RayLogLevel::level) << "\"msg\": \"" + +#define RAY_LOG3(level, key1, value1) \ + if (ray::RayLog::IsLevelEnabled(ray::RayLogLevel::level)) \ + RAY_LOG_INTERNAL(ray::RayLogLevel::level) << "\"" << key1 << "\": " \ + << "\"" << value1 << "\", \"msg\": \"" #define RAY_IGNORE_EXPR(expr) ((void)(expr)) From dc5997ad4d6fc590f98b5ce2723f42f39cb0f794 Mon Sep 17 00:00:00 2001 From: Jiajun Yao Date: Mon, 20 May 2024 09:30:53 -0700 Subject: [PATCH 02/17] up Signed-off-by: Jiajun Yao --- src/ray/util/logging.h | 56 ++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 35 deletions(-) diff --git a/src/ray/util/logging.h b/src/ray/util/logging.h index bb911c9aef05..f33010b97509 100644 --- a/src/ray/util/logging.h +++ b/src/ray/util/logging.h @@ -216,50 +216,24 @@ enum class RayLogLevel { // which hide the implementation into logging.cc file. // In logging.cc, we can choose different log libs using different macros. -// This is also a null log which does not output anything. -class RayLogBase { - public: - virtual ~RayLogBase(){}; - - // By default, this class is a null log because it return false here. - virtual bool IsEnabled() const { return false; }; - - // This function to judge whether current log is fatal or not. - virtual bool IsFatal() const { return false; }; - - template - RayLogBase &operator<<(const T &t) { - if (IsEnabled()) { - Stream() << t; - } - if (IsFatal()) { - ExposeStream() << t; - } - return *this; - } - - protected: - virtual std::ostream &Stream() { return std::cerr; }; - virtual std::ostream &ExposeStream() { return std::cerr; }; -}; - /// Callback function which will be triggered to expose fatal log. /// The first argument: a string representing log type or label. /// The second argument: log content. using FatalLogCallback = std::function; -class RayLog : public RayLogBase { +class RayLog { public: RayLog(const char *file_name, int line_number, RayLogLevel severity); - virtual ~RayLog(); + ~RayLog(); /// Return whether or not current logging instance is enabled. /// /// \return True if logging is enabled and false otherwise. - virtual bool IsEnabled() const; + bool IsEnabled() const; - virtual bool IsFatal() const; + /// This function to judge whether current log is fatal or not. + bool IsFatal() const; /// The init function of ray log for a program which should be called only once. /// @@ -315,6 +289,17 @@ class RayLog : public RayLogBase { static void AddFatalLogCallbacks( const std::vector &expose_log_callbacks); + template + RayLog &operator<<(const T &t) { + if (IsEnabled()) { + Stream() << t; + } + if (IsFatal()) { + ExposeStream() << t; + } + return *this; + } + private: FRIEND_TEST(PrintLogTest, TestRayLogEveryNOrDebug); FRIEND_TEST(PrintLogTest, TestRayLogEveryN); @@ -327,7 +312,7 @@ class RayLog : public RayLogBase { RayLogLevel severity_; /// Whether current log is fatal or not. bool is_fatal_ = false; - /// String stream of exposed log content. + /// String stream of exposed fatal log content. std::shared_ptr expose_osstream_ = nullptr; /// Whether or not the log is initialized. static std::atomic initialized_; @@ -353,8 +338,9 @@ class RayLog : public RayLogBase { static std::string logger_name_; protected: - virtual std::ostream &Stream(); - virtual std::ostream &ExposeStream(); + std::ostream &Stream(); + // Fatal log that will be exposed as event. + std::ostream &ExposeStream(); }; // This class make RAY_CHECK compilation pass to change the << operator to void. @@ -363,7 +349,7 @@ class Voidify { Voidify() {} // This has to be an operator with a precedence lower than << but // higher than ?: - void operator&(RayLogBase &) {} + void operator&(RayLog &) {} }; } // namespace ray From d2c969e4dd842fed716e6c73d72dd4d14688fd69 Mon Sep 17 00:00:00 2001 From: Jiajun Yao Date: Thu, 23 May 2024 22:46:33 -0700 Subject: [PATCH 03/17] up Signed-off-by: Jiajun Yao --- src/ray/raylet/main.cc | 2 +- src/ray/raylet/node_manager.cc | 3 +- src/ray/util/logging.cc | 167 ++++++++++++++++----------------- src/ray/util/logging.h | 72 ++++++++++---- 4 files changed, 135 insertions(+), 109 deletions(-) diff --git a/src/ray/raylet/main.cc b/src/ray/raylet/main.cc index 7c1ec3fd3843..e5d89d68fc1c 100644 --- a/src/ray/raylet/main.cc +++ b/src/ray/raylet/main.cc @@ -177,7 +177,7 @@ int main(int argc, char *argv[]) { RAY_CHECK_NE(FLAGS_cluster_id, "") << "Expected cluster ID."; ray::ClusterID cluster_id = ray::ClusterID::FromHex(FLAGS_cluster_id); - RAY_LOG(INFO, "cluster_id", cluster_id) << "Setting cluster ID to: " << cluster_id; + RAY_LOG(INFO) << "Setting cluster ID to: " << cluster_id; gflags::ShutDownCommandLineFlags(); // Configuration for the node manager. diff --git a/src/ray/raylet/node_manager.cc b/src/ray/raylet/node_manager.cc index 0f01440b9d11..56c2f9b6ef09 100644 --- a/src/ray/raylet/node_manager.cc +++ b/src/ray/raylet/node_manager.cc @@ -284,7 +284,8 @@ NodeManager::NodeManager( RayConfig::instance().min_memory_free_bytes(), RayConfig::instance().memory_monitor_refresh_ms(), CreateMemoryUsageRefreshCallback())) { - RAY_LOG(INFO) << "Initializing NodeManager with ID " << self_node_id_; + RAY_LOG(INFO) << "Initializing NodeManager" + << RAY_LOG_FIELD(kLogKeyNodeID, self_node_id_); cluster_resource_scheduler_ = std::make_shared( io_service, scheduling::NodeID(self_node_id_.Binary()), diff --git a/src/ray/util/logging.cc b/src/ray/util/logging.cc index 9a65d8a5c0ee..92bc1f50337a 100644 --- a/src/ray/util/logging.cc +++ b/src/ray/util/logging.cc @@ -47,13 +47,18 @@ namespace ray { +// Format pattern is 2020-08-21 17:00:00,000 I 100 1001 msg. +// %L is loglevel, %P is process id, %t for thread id. +constexpr char kLogFormatTextPattern[] = "[%Y-%m-%d %H:%M:%S,%e %L %P %t] %v"; +constexpr char kLogFormatJsonPattern[] = + "{\"asctime\":\"%Y-%m-%d %H:%M:%S,%e\", \"levelname\": \"%L\", %v}"; + RayLogLevel RayLog::severity_threshold_ = RayLogLevel::INFO; std::string RayLog::app_name_ = ""; std::string RayLog::log_dir_ = ""; -// Format pattern is 2020-08-21 17:00:00,000 I 100 1001 msg. -// %L is loglevel, %P is process id, %t for thread id. -std::string RayLog::log_format_pattern_ = - "{\"ts\":\"%Y-%m-%d %H:%M:%S,%e\", \"level\": \"%l\", %v"; +bool RayLog::log_format_json_ = false; +std::string RayLog::log_format_pattern_ = kLogFormatTextPattern; + std::string RayLog::logger_name_ = "ray_log_sink"; long RayLog::log_rotation_max_size_ = 1 << 29; long RayLog::log_rotation_file_num_ = 10; @@ -143,50 +148,8 @@ class DefaultStdErrLogger final { std::shared_ptr default_stderr_logger_; }; -class SpdLogMessage final { - public: - explicit SpdLogMessage(const char *file, - int line, - int loglevel, - std::shared_ptr expose_osstream) - : loglevel_(loglevel), expose_osstream_(expose_osstream) {} - - inline void Flush() { - auto logger = spdlog::get(RayLog::GetLoggerName()); - if (!logger) { - logger = DefaultStdErrLogger::Instance().GetDefaultLogger(); - } - - if (loglevel_ == static_cast(spdlog::level::critical)) { - stream() << "\n*** StackTrace Information ***\n" << ray::StackTrace(); - } - if (expose_osstream_) { - *expose_osstream_ << "\n*** StackTrace Information ***\n" << ray::StackTrace(); - } - stream() << "\"}"; - // NOTE(lingxuan.zlx): See more fmt by visiting https://github.com/fmtlib/fmt. - logger->log( - static_cast(loglevel_), /*fmt*/ "{}", str_.str()); - logger->flush(); - } - - ~SpdLogMessage() { Flush(); } - inline std::ostream &stream() { return str_; } - - private: - SpdLogMessage(const SpdLogMessage &) = delete; - SpdLogMessage &operator=(const SpdLogMessage &) = delete; - - private: - std::ostringstream str_; - int loglevel_; - std::shared_ptr expose_osstream_; -}; - -typedef ray::SpdLogMessage LoggingProvider; - // Spdlog's severity map. -static int GetMappedSeverity(RayLogLevel severity) { +static spdlog::level::level_enum GetMappedSeverity(RayLogLevel severity) { switch (severity) { case RayLogLevel::TRACE: return spdlog::level::trace; @@ -209,9 +172,7 @@ static int GetMappedSeverity(RayLogLevel severity) { std::vector RayLog::fatal_log_callbacks_; -void RayLog::StartRayLog(const std::string &app_name, - RayLogLevel severity_threshold, - const std::string &log_dir) { +void RayLog::InitSeverityThreshold(RayLogLevel severity_threshold) { const char *var_value = std::getenv("RAY_BACKEND_LOG_LEVEL"); if (var_value != nullptr) { std::string data = var_value; @@ -235,12 +196,40 @@ void RayLog::StartRayLog(const std::string &app_name, << " to " << static_cast(severity_threshold); } severity_threshold_ = severity_threshold; +} + +void RayLog::InitLogFormat() { + // Default is plain text + log_format_json_ = false; + log_format_pattern_ = kLogFormatTextPattern; + + const char *var_value = std::getenv("RAY_BACKEND_LOG_FORMAT"); + if (var_value != nullptr) { + std::string data = var_value; + std::transform(data.begin(), data.end(), data.begin(), ::tolower); + if (data == "json") { + log_format_json_ = true; + log_format_pattern_ = kLogFormatJsonPattern; + } else if (data == "text") { + // Default + } else { + RAY_LOG(WARNING) << "Unrecognized setting of RAY_BACKEND_LOG_FORMAT=" << var_value; + } + } +} + +void RayLog::StartRayLog(const std::string &app_name, + RayLogLevel severity_threshold, + const std::string &log_dir) { + InitSeverityThreshold(severity_threshold); + InitLogFormat(); + app_name_ = app_name; log_dir_ = log_dir; // All the logging sinks to add. std::vector sinks; - auto level = static_cast(severity_threshold_); + auto level = GetMappedSeverity(severity_threshold_); std::string app_name_without_path = app_name; if (app_name.empty()) { app_name_without_path = "DefaultApp"; @@ -275,8 +264,6 @@ void RayLog::StartRayLog(const std::string &app_name, log_rotation_file_num_ = file_num; } } - spdlog::set_pattern(log_format_pattern_); - spdlog::set_level(static_cast(severity_threshold_)); // Sink all log stuff to default file logger we defined here. We may need // multiple sinks for different files or loglevel. auto file_logger = spdlog::get(RayLog::GetLoggerName()); @@ -289,12 +276,12 @@ void RayLog::StartRayLog(const std::string &app_name, JoinPaths(log_dir_, app_name_without_path + "_" + std::to_string(pid) + ".log"), log_rotation_max_size_, log_rotation_file_num_); + file_sink->set_level(level); sinks.push_back(file_sink); } else { // Format pattern is 2020-08-21 17:00:00,000 I 100 1001 msg. // %L is loglevel, %P is process id, %t for thread id. auto console_sink = std::make_shared(); - console_sink->set_pattern(log_format_pattern_); console_sink->set_level(level); sinks.push_back(console_sink); } @@ -302,7 +289,6 @@ void RayLog::StartRayLog(const std::string &app_name, // In all cases, log errors to the console log so they are in driver logs. // https://github.com/ray-project/ray/issues/12893 auto err_sink = std::make_shared(); - err_sink->set_pattern(log_format_pattern_); err_sink->set_level(spdlog::level::err); sinks.push_back(err_sink); @@ -310,9 +296,8 @@ void RayLog::StartRayLog(const std::string &app_name, auto logger = std::make_shared( RayLog::GetLoggerName(), sinks.begin(), sinks.end()); logger->set_level(level); + // Set the pattern of all sinks. logger->set_pattern(log_format_pattern_); - spdlog::set_level(static_cast(severity_threshold_)); - spdlog::set_pattern(log_format_pattern_); spdlog::set_default_logger(logger); initialized_ = true; @@ -405,8 +390,6 @@ bool RayLog::IsLevelEnabled(RayLogLevel log_level) { return log_level >= severity_threshold_; } -std::string RayLog::GetLogFormatPattern() { return log_format_pattern_; } - std::string RayLog::GetLoggerName() { return logger_name_; } void RayLog::AddFatalLogCallbacks( @@ -417,55 +400,65 @@ void RayLog::AddFatalLogCallbacks( } RayLog::RayLog(const char *file_name, int line_number, RayLogLevel severity) - : logging_provider_(nullptr), - is_enabled_(severity >= severity_threshold_), + : is_enabled_(severity >= severity_threshold_), severity_(severity), is_fatal_(severity == RayLogLevel::FATAL) { if (is_fatal_) { - expose_osstream_ = std::make_shared(); - #ifdef _WIN32 int pid = _getpid(); #else pid_t pid = getpid(); #endif - *expose_osstream_ << absl::StrFormat("%s:%d (PID: %d, TID: %s, errno: %d (%s)):", - file_name, - line_number, - pid, - std::to_string(GetTid()), - errno, - strerror(errno)); + expose_fatal_osstream_ << absl::StrFormat("%s:%d (PID: %d, TID: %s, errno: %d (%s)):", + file_name, + line_number, + pid, + std::to_string(GetTid()), + errno, + strerror(errno)); } if (is_enabled_) { - logging_provider_ = new LoggingProvider( - file_name, line_number, GetMappedSeverity(severity), expose_osstream_); + if (log_format_json_) { + context_osstream_ << "\"" << kLogKeyFilename << "\":" << ConstBasename(file_name) + << ",\"" << kLogKeyLineno << "\":" << line_number; + } else { + msg_osstream_ << ConstBasename(file_name) << ":" << line_number << ": "; + } } } -std::ostream &RayLog::Stream() { - auto logging_provider = reinterpret_cast(logging_provider_); - // Before calling this function, user should check IsEnabled. - // When IsEnabled == false, logging_provider_ will be empty. - return logging_provider->stream(); -} - bool RayLog::IsEnabled() const { return is_enabled_; } bool RayLog::IsFatal() const { return is_fatal_; } -std::ostream &RayLog::ExposeStream() { return *expose_osstream_; } - RayLog::~RayLog() { - if (logging_provider_ != nullptr) { - delete reinterpret_cast(logging_provider_); - logging_provider_ = nullptr; - } - if (expose_osstream_ != nullptr) { + if (IsFatal()) { + msg_osstream_ << "\n*** StackTrace Information ***\n" << ray::StackTrace(); + expose_fatal_osstream_ << "\n*** StackTrace Information ***\n" << ray::StackTrace(); for (const auto &callback : fatal_log_callbacks_) { - callback(EL_RAY_FATAL_CHECK_FAILED, expose_osstream_->str()); + callback(EL_RAY_FATAL_CHECK_FAILED, expose_fatal_osstream_.str()); } } + + auto logger = spdlog::get(RayLog::GetLoggerName()); + if (!logger) { + logger = DefaultStdErrLogger::Instance().GetDefaultLogger(); + } + // NOTE(lingxuan.zlx): See more fmt by visiting https://github.com/fmtlib/fmt. + if (log_format_json_) { + logger->log(GetMappedSeverity(severity_), + /*fmt*/ ",\"{}\":\"{}\"{}", + kLogKeyMessage, + msg_osstream_.str(), + context_osstream_.str()); + } else { + logger->log(GetMappedSeverity(severity_), + /*fmt*/ "{}{}", + msg_osstream_.str(), + context_osstream_.str()); + } + logger->flush(); + if (severity_ == RayLogLevel::FATAL) { std::_Exit(EXIT_FAILURE); } diff --git a/src/ray/util/logging.h b/src/ray/util/logging.h index f33010b97509..64e43aa89ca1 100644 --- a/src/ray/util/logging.h +++ b/src/ray/util/logging.h @@ -85,6 +85,17 @@ enum { ERROR = 0 }; #endif namespace ray { +constexpr char kLogKeyAsctime[] = "asctime"; +constexpr char kLogKeyLevelname[] = "levelname"; +constexpr char kLogKeyMessage[] = "message"; +constexpr char kLogKeyFilename[] = "filename"; +constexpr char kLogKeyLineno[] = "lineno"; +constexpr char kLogKeyJobID[] = "job_id"; +constexpr char kLogKeyWorkerID[] = "worker_id"; +constexpr char kLogKeyNodeID[] = "node_id"; +constexpr char kLogKeyActorID[] = "actor_id"; +constexpr char kLogKeyTaskID[] = "task_id"; + class StackTrace { /// This dumps the current stack trace information. friend std::ostream &operator<<(std::ostream &os, const StackTrace &stack_trace); @@ -103,17 +114,11 @@ enum class RayLogLevel { #define RAY_LOG_ENABLED(level) ray::RayLog::IsLevelEnabled(ray::RayLogLevel::level) -#define GET_MACRO(_1, _2, _3, NAME, ...) NAME -#define RAY_LOG(...) GET_MACRO(__VA_ARGS__, RAY_LOG3, RAY_LOG2, RAY_LOG1)(__VA_ARGS__) +#define RAY_LOG_FIELD(key, value) ::ray::MakeRayLogField(key, value) -#define RAY_LOG1(level) \ +#define RAY_LOG(level) \ if (ray::RayLog::IsLevelEnabled(ray::RayLogLevel::level)) \ - RAY_LOG_INTERNAL(ray::RayLogLevel::level) << "\"msg\": \"" - -#define RAY_LOG3(level, key1, value1) \ - if (ray::RayLog::IsLevelEnabled(ray::RayLogLevel::level)) \ - RAY_LOG_INTERNAL(ray::RayLogLevel::level) << "\"" << key1 << "\": " \ - << "\"" << value1 << "\", \"msg\": \"" + RAY_LOG_INTERNAL(ray::RayLogLevel::level) #define RAY_IGNORE_EXPR(expr) ((void)(expr)) @@ -221,6 +226,19 @@ enum class RayLogLevel { /// The second argument: log content. using FatalLogCallback = std::function; +template +struct RayLogField { + RayLogField(const std::string &key, const T &value) : key(key), value(value) {} + + const std::string &key; + const T &value; +}; + +template +RayLogField MakeRayLogField(const std::string &key, const T &value) { + return RayLogField(key, value); +} + class RayLog { public: RayLog(const char *file_name, int line_number, RayLogLevel severity); @@ -292,10 +310,20 @@ class RayLog { template RayLog &operator<<(const T &t) { if (IsEnabled()) { - Stream() << t; + msg_osstream_ << t; } if (IsFatal()) { - ExposeStream() << t; + expose_fatal_osstream_ << t; + } + return *this; + } + + template + RayLog &operator<<(const RayLogField &f) { + if (log_format_json_) { + context_osstream_ << ",\"" << f.key << "\"=\"" << f.value << "\""; + } else { + context_osstream_ << " " << f.key << "=" << f.value; } return *this; } @@ -303,24 +331,28 @@ class RayLog { private: FRIEND_TEST(PrintLogTest, TestRayLogEveryNOrDebug); FRIEND_TEST(PrintLogTest, TestRayLogEveryN); - // Hide the implementation of log provider by void *. - // Otherwise, lib user may define the same macro to use the correct header file. - void *logging_provider_; + + static void InitSeverityThreshold(RayLogLevel severity_threshold); + static void InitLogFormat(); + /// True if log messages should be logged and false if they should be ignored. bool is_enabled_; /// log level. RayLogLevel severity_; /// Whether current log is fatal or not. bool is_fatal_ = false; + /// String stream of the log message + std::ostringstream msg_osstream_; + /// String stream of the log contexts: a list of key-value pairs. + std::ostringstream context_osstream_; /// String stream of exposed fatal log content. - std::shared_ptr expose_osstream_ = nullptr; + std::ostringstream expose_fatal_osstream_; + /// Whether or not the log is initialized. static std::atomic initialized_; /// Callback functions which will be triggered to expose fatal log. static std::vector fatal_log_callbacks_; static RayLogLevel severity_threshold_; - // In InitGoogleLogging, it simply keeps the pointer. - // We need to make sure the app name passed to InitGoogleLogging exist. static std::string app_name_; /// The directory where the log files are stored. /// If this is empty, logs are printed to stdout. @@ -328,6 +360,8 @@ class RayLog { /// This flag is used to avoid calling UninstallSignalAction in ShutDownRayLog if /// InstallFailureSignalHandler was not called. static bool is_failure_signal_handler_installed_; + /// Whether emit json logs. + static bool log_format_json_; // Log format content. static std::string log_format_pattern_; // Log rotation file size limitation. @@ -338,9 +372,7 @@ class RayLog { static std::string logger_name_; protected: - std::ostream &Stream(); - // Fatal log that will be exposed as event. - std::ostream &ExposeStream(); + virtual std::ostream &Stream() { return msg_osstream_; } }; // This class make RAY_CHECK compilation pass to change the << operator to void. From 175dcf0e64a1ce95414f187c0c8a35b2d8663acc Mon Sep 17 00:00:00 2001 From: Jiajun Yao Date: Thu, 23 May 2024 23:46:28 -0700 Subject: [PATCH 04/17] up Signed-off-by: Jiajun Yao --- src/ray/util/logging.cc | 8 +++++--- src/ray/util/logging.h | 5 +---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/ray/util/logging.cc b/src/ray/util/logging.cc index 92bc1f50337a..f97ef64fd930 100644 --- a/src/ray/util/logging.cc +++ b/src/ray/util/logging.cc @@ -51,7 +51,7 @@ namespace ray { // %L is loglevel, %P is process id, %t for thread id. constexpr char kLogFormatTextPattern[] = "[%Y-%m-%d %H:%M:%S,%e %L %P %t] %v"; constexpr char kLogFormatJsonPattern[] = - "{\"asctime\":\"%Y-%m-%d %H:%M:%S,%e\", \"levelname\": \"%L\", %v}"; + "{\"asctime\":\"%Y-%m-%d %H:%M:%S,%e\",\"levelname\":\"%L\"%v}"; RayLogLevel RayLog::severity_threshold_ = RayLogLevel::INFO; std::string RayLog::app_name_ = ""; @@ -390,6 +390,8 @@ bool RayLog::IsLevelEnabled(RayLogLevel log_level) { return log_level >= severity_threshold_; } +std::string RayLog::GetLogFormatPattern() { return log_format_pattern_; } + std::string RayLog::GetLoggerName() { return logger_name_; } void RayLog::AddFatalLogCallbacks( @@ -419,8 +421,8 @@ RayLog::RayLog(const char *file_name, int line_number, RayLogLevel severity) } if (is_enabled_) { if (log_format_json_) { - context_osstream_ << "\"" << kLogKeyFilename << "\":" << ConstBasename(file_name) - << ",\"" << kLogKeyLineno << "\":" << line_number; + context_osstream_ << ",\"" << kLogKeyFilename << "\":\"" << ConstBasename(file_name) + << "\",\"" << kLogKeyLineno << "\":" << line_number; } else { msg_osstream_ << ConstBasename(file_name) << ":" << line_number << ": "; } diff --git a/src/ray/util/logging.h b/src/ray/util/logging.h index 64e43aa89ca1..3fd078d41f0f 100644 --- a/src/ray/util/logging.h +++ b/src/ray/util/logging.h @@ -296,9 +296,6 @@ class RayLog { /// To check failure signal handler enabled or not. static bool IsFailureSignalHandlerEnabled(); - /// Get the log level from environment variable. - static RayLogLevel GetLogLevelFromEnv(); - static std::string GetLogFormatPattern(); static std::string GetLoggerName(); @@ -321,7 +318,7 @@ class RayLog { template RayLog &operator<<(const RayLogField &f) { if (log_format_json_) { - context_osstream_ << ",\"" << f.key << "\"=\"" << f.value << "\""; + context_osstream_ << ",\"" << f.key << "\":\"" << f.value << "\""; } else { context_osstream_ << " " << f.key << "=" << f.value; } From f0bd19909b79ce9ddc1e531cca6f7e823fc6ff1d Mon Sep 17 00:00:00 2001 From: Jiajun Yao Date: Fri, 24 May 2024 10:44:15 -0700 Subject: [PATCH 05/17] up Signed-off-by: Jiajun Yao --- src/ray/gcs/gcs_server/gcs_actor_manager.cc | 16 ++++++++-------- src/ray/util/logging.cc | 7 +++++-- src/ray/util/logging.h | 4 ++++ 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/ray/gcs/gcs_server/gcs_actor_manager.cc b/src/ray/gcs/gcs_server/gcs_actor_manager.cc index 33183a0489a4..7fbbd7ab3801 100644 --- a/src/ray/gcs/gcs_server/gcs_actor_manager.cc +++ b/src/ray/gcs/gcs_server/gcs_actor_manager.cc @@ -259,8 +259,8 @@ void GcsActorManager::HandleRegisterActor(rpc::RegisterActorRequest request, auto actor_id = ActorID::FromBinary(request.task_spec().actor_creation_task_spec().actor_id()); - RAY_LOG(INFO) << "Registering actor, job id = " << actor_id.JobId() - << ", actor id = " << actor_id; + RAY_LOG(INFO) << "Registering actor" << RAY_LOG_FIELD(kLogKeyJobID, actor_id.JobId()) + << RAY_LOG_FIELD(kLogKeyActorID, actor_id); Status status = RegisterActor(request, [reply, send_reply_callback, actor_id]( @@ -1419,18 +1419,18 @@ void GcsActorManager::Initialize(const GcsInitData &gcs_init_data) { } } -const absl::flat_hash_map> - &GcsActorManager::GetCreatedActors() const { +const absl::flat_hash_map> & +GcsActorManager::GetCreatedActors() const { return created_actors_; } -const absl::flat_hash_map> - &GcsActorManager::GetRegisteredActors() const { +const absl::flat_hash_map> & +GcsActorManager::GetRegisteredActors() const { return registered_actors_; } -const absl::flat_hash_map> - &GcsActorManager::GetActorRegisterCallbacks() const { +const absl::flat_hash_map> & +GcsActorManager::GetActorRegisterCallbacks() const { return actor_to_register_callbacks_; } diff --git a/src/ray/util/logging.cc b/src/ray/util/logging.cc index f97ef64fd930..03bdaebf9b91 100644 --- a/src/ray/util/logging.cc +++ b/src/ray/util/logging.cc @@ -55,6 +55,7 @@ constexpr char kLogFormatJsonPattern[] = RayLogLevel RayLog::severity_threshold_ = RayLogLevel::INFO; std::string RayLog::app_name_ = ""; +std::string RayLog::component_name_ = ""; std::string RayLog::log_dir_ = ""; bool RayLog::log_format_json_ = false; std::string RayLog::log_format_pattern_ = kLogFormatTextPattern; @@ -279,8 +280,7 @@ void RayLog::StartRayLog(const std::string &app_name, file_sink->set_level(level); sinks.push_back(file_sink); } else { - // Format pattern is 2020-08-21 17:00:00,000 I 100 1001 msg. - // %L is loglevel, %P is process id, %t for thread id. + component_name_ = app_name_without_path; auto console_sink = std::make_shared(); console_sink->set_level(level); sinks.push_back(console_sink); @@ -420,6 +420,9 @@ RayLog::RayLog(const char *file_name, int line_number, RayLogLevel severity) strerror(errno)); } if (is_enabled_) { + if (!component_name_.empty()) { + msg_osstream_ << "(" << component_name_ << ") "; + } if (log_format_json_) { context_osstream_ << ",\"" << kLogKeyFilename << "\":\"" << ConstBasename(file_name) << "\",\"" << kLogKeyLineno << "\":" << line_number; diff --git a/src/ray/util/logging.h b/src/ray/util/logging.h index 3fd078d41f0f..781e95564c81 100644 --- a/src/ray/util/logging.h +++ b/src/ray/util/logging.h @@ -351,6 +351,10 @@ class RayLog { static std::vector fatal_log_callbacks_; static RayLogLevel severity_threshold_; static std::string app_name_; + /// This is used when we log to stderr + /// to indicate which component generates the log. + /// This is empty if we log to file. + static std::string component_name_; /// The directory where the log files are stored. /// If this is empty, logs are printed to stdout. static std::string log_dir_; From 748a9fdfd03ce3d207960aaf5ebabbefc5c35300 Mon Sep 17 00:00:00 2001 From: Jiajun Yao Date: Fri, 24 May 2024 13:00:20 -0700 Subject: [PATCH 06/17] up Signed-off-by: Jiajun Yao --- src/ray/util/logging.cc | 100 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/src/ray/util/logging.cc b/src/ray/util/logging.cc index 03bdaebf9b91..b93478a639ed 100644 --- a/src/ray/util/logging.cc +++ b/src/ray/util/logging.cc @@ -125,6 +125,104 @@ inline const char *ConstBasename(const char *filepath) { return base ? (base + 1) : filepath; } +std::size_t json_extra_space(const std::string &s) { + std::size_t result = 0; + + for (const auto &c : s) { + switch (c) { + case '"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': { + // from c (1 byte) to \x (2 bytes) + result += 1; + break; + } + + default: + break; + } + } + + return result; +} + +// Adapted from nlohmann/json +std::string json_escape_string(const std::string &s) noexcept { + const auto space = json_extra_space(s); + if (space == 0) { + return s; + } + + // create a result string of necessary size + std::string result(s.size() + space, '\\'); + std::size_t pos = 0; + + for (const auto &c : s) { + switch (c) { + // quotation mark (0x22) + case '"': { + result[pos + 1] = '"'; + pos += 2; + break; + } + + // reverse solidus (0x5c) + case '\\': { + // nothing to change + pos += 2; + break; + } + + // backspace (0x08) + case '\b': { + result[pos + 1] = 'b'; + pos += 2; + break; + } + + // formfeed (0x0c) + case '\f': { + result[pos + 1] = 'f'; + pos += 2; + break; + } + + // newline (0x0a) + case '\n': { + result[pos + 1] = 'n'; + pos += 2; + break; + } + + // carriage return (0x0d) + case '\r': { + result[pos + 1] = 'r'; + pos += 2; + break; + } + + // horizontal tab (0x09) + case '\t': { + result[pos + 1] = 't'; + pos += 2; + break; + } + + default: { + // all other characters are added as-is + result[pos++] = c; + break; + } + } + } + + return result; +} + /// A logger that prints logs to stderr. /// This is the default logger if logging is not initialized. /// NOTE(lingxuan.zlx): Default stderr logger must be singleton and global @@ -454,7 +552,7 @@ RayLog::~RayLog() { logger->log(GetMappedSeverity(severity_), /*fmt*/ ",\"{}\":\"{}\"{}", kLogKeyMessage, - msg_osstream_.str(), + json_escape_string(msg_osstream_.str()), context_osstream_.str()); } else { logger->log(GetMappedSeverity(severity_), From a02a99a9012e5535f90094c4f410fe8e099c226a Mon Sep 17 00:00:00 2001 From: Jiajun Yao Date: Fri, 24 May 2024 21:52:57 -0700 Subject: [PATCH 07/17] up Signed-off-by: Jiajun Yao --- src/ray/gcs/gcs_server/gcs_actor_manager.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ray/gcs/gcs_server/gcs_actor_manager.cc b/src/ray/gcs/gcs_server/gcs_actor_manager.cc index 7fbbd7ab3801..50a17542b379 100644 --- a/src/ray/gcs/gcs_server/gcs_actor_manager.cc +++ b/src/ray/gcs/gcs_server/gcs_actor_manager.cc @@ -1419,18 +1419,18 @@ void GcsActorManager::Initialize(const GcsInitData &gcs_init_data) { } } -const absl::flat_hash_map> & -GcsActorManager::GetCreatedActors() const { +const absl::flat_hash_map> + &GcsActorManager::GetCreatedActors() const { return created_actors_; } -const absl::flat_hash_map> & -GcsActorManager::GetRegisteredActors() const { +const absl::flat_hash_map> + &GcsActorManager::GetRegisteredActors() const { return registered_actors_; } -const absl::flat_hash_map> & -GcsActorManager::GetActorRegisterCallbacks() const { +const absl::flat_hash_map> + &GcsActorManager::GetActorRegisterCallbacks() const { return actor_to_register_callbacks_; } From a2e9974c5f77485da695048d4ca95773dce89831 Mon Sep 17 00:00:00 2001 From: Jiajun Yao Date: Wed, 29 May 2024 11:15:48 -0700 Subject: [PATCH 08/17] up Signed-off-by: Jiajun Yao --- src/ray/gcs/gcs_server/gcs_actor_manager.cc | 6 +++-- src/ray/raylet/node_manager.cc | 4 +-- src/ray/util/logging.cc | 9 +++++++ src/ray/util/logging.h | 29 +++------------------ 4 files changed, 18 insertions(+), 30 deletions(-) diff --git a/src/ray/gcs/gcs_server/gcs_actor_manager.cc b/src/ray/gcs/gcs_server/gcs_actor_manager.cc index 50a17542b379..c73377ae11f9 100644 --- a/src/ray/gcs/gcs_server/gcs_actor_manager.cc +++ b/src/ray/gcs/gcs_server/gcs_actor_manager.cc @@ -259,8 +259,10 @@ void GcsActorManager::HandleRegisterActor(rpc::RegisterActorRequest request, auto actor_id = ActorID::FromBinary(request.task_spec().actor_creation_task_spec().actor_id()); - RAY_LOG(INFO) << "Registering actor" << RAY_LOG_FIELD(kLogKeyJobID, actor_id.JobId()) - << RAY_LOG_FIELD(kLogKeyActorID, actor_id); + RAY_LOG(INFO) + .WithField(kLogKeyJobID, actor_id.JobId().Hex()) + .WithField(kLogKeyActorID, actor_id.Hex()) + << "Registering actor"; Status status = RegisterActor(request, [reply, send_reply_callback, actor_id]( diff --git a/src/ray/raylet/node_manager.cc b/src/ray/raylet/node_manager.cc index 56c2f9b6ef09..2c3fdf34f47a 100644 --- a/src/ray/raylet/node_manager.cc +++ b/src/ray/raylet/node_manager.cc @@ -284,8 +284,8 @@ NodeManager::NodeManager( RayConfig::instance().min_memory_free_bytes(), RayConfig::instance().memory_monitor_refresh_ms(), CreateMemoryUsageRefreshCallback())) { - RAY_LOG(INFO) << "Initializing NodeManager" - << RAY_LOG_FIELD(kLogKeyNodeID, self_node_id_); + RAY_LOG(INFO).WithField(kLogKeyNodeID, self_node_id_.Hex()) + << "Initializing NodeManager"; cluster_resource_scheduler_ = std::make_shared( io_service, scheduling::NodeID(self_node_id_.Binary()), diff --git a/src/ray/util/logging.cc b/src/ray/util/logging.cc index b93478a639ed..924a32c93293 100644 --- a/src/ray/util/logging.cc +++ b/src/ray/util/logging.cc @@ -567,4 +567,13 @@ RayLog::~RayLog() { } } +RayLog &RayLog::WithField(const std::string &key, const std::string &value) { + if (log_format_json_) { + context_osstream_ << ",\"" << key << "\":\"" << json_escape_string(value) << "\""; + } else { + context_osstream_ << " " << key << "=" << value; + } + return *this; +} + } // namespace ray diff --git a/src/ray/util/logging.h b/src/ray/util/logging.h index 781e95564c81..c3055ba00ebd 100644 --- a/src/ray/util/logging.h +++ b/src/ray/util/logging.h @@ -114,8 +114,6 @@ enum class RayLogLevel { #define RAY_LOG_ENABLED(level) ray::RayLog::IsLevelEnabled(ray::RayLogLevel::level) -#define RAY_LOG_FIELD(key, value) ::ray::MakeRayLogField(key, value) - #define RAY_LOG(level) \ if (ray::RayLog::IsLevelEnabled(ray::RayLogLevel::level)) \ RAY_LOG_INTERNAL(ray::RayLogLevel::level) @@ -226,19 +224,6 @@ enum class RayLogLevel { /// The second argument: log content. using FatalLogCallback = std::function; -template -struct RayLogField { - RayLogField(const std::string &key, const T &value) : key(key), value(value) {} - - const std::string &key; - const T &value; -}; - -template -RayLogField MakeRayLogField(const std::string &key, const T &value) { - return RayLogField(key, value); -} - class RayLog { public: RayLog(const char *file_name, int line_number, RayLogLevel severity); @@ -315,15 +300,7 @@ class RayLog { return *this; } - template - RayLog &operator<<(const RayLogField &f) { - if (log_format_json_) { - context_osstream_ << ",\"" << f.key << "\":\"" << f.value << "\""; - } else { - context_osstream_ << " " << f.key << "=" << f.value; - } - return *this; - } + RayLog &WithField(const std::string &key, const std::string &value); private: FRIEND_TEST(PrintLogTest, TestRayLogEveryNOrDebug); @@ -340,7 +317,7 @@ class RayLog { bool is_fatal_ = false; /// String stream of the log message std::ostringstream msg_osstream_; - /// String stream of the log contexts: a list of key-value pairs. + /// String stream of the log context: a list of key-value pairs. std::ostringstream context_osstream_; /// String stream of exposed fatal log content. std::ostringstream expose_fatal_osstream_; @@ -363,7 +340,7 @@ class RayLog { static bool is_failure_signal_handler_installed_; /// Whether emit json logs. static bool log_format_json_; - // Log format content. + // Log format pattern. static std::string log_format_pattern_; // Log rotation file size limitation. static long log_rotation_max_size_; From 2ce48bc4997eb1c2460f4165daf3213f908c0701 Mon Sep 17 00:00:00 2001 From: Jiajun Yao Date: Wed, 29 May 2024 23:49:56 -0700 Subject: [PATCH 09/17] tests Signed-off-by: Jiajun Yao --- src/ray/util/logging.cc | 10 ++-- src/ray/util/logging.h | 1 + src/ray/util/tests/BUILD | 1 - src/ray/util/tests/logging_test.cc | 86 +++++++++++++++--------------- 4 files changed, 52 insertions(+), 46 deletions(-) diff --git a/src/ray/util/logging.cc b/src/ray/util/logging.cc index 6210dab25af2..0c7c6cb6137c 100644 --- a/src/ray/util/logging.cc +++ b/src/ray/util/logging.cc @@ -517,13 +517,17 @@ RayLog::RayLog(const char *file_name, int line_number, RayLogLevel severity) strerror(errno)); } if (is_enabled_) { - if (!component_name_.empty()) { - msg_osstream_ << "(" << component_name_ << ") "; - } if (log_format_json_) { + if (!component_name_.empty()) { + context_osstream_ << ",\"" << kLogKeyComponent << "\":\"" << component_name_ + << "\""; + } context_osstream_ << ",\"" << kLogKeyFilename << "\":\"" << ConstBasename(file_name) << "\",\"" << kLogKeyLineno << "\":" << line_number; } else { + if (!component_name_.empty()) { + msg_osstream_ << "(" << component_name_ << ") "; + } msg_osstream_ << ConstBasename(file_name) << ":" << line_number << ": "; } } diff --git a/src/ray/util/logging.h b/src/ray/util/logging.h index c3055ba00ebd..ba9c72bccdfc 100644 --- a/src/ray/util/logging.h +++ b/src/ray/util/logging.h @@ -95,6 +95,7 @@ constexpr char kLogKeyWorkerID[] = "worker_id"; constexpr char kLogKeyNodeID[] = "node_id"; constexpr char kLogKeyActorID[] = "actor_id"; constexpr char kLogKeyTaskID[] = "task_id"; +constexpr char kLogKeyComponent[] = "component"; class StackTrace { /// This dumps the current stack trace information. diff --git a/src/ray/util/tests/BUILD b/src/ray/util/tests/BUILD index d1008fb40ac7..4ce6b5e4d5ff 100644 --- a/src/ray/util/tests/BUILD +++ b/src/ray/util/tests/BUILD @@ -74,7 +74,6 @@ cc_test( size = "small", srcs = ["logging_test.cc"], args = [ - "--gtest_filter=PrintLogTest*", # Disable so we can test terminate handler. "--gtest_catch_exceptions=0", ], diff --git a/src/ray/util/tests/logging_test.cc b/src/ray/util/tests/logging_test.cc index 965e443eb466..56fffa0d63d7 100644 --- a/src/ray/util/tests/logging_test.cc +++ b/src/ray/util/tests/logging_test.cc @@ -16,24 +16,22 @@ #include #include +#include #include #include "absl/strings/str_format.h" +#include "absl/strings/str_split.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "nlohmann/json.hpp" #include "ray/util/filesystem.h" +#include "ray/util/util.h" using namespace testing; +using json = nlohmann::json; namespace ray { -int64_t current_time_ms() { - std::chrono::milliseconds ms_since_epoch = - std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()); - return ms_since_epoch.count(); -} - // This is not really test. // This file just print some information using the logging macro. @@ -195,41 +193,6 @@ TEST(PrintLogTest, LogTestWithInit) { RayLog::ShutDownRayLog(); } -// This test will output large amount of logs to stderr, should be disabled in travis. -TEST(LogPerfTest, PerfTest) { - RayLog::StartRayLog( - "/fake/path/to/appdire/LogPerfTest", RayLogLevel::ERROR, ray::GetUserTempDir()); - int rounds = 10; - - int64_t start_time = current_time_ms(); - for (int i = 0; i < rounds; ++i) { - RAY_LOG(DEBUG) << "This is the " - << "RAY_DEBUG message"; - } - int64_t elapsed = current_time_ms() - start_time; - std::cout << "Testing DEBUG log for " << rounds << " rounds takes " << elapsed << " ms." - << std::endl; - - start_time = current_time_ms(); - for (int i = 0; i < rounds; ++i) { - RAY_LOG(ERROR) << "This is the " - << "RAY_ERROR message"; - } - elapsed = current_time_ms() - start_time; - std::cout << "Testing RAY_ERROR log for " << rounds << " rounds takes " << elapsed - << " ms." << std::endl; - - start_time = current_time_ms(); - for (int i = 0; i < rounds; ++i) { - RAY_CHECK(i >= 0) << "This is a RAY_CHECK " - << "message but it won't show up"; - } - elapsed = current_time_ms() - start_time; - std::cout << "Testing RAY_CHECK(true) for " << rounds << " rounds takes " << elapsed - << " ms." << std::endl; - RayLog::ShutDownRayLog(); -} - TEST(PrintLogTest, TestCheckOp) { int i = 1; RAY_CHECK_EQ(i, 1); @@ -308,6 +271,45 @@ TEST(PrintLogTest, TestFailureSignalHandler) { ASSERT_DEATH(abort(), ".*SIGABRT received.*"); } +class LogTest : public ::testing::Test { + protected: + std::filesystem::path log_dir_; + LogTest() { + log_dir_ = std::filesystem::temp_directory_path() / GenerateUUIDV4(); + std::filesystem::create_directories(log_dir_); + } + + ~LogTest() { std::filesystem::remove_all(log_dir_); } + + std::vector ReadLogFile() { + std::filesystem::path log_file; + for (const auto &entry : std::filesystem::directory_iterator(log_dir_)) { + log_file = entry.path(); + break; + } + + std::ifstream fstream(log_file.c_str()); + std::stringstream sstream; + sstream << fstream.rdbuf(); + return absl::StrSplit(sstream.str(), '\n', absl::SkipEmpty()); + } +}; + +TEST_F(LogTest, TestJSONLogging) { + setenv("RAY_BACKEND_LOG_FORMAT", "JSON", true); + RayLog::StartRayLog("", RayLogLevel::INFO, log_dir_.string()); + RAY_LOG(DEBUG) << "this is not logged"; + RAY_LOG(INFO) << "this is info logged"; + RAY_LOG(WARNING) << "this needs\nescape\""; + RAY_LOG(INFO).WithField("key1", "value1").WithField("key2", "value2") + << "contextual log"; + auto log_lines = ReadLogFile(); + ASSERT_EQ(3, log_lines.size()); + json log1 = json::parse(log_lines[0]); + ASSERT_EQ(log1[kLogKeyMessage], "this is info logged"); + RayLog::ShutDownRayLog(); +} + } // namespace ray int main(int argc, char **argv) { From 5f3085c6e36950dd36035eba9391f418c48f530b Mon Sep 17 00:00:00 2001 From: Jiajun Yao Date: Thu, 30 May 2024 07:23:42 -0700 Subject: [PATCH 10/17] up Signed-off-by: Jiajun Yao --- src/ray/util/logging.h | 2 +- src/ray/util/tests/BUILD | 1 + src/ray/util/tests/logging_test.cc | 105 ++++++++++++++++++----------- 3 files changed, 68 insertions(+), 40 deletions(-) diff --git a/src/ray/util/logging.h b/src/ray/util/logging.h index ba9c72bccdfc..b495df657c5e 100644 --- a/src/ray/util/logging.h +++ b/src/ray/util/logging.h @@ -90,12 +90,12 @@ constexpr char kLogKeyLevelname[] = "levelname"; constexpr char kLogKeyMessage[] = "message"; constexpr char kLogKeyFilename[] = "filename"; constexpr char kLogKeyLineno[] = "lineno"; +constexpr char kLogKeyComponent[] = "component"; constexpr char kLogKeyJobID[] = "job_id"; constexpr char kLogKeyWorkerID[] = "worker_id"; constexpr char kLogKeyNodeID[] = "node_id"; constexpr char kLogKeyActorID[] = "actor_id"; constexpr char kLogKeyTaskID[] = "task_id"; -constexpr char kLogKeyComponent[] = "component"; class StackTrace { /// This dumps the current stack trace information. diff --git a/src/ray/util/tests/BUILD b/src/ray/util/tests/BUILD index 4ce6b5e4d5ff..d1008fb40ac7 100644 --- a/src/ray/util/tests/BUILD +++ b/src/ray/util/tests/BUILD @@ -74,6 +74,7 @@ cc_test( size = "small", srcs = ["logging_test.cc"], args = [ + "--gtest_filter=PrintLogTest*", # Disable so we can test terminate handler. "--gtest_catch_exceptions=0", ], diff --git a/src/ray/util/tests/logging_test.cc b/src/ray/util/tests/logging_test.cc index 56fffa0d63d7..3738af1e2445 100644 --- a/src/ray/util/tests/logging_test.cc +++ b/src/ray/util/tests/logging_test.cc @@ -59,7 +59,9 @@ TEST(PrintLogTest, LogTestWithoutInit) { #if GTEST_HAS_STREAM_REDIRECTION using testing::internal::CaptureStderr; +using testing::internal::CaptureStdout; using testing::internal::GetCapturedStderr; +using testing::internal::GetCapturedStdout; namespace { void VerifyOnlyNthOccurenceLogged(bool fallback_to_debug) { @@ -184,6 +186,35 @@ TEST(PrintLogTest, TestRayLogEveryMs) { EXPECT_LT(occurrences, 15); } +TEST(PrintLogTest, TestJSONLogging) { + setenv("RAY_BACKEND_LOG_FORMAT", "JSON", true); + RayLog::StartRayLog("/tmp/raylet", RayLogLevel::INFO, ""); + CaptureStdout(); + RAY_LOG(DEBUG) << "this is not logged"; + RAY_LOG(INFO) << "this is info logged"; + RAY_LOG(WARNING) << "this needs\nescape\""; + RAY_LOG(INFO).WithField("key1", "value1").WithField("key2", "value\n2") + << "contextual log"; + + std::vector log_lines = + absl::StrSplit(GetCapturedStdout(), '\n', absl::SkipEmpty()); + ASSERT_EQ(3, log_lines.size()); + json log1 = json::parse(log_lines[0]); + json log2 = json::parse(log_lines[1]); + json log3 = json::parse(log_lines[2]); + ASSERT_EQ(log1[kLogKeyMessage], "this is info logged"); + ASSERT_EQ(log2[kLogKeyMessage], "this needs\nescape\""); + ASSERT_EQ(log3[kLogKeyMessage], "contextual log"); + ASSERT_TRUE(log3.contains(kLogKeyAsctime)); + ASSERT_TRUE(log3.contains(kLogKeyFilename)); + ASSERT_TRUE(log3.contains(kLogKeyLineno)); + ASSERT_EQ(log3[kLogKeyLevelname], "I"); + ASSERT_EQ(log3[kLogKeyComponent], "raylet"); + ASSERT_EQ(log3["key1"], "value1"); + ASSERT_EQ(log3["key2"], "value\n2"); + RayLog::ShutDownRayLog(); +} + #endif /* GTEST_HAS_STREAM_REDIRECTION */ TEST(PrintLogTest, LogTestWithInit) { @@ -193,6 +224,41 @@ TEST(PrintLogTest, LogTestWithInit) { RayLog::ShutDownRayLog(); } +// This test will output large amount of logs to stderr, should be disabled in travis. +TEST(LogPerfTest, PerfTest) { + RayLog::StartRayLog( + "/fake/path/to/appdire/LogPerfTest", RayLogLevel::ERROR, ray::GetUserTempDir()); + int rounds = 10; + + int64_t start_time = current_time_ms(); + for (int i = 0; i < rounds; ++i) { + RAY_LOG(DEBUG) << "This is the " + << "RAY_DEBUG message"; + } + int64_t elapsed = current_time_ms() - start_time; + std::cout << "Testing DEBUG log for " << rounds << " rounds takes " << elapsed << " ms." + << std::endl; + + start_time = current_time_ms(); + for (int i = 0; i < rounds; ++i) { + RAY_LOG(ERROR) << "This is the " + << "RAY_ERROR message"; + } + elapsed = current_time_ms() - start_time; + std::cout << "Testing RAY_ERROR log for " << rounds << " rounds takes " << elapsed + << " ms." << std::endl; + + start_time = current_time_ms(); + for (int i = 0; i < rounds; ++i) { + RAY_CHECK(i >= 0) << "This is a RAY_CHECK " + << "message but it won't show up"; + } + elapsed = current_time_ms() - start_time; + std::cout << "Testing RAY_CHECK(true) for " << rounds << " rounds takes " << elapsed + << " ms." << std::endl; + RayLog::ShutDownRayLog(); +} + TEST(PrintLogTest, TestCheckOp) { int i = 1; RAY_CHECK_EQ(i, 1); @@ -271,45 +337,6 @@ TEST(PrintLogTest, TestFailureSignalHandler) { ASSERT_DEATH(abort(), ".*SIGABRT received.*"); } -class LogTest : public ::testing::Test { - protected: - std::filesystem::path log_dir_; - LogTest() { - log_dir_ = std::filesystem::temp_directory_path() / GenerateUUIDV4(); - std::filesystem::create_directories(log_dir_); - } - - ~LogTest() { std::filesystem::remove_all(log_dir_); } - - std::vector ReadLogFile() { - std::filesystem::path log_file; - for (const auto &entry : std::filesystem::directory_iterator(log_dir_)) { - log_file = entry.path(); - break; - } - - std::ifstream fstream(log_file.c_str()); - std::stringstream sstream; - sstream << fstream.rdbuf(); - return absl::StrSplit(sstream.str(), '\n', absl::SkipEmpty()); - } -}; - -TEST_F(LogTest, TestJSONLogging) { - setenv("RAY_BACKEND_LOG_FORMAT", "JSON", true); - RayLog::StartRayLog("", RayLogLevel::INFO, log_dir_.string()); - RAY_LOG(DEBUG) << "this is not logged"; - RAY_LOG(INFO) << "this is info logged"; - RAY_LOG(WARNING) << "this needs\nescape\""; - RAY_LOG(INFO).WithField("key1", "value1").WithField("key2", "value2") - << "contextual log"; - auto log_lines = ReadLogFile(); - ASSERT_EQ(3, log_lines.size()); - json log1 = json::parse(log_lines[0]); - ASSERT_EQ(log1[kLogKeyMessage], "this is info logged"); - RayLog::ShutDownRayLog(); -} - } // namespace ray int main(int argc, char **argv) { From b348bc521e7cc0fa6e17e7d8a503b4830dbd1182 Mon Sep 17 00:00:00 2001 From: Jiajun Yao Date: Thu, 30 May 2024 08:13:59 -0700 Subject: [PATCH 11/17] up Signed-off-by: Jiajun Yao --- src/ray/util/tests/logging_test.cc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/ray/util/tests/logging_test.cc b/src/ray/util/tests/logging_test.cc index 3738af1e2445..89c6092979a1 100644 --- a/src/ray/util/tests/logging_test.cc +++ b/src/ray/util/tests/logging_test.cc @@ -186,6 +186,23 @@ TEST(PrintLogTest, TestRayLogEveryMs) { EXPECT_LT(occurrences, 15); } +TEST(PrintLogTest, TestTextLogging) { + setenv("RAY_BACKEND_LOG_FORMAT", "TEXT", true); + RayLog::StartRayLog("/tmp/gcs", RayLogLevel::INFO, ""); + CaptureStdout(); + RAY_LOG(INFO).WithField("key1", "value1").WithField("key2", "value2") + << "contextual log"; + + std::vector log_lines = + absl::StrSplit(GetCapturedStdout(), '\n', absl::SkipEmpty()); + ASSERT_EQ(1, log_lines.size()); + ASSERT_NE(log_lines[0].find("contextual log key1=value1 key2=value2"), + std::string::npos); + + RayLog::ShutDownRayLog(); + unsetenv("RAY_BACKEND_LOG_FORMAT"); +} + TEST(PrintLogTest, TestJSONLogging) { setenv("RAY_BACKEND_LOG_FORMAT", "JSON", true); RayLog::StartRayLog("/tmp/raylet", RayLogLevel::INFO, ""); @@ -212,7 +229,9 @@ TEST(PrintLogTest, TestJSONLogging) { ASSERT_EQ(log3[kLogKeyComponent], "raylet"); ASSERT_EQ(log3["key1"], "value1"); ASSERT_EQ(log3["key2"], "value\n2"); + RayLog::ShutDownRayLog(); + unsetenv("RAY_BACKEND_LOG_FORMAT"); } #endif /* GTEST_HAS_STREAM_REDIRECTION */ From c17fd3bb2a9093e3a3b1903acd46448ec367577a Mon Sep 17 00:00:00 2001 From: Jiajun Yao Date: Thu, 30 May 2024 15:58:43 -0700 Subject: [PATCH 12/17] up Signed-off-by: Jiajun Yao --- src/ray/raylet/node_manager.cc | 3 +- src/ray/util/logging.cc | 111 +-------------------------------- src/ray/util/logging.h | 41 ++++++++---- 3 files changed, 32 insertions(+), 123 deletions(-) diff --git a/src/ray/raylet/node_manager.cc b/src/ray/raylet/node_manager.cc index f4a16e5f971b..29099231237d 100644 --- a/src/ray/raylet/node_manager.cc +++ b/src/ray/raylet/node_manager.cc @@ -284,8 +284,7 @@ NodeManager::NodeManager( RayConfig::instance().min_memory_free_bytes(), RayConfig::instance().memory_monitor_refresh_ms(), CreateMemoryUsageRefreshCallback())) { - RAY_LOG(INFO).WithField(kLogKeyNodeID, self_node_id_.Hex()) - << "Initializing NodeManager"; + RAY_LOG(INFO).WithField(kLogKeyNodeID, self_node_id_) << "Initializing NodeManager"; cluster_resource_scheduler_ = std::make_shared( io_service, scheduling::NodeID(self_node_id_.Binary()), diff --git a/src/ray/util/logging.cc b/src/ray/util/logging.cc index 0c7c6cb6137c..454e0e91ffe6 100644 --- a/src/ray/util/logging.cc +++ b/src/ray/util/logging.cc @@ -124,104 +124,6 @@ inline const char *ConstBasename(const char *filepath) { return base ? (base + 1) : filepath; } -std::size_t json_extra_space(const std::string &s) { - std::size_t result = 0; - - for (const auto &c : s) { - switch (c) { - case '"': - case '\\': - case '\b': - case '\f': - case '\n': - case '\r': - case '\t': { - // from c (1 byte) to \x (2 bytes) - result += 1; - break; - } - - default: - break; - } - } - - return result; -} - -// Adapted from nlohmann/json -std::string json_escape_string(const std::string &s) noexcept { - const auto space = json_extra_space(s); - if (space == 0) { - return s; - } - - // create a result string of necessary size - std::string result(s.size() + space, '\\'); - std::size_t pos = 0; - - for (const auto &c : s) { - switch (c) { - // quotation mark (0x22) - case '"': { - result[pos + 1] = '"'; - pos += 2; - break; - } - - // reverse solidus (0x5c) - case '\\': { - // nothing to change - pos += 2; - break; - } - - // backspace (0x08) - case '\b': { - result[pos + 1] = 'b'; - pos += 2; - break; - } - - // formfeed (0x0c) - case '\f': { - result[pos + 1] = 'f'; - pos += 2; - break; - } - - // newline (0x0a) - case '\n': { - result[pos + 1] = 'n'; - pos += 2; - break; - } - - // carriage return (0x0d) - case '\r': { - result[pos + 1] = 'r'; - pos += 2; - break; - } - - // horizontal tab (0x09) - case '\t': { - result[pos + 1] = 't'; - pos += 2; - break; - } - - default: { - // all other characters are added as-is - result[pos++] = c; - break; - } - } - } - - return result; -} - /// A logger that prints logs to stderr. /// This is the default logger if logging is not initialized. /// NOTE(lingxuan.zlx): Default stderr logger must be singleton and global @@ -553,9 +455,9 @@ RayLog::~RayLog() { // NOTE(lingxuan.zlx): See more fmt by visiting https://github.com/fmtlib/fmt. if (log_format_json_) { logger->log(GetMappedSeverity(severity_), - /*fmt*/ ",\"{}\":\"{}\"{}", + /*fmt*/ ",\"{}\":{}{}", kLogKeyMessage, - json_escape_string(msg_osstream_.str()), + nlohmann::json(msg_osstream_.str()).dump(), context_osstream_.str()); } else { logger->log(GetMappedSeverity(severity_), @@ -570,13 +472,4 @@ RayLog::~RayLog() { } } -RayLog &RayLog::WithField(const std::string &key, const std::string &value) { - if (log_format_json_) { - context_osstream_ << ",\"" << key << "\":\"" << json_escape_string(value) << "\""; - } else { - context_osstream_ << " " << key << "=" << value; - } - return *this; -} - } // namespace ray diff --git a/src/ray/util/logging.h b/src/ray/util/logging.h index b495df657c5e..29ea28b664da 100644 --- a/src/ray/util/logging.h +++ b/src/ray/util/logging.h @@ -59,6 +59,8 @@ #include #include +#include "nlohmann/json.hpp" + #if defined(_WIN32) #ifndef _WINDOWS_ #ifndef WIN32_LEAN_AND_MEAN // Sorry for the inconvenience. Please include any related @@ -85,17 +87,17 @@ enum { ERROR = 0 }; #endif namespace ray { -constexpr char kLogKeyAsctime[] = "asctime"; -constexpr char kLogKeyLevelname[] = "levelname"; -constexpr char kLogKeyMessage[] = "message"; -constexpr char kLogKeyFilename[] = "filename"; -constexpr char kLogKeyLineno[] = "lineno"; -constexpr char kLogKeyComponent[] = "component"; -constexpr char kLogKeyJobID[] = "job_id"; -constexpr char kLogKeyWorkerID[] = "worker_id"; -constexpr char kLogKeyNodeID[] = "node_id"; -constexpr char kLogKeyActorID[] = "actor_id"; -constexpr char kLogKeyTaskID[] = "task_id"; +constexpr std::string_view kLogKeyAsctime = "asctime"; +constexpr std::string_view kLogKeyLevelname = "levelname"; +constexpr std::string_view kLogKeyMessage = "message"; +constexpr std::string_view kLogKeyFilename = "filename"; +constexpr std::string_view kLogKeyLineno = "lineno"; +constexpr std::string_view kLogKeyComponent = "component"; +constexpr std::string_view kLogKeyJobID = "job_id"; +constexpr std::string_view kLogKeyWorkerID = "worker_id"; +constexpr std::string_view kLogKeyNodeID = "node_id"; +constexpr std::string_view kLogKeyActorID = "actor_id"; +constexpr std::string_view kLogKeyTaskID = "task_id"; class StackTrace { /// This dumps the current stack trace information. @@ -301,7 +303,22 @@ class RayLog { return *this; } - RayLog &WithField(const std::string &key, const std::string &value); + template + RayLog &WithField(std::string_view key, const T &value) { + std::stringstream ss; + ss << value; + return WithField(key, ss.str()); + } + + template <> + RayLog &WithField(std::string_view key, const std::string &value) { + if (log_format_json_) { + context_osstream_ << ",\"" << key << "\":" << nlohmann::json(value).dump(); + } else { + context_osstream_ << " " << key << "=" << value; + } + return *this; + } private: FRIEND_TEST(PrintLogTest, TestRayLogEveryNOrDebug); From 884889327d6d64f26795d74ceac2a996313524a7 Mon Sep 17 00:00:00 2001 From: Jiajun Yao Date: Thu, 30 May 2024 16:22:07 -0700 Subject: [PATCH 13/17] up Signed-off-by: Jiajun Yao --- src/ray/util/logging.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ray/util/logging.h b/src/ray/util/logging.h index 29ea28b664da..ab0dc014566d 100644 --- a/src/ray/util/logging.h +++ b/src/ray/util/logging.h @@ -87,6 +87,7 @@ enum { ERROR = 0 }; #endif namespace ray { +/// Sync with ray._private.structured_logging.constants.LogKey constexpr std::string_view kLogKeyAsctime = "asctime"; constexpr std::string_view kLogKeyLevelname = "levelname"; constexpr std::string_view kLogKeyMessage = "message"; @@ -303,6 +304,9 @@ class RayLog { return *this; } + /// Add log context to the log. + /// Caller should make sure key is not duplicated + /// and doesn't conflict with system keys like levelname. template RayLog &WithField(std::string_view key, const T &value) { std::stringstream ss; From 0840058027c4814061863880bf23bfb5b8a689b6 Mon Sep 17 00:00:00 2001 From: Jiajun Yao Date: Thu, 30 May 2024 21:37:49 -0700 Subject: [PATCH 14/17] up Signed-off-by: Jiajun Yao --- src/ray/gcs/gcs_server/gcs_actor_manager.cc | 4 +-- src/ray/util/logging.cc | 16 +++------ src/ray/util/logging.h | 37 +++++++++++++++------ src/ray/util/tests/logging_test.cc | 18 +++++----- 4 files changed, 43 insertions(+), 32 deletions(-) diff --git a/src/ray/gcs/gcs_server/gcs_actor_manager.cc b/src/ray/gcs/gcs_server/gcs_actor_manager.cc index c73377ae11f9..008b6c13e3a2 100644 --- a/src/ray/gcs/gcs_server/gcs_actor_manager.cc +++ b/src/ray/gcs/gcs_server/gcs_actor_manager.cc @@ -260,8 +260,8 @@ void GcsActorManager::HandleRegisterActor(rpc::RegisterActorRequest request, ActorID::FromBinary(request.task_spec().actor_creation_task_spec().actor_id()); RAY_LOG(INFO) - .WithField(kLogKeyJobID, actor_id.JobId().Hex()) - .WithField(kLogKeyActorID, actor_id.Hex()) + .WithField(kLogKeyJobID, actor_id.JobId()) + .WithField(kLogKeyActorID, actor_id) << "Registering actor"; Status status = RegisterActor(request, diff --git a/src/ray/util/logging.cc b/src/ray/util/logging.cc index 454e0e91ffe6..24f6e9dcd153 100644 --- a/src/ray/util/logging.cc +++ b/src/ray/util/logging.cc @@ -203,17 +203,12 @@ void RayLog::InitLogFormat() { log_format_json_ = false; log_format_pattern_ = kLogFormatTextPattern; - const char *var_value = std::getenv("RAY_BACKEND_LOG_FORMAT"); + const char *var_value = std::getenv("RAY_BACKEND_LOG_JSON"); if (var_value != nullptr) { std::string data = var_value; - std::transform(data.begin(), data.end(), data.begin(), ::tolower); - if (data == "json") { + if (data == "1") { log_format_json_ = true; log_format_pattern_ = kLogFormatJsonPattern; - } else if (data == "text") { - // Default - } else { - RAY_LOG(WARNING) << "Unrecognized setting of RAY_BACKEND_LOG_FORMAT=" << var_value; } } } @@ -421,11 +416,10 @@ RayLog::RayLog(const char *file_name, int line_number, RayLogLevel severity) if (is_enabled_) { if (log_format_json_) { if (!component_name_.empty()) { - context_osstream_ << ",\"" << kLogKeyComponent << "\":\"" << component_name_ - << "\""; + WithField(kLogKeyComponent, component_name_); } - context_osstream_ << ",\"" << kLogKeyFilename << "\":\"" << ConstBasename(file_name) - << "\",\"" << kLogKeyLineno << "\":" << line_number; + WithField(kLogKeyFilename, ConstBasename(file_name)); + WithField(kLogKeyLineno, line_number); } else { if (!component_name_.empty()) { msg_osstream_ << "(" << component_name_ << ") "; diff --git a/src/ray/util/logging.h b/src/ray/util/logging.h index ab0dc014566d..1a922c5b5041 100644 --- a/src/ray/util/logging.h +++ b/src/ray/util/logging.h @@ -309,24 +309,38 @@ class RayLog { /// and doesn't conflict with system keys like levelname. template RayLog &WithField(std::string_view key, const T &value) { + if (log_format_json_) { + return WithFieldJsonFormat(key, value); + } else { + return WithFieldTextFormat(key, value); + } + } + + private: + template + RayLog &WithFieldTextFormat(std::string_view key, const T &value) { + context_osstream_ << " " << key << "=" << value; + return *this; + } + + template + RayLog &WithFieldJsonFormat(std::string_view key, const T &value) { std::stringstream ss; ss << value; - return WithField(key, ss.str()); + return WithFieldJsonFormat(key, ss.str()); } template <> - RayLog &WithField(std::string_view key, const std::string &value) { - if (log_format_json_) { - context_osstream_ << ",\"" << key << "\":" << nlohmann::json(value).dump(); - } else { - context_osstream_ << " " << key << "=" << value; - } + RayLog &WithFieldJsonFormat(std::string_view key, const std::string &value) { + context_osstream_ << ",\"" << key << "\":" << nlohmann::json(value).dump(); return *this; } - private: - FRIEND_TEST(PrintLogTest, TestRayLogEveryNOrDebug); - FRIEND_TEST(PrintLogTest, TestRayLogEveryN); + template <> + RayLog &WithFieldJsonFormat(std::string_view key, const int &value) { + context_osstream_ << ",\"" << key << "\":" << value; + return *this; + } static void InitSeverityThreshold(RayLogLevel severity_threshold); static void InitLogFormat(); @@ -371,6 +385,9 @@ class RayLog { // Ray default logger name. static std::string logger_name_; + FRIEND_TEST(PrintLogTest, TestRayLogEveryNOrDebug); + FRIEND_TEST(PrintLogTest, TestRayLogEveryN); + protected: virtual std::ostream &Stream() { return msg_osstream_; } }; diff --git a/src/ray/util/tests/logging_test.cc b/src/ray/util/tests/logging_test.cc index 89c6092979a1..b09197b64a0f 100644 --- a/src/ray/util/tests/logging_test.cc +++ b/src/ray/util/tests/logging_test.cc @@ -187,7 +187,7 @@ TEST(PrintLogTest, TestRayLogEveryMs) { } TEST(PrintLogTest, TestTextLogging) { - setenv("RAY_BACKEND_LOG_FORMAT", "TEXT", true); + setenv("RAY_BACKEND_LOG_JSON", "0", true); RayLog::StartRayLog("/tmp/gcs", RayLogLevel::INFO, ""); CaptureStdout(); RAY_LOG(INFO).WithField("key1", "value1").WithField("key2", "value2") @@ -200,11 +200,11 @@ TEST(PrintLogTest, TestTextLogging) { std::string::npos); RayLog::ShutDownRayLog(); - unsetenv("RAY_BACKEND_LOG_FORMAT"); + unsetenv("RAY_BACKEND_LOG_JSON"); } TEST(PrintLogTest, TestJSONLogging) { - setenv("RAY_BACKEND_LOG_FORMAT", "JSON", true); + setenv("RAY_BACKEND_LOG_JSON", "1", true); RayLog::StartRayLog("/tmp/raylet", RayLogLevel::INFO, ""); CaptureStdout(); RAY_LOG(DEBUG) << "this is not logged"; @@ -219,19 +219,19 @@ TEST(PrintLogTest, TestJSONLogging) { json log1 = json::parse(log_lines[0]); json log2 = json::parse(log_lines[1]); json log3 = json::parse(log_lines[2]); - ASSERT_EQ(log1[kLogKeyMessage], "this is info logged"); - ASSERT_EQ(log2[kLogKeyMessage], "this needs\nescape\""); - ASSERT_EQ(log3[kLogKeyMessage], "contextual log"); + ASSERT_EQ(log1[std::string(kLogKeyMessage)], "this is info logged"); + ASSERT_EQ(log2[std::string(kLogKeyMessage)], "this needs\nescape\""); + ASSERT_EQ(log3[std::string(kLogKeyMessage)], "contextual log"); ASSERT_TRUE(log3.contains(kLogKeyAsctime)); ASSERT_TRUE(log3.contains(kLogKeyFilename)); ASSERT_TRUE(log3.contains(kLogKeyLineno)); - ASSERT_EQ(log3[kLogKeyLevelname], "I"); - ASSERT_EQ(log3[kLogKeyComponent], "raylet"); + ASSERT_EQ(log3[std::string(kLogKeyLevelname)], "I"); + ASSERT_EQ(log3[std::string(kLogKeyComponent)], "raylet"); ASSERT_EQ(log3["key1"], "value1"); ASSERT_EQ(log3["key2"], "value\n2"); RayLog::ShutDownRayLog(); - unsetenv("RAY_BACKEND_LOG_FORMAT"); + unsetenv("RAY_BACKEND_LOG_JSON"); } #endif /* GTEST_HAS_STREAM_REDIRECTION */ From cf8faa18745a7193c1392a55c611cdcce9406ec0 Mon Sep 17 00:00:00 2001 From: Jiajun Yao Date: Thu, 30 May 2024 23:11:30 -0700 Subject: [PATCH 15/17] up Signed-off-by: Jiajun Yao --- src/ray/util/logging.h | 44 +++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/ray/util/logging.h b/src/ray/util/logging.h index 1a922c5b5041..559978e50990 100644 --- a/src/ray/util/logging.h +++ b/src/ray/util/logging.h @@ -317,6 +317,9 @@ class RayLog { } private: + FRIEND_TEST(PrintLogTest, TestRayLogEveryNOrDebug); + FRIEND_TEST(PrintLogTest, TestRayLogEveryN); + template RayLog &WithFieldTextFormat(std::string_view key, const T &value) { context_osstream_ << " " << key << "=" << value; @@ -324,23 +327,7 @@ class RayLog { } template - RayLog &WithFieldJsonFormat(std::string_view key, const T &value) { - std::stringstream ss; - ss << value; - return WithFieldJsonFormat(key, ss.str()); - } - - template <> - RayLog &WithFieldJsonFormat(std::string_view key, const std::string &value) { - context_osstream_ << ",\"" << key << "\":" << nlohmann::json(value).dump(); - return *this; - } - - template <> - RayLog &WithFieldJsonFormat(std::string_view key, const int &value) { - context_osstream_ << ",\"" << key << "\":" << value; - return *this; - } + RayLog &WithFieldJsonFormat(std::string_view key, const T &value); static void InitSeverityThreshold(RayLogLevel severity_threshold); static void InitLogFormat(); @@ -385,13 +372,30 @@ class RayLog { // Ray default logger name. static std::string logger_name_; - FRIEND_TEST(PrintLogTest, TestRayLogEveryNOrDebug); - FRIEND_TEST(PrintLogTest, TestRayLogEveryN); - protected: virtual std::ostream &Stream() { return msg_osstream_; } }; +template +inline RayLog &RayLog::WithFieldJsonFormat(std::string_view key, const T &value) { + std::stringstream ss; + ss << value; + return WithFieldJsonFormat(key, ss.str()); +} + +template <> +inline RayLog &RayLog::WithFieldJsonFormat(std::string_view key, + const std::string &value) { + context_osstream_ << ",\"" << key << "\":" << nlohmann::json(value).dump(); + return *this; +} + +template <> +inline RayLog &RayLog::WithFieldJsonFormat(std::string_view key, const int &value) { + context_osstream_ << ",\"" << key << "\":" << value; + return *this; +} + // This class make RAY_CHECK compilation pass to change the << operator to void. class Voidify { public: From 100728947c2319fa1d3c00b68674707a9238e100 Mon Sep 17 00:00:00 2001 From: Jiajun Yao Date: Fri, 31 May 2024 09:28:32 -0700 Subject: [PATCH 16/17] up Signed-off-by: Jiajun Yao --- src/ray/util/logging.cc | 14 ++++++++++++++ src/ray/util/logging.h | 33 ++++++++++----------------------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/ray/util/logging.cc b/src/ray/util/logging.cc index 24f6e9dcd153..5e3d55e46e79 100644 --- a/src/ray/util/logging.cc +++ b/src/ray/util/logging.cc @@ -36,6 +36,7 @@ #include "absl/debugging/stacktrace.h" #include "absl/debugging/symbolize.h" #include "absl/strings/str_format.h" +#include "nlohmann/json.hpp" #include "ray/util/event_label.h" #include "ray/util/filesystem.h" #include "ray/util/util.h" @@ -466,4 +467,17 @@ RayLog::~RayLog() { } } +template <> +RayLog &RayLog::WithFieldJsonFormat(std::string_view key, + const std::string &value) { + context_osstream_ << ",\"" << key << "\":" << nlohmann::json(value).dump(); + return *this; +} + +template <> +RayLog &RayLog::WithFieldJsonFormat(std::string_view key, const int &value) { + context_osstream_ << ",\"" << key << "\":" << value; + return *this; +} + } // namespace ray diff --git a/src/ray/util/logging.h b/src/ray/util/logging.h index 559978e50990..9c5a31620640 100644 --- a/src/ray/util/logging.h +++ b/src/ray/util/logging.h @@ -59,8 +59,6 @@ #include #include -#include "nlohmann/json.hpp" - #if defined(_WIN32) #ifndef _WINDOWS_ #ifndef WIN32_LEAN_AND_MEAN // Sorry for the inconvenience. Please include any related @@ -327,7 +325,16 @@ class RayLog { } template - RayLog &WithFieldJsonFormat(std::string_view key, const T &value); + RayLog &WithFieldJsonFormat(std::string_view key, const T &value) { + std::stringstream ss; + ss << value; + return WithFieldJsonFormat(key, ss.str()); + } + template <> + RayLog &WithFieldJsonFormat(std::string_view key, + const std::string &value); + template <> + RayLog &WithFieldJsonFormat(std::string_view key, const int &value); static void InitSeverityThreshold(RayLogLevel severity_threshold); static void InitLogFormat(); @@ -376,26 +383,6 @@ class RayLog { virtual std::ostream &Stream() { return msg_osstream_; } }; -template -inline RayLog &RayLog::WithFieldJsonFormat(std::string_view key, const T &value) { - std::stringstream ss; - ss << value; - return WithFieldJsonFormat(key, ss.str()); -} - -template <> -inline RayLog &RayLog::WithFieldJsonFormat(std::string_view key, - const std::string &value) { - context_osstream_ << ",\"" << key << "\":" << nlohmann::json(value).dump(); - return *this; -} - -template <> -inline RayLog &RayLog::WithFieldJsonFormat(std::string_view key, const int &value) { - context_osstream_ << ",\"" << key << "\":" << value; - return *this; -} - // This class make RAY_CHECK compilation pass to change the << operator to void. class Voidify { public: From fa64119edd8a9884f9fbb59053bf9be16ea5b13a Mon Sep 17 00:00:00 2001 From: Jiajun Yao Date: Fri, 31 May 2024 10:26:27 -0700 Subject: [PATCH 17/17] up Signed-off-by: Jiajun Yao --- src/ray/util/logging.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ray/util/logging.h b/src/ray/util/logging.h index 9c5a31620640..16abe4272509 100644 --- a/src/ray/util/logging.h +++ b/src/ray/util/logging.h @@ -330,11 +330,6 @@ class RayLog { ss << value; return WithFieldJsonFormat(key, ss.str()); } - template <> - RayLog &WithFieldJsonFormat(std::string_view key, - const std::string &value); - template <> - RayLog &WithFieldJsonFormat(std::string_view key, const int &value); static void InitSeverityThreshold(RayLogLevel severity_threshold); static void InitLogFormat(); @@ -383,6 +378,12 @@ class RayLog { virtual std::ostream &Stream() { return msg_osstream_; } }; +template <> +RayLog &RayLog::WithFieldJsonFormat(std::string_view key, + const std::string &value); +template <> +RayLog &RayLog::WithFieldJsonFormat(std::string_view key, const int &value); + // This class make RAY_CHECK compilation pass to change the << operator to void. class Voidify { public: