Merge branch 'gabime:v1.x' into feature-source_location

pull/2690/head
M. Galib Uludag 2 years ago committed by GitHub
commit 48db684a3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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) 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 ## 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. 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) #### Compiled version (recommended - much faster compile times)
@ -39,7 +39,7 @@ $ cmake .. && make -j
## Features ## Features
* Very fast (see [benchmarks](#benchmarks) below). * Very fast (see [benchmarks](#benchmarks) below).
* Headers only or compiled * 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) * Asynchronous mode (optional)
* [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting. * [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting.
* Multi/Single threaded loggers. * Multi/Single threaded loggers.
@ -51,9 +51,9 @@ $ cmake .. && make -j
* Windows event log. * Windows event log.
* Windows debugger (```OutputDebugString(..)```). * Windows debugger (```OutputDebugString(..)```).
* Easily [extendable](https://github.com/gabime/spdlog/wiki/4.-Sinks#implementing-your-own-sink) with custom log targets. * 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. * Log filtering - log levels can be modified at runtime as well as compile time.
* Support for loading log levels from argv or from environment var. * Support for loading log levels from argv or environment var.
* [Backtrace](#backtrace-support) support - store debug messages in a ring buffer and display later on demand. * [Backtrace](#backtrace-support) support - store debug messages in a ring buffer and display them later on demand.
## Usage samples ## Usage samples
@ -92,7 +92,7 @@ int main()
#include "spdlog/sinks/stdout_color_sinks.h" #include "spdlog/sinks/stdout_color_sinks.h"
void stdout_example() void stdout_example()
{ {
// create color multi threaded logger // create a color multi-threaded logger
auto console = spdlog::stdout_color_mt("console"); auto console = spdlog::stdout_color_mt("console");
auto err_logger = spdlog::stderr_color_mt("stderr"); 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)"); 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" #include "spdlog/sinks/rotating_file_sink.h"
void rotating_example() 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_size = 1048576 * 5;
auto max_files = 3; auto max_files = 3;
auto logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", max_size, max_files); 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" #include "spdlog/sinks/daily_file_sink.h"
void daily_example() 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); auto logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
} }
@ -145,7 +145,7 @@ void daily_example()
#### Backtrace support #### Backtrace support
```c++ ```c++
// Debug messages can be stored in a ring buffer instead of being logged immediately. // 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. // When needed, call dump_backtrace() to dump them to your log.
spdlog::enable_backtrace(32); // Store the latest 32 messages in a buffer. 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.. 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 spdlog::dump_backtrace(); // log them now! show the last 32 messages
// or my_logger->dump_backtrace(32).. // or my_logger->dump_backtrace(32)..
``` ```
@ -163,7 +163,7 @@ spdlog::dump_backtrace(); // log them now! show the last 32 messages
#### Periodic flush #### Periodic flush
```c++ ```c++
// periodically flush all *registered* loggers every 3 seconds: // 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)); spdlog::flush_every(std::chrono::seconds(3));
``` ```
@ -191,7 +191,7 @@ void stopwatch_example()
// {:X} - print in uppercase. // {:X} - print in uppercase.
// {:s} - don't separate each byte with space. // {:s} - don't separate each byte with space.
// {:p} - don't print the position on each line start. // {: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. // {:a} - show ASCII if :n is not set.
#include "spdlog/fmt/bin_to_hex.h" #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++ ```c++
// create logger with 2 targets with different log levels and formats. // 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. // The console will show only warnings or errors, while the file will log all.
void multi_sink_example() void multi_sink_example()
{ {
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>(); auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
@ -233,10 +233,10 @@ void multi_sink_example()
``` ```
--- ---
#### User defined callbacks about log events #### User-defined callbacks about log events
```c++ ```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 // each time something is logged to the logger
void callback_example() void callback_example()
{ {
@ -287,7 +287,7 @@ void multi_sink_example2()
``` ```
--- ---
#### User defined types #### User-defined types
```c++ ```c++
template<> template<>
struct fmt::formatter<my_type> : fmt::formatter<std::string> struct fmt::formatter<my_type> : fmt::formatter<std::string>
@ -306,7 +306,7 @@ void user_defined_example()
``` ```
--- ---
#### User defined flags in the log pattern #### User-defined flags in the log pattern
```c++ ```c++
// Log patterns can contain custom flags. // Log patterns can contain custom flags.
// the following example will add new flag '%*' - which will be bound to a <my_formatter_flag> instance. // the following example will add new flag '%*' - which will be bound to a <my_formatter_flag> 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++ ```c++
#include "spdlog/cfg/env.h" #include "spdlog/cfg/env.h"
int main (int argc, char *argv[]) int main (int argc, char *argv[])
{ {
spdlog::cfg::load_env_levels(); spdlog::cfg::load_env_levels();
// or from command line: // or from the command line:
// ./example SPDLOG_LEVEL=info,mylogger=trace // ./example SPDLOG_LEVEL=info,mylogger=trace
// #include "spdlog/cfg/argv.h" // for loading levels from argv // #include "spdlog/cfg/argv.h" // for loading levels from argv
// spdlog::cfg::load_argv_levels(argc, argv); // spdlog::cfg::load_argv_levels(argc, argv);
@ -395,8 +395,8 @@ $ ./example
--- ---
#### Log file open/close event handlers #### Log file open/close event handlers
```c++ ```c++
// You can get callbacks from spdlog before/after log file has been opened or closed. // 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 the start/end of the log files. // This is useful for cleanup procedures or for adding something to the start/end of the log file.
void file_events_example() void file_events_example()
{ {
// pass the spdlog::file_event_handlers to file sinks for open/close log file notifications // pass the spdlog::file_event_handlers to file sinks for open/close log file notifications

@ -38,6 +38,15 @@ void bench_logger(benchmark::State &state, std::shared_ptr<spdlog::logger> logge
logger->info("Hello logger: msg number {}...............", ++i); logger->info("Hello logger: msg number {}...............", ++i);
} }
} }
void bench_global_logger(benchmark::State &state, std::shared_ptr<spdlog::logger> 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<spdlog::logger> logger) void bench_disabled_macro(benchmark::State &state, std::shared_ptr<spdlog::logger> logger)
{ {
@ -47,6 +56,17 @@ void bench_disabled_macro(benchmark::State &state, std::shared_ptr<spdlog::logge
for (auto _ : state) for (auto _ : state)
{ {
SPDLOG_LOGGER_DEBUG(logger, "Hello logger: msg number {}...............", i++); SPDLOG_LOGGER_DEBUG(logger, "Hello logger: msg number {}...............", i++);
}
}
void bench_disabled_macro_global_logger(benchmark::State &state, std::shared_ptr<spdlog::logger> 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++); SPDLOG_DEBUG("Hello logger: msg number {}...............", i++);
} }
} }
@ -79,7 +99,9 @@ int main(int argc, char *argv[])
auto disabled_logger = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>()); auto disabled_logger = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>());
disabled_logger->set_level(spdlog::level::off); disabled_logger->set_level(spdlog::level::off);
benchmark::RegisterBenchmark("disabled-at-compile-time", bench_disabled_macro, disabled_logger); 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", bench_logger, disabled_logger);
benchmark::RegisterBenchmark("disabled-at-runtime (global logger)", bench_global_logger, disabled_logger);
// with backtrace of 64 // with backtrace of 64
auto tracing_disabled_logger = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>()); auto tracing_disabled_logger = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>());
tracing_disabled_logger->enable_backtrace(64); tracing_disabled_logger->enable_backtrace(64);
@ -88,11 +110,15 @@ int main(int argc, char *argv[])
auto null_logger_st = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_st>()); auto null_logger_st = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_st>());
benchmark::RegisterBenchmark("null_sink_st (500_bytes c_str)", bench_c_string, std::move(null_logger_st)); 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", bench_logger, null_logger_st);
benchmark::RegisterBenchmark("null_sink_st (global logger)", bench_global_logger, null_logger_st);
// with backtrace of 64 // with backtrace of 64
auto tracing_null_logger_st = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_st>()); auto tracing_null_logger_st = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_st>());
tracing_null_logger_st->enable_backtrace(64); tracing_null_logger_st->enable_backtrace(64);
benchmark::RegisterBenchmark("null_sink_st/backtrace", bench_logger, tracing_null_logger_st); benchmark::RegisterBenchmark("null_sink_st/backtrace", bench_logger, tracing_null_logger_st);
#ifdef __linux #ifdef __linux
bench_dev_null(); bench_dev_null();
#endif // __linux__ #endif // __linux__

@ -13,9 +13,10 @@
#include <spdlog/details/circular_q.h> #include <spdlog/details/circular_q.h>
#include <spdlog/details/synchronous_factory.h> #include <spdlog/details/synchronous_factory.h>
#include <sstream>
#include <iomanip>
#include <chrono> #include <chrono>
#include <cstdio> #include <cstdio>
#include <ctime>
#include <mutex> #include <mutex>
#include <string> #include <string>
@ -46,67 +47,16 @@ struct daily_filename_calculator
*/ */
struct daily_filename_format_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 #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
// adapted from fmtlib: https://github.com/fmtlib/fmt/blob/8.0.1/include/fmt/chrono.h#L522-L546 std::wstringstream stream;
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;
#else #else
// generate fmt datetime format string, e.g. {:%Y-%m-%d}. std::stringstream stream;
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
#endif #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
}; };
/* /*

@ -50,7 +50,7 @@ public:
{ {
memory_buf_t formatted; memory_buf_t formatted;
base_sink<Mutex>::formatter_->format(q_.at(i), formatted); base_sink<Mutex>::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; return ret;
} }

Loading…
Cancel
Save