From 42b10209fec1079cc020a71998e8e920e8006460 Mon Sep 17 00:00:00 2001 From: Satori Date: Sun, 6 Sep 2020 19:20:59 +0100 Subject: [PATCH] [Base] Add support for multiple log sinks in Logger --- src/xenia/base/logging.cc | 70 ++++++++++++++++++++++++++------------- src/xenia/base/logging.h | 25 ++++++++++++++ 2 files changed, 72 insertions(+), 23 deletions(-) diff --git a/src/xenia/base/logging.cc b/src/xenia/base/logging.cc index 8584892d4..9a565fd64 100644 --- a/src/xenia/base/logging.cc +++ b/src/xenia/base/logging.cc @@ -66,30 +66,30 @@ struct LogLine { thread_local char thread_log_buffer_[64 * 1024]; + +void FileLogSink::Write(const char* buf, size_t size) { + if (file_) { + fwrite(buf, 1, size, file_); + } +} + +void FileLogSink::Flush() { + if (file_) { + fflush(file_); + } +} + class Logger { public: explicit Logger(const std::string_view app_name) - : file_(nullptr), - running_(true), + : wait_strategy_(), claim_strategy_(kBlockCount, wait_strategy_), - consumed_(wait_strategy_) { + consumed_(wait_strategy_), + running_(true) { claim_strategy_.add_claim_barrier(consumed_); - if (cvars::log_file.empty()) { - // Default to app name. - auto file_name = fmt::format("{}.log", app_name); - auto file_path = std::filesystem::path(file_name); - xe::filesystem::CreateParentFolder(file_path); - file_ = xe::filesystem::OpenFile(file_path, "wt"); - } else { - if (cvars::log_file == "stdout") { - file_ = stdout; - } else { - xe::filesystem::CreateParentFolder(cvars::log_file); - file_ = xe::filesystem::OpenFile(cvars::log_file, "wt"); - } - } + write_thread_ = xe::threading::Thread::Create({}, [this]() { WriteThread(); }); @@ -99,8 +99,10 @@ class Logger { ~Logger() { running_ = false; xe::threading::Wait(write_thread_.get(), true); - fflush(file_); - fclose(file_); + } + + void AddLogSink(std::unique_ptr sink) { + sinks_.push_back(std::move(sink)); } private: @@ -126,14 +128,14 @@ class Logger { dp::multi_threaded_claim_strategy claim_strategy_; dp::sequence_barrier consumed_; - FILE* file_; + std::vector> sinks_; std::atomic running_; std::unique_ptr write_thread_; void Write(const char* buf, size_t size) { - if (file_) { - fwrite(buf, 1, size, file_); + for (const auto& sink : sinks_) { + sink->Write(buf, size); } if (cvars::log_to_debugprint) { debugging::DebugPrint("{}", std::string_view(buf, size)); @@ -246,7 +248,9 @@ class Logger { desired_count = 1; if (cvars::flush_log) { - fflush(file_); + for (const auto& sink : sinks_) { + sink->Flush(); + } } idle_loops = 0; @@ -291,6 +295,26 @@ class Logger { void InitializeLogging(const std::string_view app_name) { auto mem = memory::AlignedAlloc(0x10); logger_ = new (mem) Logger(app_name); + + FILE* file = nullptr; + + if (cvars::log_file.empty()) { + // Default to app name. + auto file_name = fmt::format("{}.log", app_name); + auto file_path = std::filesystem::path(file_name); + xe::filesystem::CreateParentFolder(file_path); + + file = xe::filesystem::OpenFile(file_path, "wt"); + } else { + if (cvars::log_file == "stdout") { + file = stdout; + } else { + xe::filesystem::CreateParentFolder(cvars::log_file); + file = xe::filesystem::OpenFile(cvars::log_file, "wt"); + } + } + auto sink = std::make_unique(file); + logger_->AddLogSink(std::move(sink)); } void ShutdownLogging() { diff --git a/src/xenia/base/logging.h b/src/xenia/base/logging.h index 864d5d620..d2df15cce 100644 --- a/src/xenia/base/logging.h +++ b/src/xenia/base/logging.h @@ -34,6 +34,31 @@ enum class LogLevel { Trace, }; +class LogSink { + public: + virtual ~LogSink() = default; + + virtual void Write(const char* buf, size_t size) = 0; + virtual void Flush() = 0; +}; + +class FileLogSink final : public LogSink { + public: + explicit FileLogSink(FILE* file) : file_(file) {} + virtual ~FileLogSink() { + if (file_) { + fflush(file_); + fclose(file_); + } + } + + void Write(const char* buf, size_t size) override; + void Flush() override; + + private: + FILE* file_; +}; + // Initializes the logging system and any outputs requested. // Must be called on startup. void InitializeLogging(const std::string_view app_name);