diff --git a/README.md b/README.md index 9f6291b9..d7434356 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Very fast, header-only/compiled, C++ logging library. [![ci](https://github.com/gabime/spdlog/actions/workflows/ci.yml/badge.svg)](https://github.com/gabime/spdlog/actions/workflows/ci.yml)  [![Build status](https://ci.appveyor.com/api/projects/status/d2jnxclg20vd0o50?svg=true&branch=v1.x)](https://ci.appveyor.com/project/gabime/spdlog) [![Release](https://img.shields.io/github/release/gabime/spdlog.svg)](https://github.com/gabime/spdlog/releases/latest) ## Install -#### Header only version +#### Header-only version Copy the include [folder](https://github.com/gabime/spdlog/tree/v1.x/include/spdlog) to your build tree and use a C++11 compiler. #### Compiled version (recommended - much faster compile times) @@ -39,7 +39,7 @@ $ cmake .. && make -j ## Features * Very fast (see [benchmarks](#benchmarks) below). * Headers only or compiled -* Feature rich formatting, using the excellent [fmt](https://github.com/fmtlib/fmt) library. +* Feature-rich formatting, using the excellent [fmt](https://github.com/fmtlib/fmt) library. * Asynchronous mode (optional) * [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting. * Multi/Single threaded loggers. @@ -51,9 +51,9 @@ $ cmake .. && make -j * Windows event log. * Windows debugger (```OutputDebugString(..)```). * Easily [extendable](https://github.com/gabime/spdlog/wiki/4.-Sinks#implementing-your-own-sink) with custom log targets. -* Log filtering - log levels can be modified in runtime as well as in compile time. -* Support for loading log levels from argv or from environment var. -* [Backtrace](#backtrace-support) support - store debug messages in a ring buffer and display later on demand. +* Log filtering - log levels can be modified at runtime as well as compile time. +* Support for loading log levels from argv or environment var. +* [Backtrace](#backtrace-support) support - store debug messages in a ring buffer and display them later on demand. ## Usage samples @@ -92,7 +92,7 @@ int main() #include "spdlog/sinks/stdout_color_sinks.h" void stdout_example() { - // create color multi threaded logger + // create a color multi-threaded logger auto console = spdlog::stdout_color_mt("console"); auto err_logger = spdlog::stderr_color_mt("stderr"); spdlog::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)"); @@ -121,7 +121,7 @@ void basic_logfile_example() #include "spdlog/sinks/rotating_file_sink.h" void rotating_example() { - // Create a file rotating logger with 5mb size max and 3 rotated files + // Create a file rotating logger with 5 MB size max and 3 rotated files auto max_size = 1048576 * 5; auto max_files = 3; auto logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", max_size, max_files); @@ -135,7 +135,7 @@ void rotating_example() #include "spdlog/sinks/daily_file_sink.h" void daily_example() { - // Create a daily logger - a new file is created every day on 2:30am + // Create a daily logger - a new file is created every day at 2:30 am auto logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30); } @@ -145,7 +145,7 @@ void daily_example() #### Backtrace support ```c++ // Debug messages can be stored in a ring buffer instead of being logged immediately. -// This is useful in order to display debug logs only when really needed (e.g. when error happens). +// This is useful to display debug logs only when needed (e.g. when an error happens). // When needed, call dump_backtrace() to dump them to your log. spdlog::enable_backtrace(32); // Store the latest 32 messages in a buffer. @@ -154,7 +154,7 @@ for(int i = 0; i < 100; i++) { spdlog::debug("Backtrace message {}", i); // not logged yet.. } -// e.g. if some has error happened: +// e.g. if some error happened: spdlog::dump_backtrace(); // log them now! show the last 32 messages // or my_logger->dump_backtrace(32).. ``` @@ -163,7 +163,7 @@ spdlog::dump_backtrace(); // log them now! show the last 32 messages #### Periodic flush ```c++ // periodically flush all *registered* loggers every 3 seconds: -// warning: only use if all your loggers are thread safe ("_mt" loggers) +// warning: only use if all your loggers are thread-safe ("_mt" loggers) spdlog::flush_every(std::chrono::seconds(3)); ``` @@ -191,7 +191,7 @@ void stopwatch_example() // {:X} - print in uppercase. // {:s} - don't separate each byte with space. // {:p} - don't print the position on each line start. -// {:n} - don't split the output to lines. +// {:n} - don't split the output into lines. // {:a} - show ASCII if :n is not set. #include "spdlog/fmt/bin_to_hex.h" @@ -211,11 +211,11 @@ void binary_example() ``` --- -#### Logger with multi sinks - each with different format and log level +#### Logger with multi sinks - each with a different format and log level ```c++ -// create logger with 2 targets with different log levels and formats. -// the console will show only warnings or errors, while the file will log all. +// create a logger with 2 targets, with different log levels and formats. +// The console will show only warnings or errors, while the file will log all. void multi_sink_example() { auto console_sink = std::make_shared(); @@ -233,10 +233,10 @@ void multi_sink_example() ``` --- -#### User defined callbacks about log events +#### User-defined callbacks about log events ```c++ -// create logger with a lambda function callback, the callback will be called +// create a logger with a lambda function callback, the callback will be called // each time something is logged to the logger void callback_example() { @@ -287,7 +287,7 @@ void multi_sink_example2() ``` --- -#### User defined types +#### User-defined types ```c++ template<> struct fmt::formatter : fmt::formatter @@ -306,7 +306,7 @@ void user_defined_example() ``` --- -#### User defined flags in the log pattern +#### User-defined flags in the log pattern ```c++ // Log patterns can contain custom flags. // the following example will add new flag '%*' - which will be bound to a instance. @@ -371,14 +371,14 @@ void android_example() ``` --- -#### Load log levels from env variable or from argv +#### Load log levels from the env variable or argv ```c++ #include "spdlog/cfg/env.h" int main (int argc, char *argv[]) { spdlog::cfg::load_env_levels(); - // or from command line: + // or from the command line: // ./example SPDLOG_LEVEL=info,mylogger=trace // #include "spdlog/cfg/argv.h" // for loading levels from argv // spdlog::cfg::load_argv_levels(argc, argv); @@ -395,8 +395,8 @@ $ ./example --- #### Log file open/close event handlers ```c++ -// You can get callbacks from spdlog before/after log file has been opened or closed. -// This is useful for cleanup procedures or for adding something the start/end of the log files. +// You can get callbacks from spdlog before/after a log file has been opened or closed. +// This is useful for cleanup procedures or for adding something to the start/end of the log file. void file_events_example() { // pass the spdlog::file_event_handlers to file sinks for open/close log file notifications diff --git a/bench/latency.cpp b/bench/latency.cpp index a3f12c48..f909cf5e 100644 --- a/bench/latency.cpp +++ b/bench/latency.cpp @@ -38,6 +38,15 @@ void bench_logger(benchmark::State &state, std::shared_ptr logge logger->info("Hello logger: msg number {}...............", ++i); } } +void bench_global_logger(benchmark::State &state, std::shared_ptr logger) +{ + spdlog::set_default_logger(std::move(logger)); + int i = 0; + for (auto _ : state) + { + spdlog::info("Hello logger: msg number {}...............", ++i); + } +} void bench_disabled_macro(benchmark::State &state, std::shared_ptr logger) { @@ -47,6 +56,17 @@ void bench_disabled_macro(benchmark::State &state, std::shared_ptr logger) +{ + spdlog::set_default_logger(std::move(logger)); + int i = 0; + benchmark::DoNotOptimize(i); // prevent unused warnings + benchmark::DoNotOptimize(logger); // prevent unused warnings + for (auto _ : state) + { SPDLOG_DEBUG("Hello logger: msg number {}...............", i++); } } @@ -79,7 +99,9 @@ int main(int argc, char *argv[]) auto disabled_logger = std::make_shared("bench", std::make_shared()); disabled_logger->set_level(spdlog::level::off); benchmark::RegisterBenchmark("disabled-at-compile-time", bench_disabled_macro, disabled_logger); + benchmark::RegisterBenchmark("disabled-at-compile-time (global logger)", bench_disabled_macro_global_logger, disabled_logger); benchmark::RegisterBenchmark("disabled-at-runtime", bench_logger, disabled_logger); + benchmark::RegisterBenchmark("disabled-at-runtime (global logger)", bench_global_logger, disabled_logger); // with backtrace of 64 auto tracing_disabled_logger = std::make_shared("bench", std::make_shared()); tracing_disabled_logger->enable_backtrace(64); @@ -88,11 +110,15 @@ int main(int argc, char *argv[]) auto null_logger_st = std::make_shared("bench", std::make_shared()); benchmark::RegisterBenchmark("null_sink_st (500_bytes c_str)", bench_c_string, std::move(null_logger_st)); benchmark::RegisterBenchmark("null_sink_st", bench_logger, null_logger_st); + benchmark::RegisterBenchmark("null_sink_st (global logger)", bench_global_logger, null_logger_st); // with backtrace of 64 auto tracing_null_logger_st = std::make_shared("bench", std::make_shared()); tracing_null_logger_st->enable_backtrace(64); benchmark::RegisterBenchmark("null_sink_st/backtrace", bench_logger, tracing_null_logger_st); + + + #ifdef __linux bench_dev_null(); #endif // __linux__ diff --git a/include/spdlog/sinks/daily_file_sink.h b/include/spdlog/sinks/daily_file_sink.h index f6f1bb1d..25abb02b 100644 --- a/include/spdlog/sinks/daily_file_sink.h +++ b/include/spdlog/sinks/daily_file_sink.h @@ -13,9 +13,10 @@ #include #include +#include +#include #include #include -#include #include #include @@ -46,67 +47,16 @@ struct daily_filename_calculator */ struct daily_filename_format_calculator { - static filename_t calc_filename(const filename_t &filename, const tm &now_tm) + static filename_t calc_filename(const filename_t &file_path, const tm &now_tm) { -#ifdef SPDLOG_USE_STD_FORMAT - // adapted from fmtlib: https://github.com/fmtlib/fmt/blob/8.0.1/include/fmt/chrono.h#L522-L546 - - filename_t tm_format; - tm_format.append(filename); - // By appending an extra space we can distinguish an empty result that - // indicates insufficient buffer size from a guaranteed non-empty result - // https://github.com/fmtlib/fmt/issues/2238 - tm_format.push_back(' '); - - const size_t MIN_SIZE = 10; - filename_t buf; - buf.resize(MIN_SIZE); - for (;;) - { - size_t count = strftime(buf.data(), buf.size(), tm_format.c_str(), &now_tm); - if (count != 0) - { - // Remove the extra space. - buf.resize(count - 1); - break; - } - buf.resize(buf.size() * 2); - } - - return buf; +#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) + std::wstringstream stream; #else - // generate fmt datetime format string, e.g. {:%Y-%m-%d}. - filename_t fmt_filename = fmt::format(SPDLOG_FMT_STRING(SPDLOG_FILENAME_T("{{:{}}}")), filename); - - // MSVC doesn't allow fmt::runtime(..) with wchar, with fmtlib versions < 9.1.x -# if defined(_MSC_VER) && defined(SPDLOG_WCHAR_FILENAMES) && FMT_VERSION < 90101 - return fmt::format(fmt_filename, now_tm); -# else - return fmt::format(SPDLOG_FMT_RUNTIME(fmt_filename), now_tm); -# endif - + std::stringstream stream; #endif + stream << std::put_time(&now_tm, file_path.c_str()); + return stream.str(); } - -private: -#if defined __GNUC__ -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif - - static size_t strftime(char *str, size_t count, const char *format, const std::tm *time) - { - return std::strftime(str, count, format, time); - } - - static size_t strftime(wchar_t *str, size_t count, const wchar_t *format, const std::tm *time) - { - return std::wcsftime(str, count, format, time); - } - -#if defined(__GNUC__) -# pragma GCC diagnostic pop -#endif }; /* diff --git a/include/spdlog/sinks/ringbuffer_sink.h b/include/spdlog/sinks/ringbuffer_sink.h index 65e227aa..3ca47c6f 100644 --- a/include/spdlog/sinks/ringbuffer_sink.h +++ b/include/spdlog/sinks/ringbuffer_sink.h @@ -50,7 +50,7 @@ public: { memory_buf_t formatted; base_sink::formatter_->format(q_.at(i), formatted); - ret.push_back(std::move(SPDLOG_BUF_TO_STRING(formatted))); + ret.push_back(SPDLOG_BUF_TO_STRING(formatted)); } return ret; }