mirror of
https://github.com/gabime/spdlog.git
synced 2025-04-01 02:42:41 +08:00
wip
This commit is contained in:
parent
abbbda6f74
commit
0f24399887
@ -4,21 +4,21 @@
|
|||||||
|
|
||||||
// spdlog usage example
|
// spdlog usage example
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
#include <spdlog/cfg/env.h>
|
#include <spdlog/cfg/env.h>
|
||||||
|
|
||||||
int main(int, char *[]) {
|
int main(int, char *[])
|
||||||
|
{
|
||||||
|
try
|
||||||
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);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}catch(spdlog::spdlog_ex& ex){
|
catch (spdlog::spdlog_ex &ex)
|
||||||
|
{
|
||||||
spdlog::info("spdlog_ex: {}", ex.what());
|
spdlog::info("spdlog_ex: {}", ex.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,114 +18,114 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
namespace cfg {
|
namespace cfg {
|
||||||
// inplace convert to lowercase
|
// inplace convert to lowercase
|
||||||
inline std::string& to_lower_(std::string &str)
|
inline std::string &to_lower_(std::string &str)
|
||||||
|
{
|
||||||
|
std::transform(
|
||||||
|
str.begin(), str.end(), str.begin(), [](char ch) { return static_cast<char>((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<std::string, std::string>;
|
||||||
|
|
||||||
|
// 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<name_val_pair> extract_name_vals_(const std::string &str)
|
||||||
|
{
|
||||||
|
std::vector<name_val_pair> 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")
|
||||||
{
|
{
|
||||||
std::transform(str.begin(), str.end(), str.begin(), [](char ch) {
|
log_level = spdlog::level::info;
|
||||||
return static_cast<char>((ch >= 'A' && ch <= 'Z') ? ch + ('a' - 'A') : ch);
|
|
||||||
});
|
|
||||||
return str;
|
|
||||||
}
|
}
|
||||||
|
auto it = configs.find(logger_name);
|
||||||
// inplace trim spaces
|
if (it != configs.end())
|
||||||
inline std::string& trim_(std::string &str)
|
|
||||||
{
|
{
|
||||||
const char* spaces = " \n\r\t";
|
it->second.level = log_level;
|
||||||
str.erase(str.find_last_not_of(spaces) + 1);
|
|
||||||
str.erase(0, str.find_first_not_of(spaces));
|
|
||||||
return str;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
using name_val_pair = std::pair<std::string, std::string>;
|
|
||||||
|
|
||||||
// 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);
|
configs.insert({logger_name, logger_cfg{log_level, "%+"}});
|
||||||
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.
|
SPDLOG_INLINE void load_patterns_(cfg_map &configs)
|
||||||
// str format: "a=A,b=B,c=C,d=D,.."
|
{
|
||||||
SPDLOG_INLINE std::vector<name_val_pair> extract_name_vals_(const std::string &str)
|
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())
|
||||||
{
|
{
|
||||||
std::vector<name_val_pair > rv;
|
it->second.pattern = pattern;
|
||||||
std::string token;
|
|
||||||
std::istringstream tokenStream(str);
|
|
||||||
while (std::getline(tokenStream, token, ','))
|
|
||||||
{
|
|
||||||
rv.push_back(extract_kv_('=', token));
|
|
||||||
}
|
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
|
||||||
inline void load_levels_(cfg_map &configs)
|
|
||||||
{
|
{
|
||||||
using details::os::getenv;
|
configs.insert({logger_name, logger_cfg{level::info, pattern}});
|
||||||
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)
|
SPDLOG_INLINE cfg_map from_env()
|
||||||
{
|
{
|
||||||
using details::os::getenv;
|
cfg_map configs;
|
||||||
std::string patterns = getenv("SPDLOG_PATTERN");
|
load_levels_(configs);
|
||||||
auto name_vals = extract_name_vals_(patterns);
|
load_patterns_(configs);
|
||||||
for (auto &nv : name_vals)
|
return configs;
|
||||||
{
|
}
|
||||||
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()
|
} // namespace cfg
|
||||||
{
|
|
||||||
cfg_map configs;
|
|
||||||
load_levels_(configs);
|
|
||||||
load_patterns_(configs);
|
|
||||||
return configs;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace cfg
|
|
||||||
} // namespace spdlog
|
} // namespace spdlog
|
||||||
|
@ -8,30 +8,31 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
// config spdlog from environment variables
|
// config spdlog from environment variables
|
||||||
namespace spdlog
|
namespace spdlog {
|
||||||
|
namespace cfg {
|
||||||
|
struct logger_cfg
|
||||||
{
|
{
|
||||||
namespace cfg
|
logger_cfg(level::level_enum level, std::string pattern)
|
||||||
{
|
: level{level}
|
||||||
struct logger_cfg {
|
, pattern(std::move(pattern))
|
||||||
logger_cfg(level::level_enum level, std::string pattern):
|
{}
|
||||||
level{level}, pattern(std::move(pattern)) {}
|
|
||||||
|
|
||||||
level::level_enum level;
|
level::level_enum level;
|
||||||
std::string pattern;
|
std::string pattern;
|
||||||
};
|
};
|
||||||
using cfg_map = std::unordered_map<std::string, logger_cfg>;
|
using cfg_map = std::unordered_map<std::string, logger_cfg>;
|
||||||
|
|
||||||
// Init levels and patterns from env variabls SPDLOG_LEVEL & SPDLOG_PATTERN
|
// Init levels and patterns from env variabls SPDLOG_LEVEL & SPDLOG_PATTERN
|
||||||
// Examples:
|
// Examples:
|
||||||
// export SPDLOG_LEVEL=debug
|
// export SPDLOG_LEVEL=debug
|
||||||
// export SPDLOG_LEVEL=logger1=%v,*=[%x] [%l] [%n] %v
|
// export SPDLOG_LEVEL=logger1=%v,*=[%x] [%l] [%n] %v
|
||||||
// export SPDLOG_LEVEL=logger1=debug,logger2=info,*=error
|
// export SPDLOG_LEVEL=logger1=debug,logger2=info,*=error
|
||||||
// export SPDLOG_PATTERN=[%x] [%l] [%n] %v
|
// export SPDLOG_PATTERN=[%x] [%l] [%n] %v
|
||||||
//
|
//
|
||||||
// Note: will set the level to info if finds unknown level in SPDLOG_LEVEL
|
// Note: will set the level to info if finds unknown level in SPDLOG_LEVEL
|
||||||
cfg_map from_env();
|
cfg_map from_env();
|
||||||
}
|
} // namespace cfg
|
||||||
}
|
} // namespace spdlog
|
||||||
|
|
||||||
#ifdef SPDLOG_HEADER_ONLY
|
#ifdef SPDLOG_HEADER_ONLY
|
||||||
#include "env-inl.h"
|
#include "env-inl.h"
|
||||||
|
@ -536,18 +536,17 @@ SPDLOG_INLINE filename_t dir_name(filename_t path)
|
|||||||
return pos != filename_t::npos ? path.substr(0, pos) : filename_t{};
|
return pos != filename_t::npos ? path.substr(0, pos) : filename_t{};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SPDLOG_INLINE getenv(const char* field)
|
std::string SPDLOG_INLINE getenv(const char *field)
|
||||||
{
|
{
|
||||||
#if defined(_MSC_VER) && !defined(__cplusplus_winrt)
|
#if defined(_MSC_VER) && !defined(__cplusplus_winrt)
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
char buf[128];
|
char buf[128];
|
||||||
bool ok = ::getenv_s(&len , buf, sizeof(buf), field) == 0;
|
bool ok = ::getenv_s(&len, buf, sizeof(buf), field) == 0;
|
||||||
return ok ? buf : std::string{};
|
return ok ? buf : std::string{};
|
||||||
#else // revert to getenv
|
#else // revert to getenv
|
||||||
char *buf = ::getenv(field);
|
char *buf = ::getenv(field);
|
||||||
return buf ? buf : std::string{};
|
return buf ? buf : std::string{};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace os
|
} // namespace os
|
||||||
|
@ -104,7 +104,7 @@ bool create_dir(filename_t path);
|
|||||||
|
|
||||||
// non thread safe, cross platform getenv/getenv_s
|
// non thread safe, cross platform getenv/getenv_s
|
||||||
// return empty string if field not found
|
// return empty string if field not found
|
||||||
std::string getenv(const char* field);
|
std::string getenv(const char *field);
|
||||||
|
|
||||||
} // namespace os
|
} // namespace os
|
||||||
} // namespace details
|
} // namespace details
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||||
#endif // __GNUC__ || __clang__
|
#endif // __GNUC__ || __clang__
|
||||||
|
|
||||||
|
|
||||||
#if !defined(SPDLOG_FMT_EXTERNAL)
|
#if !defined(SPDLOG_FMT_EXTERNAL)
|
||||||
#ifdef SPDLOG_HEADER_ONLY
|
#ifdef SPDLOG_HEADER_ONLY
|
||||||
#ifndef FMT_HEADER_ONLY
|
#ifndef FMT_HEADER_ONLY
|
||||||
|
40
src/fmt.cpp
40
src/fmt.cpp
@ -15,23 +15,19 @@
|
|||||||
#if !defined(SPDLOG_FMT_EXTERNAL)
|
#if !defined(SPDLOG_FMT_EXTERNAL)
|
||||||
#include "spdlog/fmt/bundled/format-inl.h"
|
#include "spdlog/fmt/bundled/format-inl.h"
|
||||||
|
|
||||||
|
|
||||||
// pop warnings supressions
|
// pop warnings supressions
|
||||||
#if defined(__GNUC__) || defined(__clang__)
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
template struct FMT_API internal::basic_data<void>;
|
template struct FMT_API internal::basic_data<void>;
|
||||||
|
|
||||||
// Workaround a bug in MSVC2013 that prevents instantiation of format_float.
|
// Workaround a bug in MSVC2013 that prevents instantiation of format_float.
|
||||||
int (*instantiate_format_float)(double, int, internal::float_specs,
|
int (*instantiate_format_float)(double, int, internal::float_specs, internal::buffer<char> &) = internal::format_float;
|
||||||
internal::buffer<char>&) =
|
|
||||||
internal::format_float;
|
|
||||||
|
|
||||||
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
template FMT_API internal::locale_ref::locale_ref(const std::locale& loc);
|
template FMT_API internal::locale_ref::locale_ref(const std::locale &loc);
|
||||||
template FMT_API std::locale internal::locale_ref::get<std::locale>() const;
|
template FMT_API std::locale internal::locale_ref::get<std::locale>() const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -41,28 +37,18 @@ template FMT_API std::string internal::grouping_impl<char>(locale_ref);
|
|||||||
template FMT_API char internal::thousands_sep_impl(locale_ref);
|
template FMT_API char internal::thousands_sep_impl(locale_ref);
|
||||||
template FMT_API char internal::decimal_point_impl(locale_ref);
|
template FMT_API char internal::decimal_point_impl(locale_ref);
|
||||||
|
|
||||||
template FMT_API void internal::buffer<char>::append(const char*, const char*);
|
template FMT_API void internal::buffer<char>::append(const char *, const char *);
|
||||||
|
|
||||||
template FMT_API void internal::arg_map<format_context>::init(
|
template FMT_API void internal::arg_map<format_context>::init(const basic_format_args<format_context> &args);
|
||||||
const basic_format_args<format_context>& args);
|
|
||||||
|
|
||||||
template FMT_API std::string internal::vformat<char>(
|
template FMT_API std::string internal::vformat<char>(string_view, basic_format_args<format_context>);
|
||||||
string_view, basic_format_args<format_context>);
|
|
||||||
|
|
||||||
template FMT_API format_context::iterator internal::vformat_to(
|
template FMT_API format_context::iterator internal::vformat_to(internal::buffer<char> &, string_view, basic_format_args<format_context>);
|
||||||
internal::buffer<char>&, string_view, basic_format_args<format_context>);
|
|
||||||
|
|
||||||
template FMT_API int internal::snprintf_float(double, int,
|
template FMT_API int internal::snprintf_float(double, int, internal::float_specs, internal::buffer<char> &);
|
||||||
internal::float_specs,
|
template FMT_API int internal::snprintf_float(long double, int, internal::float_specs, internal::buffer<char> &);
|
||||||
internal::buffer<char>&);
|
template FMT_API int internal::format_float(double, int, internal::float_specs, internal::buffer<char> &);
|
||||||
template FMT_API int internal::snprintf_float(long double, int,
|
template FMT_API int internal::format_float(long double, int, internal::float_specs, internal::buffer<char> &);
|
||||||
internal::float_specs,
|
|
||||||
internal::buffer<char>&);
|
|
||||||
template FMT_API int internal::format_float(double, int, internal::float_specs,
|
|
||||||
internal::buffer<char>&);
|
|
||||||
template FMT_API int internal::format_float(long double, int,
|
|
||||||
internal::float_specs,
|
|
||||||
internal::buffer<char>&);
|
|
||||||
|
|
||||||
// Explicit instantiations for wchar_t.
|
// Explicit instantiations for wchar_t.
|
||||||
|
|
||||||
@ -70,11 +56,9 @@ template FMT_API std::string internal::grouping_impl<wchar_t>(locale_ref);
|
|||||||
template FMT_API wchar_t internal::thousands_sep_impl(locale_ref);
|
template FMT_API wchar_t internal::thousands_sep_impl(locale_ref);
|
||||||
template FMT_API wchar_t internal::decimal_point_impl(locale_ref);
|
template FMT_API wchar_t internal::decimal_point_impl(locale_ref);
|
||||||
|
|
||||||
template FMT_API void internal::buffer<wchar_t>::append(const wchar_t*,
|
template FMT_API void internal::buffer<wchar_t>::append(const wchar_t *, const wchar_t *);
|
||||||
const wchar_t*);
|
|
||||||
|
|
||||||
template FMT_API std::wstring internal::vformat<wchar_t>(
|
template FMT_API std::wstring internal::vformat<wchar_t>(wstring_view, basic_format_args<wformat_context>);
|
||||||
wstring_view, basic_format_args<wformat_context>);
|
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user