Added a function to add callbacks that are called when a logger is registered (#2883)

* Added a function to add callbacks that are called when a logger is registered

* Fix non captured registration 2 not being properly tested for

* Replace std::list by std::vector

* Remove const refs to shared pointers

* Fix missing header
This commit is contained in:
Jonathan Vannier 2023-09-25 17:49:04 +02:00 committed by GitHub
parent 0a53eafe18
commit b6eeb7364c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 72 additions and 0 deletions

View File

@ -259,6 +259,22 @@ SPDLOG_INLINE void registry::register_logger_(std::shared_ptr<logger> new_logger
auto logger_name = new_logger->name(); auto logger_name = new_logger->name();
throw_if_exists_(logger_name); throw_if_exists_(logger_name);
loggers_[logger_name] = std::move(new_logger); loggers_[logger_name] = std::move(new_logger);
const auto& logger = loggers_[logger_name];
for (const auto& on_registration_callback : on_registration_callbacks_) {
on_registration_callback(logger);
}
}
SPDLOG_INLINE void registry::add_on_registration_callback(
const std::function<void(std::shared_ptr<logger>)>& callback) {
std::lock_guard<std::mutex> lock(logger_map_mutex_);
on_registration_callbacks_.push_back(callback);
}
SPDLOG_INLINE void registry::drop_all_on_registration_callbacks() {
std::lock_guard<std::mutex> lock(logger_map_mutex_);
on_registration_callbacks_.clear();
} }
} // namespace details } // namespace details

View File

@ -17,6 +17,7 @@
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <vector>
namespace spdlog { namespace spdlog {
class logger; class logger;
@ -92,6 +93,10 @@ public:
void apply_logger_env_levels(std::shared_ptr<logger> new_logger); void apply_logger_env_levels(std::shared_ptr<logger> new_logger);
void add_on_registration_callback(const std::function<void(std::shared_ptr<logger>)>& callback);
void drop_all_on_registration_callbacks();
private: private:
registry(); registry();
~registry(); ~registry();
@ -112,6 +117,7 @@ private:
std::shared_ptr<logger> default_logger_; std::shared_ptr<logger> default_logger_;
bool automatic_registration_ = true; bool automatic_registration_ = true;
size_t backtrace_n_messages_ = 0; size_t backtrace_n_messages_ = 0;
std::vector<std::function<void(std::shared_ptr<logger>)>> on_registration_callbacks_;
}; };
} // namespace details } // namespace details

View File

@ -89,4 +89,12 @@ SPDLOG_INLINE void apply_logger_env_levels(std::shared_ptr<logger> logger) {
details::registry::instance().apply_logger_env_levels(std::move(logger)); details::registry::instance().apply_logger_env_levels(std::move(logger));
} }
SPDLOG_INLINE void add_on_registration_callback(const std::function<void(const std::shared_ptr<logger>&)>& callback) {
details::registry::instance().add_on_registration_callback(callback);
}
SPDLOG_INLINE void drop_all_on_registration_callbacks() {
details::registry::instance().drop_all_on_registration_callbacks();
}
} // namespace spdlog } // namespace spdlog

View File

@ -140,6 +140,21 @@ SPDLOG_API void set_default_logger(std::shared_ptr<spdlog::logger> default_logge
// spdlog::apply_logger_env_levels(mylogger); // spdlog::apply_logger_env_levels(mylogger);
SPDLOG_API void apply_logger_env_levels(std::shared_ptr<logger> logger); SPDLOG_API void apply_logger_env_levels(std::shared_ptr<logger> logger);
// Add a callback that is called whenever a logger is registered
//
// Useful for intercepting loggers that are dynamically created during the application's lifetime
// (e.g. from dynamically loaded libraries, etc.)
// Example:
// void my_on_registration_callback(const std::shared_ptr<spdlog::logger>& logger) {
// logger->do_stuff();
// }
// ...
// spdlog::add_on_registration_callback(my_on_registration_callback);
SPDLOG_API void add_on_registration_callback(const std::function<void(const std::shared_ptr<logger>&)>& callback);
// Clear all callbacks that were added to intercept registrations (see "add_on_registration_callback")
SPDLOG_API void drop_all_on_registration_callbacks();
template <typename... Args> template <typename... Args>
inline void log(source_loc source, inline void log(source_loc source,
level::level_enum lvl, level::level_enum lvl,

View File

@ -110,3 +110,30 @@ TEST_CASE("disable automatic registration", "[registry]") {
spdlog::set_level(spdlog::level::info); spdlog::set_level(spdlog::level::info);
spdlog::set_automatic_registration(true); spdlog::set_automatic_registration(true);
} }
TEST_CASE("add_on_registration_callback", "[registry]") {
std::vector<std::string> registered_logger_names;
auto on_registration_callback = [&](std::shared_ptr<spdlog::logger> logger)
{
registered_logger_names.push_back(logger->name());
};
spdlog::add_on_registration_callback(on_registration_callback);
auto captured_registration_logger1 = spdlog::create<spdlog::sinks::stdout_color_sink_mt>("captured_registration_logger1");
spdlog::set_automatic_registration(false);
auto non_captured_registration_logger1 = spdlog::create<spdlog::sinks::stdout_color_sink_mt>("non_captured_registration_logger1");
auto captured_registration_logger2 = spdlog::create<spdlog::sinks::stdout_color_sink_mt>("captured_registration_logger2");
spdlog::register_logger(captured_registration_logger2);
spdlog::drop_all_on_registration_callbacks();
auto non_captured_registration_logger2 = spdlog::create<spdlog::sinks::stdout_color_sink_mt>("non_captured_registration_logger2");
spdlog::register_logger(non_captured_registration_logger2);
// Check that only the automatically registered logged and the manually registered logger were captured
REQUIRE(registered_logger_names == std::vector<std::string>({"captured_registration_logger1", "captured_registration_logger2"}));
spdlog::set_level(spdlog::level::info);
spdlog::set_automatic_registration(true);
}