From da2c15ecb4cf7a2c654c9d1e1347cf5810e4278f Mon Sep 17 00:00:00 2001 From: gabime Date: Wed, 11 Dec 2019 00:13:27 +0200 Subject: [PATCH] wip config from env --- example/example.cpp | 3 +- include/spdlog/cfg/env-inl.h | 104 ++++++++++++++++++++--------------- include/spdlog/cfg/env.h | 7 +-- 3 files changed, 63 insertions(+), 51 deletions(-) diff --git a/example/example.cpp b/example/example.cpp index e39b1d25..c4c1567b 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -9,12 +9,13 @@ int main(int, char *[]) { + spdlog::set_pattern("%v"); try { auto cfg = spdlog::cfg::from_env(); for (auto &item : cfg) { - spdlog::info("['{}'] level: {} pattern: {}", item.first, spdlog::level::to_string_view(item.second.level), item.second.pattern); + spdlog::info("logger: '{}' level: '{}' pattern: '{}'", item.first, item.second.level_name, item.second.pattern); } } catch (spdlog::spdlog_ex &ex) diff --git a/include/spdlog/cfg/env-inl.h b/include/spdlog/cfg/env-inl.h index e8db23ed..1141d676 100644 --- a/include/spdlog/cfg/env-inl.h +++ b/include/spdlog/cfg/env-inl.h @@ -37,12 +37,16 @@ inline std::string &trim_(std::string &str) using name_val_pair = std::pair; -// return tuple with name, value from "name=value" string. replace with empty string on missing parts +// return (name,value) pair from given "name=value" string. +// return empty string on missing parts +// "key=val" => ("key", "val") +// " key = val " => ("key", "val") +// "key=" => ("key", "") +// "val" => ("", "val") inline name_val_pair extract_kv_(char sep, const std::string &str) { auto n = str.find(sep); - std::string k; - std::string v; + std::string k, v; if (n == std::string::npos) { v = str; @@ -55,74 +59,86 @@ inline name_val_pair extract_kv_(char sep, const std::string &str) return std::make_pair(trim_(k), trim_(v)); } -// return vector of name/value pairs from str. +// return vector of key/value pairs from str. // str format: "a=A,b=B,c=C,d=D,.." -SPDLOG_INLINE std::vector extract_name_vals_(const std::string &str) +SPDLOG_INLINE std::unordered_map extract_key_vals_(const std::string &str) { - std::vector rv; std::string token; - std::istringstream tokenStream(str); - while (std::getline(tokenStream, token, ',')) + std::istringstream token_stream(str); + std::unordered_map rv; + while (std::getline(token_stream, token, ',')) { - rv.push_back(extract_kv_('=', token)); + auto kv = extract_kv_('=', token); + + // empty logger name or '*' marks all loggers + if(kv.first.empty()) + { + kv.first = "*"; + } + rv.insert(std::move(kv)); } return rv; } -inline void load_levels_(cfg_map &configs) +SPDLOG_INLINE cfg_map from_env() { using details::os::getenv; - std::string levels = getenv("SPDLOG_LEVEL"); - auto name_vals = extract_name_vals_(levels); + cfg_map configs; - for (auto &nv : name_vals) + auto levels = extract_key_vals_(getenv("SPDLOG_LEVEL")); + auto patterns = extract_key_vals_(getenv("SPDLOG_PATTERN")); + + // merge to single dict. and take into account "*" + std::string default_level_name = "info"; + std::string default_pattern = "%+"; + for(auto &name_level: levels) { - auto logger_name = nv.first.empty() ? "*" : nv.first; - auto level_lowercase = to_lower_(nv.second); - auto log_level = level::from_str(level_lowercase); - // set as info if unknown log level given - if (log_level == level::off && level_lowercase != "off") + auto &logger_name = name_level.first; + auto level_name = to_lower_(name_level.second); + logger_cfg cfg; + cfg.level_name = level_name; + configs[logger_name] = cfg; + if(logger_name == "*") { - log_level = spdlog::level::info; - } - auto it = configs.find(logger_name); - if (it != configs.end()) - { - it->second.level = log_level; - } - else - { - configs.insert({logger_name, logger_cfg{log_level, "%+"}}); + default_level_name = cfg.level_name; } } -} -SPDLOG_INLINE void load_patterns_(cfg_map &configs) -{ - using details::os::getenv; - std::string patterns = getenv("SPDLOG_PATTERN"); - auto name_vals = extract_name_vals_(patterns); - for (auto &nv : name_vals) + for(auto &name_pattern: patterns) { - auto logger_name = nv.first.empty() ? "*" : nv.first; - auto pattern = to_lower_(nv.second); + auto &logger_name = name_pattern.first; + auto &pattern = name_pattern.second; auto it = configs.find(logger_name); + if (it != configs.end()) { it->second.pattern = pattern; } else { - configs.insert({logger_name, logger_cfg{level::info, pattern}}); + logger_cfg cfg; + cfg.pattern = pattern; + configs.insert({logger_name, cfg}); + } + if(logger_name == "*") + { + default_pattern = pattern; } } -} -SPDLOG_INLINE cfg_map from_env() -{ - cfg_map configs; - load_levels_(configs); - load_patterns_(configs); + //fill missing fields with the default values + for(auto &cfg:configs) + { + auto &val = cfg.second; + if(val.pattern.empty()) + { + val.pattern = default_pattern; + } + if(val.level_name.empty()) + { + val.level_name = default_level_name; + } + } return configs; } diff --git a/include/spdlog/cfg/env.h b/include/spdlog/cfg/env.h index 12c46568..b22717d4 100644 --- a/include/spdlog/cfg/env.h +++ b/include/spdlog/cfg/env.h @@ -12,12 +12,7 @@ namespace spdlog { namespace cfg { struct logger_cfg { - logger_cfg(level::level_enum level, std::string pattern) - : level{level} - , pattern(std::move(pattern)) - {} - - level::level_enum level; + std::string level_name; std::string pattern; }; using cfg_map = std::unordered_map;