Logger id lookup improvements
This commit is contained in:
parent
401719e306
commit
1dd8ab4746
2 changed files with 95 additions and 64 deletions
|
@ -3,6 +3,7 @@
|
|||
#include <nano/lib/utility.hpp>
|
||||
|
||||
#include <fmt/chrono.h>
|
||||
#include <magic_enum.hpp>
|
||||
#include <spdlog/pattern_formatter.h>
|
||||
#include <spdlog/sinks/basic_file_sink.h>
|
||||
#include <spdlog/sinks/rotating_file_sink.h>
|
||||
|
@ -24,8 +25,8 @@ nano::log_config nano::logger::global_config{};
|
|||
std::vector<spdlog::sink_ptr> nano::logger::global_sinks{};
|
||||
|
||||
// By default, use only the tag as the logger name, since only one node is running in the process
|
||||
std::function<std::string (nano::log::type tag, std::string identifier)> nano::logger::global_name_formatter{ [] (auto tag, auto identifier) {
|
||||
return std::string{ to_string (tag) };
|
||||
std::function<std::string (nano::log::logger_id, std::string identifier)> nano::logger::global_name_formatter{ [] (nano::log::logger_id logger_id, std::string identifier) {
|
||||
return to_string (logger_id);
|
||||
} };
|
||||
|
||||
void nano::logger::initialize (nano::log_config fallback, std::optional<std::filesystem::path> data_path, std::vector<std::string> const & config_overrides)
|
||||
|
@ -96,8 +97,8 @@ void nano::logger::initialize_for_tests (nano::log_config fallback)
|
|||
initialize_common (config, /* store log file in current workdir */ std::filesystem::current_path ());
|
||||
|
||||
// Use tag and identifier as the logger name, since multiple nodes may be running in the same process
|
||||
global_name_formatter = [] (nano::log::type tag, std::string identifier) {
|
||||
return fmt::format ("{}::{}", identifier, to_string (tag));
|
||||
global_name_formatter = [] (nano::log::logger_id logger_id, std::string identifier) {
|
||||
return fmt::format ("{}::{}", identifier, to_string (logger_id));
|
||||
};
|
||||
|
||||
// Setup formatter to include information about node identifier `[%i]` and tag `[%n]`
|
||||
|
@ -209,13 +210,13 @@ nano::logger::~logger ()
|
|||
flush ();
|
||||
}
|
||||
|
||||
spdlog::logger & nano::logger::get_logger (nano::log::type tag)
|
||||
spdlog::logger & nano::logger::get_logger (nano::log::type type, nano::log::detail detail)
|
||||
{
|
||||
// This is a two-step process to avoid exclusively locking the mutex in the common case
|
||||
{
|
||||
std::shared_lock lock{ mutex };
|
||||
|
||||
if (auto it = spd_loggers.find (tag); it != spd_loggers.end ())
|
||||
if (auto it = spd_loggers.find ({ type, detail }); it != spd_loggers.end ())
|
||||
{
|
||||
return *it->second;
|
||||
}
|
||||
|
@ -224,33 +225,44 @@ spdlog::logger & nano::logger::get_logger (nano::log::type tag)
|
|||
{
|
||||
std::unique_lock lock{ mutex };
|
||||
|
||||
auto [it, inserted] = spd_loggers.emplace (tag, make_logger (tag));
|
||||
auto [it, inserted] = spd_loggers.emplace (std::make_pair (type, detail), make_logger ({ type, detail }));
|
||||
return *it->second;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<spdlog::logger> nano::logger::make_logger (nano::log::type tag)
|
||||
std::shared_ptr<spdlog::logger> nano::logger::make_logger (nano::log::logger_id logger_id)
|
||||
{
|
||||
auto const & config = global_config;
|
||||
auto const & sinks = global_sinks;
|
||||
|
||||
auto name = global_name_formatter (tag, identifier);
|
||||
auto name = global_name_formatter (logger_id, identifier);
|
||||
auto spd_logger = std::make_shared<spdlog::logger> (name, sinks.begin (), sinks.end ());
|
||||
|
||||
if (auto it = config.levels.find ({ tag, nano::log::detail::all }); it != config.levels.end ())
|
||||
{
|
||||
spd_logger->set_level (to_spdlog_level (it->second));
|
||||
}
|
||||
else
|
||||
{
|
||||
spd_logger->set_level (to_spdlog_level (config.default_level));
|
||||
}
|
||||
|
||||
spd_logger->set_level (to_spdlog_level (find_level (logger_id)));
|
||||
spd_logger->flush_on (to_spdlog_level (config.flush_level));
|
||||
|
||||
return spd_logger;
|
||||
}
|
||||
|
||||
nano::log::level nano::logger::find_level (nano::log::logger_id logger_id) const
|
||||
{
|
||||
auto const & config = global_config;
|
||||
auto const & [type, detail] = logger_id;
|
||||
|
||||
// Check for a specific level for this logger
|
||||
if (auto it = config.levels.find (logger_id); it != config.levels.end ())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
// Check for a default level for this logger type
|
||||
if (auto it = config.levels.find ({ type, nano::log::detail::all }); it != config.levels.end ())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
// Use the default level
|
||||
return config.default_level;
|
||||
}
|
||||
|
||||
spdlog::level::level_enum nano::logger::to_spdlog_level (nano::log::level level)
|
||||
{
|
||||
switch (level)
|
||||
|
@ -400,7 +412,7 @@ void nano::log_config::deserialize (nano::tomlconfig & toml)
|
|||
{
|
||||
auto & [name_str, level_str] = level;
|
||||
auto logger_level = nano::log::parse_level (level_str);
|
||||
auto logger_id = parse_logger_id (name_str);
|
||||
auto logger_id = nano::log::parse_logger_id (name_str);
|
||||
|
||||
levels[logger_id] = logger_level;
|
||||
}
|
||||
|
@ -413,29 +425,9 @@ void nano::log_config::deserialize (nano::tomlconfig & toml)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse `logger_name[:logger_detail]` into a pair of `log::type` and `log::detail`
|
||||
* @throw std::invalid_argument if `logger_name` or `logger_detail` are invalid
|
||||
*/
|
||||
nano::log_config::logger_id_t nano::log_config::parse_logger_id (const std::string & logger_name)
|
||||
std::map<nano::log::logger_id, nano::log::level> nano::log_config::default_levels (nano::log::level default_level)
|
||||
{
|
||||
auto pos = logger_name.find ("::");
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
return { nano::log::parse_type (logger_name), nano::log::detail::all };
|
||||
}
|
||||
else
|
||||
{
|
||||
auto logger_type = logger_name.substr (0, pos);
|
||||
auto logger_detail = logger_name.substr (pos + 1);
|
||||
|
||||
return { nano::log::parse_type (logger_type), nano::log::parse_detail (logger_detail) };
|
||||
}
|
||||
}
|
||||
|
||||
std::map<nano::log_config::logger_id_t, nano::log::level> nano::log_config::default_levels (nano::log::level default_level)
|
||||
{
|
||||
std::map<nano::log_config::logger_id_t, nano::log::level> result;
|
||||
std::map<nano::log::logger_id, nano::log::level> result;
|
||||
for (auto const & type : nano::log::all_types ())
|
||||
{
|
||||
result.emplace (std::make_pair (type, nano::log::detail::all), default_level);
|
||||
|
@ -475,7 +467,7 @@ nano::log_config nano::load_log_config (nano::log_config fallback, const std::fi
|
|||
auto env_levels = nano::get_env ("NANO_LOG_LEVELS");
|
||||
if (env_levels)
|
||||
{
|
||||
std::map<nano::log_config::logger_id_t, nano::log::level> levels;
|
||||
std::map<nano::log::logger_id, nano::log::level> levels;
|
||||
for (auto const & env_level_str : nano::util::split (*env_levels, ','))
|
||||
{
|
||||
try
|
||||
|
@ -490,7 +482,7 @@ nano::log_config nano::load_log_config (nano::log_config fallback, const std::fi
|
|||
auto name_str = arr[0];
|
||||
auto level_str = arr[1];
|
||||
|
||||
auto logger_id = nano::log_config::parse_logger_id (name_str);
|
||||
auto logger_id = nano::log::parse_logger_id (name_str);
|
||||
auto logger_level = nano::log::parse_level (level_str);
|
||||
|
||||
levels[logger_id] = logger_level;
|
||||
|
@ -517,4 +509,37 @@ nano::log_config nano::load_log_config (nano::log_config fallback, const std::fi
|
|||
std::cerr << "Unable to load log config. Using defaults. Error: " << ex.what () << std::endl;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
std::string nano::log::to_string (nano::log::logger_id logger_id)
|
||||
{
|
||||
auto const & [type, detail] = logger_id;
|
||||
if (detail == nano::log::detail::all)
|
||||
{
|
||||
return fmt::format ("{}", to_string (type));
|
||||
}
|
||||
else
|
||||
{
|
||||
return fmt::format ("{}::{}", to_string (type), to_string (detail));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse `logger_name[:logger_detail]` into a pair of `log::type` and `log::detail`
|
||||
* @throw std::invalid_argument if `logger_name` or `logger_detail` are invalid
|
||||
*/
|
||||
nano::log::logger_id nano::log::parse_logger_id (const std::string & logger_name)
|
||||
{
|
||||
auto pos = logger_name.find ("::");
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
return { nano::log::parse_type (logger_name), nano::log::detail::all };
|
||||
}
|
||||
else
|
||||
{
|
||||
auto logger_type = logger_name.substr (0, pos);
|
||||
auto logger_detail = logger_name.substr (pos + 1);
|
||||
|
||||
return { nano::log::parse_type (logger_type), nano::log::parse_detail (logger_detail) };
|
||||
}
|
||||
}
|
|
@ -10,6 +10,14 @@
|
|||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
namespace nano::log
|
||||
{
|
||||
using logger_id = std::pair<nano::log::type, nano::log::detail>;
|
||||
|
||||
std::string to_string (logger_id);
|
||||
logger_id parse_logger_id (std::string const &);
|
||||
}
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class log_config final
|
||||
|
@ -26,8 +34,7 @@ public:
|
|||
nano::log::level default_level{ nano::log::level::info };
|
||||
nano::log::level flush_level{ nano::log::level::error };
|
||||
|
||||
using logger_id_t = std::pair<nano::log::type, nano::log::detail>;
|
||||
std::map<logger_id_t, nano::log::level> levels;
|
||||
std::map<nano::log::logger_id, nano::log::level> levels;
|
||||
|
||||
struct console_config
|
||||
{
|
||||
|
@ -52,11 +59,9 @@ public: // Predefined defaults
|
|||
static log_config tests_default ();
|
||||
static log_config sample_config (); // For auto-generated sample config files
|
||||
|
||||
static logger_id_t parse_logger_id (std::string const &);
|
||||
|
||||
private:
|
||||
/// Returns placeholder log levels for all loggers
|
||||
static std::map<logger_id_t, nano::log::level> default_levels (nano::log::level);
|
||||
static std::map<nano::log::logger_id, nano::log::level> default_levels (nano::log::level);
|
||||
};
|
||||
|
||||
nano::log_config load_log_config (nano::log_config fallback, std::filesystem::path const & data_path, std::vector<std::string> const & config_overrides = {});
|
||||
|
@ -79,56 +84,57 @@ private:
|
|||
static bool global_initialized;
|
||||
static nano::log_config global_config;
|
||||
static std::vector<spdlog::sink_ptr> global_sinks;
|
||||
static std::function<std::string (nano::log::type tag, std::string identifier)> global_name_formatter;
|
||||
static std::function<std::string (nano::log::logger_id, std::string identifier)> global_name_formatter;
|
||||
|
||||
static void initialize_common (nano::log_config const &, std::optional<std::filesystem::path> data_path);
|
||||
|
||||
public:
|
||||
template <class... Args>
|
||||
void log (nano::log::level level, nano::log::type tag, spdlog::format_string_t<Args...> fmt, Args &&... args)
|
||||
void log (nano::log::level level, nano::log::type type, spdlog::format_string_t<Args...> fmt, Args &&... args)
|
||||
{
|
||||
get_logger (tag).log (to_spdlog_level (level), fmt, std::forward<Args> (args)...);
|
||||
get_logger (type).log (to_spdlog_level (level), fmt, std::forward<Args> (args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
void debug (nano::log::type tag, spdlog::format_string_t<Args...> fmt, Args &&... args)
|
||||
void debug (nano::log::type type, spdlog::format_string_t<Args...> fmt, Args &&... args)
|
||||
{
|
||||
get_logger (tag).debug (fmt, std::forward<Args> (args)...);
|
||||
get_logger (type).debug (fmt, std::forward<Args> (args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
void info (nano::log::type tag, spdlog::format_string_t<Args...> fmt, Args &&... args)
|
||||
void info (nano::log::type type, spdlog::format_string_t<Args...> fmt, Args &&... args)
|
||||
{
|
||||
get_logger (tag).info (fmt, std::forward<Args> (args)...);
|
||||
get_logger (type).info (fmt, std::forward<Args> (args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
void warn (nano::log::type tag, spdlog::format_string_t<Args...> fmt, Args &&... args)
|
||||
void warn (nano::log::type type, spdlog::format_string_t<Args...> fmt, Args &&... args)
|
||||
{
|
||||
get_logger (tag).warn (fmt, std::forward<Args> (args)...);
|
||||
get_logger (type).warn (fmt, std::forward<Args> (args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
void error (nano::log::type tag, spdlog::format_string_t<Args...> fmt, Args &&... args)
|
||||
void error (nano::log::type type, spdlog::format_string_t<Args...> fmt, Args &&... args)
|
||||
{
|
||||
get_logger (tag).error (fmt, std::forward<Args> (args)...);
|
||||
get_logger (type).error (fmt, std::forward<Args> (args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
void critical (nano::log::type tag, spdlog::format_string_t<Args...> fmt, Args &&... args)
|
||||
void critical (nano::log::type type, spdlog::format_string_t<Args...> fmt, Args &&... args)
|
||||
{
|
||||
get_logger (tag).critical (fmt, std::forward<Args> (args)...);
|
||||
get_logger (type).critical (fmt, std::forward<Args> (args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string identifier;
|
||||
|
||||
std::unordered_map<nano::log::type, std::shared_ptr<spdlog::logger>> spd_loggers;
|
||||
std::map<nano::log::logger_id, std::shared_ptr<spdlog::logger>> spd_loggers;
|
||||
std::shared_mutex mutex;
|
||||
|
||||
private:
|
||||
spdlog::logger & get_logger (nano::log::type tag);
|
||||
std::shared_ptr<spdlog::logger> make_logger (nano::log::type tag);
|
||||
spdlog::logger & get_logger (nano::log::type, nano::log::detail = nano::log::detail::all);
|
||||
std::shared_ptr<spdlog::logger> make_logger (nano::log::logger_id);
|
||||
nano::log::level find_level (nano::log::logger_id) const;
|
||||
|
||||
static spdlog::level::level_enum to_spdlog_level (nano::log::level);
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue