mirror of
https://github.com/gabime/spdlog.git
synced 2025-01-16 01:37:58 +00:00
Compare commits
19 Commits
c861e2d9cf
...
69f3d2678e
Author | SHA1 | Date | |
---|---|---|---|
|
69f3d2678e | ||
|
8038bc2fc8 | ||
|
f20b12cf3f | ||
|
c8bd53509c | ||
|
006124d816 | ||
|
efd73ac956 | ||
|
b7d7334451 | ||
|
8284865f9a | ||
|
1f8b04cbd1 | ||
|
b3402a0b9f | ||
|
4037959945 | ||
|
d7313a3274 | ||
|
8302086942 | ||
|
6095db951b | ||
|
817d2764b6 | ||
|
62189602cb | ||
|
0120dcc787 | ||
|
6bfc0ec3a7 | ||
|
f999d879d5 |
31
README.md
31
README.md
@ -36,10 +36,10 @@ $ cmake .. && make -j
|
||||
|
||||
## Features
|
||||
* Very fast (see [benchmarks](#benchmarks) below).
|
||||
* Headers only, just copy and use. Or use as a compiled library.
|
||||
* Headers only or compiled version
|
||||
* Feature rich formatting, using the excellent [fmt](https://github.com/fmtlib/fmt) library.
|
||||
* **New!** [Backtrace](#backtrace-support) support - store debug messages in a ring buffer and display later on demand.
|
||||
* Fast asynchronous mode (optional)
|
||||
* Asynchronous mode (optional)
|
||||
* [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting.
|
||||
* Multi/Single threaded loggers.
|
||||
* Various log targets:
|
||||
@ -49,7 +49,8 @@ $ cmake .. && make -j
|
||||
* syslog.
|
||||
* Windows debugger (```OutputDebugString(..)```)
|
||||
* Easily extendable with custom log targets (just implement a single function in the [sink](include/spdlog/sinks/sink.h) interface).
|
||||
* Severity based filtering - threshold levels can be modified in runtime as well as in compile time.
|
||||
* Log filtering - log levels can be modified in runtime as well as in compile time.
|
||||
* Support for loading log levels can be argv or env vars
|
||||
|
||||
|
||||
## Usage samples
|
||||
@ -85,6 +86,21 @@ int main()
|
||||
auto file_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic.txt");
|
||||
spdlog::set_default_logger(file_logger);
|
||||
}
|
||||
|
||||
```
|
||||
#### load log levels from env variable
|
||||
```c++
|
||||
#include "spdlog/cfg/env.h"
|
||||
void load_levels_example()
|
||||
{
|
||||
// Set the log level to "info" and mylogger to to "trace":
|
||||
// SPDLOG_LEVEL=info,mylogger=trace && ./example
|
||||
spdlog::cfg::load_env_levels();
|
||||
// or from command line:
|
||||
// ./example SPDLOG_LEVEL=info,mylogger=trace
|
||||
// #include "spdlog/cfg/argv.h" // for loading levels from argv
|
||||
// spdlog::cfg::load_argv_levels(args, argv);
|
||||
}
|
||||
```
|
||||
#### create stdout/stderr logger object
|
||||
```c++
|
||||
@ -300,15 +316,6 @@ void android_example()
|
||||
android_logger->critical("Use \"adb shell logcat\" to view this message.");
|
||||
}
|
||||
```
|
||||
---
|
||||
#### Compile-time format string syntax checking
|
||||
```C++
|
||||
#include "spdlog/spdlog.h"
|
||||
int main()
|
||||
{
|
||||
spdlog::info(FMT_STRING("{:d} is an invalid format tag"));
|
||||
}
|
||||
```
|
||||
|
||||
## Benchmarks
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
void load_levels_example();
|
||||
void stdout_logger_example();
|
||||
void basic_example();
|
||||
void rotating_example();
|
||||
@ -23,17 +24,11 @@ void syslog_example();
|
||||
|
||||
int main(int, char *[])
|
||||
{
|
||||
// Log levels can be loaded from argv/env using "SPDLOG_LEVEL"
|
||||
load_levels_example();
|
||||
|
||||
spdlog::info("Welcome to spdlog version {}.{}.{} !", SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH);
|
||||
|
||||
// Optionally load log levels from the SPDLOG_LEVEL env variable or from argv.
|
||||
// For example: set the global level to info and mylogger to to trace:
|
||||
// SPDLOG_LEVEL=info,mylogger=trace && ./example
|
||||
spdlog::cfg::load_env();
|
||||
|
||||
// or from command line: "./example SPDLOG_LEVEL=info,mylogger=trace"
|
||||
// #include "spdlog/cfg/argv.h" // for loading levels from argv
|
||||
// spdlog::cfg::load_argv(args, argv);
|
||||
|
||||
spdlog::warn("Easy padding in numbers like {:08d}", 12);
|
||||
spdlog::critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
|
||||
spdlog::info("Support for floats {:03.2f}", 1.23456);
|
||||
@ -127,6 +122,18 @@ void daily_example()
|
||||
auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
|
||||
}
|
||||
|
||||
#include "spdlog/cfg/env.h"
|
||||
void load_levels_example()
|
||||
{
|
||||
// Set the log level to "info" and mylogger to to "trace":
|
||||
// SPDLOG_LEVEL=info,mylogger=trace && ./example
|
||||
spdlog::cfg::load_env_levels();
|
||||
// or from command line:
|
||||
// ./example SPDLOG_LEVEL=info,mylogger=trace
|
||||
// #include "spdlog/cfg/argv.h" // for loading levels from argv
|
||||
// spdlog::cfg::load_argv_levels(args, argv);
|
||||
}
|
||||
|
||||
#include "spdlog/async.h"
|
||||
void async_example()
|
||||
{
|
||||
|
@ -21,7 +21,7 @@ namespace spdlog {
|
||||
namespace cfg {
|
||||
|
||||
// search for SPDLOG_LEVEL= in the args and use it to init the levels
|
||||
void load_argv(int args, char **argv)
|
||||
void load_argv_levels(int args, char **argv)
|
||||
{
|
||||
const std::string spdlog_level_prefix = "SPDLOG_LEVEL=";
|
||||
for (int i = 1; i < args; i++)
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
namespace spdlog {
|
||||
namespace cfg {
|
||||
void load_env()
|
||||
void load_env_levels()
|
||||
{
|
||||
auto env_val = details::os::getenv("SPDLOG_LEVEL");
|
||||
auto levels = helpers::extract_levels(env_val);
|
||||
|
@ -390,13 +390,13 @@ SPDLOG_INLINE int pid() SPDLOG_NOEXCEPT
|
||||
}
|
||||
|
||||
// Determine if the terminal supports colors
|
||||
// Source: https://github.com/agauniyal/rang/
|
||||
// Based on: https://github.com/agauniyal/rang/
|
||||
SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return true;
|
||||
#else
|
||||
static constexpr std::array<const char *, 14> Terms = {
|
||||
static constexpr std::array<const char *, 14> terms = {
|
||||
{"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"}};
|
||||
|
||||
const char *env_p = std::getenv("TERM");
|
||||
@ -406,7 +406,7 @@ SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT
|
||||
}
|
||||
|
||||
static const bool result =
|
||||
std::any_of(std::begin(Terms), std::end(Terms), [&](const char *term) { return std::strstr(env_p, term) != nullptr; });
|
||||
std::any_of(terms.begin(), terms.end(), [&](const char *term) { return std::strstr(env_p, term) != nullptr; });
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ private:
|
||||
// Extract given pad spec (e.g. %8X)
|
||||
// Advance the given it pass the end of the padding spec found (if any)
|
||||
// Return padding.
|
||||
details::padding_info handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end);
|
||||
static details::padding_info handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end);
|
||||
|
||||
void compile_pattern_(const std::string &pattern);
|
||||
};
|
||||
|
@ -184,7 +184,7 @@ SPDLOG_INLINE void registry::flush_on(level::level_enum log_level)
|
||||
SPDLOG_INLINE void registry::flush_every(std::chrono::seconds interval)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(flusher_mutex_);
|
||||
std::function<void()> clbk = std::bind(®istry::flush_all, this);
|
||||
auto clbk = [this](){this->flush_all();};
|
||||
periodic_flusher_ = details::make_unique<periodic_worker>(clbk, interval);
|
||||
}
|
||||
|
||||
|
@ -54,8 +54,8 @@ public:
|
||||
void connect(const std::string &host, int port)
|
||||
{
|
||||
close();
|
||||
spdlog::info("Connecting..");
|
||||
struct addrinfo hints{};
|
||||
struct addrinfo hints
|
||||
{};
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_INET; // IPv4
|
||||
hints.ai_socktype = SOCK_STREAM; // TCP
|
||||
|
@ -113,7 +113,7 @@ bool SPDLOG_INLINE thread_pool::process_next_msg_()
|
||||
}
|
||||
|
||||
default: {
|
||||
assert(false && "Unexpected async_msg_type");
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,6 +89,7 @@ SPDLOG_INLINE void logger::set_formatter(std::unique_ptr<formatter> f)
|
||||
{
|
||||
// last element - we can be move it.
|
||||
(*it)->set_formatter(std::move(f));
|
||||
break; // to prevent clang-tidy warning
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -73,7 +73,7 @@ struct win32_error : public spdlog_ex
|
||||
return fmt::format("{}: {}{}", user_message, error_code, system_message);
|
||||
}
|
||||
|
||||
win32_error(std::string const &func_name, DWORD error = GetLastError())
|
||||
explicit win32_error(std::string const &func_name, DWORD error = GetLastError())
|
||||
: spdlog_ex(format(func_name, error))
|
||||
{}
|
||||
};
|
||||
|
@ -4,8 +4,8 @@
|
||||
#include <spdlog/cfg/env.h>
|
||||
#include <spdlog/cfg/argv.h>
|
||||
|
||||
using spdlog::cfg::load_argv;
|
||||
using spdlog::cfg::load_env;
|
||||
using spdlog::cfg::load_argv_levels;
|
||||
using spdlog::cfg::load_env_levels;
|
||||
using spdlog::sinks::test_sink_st;
|
||||
|
||||
TEST_CASE("env", "[cfg]")
|
||||
@ -17,7 +17,7 @@ TEST_CASE("env", "[cfg]")
|
||||
#else
|
||||
setenv("SPDLOG_LEVEL", "l1=warn", 1);
|
||||
#endif
|
||||
load_env();
|
||||
load_env_levels();
|
||||
REQUIRE(l1->level() == spdlog::level::warn);
|
||||
spdlog::set_default_logger(spdlog::create<test_sink_st>("cfg-default"));
|
||||
REQUIRE(spdlog::default_logger()->level() == spdlog::level::info);
|
||||
@ -27,7 +27,7 @@ TEST_CASE("argv1", "[cfg]")
|
||||
{
|
||||
spdlog::drop("l1");
|
||||
const char *argv[] = {"ignore", "SPDLOG_LEVEL=l1=warn"};
|
||||
load_argv(2, const_cast<char**>(argv));
|
||||
load_argv_levels(2, const_cast<char **>(argv));
|
||||
auto l1 = spdlog::create<spdlog::sinks::test_sink_st>("l1");
|
||||
REQUIRE(l1->level() == spdlog::level::warn);
|
||||
REQUIRE(spdlog::default_logger()->level() == spdlog::level::info);
|
||||
@ -37,7 +37,7 @@ TEST_CASE("argv2", "[cfg]")
|
||||
{
|
||||
spdlog::drop("l1");
|
||||
const char *argv[] = {"ignore", "SPDLOG_LEVEL=l1=warn,trace"};
|
||||
load_argv(2, const_cast<char**>(argv));
|
||||
load_argv_levels(2, const_cast<char **>(argv));
|
||||
auto l1 = spdlog::create<test_sink_st>("l1");
|
||||
REQUIRE(l1->level() == spdlog::level::warn);
|
||||
REQUIRE(spdlog::default_logger()->level() == spdlog::level::trace);
|
||||
@ -48,7 +48,7 @@ TEST_CASE("argv3", "[cfg]")
|
||||
{
|
||||
spdlog::drop("l1");
|
||||
const char *argv[] = {"ignore", "SPDLOG_LEVEL="};
|
||||
load_argv(2, const_cast<char**>(argv));
|
||||
load_argv_levels(2, const_cast<char **>(argv));
|
||||
auto l1 = spdlog::create<test_sink_st>("l1");
|
||||
REQUIRE(l1->level() == spdlog::level::info);
|
||||
REQUIRE(spdlog::default_logger()->level() == spdlog::level::info);
|
||||
@ -58,7 +58,7 @@ TEST_CASE("argv4", "[cfg]")
|
||||
{
|
||||
spdlog::drop("l1");
|
||||
const char *argv[] = {"ignore", "SPDLOG_LEVEL=junk"};
|
||||
load_argv(2, const_cast<char**>(argv));
|
||||
load_argv_levels(2, const_cast<char **>(argv));
|
||||
auto l1 = spdlog::create<test_sink_st>("l1");
|
||||
REQUIRE(l1->level() == spdlog::level::info);
|
||||
}
|
||||
@ -67,7 +67,7 @@ TEST_CASE("argv5", "[cfg]")
|
||||
{
|
||||
spdlog::drop("l1");
|
||||
const char *argv[] = {"ignore", "ignore", "SPDLOG_LEVEL=l1=warn,trace"};
|
||||
load_argv(3, const_cast<char**>(argv));
|
||||
load_argv_levels(3, const_cast<char **>(argv));
|
||||
auto l1 = spdlog::create<test_sink_st>("l1");
|
||||
REQUIRE(l1->level() == spdlog::level::warn);
|
||||
REQUIRE(spdlog::default_logger()->level() == spdlog::level::trace);
|
||||
@ -78,7 +78,7 @@ TEST_CASE("argv6", "[cfg]")
|
||||
{
|
||||
spdlog::set_level(spdlog::level::err);
|
||||
const char *argv[] = {""};
|
||||
load_argv(1, const_cast<char**>(argv));
|
||||
load_argv_levels(1, const_cast<char **>(argv));
|
||||
REQUIRE(spdlog::default_logger()->level() == spdlog::level::err);
|
||||
spdlog::set_level(spdlog::level::info);
|
||||
}
|
||||
@ -87,7 +87,7 @@ TEST_CASE("argv7", "[cfg]")
|
||||
{
|
||||
spdlog::set_level(spdlog::level::err);
|
||||
const char *argv[] = {""};
|
||||
load_argv(0, const_cast<char**>(argv));
|
||||
load_argv_levels(0, const_cast<char **>(argv));
|
||||
REQUIRE(spdlog::default_logger()->level() == spdlog::level::err);
|
||||
spdlog::set_level(spdlog::level::info);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ class failing_sink : public spdlog::sinks::base_sink<std::mutex>
|
||||
{
|
||||
public:
|
||||
failing_sink() = default;
|
||||
~failing_sink() final = default;
|
||||
~failing_sink() = default;
|
||||
|
||||
protected:
|
||||
void sink_it_(const spdlog::details::log_msg &) final
|
||||
|
Loading…
Reference in New Issue
Block a user