From abbbda6f74e4ab0013e40cfc6d1c0f363d57fc65 Mon Sep 17 00:00:00 2001 From: gabime Date: Sun, 8 Dec 2019 17:07:52 +0200 Subject: [PATCH] wip --- example/example.cpp | 11 ++- include/spdlog/cfg/env-inl.h | 131 +++++++++++++++++++++++++++++++++++ include/spdlog/cfg/env.h | 38 ++++++++++ 3 files changed, 177 insertions(+), 3 deletions(-) create mode 100644 include/spdlog/cfg/env-inl.h create mode 100644 include/spdlog/cfg/env.h diff --git a/example/example.cpp b/example/example.cpp index 924042f8..2135be04 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -9,11 +9,16 @@ #include #include - int main(int, char *[]) { + + + try { auto cfg = spdlog::cfg::from_env(); - for(auto &item:cfg)\ + for(auto &item:cfg) { - spdlog::info("[{:>8}] level: {} pattern: {}", item.first, spdlog::level::to_string_view(item.second.level), item.second.pattern); + spdlog::info("['{}'] level: {} pattern: {}", item.first, spdlog::level::to_string_view(item.second.level), item.second.pattern); + } + }catch(spdlog::spdlog_ex& ex){ + spdlog::info("spdlog_ex: {}", ex.what()); } } diff --git a/include/spdlog/cfg/env-inl.h b/include/spdlog/cfg/env-inl.h new file mode 100644 index 00000000..7e5f297e --- /dev/null +++ b/include/spdlog/cfg/env-inl.h @@ -0,0 +1,131 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY +#include "spdlog/cfg/env.h" +#endif + +#include "spdlog/spdlog.h" +#include "spdlog/details/os.h" +#include "spdlog/details/registry.h" + +#include +#include +#include +#include +#include + +namespace spdlog { + namespace cfg { + // inplace convert to lowercase + inline std::string& to_lower_(std::string &str) + { + std::transform(str.begin(), str.end(), str.begin(), [](char ch) { + return static_cast((ch >= 'A' && ch <= 'Z') ? ch + ('a' - 'A') : ch); + }); + return str; + } + + // inplace trim spaces + inline std::string& trim_(std::string &str) + { + const char* spaces = " \n\r\t"; + str.erase(str.find_last_not_of(spaces) + 1); + str.erase(0, str.find_first_not_of(spaces)); + return str; + } + + using name_val_pair = std::pair; + + // return tuple with name, value from "name=value" string. replace with empty string on missing parts + inline name_val_pair extract_kv_(char sep, const std::string &str) + { + auto n = str.find(sep); + std::string k; + std::string v; + if (n == std::string::npos) + { + v = str; + } else{ + k = str.substr(0, n); + v = str.substr(n + 1); + } + return std::make_pair(trim_(k), trim_(v)); + } + + // return vector of name/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) + { + std::vector rv; + std::string token; + std::istringstream tokenStream(str); + while (std::getline(tokenStream, token, ',')) + { + rv.push_back(extract_kv_('=', token)); + } + return rv; + } + + + inline void load_levels_(cfg_map &configs) + { + using details::os::getenv; + std::string levels = getenv("SPDLOG_LEVEL"); + auto name_vals = extract_name_vals_(levels); + + for (auto &nv : name_vals) + { + 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") + { + 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, "%+"}}); + } + } + } + + 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) + { + auto logger_name = nv.first.empty() ? "*" : nv.first; + auto pattern = to_lower_(nv.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}}); + } + } + } + + SPDLOG_INLINE cfg_map from_env() + { + cfg_map configs; + load_levels_(configs); + load_patterns_(configs); + return configs; + } + + } // namespace cfg +} // namespace spdlog diff --git a/include/spdlog/cfg/env.h b/include/spdlog/cfg/env.h new file mode 100644 index 00000000..0cfb961b --- /dev/null +++ b/include/spdlog/cfg/env.h @@ -0,0 +1,38 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include + +// config spdlog from environment variables +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 pattern; + }; + using cfg_map = std::unordered_map; + + // Init levels and patterns from env variabls SPDLOG_LEVEL & SPDLOG_PATTERN + // Examples: + // export SPDLOG_LEVEL=debug + // export SPDLOG_LEVEL=logger1=%v,*=[%x] [%l] [%n] %v + // export SPDLOG_LEVEL=logger1=debug,logger2=info,*=error + // export SPDLOG_PATTERN=[%x] [%l] [%n] %v + // + // Note: will set the level to info if finds unknown level in SPDLOG_LEVEL + cfg_map from_env(); + } +} + +#ifdef SPDLOG_HEADER_ONLY +#include "env-inl.h" +#endif // SPDLOG_HEADER_ONLY