// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #pragma once #include #include #include #include #include #include #include #include namespace spdlog { class logger; } class LogBufferSink; class Logger { std::shared_ptr spdlog_logger; std::shared_ptr buffer; // only on a Buffered() logger explicit Logger(std::shared_ptr sink); std::string service; std::string hostname; public: Logger(const std::string &service_name, const std::string &file_name = ""); void ErrorException(const std::exception &e); void Info(const std::string& msg) { spdlog_logger->info(msg); } void Warning(const std::string& msg) { spdlog_logger->warn(msg); } void Error(const std::string& msg) { spdlog_logger->error(msg); } void Debug(const std::string& msg) { spdlog_logger->debug(msg); } template void Info(fmt::format_string fmt, Args &&... args) { spdlog_logger->info(fmt, std::forward(args)...); } template void Error(fmt::format_string fmt, Args &&... args) { spdlog_logger->error(fmt, std::forward(args)...); } template void Debug(fmt::format_string fmt, Args &&... args) { spdlog_logger->debug(fmt, std::forward(args)...); } template void Warning(fmt::format_string fmt, Args &&... args) { spdlog_logger->warn(fmt, std::forward(args)...); } 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. static Logger Buffered(); void ReplayInto(Logger &to) const; }; // Times one section of a run: logs "TIMING
" at debug level when the section ends - // at Stop(), or when the mark goes out of scope, whichever comes first. rugnux keeps debug lines off the // terminal and in _log.txt; tools/rugnux_timing.py turns them into a table. class TimingMark { Logger &logger; std::string section; std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); bool stopped = false; public: TimingMark(Logger &in_logger, std::string in_section) : logger(in_logger), section(std::move(in_section)) {} TimingMark(const TimingMark &) = delete; TimingMark &operator=(const TimingMark &) = delete; ~TimingMark() { Stop(); } void Stop() { if (stopped) return; stopped = true; logger.Debug("TIMING {} {:.3f}", section, std::chrono::duration(std::chrono::steady_clock::now() - start).count()); } };