diff --git a/bench/bench.cpp b/bench/bench.cpp index 61e9fcb3..ad8d7a24 100644 --- a/bench/bench.cpp +++ b/bench/bench.cpp @@ -29,6 +29,7 @@ using namespace utils; void bench(int howmany, std::shared_ptr log); void bench_mt(int howmany, std::shared_ptr log, int thread_count); +void bench_default_api(int howmany, std::shared_ptr log); int main(int argc, char *argv[]) { @@ -56,16 +57,34 @@ int main(int argc, char *argv[]) "*************\n"; auto basic_st = spdlog::basic_logger_st("basic_st", "logs/basic_st.log", true); - bench(howmany, basic_st); + bench(howmany, std::move(basic_st)); + basic_st.reset(); auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st.log", file_size, rotating_files); - bench(howmany, rotating_st); + bench(howmany, std::move(rotating_st)); auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st.log"); - bench(howmany, daily_st); + bench(howmany, std::move(daily_st)); bench(howmany, spdlog::create("null_st")); + cout << "******************************************************************" + "*************\n"; + cout << "Default API. Single thread, " << format(howmany) << " iterations" << endl; + cout << "******************************************************************" + "*************\n"; + + basic_st = spdlog::basic_logger_st("basic_st", "logs/basic_st.log", true); + bench_default_api(howmany, std::move(basic_st)); + + rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st.log", file_size, rotating_files); + bench_default_api(howmany, std::move(rotating_st)); + + daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st.log"); + bench_default_api(howmany, std::move(daily_st)); + + bench_default_api(howmany, spdlog::create("null_st")); + cout << "\n****************************************************************" "***************\n"; cout << threads << " threads sharing same logger, " << format(howmany) << " iterations" << endl; @@ -73,13 +92,13 @@ int main(int argc, char *argv[]) "*************\n"; auto basic_mt = spdlog::basic_logger_mt("basic_mt", "logs/basic_mt.log", true); - bench_mt(howmany, basic_mt, threads); + bench_mt(howmany, std::move(basic_mt), threads); auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt.log", file_size, rotating_files); - bench_mt(howmany, rotating_mt, threads); + bench_mt(howmany, std::move(rotating_mt), threads); auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt.log"); - bench_mt(howmany, daily_mt, threads); + bench_mt(howmany, std::move(daily_mt), threads); bench_mt(howmany, spdlog::create("null_mt"), threads); cout << "\n****************************************************************" @@ -92,8 +111,7 @@ int main(int argc, char *argv[]) { spdlog::init_thread_pool(static_cast(queue_size), 1); auto as = spdlog::basic_logger_mt("async", "logs/basic_async.log", true); - bench_mt(howmany, as, threads); - spdlog::drop("async"); + bench_mt(howmany, std::move(as), threads); } } catch (std::exception &ex) @@ -119,7 +137,7 @@ void bench(int howmany, std::shared_ptr log) auto delta_d = duration_cast>(delta).count(); cout << "Elapsed: " << delta_d << "\t" << format(int(howmany / delta_d)) << "/sec" << endl; - spdlog::drop(log->name()); + spdlog::drop_all(); } void bench_mt(int howmany, std::shared_ptr log, int thread_count) @@ -146,4 +164,23 @@ void bench_mt(int howmany, std::shared_ptr log, int thread_count auto delta = high_resolution_clock::now() - start; auto delta_d = duration_cast>(delta).count(); cout << "Elapsed: " << delta_d << "\t" << format(int(howmany / delta_d)) << "/sec" << endl; + spdlog::drop_all(); +} + +void bench_default_api(int howmany, std::shared_ptr log) +{ + using std::chrono::high_resolution_clock; + cout << log->name() << "...\t\t" << flush; + spdlog::set_default_logger(log); + auto start = high_resolution_clock::now(); + for (auto i = 0; i < howmany; ++i) + { + spdlog::info("Hello logger: msg number {}", i); + } + + auto delta = high_resolution_clock::now() - start; + auto delta_d = duration_cast>(delta).count(); + + cout << "Elapsed: " << delta_d << "\t" << format(int(howmany / delta_d)) << "/sec" << endl; + spdlog::drop_all(); } diff --git a/example/example.cpp b/example/example.cpp index df89ae56..15ca856e 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -23,7 +23,7 @@ void syslog_example(); void clone_example(); #define SPDLOG_TRACE_ON -#define SPDLOG_DEBUG_ON + #include "spdlog/spdlog.h" int main(int, char *[]) @@ -115,7 +115,7 @@ void daily_example() // Useful for creating component/subsystem loggers from some "root" logger. void clone_example() { - auto network_logger = spdlog::get()->clone("network"); + auto network_logger = spdlog::default_logger()->clone("network"); network_logger->info("Logging network stuff.."); } @@ -156,10 +156,10 @@ void binary_example() } // Compile time log levels. -// Must define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON to turn them on. +// Must define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON before including spdlog.h to turn them on. void trace_example() { - auto logger = spdlog::get(); + auto logger = spdlog::get("file_logger"); SPDLOG_TRACE(logger, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23); SPDLOG_DEBUG(logger, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23); } diff --git a/include/spdlog/details/registry.h b/include/spdlog/details/registry.h index 26935a25..efb70ade 100644 --- a/include/spdlog/details/registry.h +++ b/include/spdlog/details/registry.h @@ -75,13 +75,23 @@ public: return found == loggers_.end() ? nullptr : found->second; } - std::shared_ptr get_default_logger() const + std::shared_ptr default_logger() { + std::lock_guard lock(logger_map_mutex_); return default_logger_; } + // Return raw ptr to the default logger. + // To be used directly by the spdlog default api (e.g. spdlog::info) + // This make the default API faster, but cannot be used concurrently with set_default_logger(). + // e.g do not call set_default_logger() from one thread while calling spdlog::info() from another. + logger *get_default_raw() + { + return default_logger_.get(); + } + // set default logger. - // default logger is stored in default_logger_ (for faster retrieval) and in the map of existing loggers. + // default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map. void set_default_logger(std::shared_ptr new_default_logger) { std::lock_guard lock(logger_map_mutex_); @@ -90,7 +100,10 @@ public: { loggers_.erase(default_logger_->name()); } - loggers_[new_default_logger->name()] = new_default_logger; + if (new_default_logger != nullptr) + { + loggers_[new_default_logger->name()] = new_default_logger; + } default_logger_ = std::move(new_default_logger); } @@ -176,6 +189,10 @@ public: { std::lock_guard lock(logger_map_mutex_); loggers_.erase(logger_name); + if (default_logger_ && default_logger_->name() == logger_name) + { + default_logger_.reset(); + } } void drop_all() diff --git a/include/spdlog/spdlog.h b/include/spdlog/spdlog.h index 3158909a..bcca2e84 100644 --- a/include/spdlog/spdlog.h +++ b/include/spdlog/spdlog.h @@ -25,7 +25,6 @@ namespace spdlog { struct synchronous_factory { template - static std::shared_ptr create(std::string logger_name, SinkArgs &&... args) { auto sink = std::make_shared(std::forward(args)...); @@ -126,28 +125,29 @@ inline void shutdown() details::registry::instance().shutdown(); } -// // API for using default logger (stdout_color_mt), // e.g: spdlog::info("Message {}", 1); // -// The default logger object can be accessed using the spdlog::get(): +// The default logger object can be accessed using the spdlog::default_logger(): // For example, to add another sink to it: -// spdlog::get()->sinks()->push_back(some_sink); +// spdlog::default_logger()->sinks()->push_back(some_sink); // // The default logger can replaced using spdlog::set_default_logger(new_logger). -// For example, to replace it with a file logger: -// spdlog::set_default_logger(std::move(spdlog::basic_logger_st("mylog.txt")); +// 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. -// Return the default logger -// inline std::shared_ptr get() -//{ -// return details::registry::instance().get_default_logger(); -//} - -inline std::shared_ptr get() +inline std::shared_ptr default_logger() { - return details::registry::instance().get_default_logger(); + return details::registry::instance().default_logger(); +} + +inline spdlog::logger *default_logger_raw() +{ + return details::registry::instance().get_default_raw(); } inline void set_default_logger(std::shared_ptr default_logger) @@ -158,128 +158,128 @@ inline void set_default_logger(std::shared_ptr default_logger) template inline void log(level::level_enum lvl, const char *fmt, const Args &... args) { - get()->log(lvl, fmt, args...); + default_logger_raw()->log(lvl, fmt, args...); } template inline void trace(const char *fmt, const Args &... args) { - get()->trace(fmt, args...); + default_logger_raw()->trace(fmt, args...); } template inline void debug(const char *fmt, const Args &... args) { - get()->debug(fmt, args...); + default_logger_raw()->debug(fmt, args...); } template inline void info(const char *fmt, const Args &... args) { - get()->info(fmt, args...); + default_logger_raw()->info(fmt, args...); } template inline void warn(const char *fmt, const Args &... args) { - get()->warn(fmt, args...); + default_logger_raw()->warn(fmt, args...); } template inline void error(const char *fmt, const Args &... args) { - get()->error(fmt, args...); + default_logger_raw()->error(fmt, args...); } template inline void critical(const char *fmt, const Args &... args) { - get()->critical(fmt, args...); + default_logger_raw()->critical(fmt, args...); } template inline void log(level::level_enum lvl, const T &msg) { - get()->log(lvl, msg); + default_logger_raw()->log(lvl, msg); } template inline void trace(const T &msg) { - get()->trace(msg); + default_logger_raw()->trace(msg); } template inline void debug(const T &msg) { - get()->debug(msg); + default_logger_raw()->debug(msg); } template inline void info(const T &msg) { - get()->info(msg); + default_logger_raw()->info(msg); } template inline void warn(const T &msg) { - get()->warn(msg); + default_logger_raw()->warn(msg); } template inline void error(const T &msg) { - get()->error(msg); + default_logger_raw()->error(msg); } template inline void critical(const T &msg) { - get()->critical(msg); + default_logger_raw()->critical(msg); } #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT template inline void log(level::level_enum lvl, const wchar_t *fmt, const Args &... args) { - get()->log(lvl, fmt, args...); + default_logger_raw()->log(lvl, fmt, args...); } template inline void trace(const wchar_t *fmt, const Args &... args) { - get()->trace(fmt, args...); + default_logger_raw()->trace(fmt, args...); } template inline void debug(const wchar_t *fmt, const Args &... args) { - get()->debug(fmt, args...); + default_logger_raw()->debug(fmt, args...); } template inline void info(const wchar_t *fmt, const Args &... args) { - get()->info(fmt, args...); + default_logger_raw()->info(fmt, args...); } template inline void warn(const wchar_t *fmt, const Args &... args) { - get()->warn(fmt, args...); + default_logger_raw()->warn(fmt, args...); } template inline void error(const wchar_t *fmt, const Args &... args) { - get()->error(fmt, args...); + default_logger_raw()->error(fmt, args...); } template inline void critical(const wchar_t *fmt, const Args &... args) { - get()->critical(fmt, args...); + default_logger_raw()->critical(fmt, args...); } #endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT diff --git a/include/spdlog/tweakme.h b/include/spdlog/tweakme.h index 2c260ec5..d91159f7 100644 --- a/include/spdlog/tweakme.h +++ b/include/spdlog/tweakme.h @@ -122,7 +122,6 @@ // "MY ERROR", "MY CRITICAL", "OFF" } /////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// // Uncomment to disable default logger creation. // This might save some (very) small initialization time if no default logger is needed. diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 18d74823..ea9ffb35 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,7 +10,7 @@ set(SPDLOG_UTESTS_SOURCES test_pattern_formatter.cpp test_async.cpp includes.h - registry.cpp + test_registry.cpp test_macros.cpp utils.cpp utils.h diff --git a/tests/test_misc.cpp b/tests/test_misc.cpp index 274a328e..f69a3487 100644 --- a/tests/test_misc.cpp +++ b/tests/test_misc.cpp @@ -198,35 +198,36 @@ TEST_CASE("default logger API", "[default logger]") auto oss_sink = std::make_shared(oss); spdlog::set_default_logger(std::make_shared("oss", oss_sink)); - spdlog::get()->set_pattern("%v"); + spdlog::set_pattern("*** %v"); - spdlog::get()->set_level(spdlog::level::trace); + spdlog::default_logger()->set_level(spdlog::level::trace); spdlog::trace("hello trace"); - REQUIRE(oss.str() == "hello trace" + std::string(spdlog::details::os::default_eol)); + REQUIRE(oss.str() == "*** hello trace" + std::string(spdlog::details::os::default_eol)); oss.str(""); spdlog::debug("hello debug"); - REQUIRE(oss.str() == "hello debug" + std::string(spdlog::details::os::default_eol)); + REQUIRE(oss.str() == "*** hello debug" + std::string(spdlog::details::os::default_eol)); oss.str(""); spdlog::info("Hello"); - REQUIRE(oss.str() == "Hello" + std::string(spdlog::details::os::default_eol)); + REQUIRE(oss.str() == "*** Hello" + std::string(spdlog::details::os::default_eol)); oss.str(""); spdlog::warn("Hello again {}", 2); - REQUIRE(oss.str() == "Hello again 2" + std::string(spdlog::details::os::default_eol)); + REQUIRE(oss.str() == "*** Hello again 2" + std::string(spdlog::details::os::default_eol)); oss.str(""); spdlog::error(123); - REQUIRE(oss.str() == "123" + std::string(spdlog::details::os::default_eol)); + REQUIRE(oss.str() == "*** 123" + std::string(spdlog::details::os::default_eol)); oss.str(""); spdlog::critical(std::string("some string")); - REQUIRE(oss.str() == "some string" + std::string(spdlog::details::os::default_eol)); + REQUIRE(oss.str() == "*** some string" + std::string(spdlog::details::os::default_eol)); oss.str(""); spdlog::set_level(spdlog::level::info); spdlog::debug("should not be logged"); REQUIRE(oss.str().empty()); spdlog::drop_all(); + spdlog::set_pattern("%v"); } diff --git a/tests/registry.cpp b/tests/test_registry.cpp similarity index 83% rename from tests/registry.cpp rename to tests/test_registry.cpp index face26d3..68833012 100644 --- a/tests/registry.cpp +++ b/tests/test_registry.cpp @@ -51,6 +51,14 @@ TEST_CASE("drop", "[registry]") REQUIRE_FALSE(spdlog::get(tested_logger_name)); } +TEST_CASE("drop-default", "[registry]") +{ + spdlog::set_default_logger(spdlog::null_logger_st(tested_logger_name)); + spdlog::drop(tested_logger_name); + REQUIRE_FALSE(spdlog::default_logger()); + REQUIRE_FALSE(spdlog::get(tested_logger_name)); +} + TEST_CASE("drop_all", "[registry]") { spdlog::drop_all(); @@ -59,6 +67,7 @@ TEST_CASE("drop_all", "[registry]") spdlog::drop_all(); REQUIRE_FALSE(spdlog::get(tested_logger_name)); REQUIRE_FALSE(spdlog::get(tested_logger_name2)); + REQUIRE_FALSE(spdlog::default_logger()); } TEST_CASE("drop non existing", "[registry]") @@ -75,6 +84,12 @@ TEST_CASE("default logger", "[registry]") { spdlog::drop_all(); spdlog::set_default_logger(std::move(spdlog::null_logger_st(tested_logger_name))); - REQUIRE(spdlog::get(tested_logger_name) == spdlog::get()); + REQUIRE(spdlog::get(tested_logger_name) == spdlog::default_logger()); spdlog::drop_all(); } + +TEST_CASE("set_default_logger(nullptr)", "[registry]") +{ + spdlog::set_default_logger(nullptr); + REQUIRE_FALSE(spdlog::default_logger()); +}