From 65d7cf69b8c41aa0ce400596f5846b5a4aea404a Mon Sep 17 00:00:00 2001 From: Martin Piatka Date: Mon, 1 Aug 2022 13:56:39 +0200 Subject: [PATCH] logging: Split timestamp and repeat functionality into its own class This will eventually allow better integration with other formatting functions like color_out, color_printf --- src/debug.cpp | 4 +- src/debug.h | 109 ++++++++++++++++++++++++++------------- src/host.cpp | 4 +- src/keyboard_control.cpp | 4 +- 4 files changed, 77 insertions(+), 44 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index 9d86f63cc..49f1ef002 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -370,8 +370,6 @@ void debug_file_dump(const char *key, void (*serialize)(const void *data, FILE * } #endif -std::atomic Logger::last_msg{}; thread_local std::set Logger::oneshot_messages; -std::atomic Logger::skip_repeated{true}; -log_timestamp_mode Logger::show_timestamps = LOG_TIMESTAMP_AUTO; +thread_local std::string Log_output::buffer; diff --git a/src/debug.h b/src/debug.h index 597783556..30ab522de 100644 --- a/src/debug.h +++ b/src/debug.h @@ -117,6 +117,74 @@ bool parse_log_cfg(const char *conf_str, class keyboard_control; // friend +class Log_output{ +public: + Log_output() = default; + + Log_output(const Log_output&) = delete; + Log_output(Log_output&&) = delete; + + Log_output& operator=(const Log_output&) = delete; + Log_output& operator=(Log_output&&) = delete; + + + std::string& get_buffer() { return buffer; } + void submit(); + + void set_skip_repeats(bool val) { skip_repeated.store(val, std::memory_order_relaxed); } + + void set_timestamp_mode(log_timestamp_mode val) { show_timestamps = val; } + +private: + thread_local static std::string buffer; + + std::atomic skip_repeated; + log_timestamp_mode show_timestamps; + struct last_message { + std::string msg; + int count{0}; + }; + std::atomic last_msg; // leaks last message upon exit + + friend class keyboard_control; +}; + +inline void Log_output::submit(){ + if (skip_repeated && rang::rang_implementation::isTerminal(std::clog.rdbuf())) { + auto last = last_msg.exchange(nullptr); + if (last != nullptr && last->msg == buffer) { + int count = last->count += 1; + auto current = last_msg.exchange(last); + delete current; + std::clog << " Last message repeated " << count << " times\r"; + return; + } + if (last != nullptr) { + if (last->count > 0) { + std::clog << "\n"; + } + delete last; + } + } + + std::ostringstream timestamp; + if (show_timestamps == 1 || (show_timestamps == -1 && log_level >= LOG_LEVEL_VERBOSE)) { + auto time_ms = time_since_epoch_in_ms(); + timestamp << "[" << std::fixed << std::setprecision(3) << time_ms / 1000.0 << "] "; + } + + std::clog << timestamp.str() << buffer << rang::style::reset << rang::fg::reset; + + auto *lmsg = new last_message{std::move(buffer)}; + auto current = last_msg.exchange(lmsg); + delete current; +} + +inline Log_output& get_log_output(){ + static Log_output out; + return out; +} + // Log, version 0.1: a simple logging class class Logger { @@ -139,34 +207,13 @@ public: inline ~Logger() { std::string msg = oss.str(); - if (skip_repeated && rang::rang_implementation::isTerminal(std::clog.rdbuf())) { - auto last = last_msg.exchange(nullptr); - if (last != nullptr && last->msg == msg) { - int count = last->count += 1; - auto current = last_msg.exchange(last); - delete current; - std::clog << " Last message repeated " << count << " times\r" << std::flush; - return; - } - if (last != nullptr) { - if (last->count > 0) { - std::clog << "\n"; - } - delete last; - } - } + auto& buf = get_log_output().get_buffer(); + buf.clear(); - std::ostringstream timestamp; - if (show_timestamps == 1 || (show_timestamps == -1 && log_level >= LOG_LEVEL_VERBOSE)) { - auto time_ms = time_since_epoch_in_ms(); - timestamp << "[" << std::fixed << std::setprecision(3) << time_ms / 1000.0 << "] "; - } + buf += msg; - std::clog << timestamp.str() << msg << rang::style::reset << rang::fg::reset; + get_log_output().submit(); - auto *lmsg = new last_message{std::move(msg)}; - auto current = last_msg.exchange(lmsg); - delete current; } inline std::ostream& Get() { return oss; @@ -179,23 +226,11 @@ public: oss << msg; } - inline static void set_skip_repeats(bool val) { skip_repeated.store(val, std::memory_order_relaxed); } - - inline static void set_timestamp_mode(log_timestamp_mode val) { show_timestamps = val; } private: int level; std::ostringstream oss; - static std::atomic skip_repeated; - static log_timestamp_mode show_timestamps; - struct last_message { - std::string msg; - int count{0}; - }; - static std::atomic last_msg; // leaks last message upon exit static thread_local std::set oneshot_messages; - - friend class keyboard_control; }; #define LOG(level) \ diff --git a/src/host.cpp b/src/host.cpp index 9cb1917c3..5090b164b 100644 --- a/src/host.cpp +++ b/src/host.cpp @@ -336,8 +336,8 @@ static bool parse_opts_set_logging(int argc, char *argv[]) return false; } log_level = logging_lvl; - Logger::set_skip_repeats(logger_skip_repeats); - Logger::set_timestamp_mode(logger_show_timestamps); + get_log_output().set_skip_repeats(logger_skip_repeats); + get_log_output().set_timestamp_mode(logger_show_timestamps); return true; } diff --git a/src/keyboard_control.cpp b/src/keyboard_control.cpp index 56aa05c2e..f29ac562b 100644 --- a/src/keyboard_control.cpp +++ b/src/keyboard_control.cpp @@ -554,8 +554,8 @@ void keyboard_control::run() break; } case 'r': - Logger::skip_repeated = !Logger::skip_repeated; - cout << "Skip repeated messages: " << std::boolalpha << Logger::skip_repeated << std::noboolalpha << "\n"; + get_log_output().skip_repeated = !get_log_output().skip_repeated; + cout << "Skip repeated messages: " << std::boolalpha << get_log_output().skip_repeated << std::noboolalpha << "\n"; break; case 's': if (saved_log_level == -1) {