diff --git a/include/spdlog/details/registry-inl.h b/include/spdlog/details/registry-inl.h index f447848e..4cbdeb75 100644 --- a/include/spdlog/details/registry-inl.h +++ b/include/spdlog/details/registry-inl.h @@ -54,6 +54,11 @@ SPDLOG_INLINE void registry::register_logger(std::shared_ptr new_logger) register_logger_(std::move(new_logger)); } +SPDLOG_INLINE void registry::register_or_replace(std::shared_ptr new_logger) { + std::lock_guard lock(logger_map_mutex_); + register_or_replace_(std::move(new_logger)); +} + SPDLOG_INLINE void registry::initialize_logger(std::shared_ptr new_logger) { std::lock_guard lock(logger_map_mutex_); new_logger->set_formatter(formatter_->clone()); @@ -252,10 +257,14 @@ SPDLOG_INLINE void registry::throw_if_exists_(const std::string &logger_name) { } SPDLOG_INLINE void registry::register_logger_(std::shared_ptr new_logger) { - auto logger_name = new_logger->name(); + auto &logger_name = new_logger->name(); throw_if_exists_(logger_name); loggers_[logger_name] = std::move(new_logger); } +SPDLOG_INLINE void registry::register_or_replace_(std::shared_ptr new_logger) { + loggers_[new_logger->name()] = std::move(new_logger); +} + } // namespace details } // namespace spdlog diff --git a/include/spdlog/details/registry.h b/include/spdlog/details/registry.h index 8afcbd6f..72c70b82 100644 --- a/include/spdlog/details/registry.h +++ b/include/spdlog/details/registry.h @@ -31,6 +31,7 @@ public: registry &operator=(const registry &) = delete; void register_logger(std::shared_ptr new_logger); + void register_or_replace(std::shared_ptr new_logger); void initialize_logger(std::shared_ptr new_logger); std::shared_ptr get(const std::string &logger_name); std::shared_ptr default_logger(); @@ -105,6 +106,7 @@ private: void throw_if_exists_(const std::string &logger_name); void register_logger_(std::shared_ptr new_logger); + void register_or_replace_(std::shared_ptr new_logger); bool set_level_from_cfg_(logger *logger); std::mutex logger_map_mutex_, flusher_mutex_; std::recursive_mutex tp_mutex_; diff --git a/include/spdlog/spdlog-inl.h b/include/spdlog/spdlog-inl.h index 97c36222..e02081fe 100644 --- a/include/spdlog/spdlog-inl.h +++ b/include/spdlog/spdlog-inl.h @@ -59,6 +59,10 @@ SPDLOG_INLINE void register_logger(std::shared_ptr logger) { details::registry::instance().register_logger(std::move(logger)); } +SPDLOG_INLINE void register_or_replace(std::shared_ptr logger) { + details::registry::instance().register_or_replace(std::move(logger)); +} + SPDLOG_INLINE void apply_all(const std::function)> &fun) { details::registry::instance().apply_all(fun); } diff --git a/include/spdlog/spdlog.h b/include/spdlog/spdlog.h index a8afbcec..b51b470b 100644 --- a/include/spdlog/spdlog.h +++ b/include/spdlog/spdlog.h @@ -25,7 +25,7 @@ namespace spdlog { using default_factory = synchronous_factory; // Create and register a logger with a templated sink type -// The logger's level, formatter and flush level will be set according the +// The logger's level, formatter and flush level will be set according to the // global settings. // // Example: @@ -46,7 +46,7 @@ inline std::shared_ptr create(std::string logger_name, SinkArgs // spdlog::initialize_logger(mylogger); SPDLOG_API void initialize_logger(std::shared_ptr logger); -// Return an existing logger or nullptr if a logger with such name doesn't +// Return an existing logger or nullptr if a logger with such a name doesn't // exist. // example: spdlog::get("my_logger")->info("hello {}", "world"); SPDLOG_API std::shared_ptr get(const std::string &name); @@ -71,13 +71,13 @@ SPDLOG_API void dump_backtrace(); // Get global logging level SPDLOG_API level::level_enum get_level(); -// Set global logging level +// Set the global logging level SPDLOG_API void set_level(level::level_enum log_level); // Determine whether the default logger should log messages with a certain level SPDLOG_API bool should_log(level::level_enum lvl); -// Set global flush level +// Set a global flush level SPDLOG_API void flush_on(level::level_enum log_level); // Start/Restart a periodic flusher thread @@ -91,9 +91,14 @@ inline void flush_every(std::chrono::duration interval) { SPDLOG_API void set_error_handler(void (*handler)(const std::string &msg)); // Register the given logger with the given name +// Will throw if a logger with the same name already exists. SPDLOG_API void register_logger(std::shared_ptr logger); -// Apply a user defined function on all registered loggers +// Register the given logger with the given name +// Will replace any the existing logger with the same name if exists. +SPDLOG_API void register_or_replace(std::shared_ptr logger); + +// Apply a user-defined function on all registered loggers // Example: // spdlog::apply_all([&](std::shared_ptr l) {l->flush();}); SPDLOG_API void apply_all(const std::function)> &fun); @@ -111,19 +116,19 @@ SPDLOG_API void shutdown(); SPDLOG_API void set_automatic_registration(bool automatic_registration); // API for using default logger (stdout_color_mt), -// e.g: spdlog::info("Message {}", 1); +// e.g.: spdlog::info("Message {}", 1); // // The default logger object can be accessed using the spdlog::default_logger(): // For example, to add another sink to it: // spdlog::default_logger()->sinks().push_back(some_sink); // -// The default logger can replaced using spdlog::set_default_logger(new_logger). +// The default logger can be replaced using spdlog::set_default_logger(new_logger). // For example, to replace it with a file logger. // // IMPORTANT: // The default API is thread safe (for _mt loggers), but: // set_default_logger() *should not* be used concurrently with the default API. -// e.g do not call set_default_logger() from one thread while calling spdlog::info() from another. +// e.g., do not call set_default_logger() from one thread while calling spdlog::info() from another. SPDLOG_API std::shared_ptr default_logger(); diff --git a/tests/test_registry.cpp b/tests/test_registry.cpp index 69ec8f53..6397f2a3 100644 --- a/tests/test_registry.cpp +++ b/tests/test_registry.cpp @@ -25,6 +25,18 @@ TEST_CASE("explicit register", "[registry]") { } #endif +TEST_CASE("register_or_replace", "[registry]") { + spdlog::drop_all(); + auto logger1 = std::make_shared(tested_logger_name, + std::make_shared()); + spdlog::register_logger(logger1); + REQUIRE(spdlog::get(tested_logger_name) == logger1); + + auto logger2 = std::make_shared(tested_logger_name, std::make_shared()); + spdlog::register_or_replace(logger2); + REQUIRE(spdlog::get(tested_logger_name) == logger2); +} + TEST_CASE("apply_all", "[registry]") { spdlog::drop_all(); auto logger = std::make_shared(tested_logger_name,