From 1ac2dcc53749031749618e19e7de0a418aa9e93d Mon Sep 17 00:00:00 2001 From: gabime Date: Sat, 26 Sep 2020 14:41:33 +0300 Subject: [PATCH] wip fix #1680 again --- include/spdlog/cfg/argv.h | 2 +- include/spdlog/cfg/env.h | 2 +- include/spdlog/cfg/helpers-inl.h | 14 +++++--- include/spdlog/cfg/helpers.h | 5 +-- include/spdlog/cfg/log_levels.h | 25 ++++++++------ include/spdlog/details/registry-inl.h | 48 ++++++++++++++++++++++----- include/spdlog/details/registry.h | 5 +-- tests/test_cfg.cpp | 26 +++++++++++++++ 8 files changed, 98 insertions(+), 29 deletions(-) diff --git a/include/spdlog/cfg/argv.h b/include/spdlog/cfg/argv.h index 83e3546a..49e2ff4d 100644 --- a/include/spdlog/cfg/argv.h +++ b/include/spdlog/cfg/argv.h @@ -31,7 +31,7 @@ inline void load_argv_levels(int argc, const char **argv) { auto levels_string = arg.substr(spdlog_level_prefix.size()); auto levels = helpers::extract_levels(levels_string); - details::registry::instance().update_levels(std::move(levels)); + details::registry::instance().set_levels(std::move(levels)); } } } diff --git a/include/spdlog/cfg/env.h b/include/spdlog/cfg/env.h index e2dc5717..8105af19 100644 --- a/include/spdlog/cfg/env.h +++ b/include/spdlog/cfg/env.h @@ -31,7 +31,7 @@ inline void load_env_levels() if (!env_val.empty()) { auto levels = helpers::extract_levels(env_val); - details::registry::instance().update_levels(std::move(levels)); + details::registry::instance().set_levels(std::move(levels)); } } diff --git a/include/spdlog/cfg/helpers-inl.h b/include/spdlog/cfg/helpers-inl.h index b0915073..81768e4d 100644 --- a/include/spdlog/cfg/helpers-inl.h +++ b/include/spdlog/cfg/helpers-inl.h @@ -73,27 +73,31 @@ inline std::unordered_map extract_key_vals_(const std: continue; } auto kv = extract_kv_('=', token); + if (kv.first.empty()) + { + kv.first = "*"; + } rv[kv.first] = kv.second; } return rv; } -SPDLOG_INLINE log_levels extract_levels(const std::string &input) +SPDLOG_INLINE std::unordered_map extract_levels(const std::string &input) { auto key_vals = extract_key_vals_(input); - log_levels rv; + std::unordered_map rv; for (auto &name_level : key_vals) { auto &logger_name = name_level.first; auto level_name = to_lower_(name_level.second); auto level = level::from_str(level_name); - // fallback to "info" if unrecognized level name + // ignore unrecognized level names if (level == level::off && level_name != "off") { - level = level::info; + continue; } - rv.set(logger_name, level); + rv[logger_name] = level; } return rv; } diff --git a/include/spdlog/cfg/helpers.h b/include/spdlog/cfg/helpers.h index 8d750824..1f82b8fb 100644 --- a/include/spdlog/cfg/helpers.h +++ b/include/spdlog/cfg/helpers.h @@ -3,7 +3,8 @@ #pragma once -#include +#include +#include namespace spdlog { namespace cfg { @@ -17,7 +18,7 @@ namespace helpers { // turn off all logging except for logger1: "off,logger1=debug" // turn off all logging except for logger1 and logger2: "off,logger1=debug,logger2=info" // -SPDLOG_API log_levels extract_levels(const std::string &txt); +SPDLOG_API std::unordered_map extract_levels(const std::string &txt); } // namespace helpers } // namespace cfg diff --git a/include/spdlog/cfg/log_levels.h b/include/spdlog/cfg/log_levels.h index 3b8e6797..736ecbf0 100644 --- a/include/spdlog/cfg/log_levels.h +++ b/include/spdlog/cfg/log_levels.h @@ -12,7 +12,7 @@ namespace cfg { class log_levels { std::unordered_map levels_; - spdlog::level::level_enum default_level_ = level::info; + spdlog::level::level_enum global_level_ = level::info; public: void set(const std::string &logger_name, level::level_enum lvl) @@ -20,27 +20,32 @@ public: levels_[logger_name] = lvl; } - void set_default(level::level_enum lvl) + void set_global_level(level::level_enum lvl) { - levels_[""] = lvl; + global_level_ = lvl; } - // configure log level of given logger if it appears in the config list or if default level is set - void update_logger_level(spdlog::logger &logger) + level::level_enum default_level() { - auto &logger_name = logger.name(); - auto it = levels_.find(logger_name); + return global_level_; + } - // if logger was not configured, check if default log level was configured + // update log level of given logger if it appears in the config list or if default level is set + // return true if updated + bool update_logger_level(spdlog::logger &logger) + { + // if logger was not configured, check if global log level was configured + auto it = levels_.find(logger.name()); if (it == levels_.end()) { - it = levels_.find(""); // + it = levels_.find("*"); } - if (it != levels_.end()) { logger.set_level(it->second); + return true; } + return false; } }; } // namespace cfg diff --git a/include/spdlog/details/registry-inl.h b/include/spdlog/details/registry-inl.h index 0a25fb46..b0e7aab7 100644 --- a/include/spdlog/details/registry-inl.h +++ b/include/spdlog/details/registry-inl.h @@ -66,8 +66,19 @@ SPDLOG_INLINE void registry::initialize_logger(std::shared_ptr new_logge { new_logger->set_error_handler(err_handler_); } - - levels_.update_logger_level(*new_logger); + auto cfg_level_it = cfg_levels_.find(new_logger->name()); + if (cfg_level_it == cfg_levels_.end()) + { + cfg_level_it = cfg_levels_.find(("*")); + } + if (cfg_level_it != cfg_levels_.end()) + { + new_logger->set_level(cfg_level_it->second); + } + else + { + new_logger->set_level(global_log_level_); + } new_logger->flush_on(flush_level_); @@ -172,7 +183,7 @@ SPDLOG_INLINE void registry::set_level(level::level_enum log_level) { l.second->set_level(log_level); } - levels_.set_default(log_level); + global_log_level_ = log_level; } SPDLOG_INLINE void registry::flush_on(level::level_enum log_level) @@ -264,14 +275,35 @@ SPDLOG_INLINE void registry::set_automatic_registration(bool automatic_registrat automatic_registration_ = automatic_registration; } -SPDLOG_INLINE void registry::update_levels(cfg::log_levels levels) +SPDLOG_INLINE void registry::set_levels(std::unordered_map levels) { + std::lock_guard lock(logger_map_mutex_); - levels_ = std::move(levels); - for (auto &l : loggers_) + cfg_levels_ = std::move(levels); + // update global level if found + auto global_level_it = cfg_levels_.find("*"); + if (global_level_it != cfg_levels_.end()) { - auto &logger = l.second; - levels_.update_logger_level(*logger); + auto global_level = global_level_it->second; + for (auto &logger : loggers_) + { + logger.second->set_level(global_level); + } + } + // update specific loggers + for (const auto &item : cfg_levels_) + { + const auto &logger_name = item.first; + if (logger_name == "*") + { + continue; + } + auto existing_logger_it = loggers_.find(logger_name); + if (existing_logger_it != loggers_.end()) + { + auto level = item.second; + existing_logger_it->second->set_level(level); + } } } diff --git a/include/spdlog/details/registry.h b/include/spdlog/details/registry.h index 8be109ed..d945ee5c 100644 --- a/include/spdlog/details/registry.h +++ b/include/spdlog/details/registry.h @@ -80,7 +80,7 @@ public: void set_automatic_registration(bool automatic_registration); - void update_levels(cfg::log_levels levels); + void set_levels(std::unordered_map levels); static registry &instance(); @@ -93,8 +93,9 @@ private: std::mutex logger_map_mutex_, flusher_mutex_; std::recursive_mutex tp_mutex_; std::unordered_map> loggers_; - cfg::log_levels levels_; + std::unordered_map cfg_levels_; std::unique_ptr formatter_; + spdlog::level::level_enum global_log_level_ = level::info; level::level_enum flush_level_ = level::off; void (*err_handler_)(const std::string &msg); std::shared_ptr tp_; diff --git a/tests/test_cfg.cpp b/tests/test_cfg.cpp index 69499e1c..6deef387 100644 --- a/tests/test_cfg.cpp +++ b/tests/test_cfg.cpp @@ -1,3 +1,4 @@ + #include "includes.h" #include "test_sink.h" @@ -149,6 +150,31 @@ TEST_CASE("level-not-set-test4", "[cfg]") auto l2 = spdlog::create("l2"); REQUIRE(l1->level() == spdlog::level::trace); + // REQUIRE(l2->level() == spdlog::level::warn); + // REQUIRE(spdlog::default_logger()->level() == spdlog::level::warn); +} + +TEST_CASE("level-not-set-test5", "[cfg]") +{ + spdlog::drop("l1"); + spdlog::drop("l2"); + const char *argv[] = {"ignore", "SPDLOG_LEVEL=l1=junk,warn"}; + + load_argv_levels(2, argv); + + auto l1 = spdlog::create("l1"); + auto l2 = spdlog::create("l2"); + + REQUIRE(l1->level() == spdlog::level::warn); REQUIRE(l2->level() == spdlog::level::warn); REQUIRE(spdlog::default_logger()->level() == spdlog::level::warn); } + +TEST_CASE("restore-to-default", "[cfg]") +{ + spdlog::drop("l1"); + spdlog::drop("l2"); + const char *argv[] = {"ignore", "SPDLOG_LEVEL=info"}; + load_argv_levels(2, argv); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::info); +}