diff --git a/common/Logger.cpp b/common/Logger.cpp index df469dfc4..de61bedff 100644 --- a/common/Logger.cpp +++ b/common/Logger.cpp @@ -9,7 +9,20 @@ #include "Logger.h" #include "GitInfo.h" +namespace { + spdlog::sink_ptr routed_sink; // set once, at start-up, before any thread logs +} + +void Logger::RouteAll(spdlog::sink_ptr sink) { + routed_sink = std::move(sink); +} + Logger::Logger(const std::string &service_name, const std::string &file_name) { + if (routed_sink) { + spdlog_logger = std::make_shared(service_name, routed_sink); + spdlog_logger->set_level(spdlog::level::debug); + return; + } std::string variant = ""; #ifdef JFJOCH_USE_CUDA variant += "C"; @@ -36,10 +49,15 @@ Logger::Logger(const std::string &service_name, const std::string &file_name) { class LogBufferSink : public spdlog::sinks::base_sink { public: - std::vector> lines; + struct Line { + spdlog::log_clock::time_point time; + spdlog::level::level_enum level; + std::string text; + }; + std::vector lines; protected: void sink_it_(const spdlog::details::log_msg &msg) override { - lines.emplace_back(msg.level, std::string(msg.payload.data(), msg.payload.size())); + lines.push_back({msg.time, msg.level, std::string(msg.payload.data(), msg.payload.size())}); } void flush_() override {} }; @@ -53,10 +71,12 @@ Logger Logger::Buffered() { return Logger(std::make_shared()); } -// Called once the work that logged is finished, so nothing is still writing to the buffer. +// Called once the work that logged is finished, so nothing is still writing to the buffer. Each line +// keeps the time it was logged at, not the time of the replay, so a timestamped log still shows when +// the work happened. void Logger::ReplayInto(Logger &to) const { - for (const auto &[level, line] : buffer->lines) - to.spdlog_logger->log(level, line); + for (const auto &l : buffer->lines) + to.spdlog_logger->log(l.time, spdlog::source_loc{}, l.level, l.text); } void Logger::ErrorException(const std::exception &e) { diff --git a/common/Logger.h b/common/Logger.h index b2f8b39bc..1a6a01b72 100644 --- a/common/Logger.h +++ b/common/Logger.h @@ -56,6 +56,12 @@ public: Logger& Verbose(bool input); + // Every Logger made after this call writes to `sink` alone instead of the console, keeps every + // level down to debug (the sink decides what it shows), and skips the version line each Logger + // otherwise opens with. For a program that owns its terminal: rugnux sends the whole log to a file + // next to its outputs and shows only warnings and errors among its own step lines. + static void RouteAll(spdlog::sink_ptr sink); + // A logger that keeps its lines instead of printing them, for work run beside other work that // logs: ReplayInto hands them to `to` afterwards, in order and as one block, so the two do not // interleave. diff --git a/writer/HDF5DataFile.cpp b/writer/HDF5DataFile.cpp index 1c47c12c8..88bc90ed9 100644 --- a/writer/HDF5DataFile.cpp +++ b/writer/HDF5DataFile.cpp @@ -18,6 +18,7 @@ #include "../include/spdlog/fmt/fmt.h" #include "HDF5NXmx.h" #include "../common/time_utc.h" +#include "../common/Logger.h" HDF5DataFile::HDF5DataFile(const StartMessage &msg, uint64_t file_number, const std::string &filename) : filename(filename), @@ -123,9 +124,9 @@ HDF5DataFile::~HDF5DataFile() { std::filesystem::remove(tmp_filename, ec); } } catch (const std::exception &e) { - std::cerr << "HDF5DataFile::~HDF5DataFile: " << e.what() << std::endl; + Logger("HDF5DataFile").Error("Closing the data file failed: {}", e.what()); } catch (...) { - std::cerr << "HDF5DataFile::~HDF5DataFile: Unknown error " << std::endl; + Logger("HDF5DataFile").Error("Closing the data file failed with an unknown error"); } } }