From 024494f4b858aa904dfa45fcec3658ec77030338 Mon Sep 17 00:00:00 2001 From: Martin Pulec Date: Wed, 4 Nov 2020 13:47:42 +0100 Subject: [PATCH] Option to disable message repeats suppressing --- src/debug.cpp | 64 +++++++++++++++++++++ src/debug.h | 32 ++++++----- src/hd-rum-translator/hd-rum-translator.cpp | 2 +- src/host.cpp | 13 ++++- src/host.h | 2 +- src/main.cpp | 8 ++- test/run_tests.cpp | 2 +- 7 files changed, 101 insertions(+), 22 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index 9cd3a6d70..f80604396 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -180,4 +180,68 @@ void debug_dump(void *lp, int len) } } +bool set_log_level(const char *optarg, bool *logger_repeat_msgs) { + using namespace std::string_literals; + using std::clog; + using std::cout; + + *logger_repeat_msgs = false; + if (optarg == nullptr) { + log_level = LOG_LEVEL_VERBOSE; + return true; + } + + static const struct { const char *name; int level; } mapping[] = { + { "quiet", LOG_LEVEL_QUIET }, + { "fatal", LOG_LEVEL_FATAL }, + { "error", LOG_LEVEL_ERROR }, + { "warning", LOG_LEVEL_WARNING}, + { "notice", LOG_LEVEL_NOTICE}, + { "info", LOG_LEVEL_INFO }, + { "verbose", LOG_LEVEL_VERBOSE}, + { "debug", LOG_LEVEL_DEBUG }, + { "debug2", LOG_LEVEL_DEBUG2 }, + }; + + if ("help"s == optarg) { + cout << "log level: [0-8"; + for (auto m : mapping) { + cout << "|" << m.name; + } + cout << "][+repeat]\n"; + cout << "\trepeat - print repeating log messages\n"; + return false; + } + + if (strstr(optarg, "+repeat") != nullptr) { + *logger_repeat_msgs = true; + } + + if (optarg[0] == '+') { + return true; + } + + if (isdigit(optarg[0])) { + long val = strtol(optarg, nullptr, 0); + if (val < 0 || val > LOG_LEVEL_MAX) { + clog << "Log: wrong value: " << log_level << "\n"; + return false; + } + log_level = val; + return true; + } + + for (auto m : mapping) { + if (strstr(optarg, m.name) == optarg) { + log_level = m.level; + return true; + } + } + + LOG(LOG_LEVEL_ERROR) << "Wrong log level specification: " << optarg << "\n"; + return false; +} + std::atomic Logger::last_msg{}; +bool Logger::skip_repeated = true; + diff --git a/src/debug.h b/src/debug.h index 1cc900544..5e4aaacc6 100644 --- a/src/debug.h +++ b/src/debug.h @@ -40,6 +40,10 @@ #ifndef _RAT_DEBUG_H #define _RAT_DEBUG_H +#ifndef __cplusplus +#include +#endif // ! defined __cplusplus + #define UNUSED(x) (x=x) #define LOG_LEVEL_QUIET 0 ///< suppress all logging @@ -74,6 +78,8 @@ void debug_dump(void*lp, int len); #define debug_msg(...) log_msg(LOG_LEVEL_DEBUG, __VA_ARGS__) void log_msg(int log_level, const char *format, ...) ATTRIBUTE(format (printf, 2, 3)); +bool set_log_level(const char *optarg, bool *logger_repeat_msgs); + #ifdef __cplusplus } #endif @@ -90,19 +96,19 @@ void log_msg(int log_level, const char *format, ...) ATTRIBUTE(format (printf, 2 class Logger { public: - static void preinit() { - if (!rang::rang_implementation::supportsColor() - || !rang::rang_implementation::isTerminal(std::clog.rdbuf())) { - return; - } - // force ANSI sequences even when written to ostringstream - rang::setControlMode(rang::control::Force); + static void preinit(bool skip_repeated) { + Logger::skip_repeated = skip_repeated; + if (rang::rang_implementation::supportsColor() + && rang::rang_implementation::isTerminal(std::clog.rdbuf())) { + // force ANSI sequences even when written to ostringstream + rang::setControlMode(rang::control::Force); #ifdef _WIN32 - // ANSI control sequences need to be explicitly set in Windows - if (rang::rang_implementation::setWinTermAnsiColors(std::clog.rdbuf())) { - rang::setWinTermMode(rang::winTerm::Ansi); - } + // ANSI control sequences need to be explicitly set in Windows + if (rang::rang_implementation::setWinTermAnsiColors(std::clog.rdbuf())) { + rang::setWinTermMode(rang::winTerm::Ansi); + } #endif + } } inline Logger(int l) : level(l) {} inline ~Logger() { @@ -111,8 +117,7 @@ public: std::string msg = oss.str(); - // check for repeated message - if (rang::rang_implementation::isTerminal(std::clog.rdbuf())) { + 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; @@ -150,6 +155,7 @@ private: int level; std::ostringstream oss; + static bool skip_repeated; struct last_message { std::string msg; int count{0}; diff --git a/src/hd-rum-translator/hd-rum-translator.cpp b/src/hd-rum-translator/hd-rum-translator.cpp index e67ae1d3b..9b614a986 100644 --- a/src/hd-rum-translator/hd-rum-translator.cpp +++ b/src/hd-rum-translator/hd-rum-translator.cpp @@ -696,7 +696,7 @@ int main(int argc, char **argv) int i; struct cmdline_parameters params; - if ((init = common_preinit(argc, argv)) == nullptr) { + if ((init = common_preinit(argc, argv, nullptr)) == nullptr) { EXIT(EXIT_FAILURE); } diff --git a/src/host.cpp b/src/host.cpp index 8db0ec4ff..9c4218190 100644 --- a/src/host.cpp +++ b/src/host.cpp @@ -44,6 +44,8 @@ #include "config_win32.h" #endif +#include + #include "host.h" #include "audio/audio_capture.h" @@ -179,13 +181,20 @@ static int x11_error_handler(Display *d, XErrorEvent *e) { } #endif -struct init_data *common_preinit(int argc, char *argv[]) +struct init_data *common_preinit(int argc, char *argv[], const char *log_opt) { struct init_data *init; + bool logger_repeat_msgs = false; uv_argc = argc; uv_argv = argv; + if (!set_log_level(log_opt, &logger_repeat_msgs)) { + return nullptr; + } + + Logger::preinit(!logger_repeat_msgs); + #ifdef HAVE_X void *handle = dlopen(X11_LIB_NAME, RTLD_NOW); @@ -240,8 +249,6 @@ struct init_data *common_preinit(int argc, char *argv[]) perf_init(); perf_record(UVP_INIT, 0); - Logger::preinit(); - return init; } diff --git a/src/host.h b/src/host.h index 980c7e5fd..a8fa12c2d 100644 --- a/src/host.h +++ b/src/host.h @@ -117,7 +117,7 @@ void set_audio_delay(int val); #define RATE_FLAG_FIXED_RATE (1ll<<62ll) ///< use the bitrate as fixed, not capped struct init_data; -struct init_data *common_preinit(int argc, char *argv[]); +struct init_data *common_preinit(int argc, char *argv[], const char *log_opt); void common_cleanup(struct init_data *init_data); /** diff --git a/src/main.cpp b/src/main.cpp index 2d31f7704..8b92ab2f7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -739,6 +739,8 @@ int main(int argc, char *argv[]) const char *video_protocol = "ultragrid_rtp"; const char *video_protocol_opts = ""; + const char *log_opt = nullptr; + // First we need to set verbosity level prior to everything else. // common_preinit() uses the verbosity level. while ((ch = @@ -747,9 +749,9 @@ int main(int argc, char *argv[]) switch (ch) { case OPT_VERBOSE: if (optarg) { - log_level = atoi(optarg); + log_opt = optarg; } else { - log_level = LOG_LEVEL_VERBOSE; + log_opt = "verbose"; } break; default: @@ -758,7 +760,7 @@ int main(int argc, char *argv[]) } optind = 1; - if ((init = common_preinit(argc, argv)) == nullptr) { + if ((init = common_preinit(argc, argv, log_opt)) == nullptr) { log_msg(LOG_LEVEL_FATAL, "common_preinit() failed!\n"); EXIT(EXIT_FAILURE); } diff --git a/test/run_tests.cpp b/test/run_tests.cpp index c81a3971c..25917046a 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -144,7 +144,7 @@ static bool run_unit_tests() int main(int argc, char **argv) { struct init_data *init = nullptr; - if ((init = common_preinit(argc, argv)) == nullptr) { + if ((init = common_preinit(argc, argv, nullptr)) == nullptr) { return 2; }