mirror of
https://github.com/gabime/spdlog.git
synced 2025-01-24 06:32:06 +08:00
Merge branch 'v1.x' of https://github.com/gabime/spdlog into v1.x
This commit is contained in:
commit
f9019870da
@ -4,7 +4,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.1)
|
cmake_minimum_required(VERSION 3.1)
|
||||||
project(spdlog VERSION 0.16.3 LANGUAGES CXX)
|
project(spdlog VERSION 1.0.0 LANGUAGES CXX)
|
||||||
include(CTest)
|
include(CTest)
|
||||||
include(CMakeDependentOption)
|
include(CMakeDependentOption)
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
275
README.md
275
README.md
@ -20,7 +20,7 @@ Very fast, header only, C++ logging library. [![Build Status](https://travis-ci.
|
|||||||
|
|
||||||
|
|
||||||
## Platforms
|
## Platforms
|
||||||
* Linux, FreeBSD, Solaris
|
* Linux, FreeBSD, Solaris, AIX
|
||||||
* Windows (vc 2013+, cygwin)
|
* Windows (vc 2013+, cygwin)
|
||||||
* Mac OSX (clang 3.5+)
|
* Mac OSX (clang 3.5+)
|
||||||
* Android
|
* Android
|
||||||
@ -29,8 +29,7 @@ Very fast, header only, C++ logging library. [![Build Status](https://travis-ci.
|
|||||||
* Very fast - performance is the primary goal (see [benchmarks](#benchmarks) below).
|
* Very fast - performance is the primary goal (see [benchmarks](#benchmarks) below).
|
||||||
* Headers only, just copy and use.
|
* Headers only, just copy and use.
|
||||||
* Feature rich [call style](#usage-example) using the excellent [fmt](https://github.com/fmtlib/fmt) library.
|
* Feature rich [call style](#usage-example) using the excellent [fmt](https://github.com/fmtlib/fmt) library.
|
||||||
* Optional printf syntax support.
|
* Fast asynchronous mode (optional)
|
||||||
* Extremely fast asynchronous mode (optional) - using lockfree queues and other tricks to reach millions of calls/sec.
|
|
||||||
* [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting.
|
* [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting.
|
||||||
* Conditional Logging
|
* Conditional Logging
|
||||||
* Multi/Single threaded loggers.
|
* Multi/Single threaded loggers.
|
||||||
@ -47,169 +46,138 @@ Very fast, header only, C++ logging library. [![Build Status](https://travis-ci.
|
|||||||
|
|
||||||
## Benchmarks
|
## Benchmarks
|
||||||
|
|
||||||
Below are some [benchmarks](bench) comparing popular log libraries under Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz
|
Below are some [benchmarks](https://github.com/gabime/spdlog/blob/v1.x/bench/bench.cpp) done in Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz
|
||||||
|
|
||||||
#### Synchronous mode
|
#### Synchronous mode
|
||||||
Time needed to log 1,000,000 lines in synchronous mode (in seconds, the best of 3 runs):
|
```
|
||||||
|
*******************************************************************************
|
||||||
|threads|boost log 1.54|glog |easylogging |spdlog|
|
Single thread, 1,000,000 iterations
|
||||||
|-------|:-------:|:-----:|----------:|------:|
|
*******************************************************************************
|
||||||
|1| 4.169s |1.066s |0.975s |0.302s|
|
basic_st... Elapsed: 0.231041 4,328,228/sec
|
||||||
|10| 6.180s |3.032s |2.857s |0.968s|
|
rotating... Elapsed: 0.233466 4,283,282/sec
|
||||||
|100| 5.981s |1.139s |4.512s |0.497s|
|
daily_st... Elapsed: 0.244491 4,090,136/sec
|
||||||
|
null_st... Elapsed: 0.162708 6,145,995/sec
|
||||||
|
|
||||||
|
*******************************************************************************
|
||||||
|
10 threads sharing same logger, 1,000,000 iterations
|
||||||
|
*******************************************************************************
|
||||||
|
basic_mt... Elapsed: 0.854029 1,170,920/sec
|
||||||
|
rotating_mt Elapsed: 0.867038 1,153,351/sec
|
||||||
|
daily_mt... Elapsed: 0.869593 1,149,963/sec
|
||||||
|
null_mt... Elapsed: 0.171215 5,840,602/sec
|
||||||
|
```
|
||||||
#### Asynchronous mode
|
#### Asynchronous mode
|
||||||
Time needed to log 1,000,000 lines in asynchronous mode, i.e. the time it takes to put them in the async queue (in seconds, the best of 3 runs):
|
```
|
||||||
|
*******************************************************************************
|
||||||
|threads|g2log <sup>async logger</sup> |spdlog <sup>async mode</sup>|
|
10 threads sharing same logger, 1,000,000 iterations
|
||||||
|:-------|:-----:|-------------------------:|
|
*******************************************************************************
|
||||||
|1| 1.850s |0.216s |
|
async... Elapsed: 0.442731 2,258,706/sec
|
||||||
|10| 0.943s |0.173s|
|
async... Elapsed: 0.427072 2,341,527/sec
|
||||||
|100| 0.959s |0.202s|
|
async... Elapsed: 0.449768 2,223,369/sec
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Usage Example
|
## Usage Example
|
||||||
```c++
|
```c++
|
||||||
|
|
||||||
#define SPDLOG_TRACE_ON
|
#include "spdlog/spdlog.h"
|
||||||
#define SPDLOG_DEBUG_ON
|
|
||||||
|
|
||||||
// include only features that you use
|
|
||||||
#include "spdlog/sinks/daily_file_sink.h"
|
|
||||||
#include "spdlog/sinks/rotating_file_sink.h"
|
|
||||||
#include "spdlog/sinks/simple_file_sink.h"
|
|
||||||
#include "spdlog/sinks/stdout_color_sinks.h"
|
#include "spdlog/sinks/stdout_color_sinks.h"
|
||||||
|
void stdout_example()
|
||||||
#include <iostream>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
void async_example();
|
|
||||||
void user_defined_example();
|
|
||||||
void err_handler_example();
|
|
||||||
|
|
||||||
namespace spd = spdlog;
|
|
||||||
int main(int, char *[])
|
|
||||||
{
|
{
|
||||||
|
// create color multi threaded logger
|
||||||
|
auto console = spdlog::stdout_color_mt("console");
|
||||||
|
console->info("Welcome to spdlog!");
|
||||||
|
console->error("Some error message with arg: {}", 1);
|
||||||
|
|
||||||
try
|
auto err_logger = spdlog::stderr_color_mt("stderr");
|
||||||
|
err_logger->error("Some error message");
|
||||||
|
|
||||||
|
// Formatting examples
|
||||||
|
console->warn("Easy padding in numbers like {:08d}", 12);
|
||||||
|
console->critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
|
||||||
|
console->info("Support for floats {:03.2f}", 1.23456);
|
||||||
|
console->info("Positional args are {1} {0}..", "too", "supported");
|
||||||
|
console->info("{:<30}", "left aligned");
|
||||||
|
|
||||||
|
spdlog::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)");
|
||||||
|
|
||||||
|
// Runtime log levels
|
||||||
|
spdlog::set_level(spdlog::level::info); // Set global log level to info
|
||||||
|
console->debug("This message should not be displayed!");
|
||||||
|
console->set_level(spdlog::level::trace); // Set specific logger's log level
|
||||||
|
console->debug("This message should be displayed..");
|
||||||
|
|
||||||
|
// Customize msg format for all loggers
|
||||||
|
spdlog::set_pattern("[%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v");
|
||||||
|
console->info("This an info message with custom format");
|
||||||
|
|
||||||
|
// Compile time log levels
|
||||||
|
// define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON
|
||||||
|
SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
|
||||||
|
SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "spdlog/sinks/basic_file_sink.h"
|
||||||
|
void basic_logfile_example()
|
||||||
|
{
|
||||||
|
// Create basic file logger (not rotated)
|
||||||
|
try
|
||||||
{
|
{
|
||||||
auto console = spdlog::stdout_color_st("console");
|
auto my_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt");
|
||||||
console->info("Welcome to spdlog!");
|
|
||||||
|
|
||||||
console->info("Welcome to spdlog!");
|
|
||||||
console->error("Some error message with arg: {}", 1);
|
|
||||||
err_handler_example();
|
|
||||||
// Formatting examples
|
|
||||||
console->warn("Easy padding in numbers like {:08d}", 12);
|
|
||||||
console->critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
|
|
||||||
console->info("Support for floats {:03.2f}", 1.23456);
|
|
||||||
console->info("Positional args are {1} {0}..", "too", "supported");
|
|
||||||
console->info("{:<30}", "left aligned");
|
|
||||||
|
|
||||||
spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function");
|
|
||||||
|
|
||||||
// Create basic file logger (not rotated)
|
|
||||||
auto my_logger = spd::basic_logger_mt("basic_logger", "logs/basic-log.txt");
|
|
||||||
my_logger->info("Some log message");
|
|
||||||
|
|
||||||
// Create a file rotating logger with 5mb size max and 3 rotated files
|
|
||||||
auto rotating_logger = spd::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3);
|
|
||||||
for (int i = 0; i < 10; ++i)
|
|
||||||
{
|
|
||||||
rotating_logger->info("{} * {} equals {:>10}", i, i, i * i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a daily logger - a new file is created every day on 2:30am
|
|
||||||
auto daily_logger = spd::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
|
|
||||||
// trigger flush if the log severity is error or higher
|
|
||||||
daily_logger->flush_on(spd::level::err);
|
|
||||||
daily_logger->info(123.44);
|
|
||||||
|
|
||||||
// Customize msg format for all messages
|
|
||||||
spd::set_pattern("[%^+++%$] [%H:%M:%S %z] [thread %t] %v");
|
|
||||||
|
|
||||||
console->info("This an info message with custom format");
|
|
||||||
console->error("This an error message with custom format");
|
|
||||||
|
|
||||||
// Change format back to to default
|
|
||||||
spd::set_pattern("%+");
|
|
||||||
|
|
||||||
// Runtime log levels
|
|
||||||
spd::set_level(spd::level::info); // Set global log level to info
|
|
||||||
console->debug("This message should not be displayed!");
|
|
||||||
console->set_level(spd::level::debug); // Set specific logger's log level
|
|
||||||
console->debug("This message should be displayed..");
|
|
||||||
|
|
||||||
// Compile time log levels
|
|
||||||
// define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON
|
|
||||||
SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
|
|
||||||
SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);
|
|
||||||
|
|
||||||
// Asynchronous logging is very fast..
|
|
||||||
// Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous..
|
|
||||||
async_example();
|
|
||||||
|
|
||||||
// Log user-defined types example
|
|
||||||
user_defined_example();
|
|
||||||
|
|
||||||
// Change default log error handler
|
|
||||||
err_handler_example();
|
|
||||||
|
|
||||||
// Apply a function on all registered loggers
|
|
||||||
spd::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->info("End of example."); });
|
|
||||||
|
|
||||||
// Release and close all loggers
|
|
||||||
spdlog::drop_all();
|
|
||||||
}
|
}
|
||||||
// Exceptions will only be thrown upon failed logger or sink construction (not during logging)
|
catch (const spdlog::spdlog_ex &ex)
|
||||||
catch (const spd::spdlog_ex &ex)
|
|
||||||
{
|
{
|
||||||
std::cout << "Log init failed: " << ex.what() << std::endl;
|
std::cout << "Log init failed: " << ex.what() << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// must be included to use async logger
|
|
||||||
|
#include "spdlog/sinks/rotating_file_sink.h"
|
||||||
|
void rotating_example()
|
||||||
|
{
|
||||||
|
// Create a file rotating logger with 5mb size max and 3 rotated files
|
||||||
|
auto rotating_logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "spdlog/sinks/daily_file_sink.h"
|
||||||
|
void daily_example()
|
||||||
|
{
|
||||||
|
// Create a daily logger - a new file is created every day on 2:30am
|
||||||
|
auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
|
||||||
|
}
|
||||||
|
|
||||||
#include "spdlog/async.h"
|
#include "spdlog/async.h"
|
||||||
void async_example()
|
void async_example()
|
||||||
{
|
{
|
||||||
auto async_file = spd::basic_logger_mt<spdlog::create_async>("async_file_logger", "logs/async_log.txt");
|
// default thread pool settings can be modified *before* creating the async logger:
|
||||||
for (int i = 0; i < 100; ++i)
|
// spdlog::init_thread_pool(32768, 1); // queue with 32k items and 1 backing thread.
|
||||||
|
auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");
|
||||||
|
// alternatively:
|
||||||
|
// auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");
|
||||||
|
|
||||||
|
for (int i = 1; i < 101; ++i)
|
||||||
{
|
{
|
||||||
async_file->info("Async message #{}", i);
|
async_file->info("Async message #{}", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// you can also modify thread pool settings *before* creating the logger:
|
|
||||||
// spdlog::init_thread_pool(32768, 4); // queue with 32k of pre allocated items and 4 backing threads.
|
|
||||||
// if not called a defaults are: preallocated 8192 queue items and 1 worker thread.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// syslog example (linux/osx/freebsd)
|
// create logger with 2 targets with different log levels and formats.
|
||||||
#ifndef _WIN32
|
// the console will show only warnings or errors, while the file will log all.
|
||||||
#include "spdlog/sinks/syslog_sink.h"
|
void multi_sink_example()
|
||||||
void syslog_example()
|
|
||||||
{
|
{
|
||||||
std::string ident = "spdlog-example";
|
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
|
||||||
auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID);
|
console_sink->set_level(spdlog::level::warn);
|
||||||
syslog_logger->warn("This is warning that will end up in syslog.");
|
console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v");
|
||||||
|
|
||||||
|
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/multisink.txt", true);
|
||||||
|
file_sink->set_level(spdlog::level::trace);
|
||||||
|
|
||||||
|
spdlog::logger logger("multi_sink", {console_sink, file_sink});
|
||||||
|
logger.set_level(spdlog::level::debug);
|
||||||
|
logger.warn("this should appear in both console and file");
|
||||||
|
logger.info("this message should not appear in the console, only in the file");
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// Android example
|
|
||||||
#if defined(__ANDROID__)
|
|
||||||
#incude "spdlog/sinks/android_sink.h"
|
|
||||||
void android_example()
|
|
||||||
{
|
|
||||||
std::string tag = "spdlog-android";
|
|
||||||
auto android_logger = spd::android_logger("android", tag);
|
|
||||||
android_logger->critical("Use \"adb shell logcat\" to view this message.");
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// user defined types logging by implementing operator<<
|
// user defined types logging by implementing operator<<
|
||||||
|
#include "spdlog/fmt/ostr.h" // must be included
|
||||||
struct my_type
|
struct my_type
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -220,10 +188,9 @@ struct my_type
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "spdlog/fmt/ostr.h" // must be included
|
|
||||||
void user_defined_example()
|
void user_defined_example()
|
||||||
{
|
{
|
||||||
spd::get("console")->info("user defined type: {}", my_type{14});
|
spdlog::get("console")->info("user defined type: {}", my_type{14});
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -231,12 +198,34 @@ void user_defined_example()
|
|||||||
//
|
//
|
||||||
void err_handler_example()
|
void err_handler_example()
|
||||||
{
|
{
|
||||||
// can be set globaly or per logger(logger->set_error_handler(..))
|
// can be set globally or per logger(logger->set_error_handler(..))
|
||||||
spdlog::set_error_handler([](const std::string &msg) { spd::get("console")->error("*******my err handler: {}", msg); });
|
spdlog::set_error_handler([](const std::string &msg) { spdlog::get("console")->error("*** LOGGER ERROR ***: {}", msg); });
|
||||||
spd::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3);
|
spdlog::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3);
|
||||||
// spd::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// syslog example (linux/osx/freebsd)
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include "spdlog/sinks/syslog_sink.h"
|
||||||
|
void syslog_example()
|
||||||
|
{
|
||||||
|
std::string ident = "spdlog-example";
|
||||||
|
auto syslog_logger = spdlog::syslog_logger("syslog", ident, LOG_PID);
|
||||||
|
syslog_logger->warn("This is warning that will end up in syslog.");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Android example
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
#incude "spdlog/sinks/android_sink.h"
|
||||||
|
void android_example()
|
||||||
|
{
|
||||||
|
std::string tag = "spdlog-android";
|
||||||
|
auto android_logger = spdlog::android_logger("android", tag);
|
||||||
|
android_logger->critical("Use \"adb shell logcat\" to view this message.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
CXX ?= g++
|
CXX = g++
|
||||||
CXXFLAGS = -march=native -Wall -Wextra -pedantic -std=c++11 -pthread -I../include
|
CXXFLAGS = -march=native -Wall -Wextra -pedantic -std=c++11 -pthread -I../include -fmax-errors=1
|
||||||
CXX_RELEASE_FLAGS = -O3 -flto -DNDEBUG
|
CXX_RELEASE_FLAGS = -O3 -flto
|
||||||
|
|
||||||
|
|
||||||
binaries=bench spdlog-null-async
|
binaries=bench latency
|
||||||
|
|
||||||
all: $(binaries)
|
all: $(binaries)
|
||||||
|
|
||||||
bench: bench.cpp
|
bench: bench.cpp
|
||||||
$(CXX) bench.cpp -o bench $(CXXFLAGS) $(CXX_RELEASE_FLAGS)
|
$(CXX) bench.cpp -o bench $(CXXFLAGS) $(CXX_RELEASE_FLAGS)
|
||||||
|
|
||||||
spdlog-null-async: spdlog-null-async.cpp
|
|
||||||
$(CXX) spdlog-null-async.cpp -o spdlog-null-async $(CXXFLAGS) $(CXX_RELEASE_FLAGS)
|
latency: latency.cpp
|
||||||
|
$(CXX) latency.cpp -o latency $(CXXFLAGS) $(CXX_RELEASE_FLAGS)
|
||||||
|
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
|
||||||
|
@ -7,10 +7,10 @@
|
|||||||
// bench.cpp : spdlog benchmarks
|
// bench.cpp : spdlog benchmarks
|
||||||
//
|
//
|
||||||
#include "spdlog/async.h"
|
#include "spdlog/async.h"
|
||||||
|
#include "spdlog/sinks/basic_file_sink.h"
|
||||||
#include "spdlog/sinks/daily_file_sink.h"
|
#include "spdlog/sinks/daily_file_sink.h"
|
||||||
#include "spdlog/sinks/null_sink.h"
|
#include "spdlog/sinks/null_sink.h"
|
||||||
#include "spdlog/sinks/rotating_file_sink.h"
|
#include "spdlog/sinks/rotating_file_sink.h"
|
||||||
#include "spdlog/sinks/simple_file_sink.h"
|
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
@ -32,8 +32,9 @@ void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count
|
|||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
|
||||||
int queue_size = 1048576;
|
|
||||||
int howmany = 1000000;
|
int howmany = 1000000;
|
||||||
|
int queue_size = howmany + 2;
|
||||||
int threads = 10;
|
int threads = 10;
|
||||||
int file_size = 30 * 1024 * 1024;
|
int file_size = 30 * 1024 * 1024;
|
||||||
int rotating_files = 5;
|
int rotating_files = 5;
|
||||||
@ -52,16 +53,24 @@ int main(int argc, char *argv[])
|
|||||||
cout << "Single thread, " << format(howmany) << " iterations" << endl;
|
cout << "Single thread, " << format(howmany) << " iterations" << endl;
|
||||||
cout << "*******************************************************************************\n";
|
cout << "*******************************************************************************\n";
|
||||||
|
|
||||||
|
auto basic_st = spdlog::basic_logger_mt("basic_st", "logs/basic_st.log", true);
|
||||||
|
bench(howmany, basic_st);
|
||||||
|
|
||||||
auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st.log", file_size, rotating_files);
|
auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st.log", file_size, rotating_files);
|
||||||
bench(howmany, rotating_st);
|
bench(howmany, rotating_st);
|
||||||
|
|
||||||
auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st.log");
|
auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st.log");
|
||||||
bench(howmany, daily_st);
|
bench(howmany, daily_st);
|
||||||
|
|
||||||
bench(howmany, spdlog::create<null_sink_st>("null_st"));
|
bench(howmany, spdlog::create<null_sink_st>("null_st"));
|
||||||
|
|
||||||
cout << "\n*******************************************************************************\n";
|
cout << "\n*******************************************************************************\n";
|
||||||
cout << threads << " threads sharing same logger, " << format(howmany) << " iterations" << endl;
|
cout << threads << " threads sharing same logger, " << format(howmany) << " iterations" << endl;
|
||||||
cout << "*******************************************************************************\n";
|
cout << "*******************************************************************************\n";
|
||||||
|
|
||||||
|
auto basic_mt = spdlog::basic_logger_mt("basic_mt", "logs/basic_mt.log", true);
|
||||||
|
bench_mt(howmany, basic_mt, threads);
|
||||||
|
|
||||||
auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt.log", file_size, rotating_files);
|
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, rotating_mt, threads);
|
||||||
|
|
||||||
@ -76,9 +85,9 @@ int main(int argc, char *argv[])
|
|||||||
for (int i = 0; i < 3; ++i)
|
for (int i = 0; i < 3; ++i)
|
||||||
{
|
{
|
||||||
spdlog::init_thread_pool(queue_size, 1);
|
spdlog::init_thread_pool(queue_size, 1);
|
||||||
auto as = spdlog::basic_logger_mt<spdlog::create_async>("as", "logs/basic_async.log", true);
|
auto as = spdlog::basic_logger_mt<spdlog::async_factory>("async", "logs/basic_async.log", true);
|
||||||
bench_mt(howmany, as, threads);
|
bench_mt(howmany, as, threads);
|
||||||
spdlog::drop("as");
|
spdlog::drop("async");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception &ex)
|
catch (std::exception &ex)
|
||||||
@ -92,34 +101,31 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
void bench(int howmany, std::shared_ptr<spdlog::logger> log)
|
void bench(int howmany, std::shared_ptr<spdlog::logger> log)
|
||||||
{
|
{
|
||||||
|
using std::chrono::high_resolution_clock;
|
||||||
cout << log->name() << "...\t\t" << flush;
|
cout << log->name() << "...\t\t" << flush;
|
||||||
auto start = system_clock::now();
|
auto start = high_resolution_clock::now();
|
||||||
for (auto i = 0; i < howmany; ++i)
|
for (auto i = 0; i < howmany; ++i)
|
||||||
{
|
{
|
||||||
log->info("Hello logger: msg number {}", i);
|
log->info("Hello logger: msg number {}", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto delta = system_clock::now() - start;
|
auto delta = high_resolution_clock::now() - start;
|
||||||
auto delta_d = duration_cast<duration<double>>(delta).count();
|
auto delta_d = duration_cast<duration<double>>(delta).count();
|
||||||
cout << "Elapsed: " << delta_d << "\t" << format(int(howmany / delta_d)) << "/sec" << endl;
|
cout << "Elapsed: " << delta_d << "\t" << format(int(howmany / delta_d)) << "/sec" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count)
|
void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count)
|
||||||
{
|
{
|
||||||
|
using std::chrono::high_resolution_clock;
|
||||||
cout << log->name() << "...\t\t" << flush;
|
cout << log->name() << "...\t\t" << flush;
|
||||||
std::atomic<int> msg_counter{0};
|
|
||||||
vector<thread> threads;
|
vector<thread> threads;
|
||||||
auto start = system_clock::now();
|
auto start = high_resolution_clock::now();
|
||||||
for (int t = 0; t < thread_count; ++t)
|
for (int t = 0; t < thread_count; ++t)
|
||||||
{
|
{
|
||||||
threads.push_back(std::thread([&]() {
|
threads.push_back(std::thread([&]() {
|
||||||
for (;;)
|
for (int j = 0; j < howmany / thread_count; j++)
|
||||||
{
|
{
|
||||||
int counter = ++msg_counter;
|
log->info("Hello logger: msg number {}", j);
|
||||||
if (counter > howmany)
|
|
||||||
break;
|
|
||||||
log->info("Hello logger: msg number {}", counter);
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -129,7 +135,7 @@ void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count
|
|||||||
t.join();
|
t.join();
|
||||||
};
|
};
|
||||||
|
|
||||||
auto delta = system_clock::now() - start;
|
auto delta = high_resolution_clock::now() - start;
|
||||||
auto delta_d = duration_cast<duration<double>>(delta).count();
|
auto delta_d = duration_cast<duration<double>>(delta).count();
|
||||||
cout << "Elapsed: " << delta_d << "\t" << format(int(howmany / delta_d)) << "/sec" << endl;
|
cout << "Elapsed: " << delta_d << "\t" << format(int(howmany / delta_d)) << "/sec" << endl;
|
||||||
}
|
}
|
||||||
|
149
bench/latency.cpp
Normal file
149
bench/latency.cpp
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
//
|
||||||
|
// Copyright(c) 2018 Gabi Melman.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// latency.cpp : spdlog latency benchmarks
|
||||||
|
//
|
||||||
|
#include "spdlog/async.h"
|
||||||
|
#include "spdlog/sinks/basic_file_sink.h"
|
||||||
|
#include "spdlog/sinks/daily_file_sink.h"
|
||||||
|
#include "spdlog/sinks/null_sink.h"
|
||||||
|
#include "spdlog/sinks/rotating_file_sink.h"
|
||||||
|
#include "spdlog/spdlog.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include <atomic>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace std::chrono;
|
||||||
|
using namespace spdlog;
|
||||||
|
using namespace spdlog::sinks;
|
||||||
|
using namespace utils;
|
||||||
|
|
||||||
|
void bench(int howmany, std::shared_ptr<spdlog::logger> log);
|
||||||
|
void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count);
|
||||||
|
|
||||||
|
int main(int , char *[])
|
||||||
|
{
|
||||||
|
std::srand(std::time(nullptr)); // use current time as seed for random generator
|
||||||
|
int howmany = 1000000;
|
||||||
|
int queue_size = howmany + 2;
|
||||||
|
int threads = 10;
|
||||||
|
int file_size = 30 * 1024 * 1024;
|
||||||
|
int rotating_files = 5;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
cout << "*******************************************************************************\n";
|
||||||
|
cout << "Single thread\n";
|
||||||
|
cout << "*******************************************************************************\n";
|
||||||
|
|
||||||
|
auto basic_st = spdlog::basic_logger_mt("basic_st", "logs/basic_st.log", true);
|
||||||
|
bench(howmany, basic_st);
|
||||||
|
|
||||||
|
auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st.log", file_size, rotating_files);
|
||||||
|
bench(howmany, rotating_st);
|
||||||
|
|
||||||
|
auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st.log");
|
||||||
|
bench(howmany, daily_st);
|
||||||
|
|
||||||
|
bench(howmany, spdlog::create<null_sink_st>("null_st"));
|
||||||
|
|
||||||
|
cout << "\n*******************************************************************************\n";
|
||||||
|
cout << threads << " threads sharing same logger\n";
|
||||||
|
cout << "*******************************************************************************\n";
|
||||||
|
|
||||||
|
auto basic_mt = spdlog::basic_logger_mt("basic_mt", "logs/basic_mt.log", true);
|
||||||
|
bench_mt(howmany, 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);
|
||||||
|
|
||||||
|
auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt.log");
|
||||||
|
bench_mt(howmany, daily_mt, threads);
|
||||||
|
bench(howmany, spdlog::create<null_sink_st>("null_mt"));
|
||||||
|
|
||||||
|
cout << "\n*******************************************************************************\n";
|
||||||
|
cout << "async logging.. " << threads << " threads sharing same logger\n";
|
||||||
|
cout << "*******************************************************************************\n";
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
spdlog::init_thread_pool(queue_size, 1);
|
||||||
|
auto as = spdlog::basic_logger_mt<spdlog::async_factory>("async", "logs/basic_async.log", true);
|
||||||
|
bench_mt(howmany, as, threads);
|
||||||
|
spdlog::drop("async");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception &ex)
|
||||||
|
{
|
||||||
|
std::cerr << "Error: " << ex.what() << std::endl;
|
||||||
|
perror("Last error");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bench(int howmany, std::shared_ptr<spdlog::logger> log)
|
||||||
|
{
|
||||||
|
using namespace std::chrono;
|
||||||
|
using chrono::high_resolution_clock;
|
||||||
|
using chrono::milliseconds;
|
||||||
|
using chrono::nanoseconds;
|
||||||
|
|
||||||
|
cout << log->name() << "...\t\t" << flush;
|
||||||
|
nanoseconds total_nanos = nanoseconds::zero();
|
||||||
|
for (auto i = 0; i < howmany; ++i)
|
||||||
|
{
|
||||||
|
auto start = high_resolution_clock::now();
|
||||||
|
log->info("Hello logger: msg number {}", i);
|
||||||
|
auto delta_nanos = chrono::duration_cast<nanoseconds>(high_resolution_clock::now() - start);
|
||||||
|
total_nanos+= delta_nanos;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto avg = total_nanos.count()/howmany;
|
||||||
|
cout << format(avg) << " ns/call" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count)
|
||||||
|
{
|
||||||
|
using namespace std::chrono;
|
||||||
|
using chrono::high_resolution_clock;
|
||||||
|
using chrono::milliseconds;
|
||||||
|
using chrono::nanoseconds;
|
||||||
|
|
||||||
|
cout << log->name() << "...\t\t" << flush;
|
||||||
|
vector<thread> threads;
|
||||||
|
std::atomic<nanoseconds::rep> total_nanos{0};
|
||||||
|
for (int t = 0; t < thread_count; ++t)
|
||||||
|
{
|
||||||
|
threads.push_back(std::thread([&]() {
|
||||||
|
for (int j = 0; j < howmany / thread_count; j++)
|
||||||
|
{
|
||||||
|
auto start = high_resolution_clock::now();
|
||||||
|
log->info("Hello logger: msg number {}", j);
|
||||||
|
auto delta_nanos = chrono::duration_cast<nanoseconds>(high_resolution_clock::now() - start);
|
||||||
|
total_nanos+= delta_nanos.count();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &t : threads)
|
||||||
|
{
|
||||||
|
t.join();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto avg = total_nanos/howmany;
|
||||||
|
cout << format(avg) << " ns/call" << endl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -11,7 +11,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "spdlog/async.h"
|
#include "spdlog/async.h"
|
||||||
#include "spdlog/sinks/simple_file_sink.h"
|
#include "spdlog/sinks/basic_file_sink.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ int main(int argc, char *argv[])
|
|||||||
int howmany = 1000000;
|
int howmany = 1000000;
|
||||||
spdlog::init_thread_pool(howmany, 1);
|
spdlog::init_thread_pool(howmany, 1);
|
||||||
|
|
||||||
auto logger = spdlog::create_async_logger<spdlog::sinks::simple_file_sink_mt>("file_logger", "logs/spdlog-bench-async.log", false);
|
auto logger = spdlog::create_async_logger<spdlog::sinks::basic_file_sink_mt>("file_logger", "logs/spdlog-bench-async.log", false);
|
||||||
logger->set_pattern("[%Y-%m-%d %T.%F]: %L %t %v");
|
logger->set_pattern("[%Y-%m-%d %T.%F]: %L %t %v");
|
||||||
|
|
||||||
std::cout << "To stop, press <Enter>" << std::endl;
|
std::cout << "To stop, press <Enter>" << std::endl;
|
||||||
|
@ -1,116 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright(c) 2015 Gabi Melman.
|
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
|
||||||
//
|
|
||||||
|
|
||||||
//
|
|
||||||
// bench.cpp : spdlog benchmarks
|
|
||||||
//
|
|
||||||
#include "spdlog/async.h"
|
|
||||||
#include "spdlog/async_logger.h"
|
|
||||||
#include "spdlog/sinks/null_sink.h"
|
|
||||||
#include "spdlog/spdlog.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include <atomic>
|
|
||||||
#include <cstdlib> // EXIT_FAILURE
|
|
||||||
#include <iostream>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace std::chrono;
|
|
||||||
using namespace spdlog;
|
|
||||||
using namespace spdlog::sinks;
|
|
||||||
using namespace utils;
|
|
||||||
|
|
||||||
size_t bench_as(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count);
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
|
|
||||||
int howmany;
|
|
||||||
int tp_queue_size;
|
|
||||||
int tp_threads = 1;
|
|
||||||
int client_threads = 10;
|
|
||||||
int iters = 10;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (argc < 2)
|
|
||||||
{
|
|
||||||
cout << "Usage: " << argv[0] << " <howmany> [client_threads] [q_size] [tp_threads]" << endl;
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
howmany = atoi(argv[1]);
|
|
||||||
if (argc > 2)
|
|
||||||
client_threads = atoi(argv[2]);
|
|
||||||
|
|
||||||
if (argc > 3)
|
|
||||||
tp_queue_size = atoi(argv[3]);
|
|
||||||
else
|
|
||||||
tp_queue_size = howmany;
|
|
||||||
|
|
||||||
if (argc > 4)
|
|
||||||
tp_threads = atoi(argv[4]);
|
|
||||||
|
|
||||||
cout << "\n*******************************************************************************\n";
|
|
||||||
cout << "messages:\t" << format(howmany) << endl;
|
|
||||||
cout << "client_threads:\t" << client_threads << endl;
|
|
||||||
cout << "tp queue:\t" << format(tp_queue_size) << endl;
|
|
||||||
cout << "tp threads:\t" << tp_threads << endl;
|
|
||||||
cout << "*******************************************************************************\n";
|
|
||||||
|
|
||||||
size_t total_rate = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < iters; ++i)
|
|
||||||
{
|
|
||||||
spdlog::init_thread_pool(tp_queue_size, tp_threads);
|
|
||||||
auto as = spdlog::create_async_logger<null_sink_mt>("async(null-sink)");
|
|
||||||
total_rate += bench_as(howmany, as, client_threads);
|
|
||||||
spdlog::drop("async(null-sink)");
|
|
||||||
}
|
|
||||||
std::cout << endl;
|
|
||||||
std::cout << "Avg rate: " << format(total_rate / iters) << "/sec" << std::endl;
|
|
||||||
}
|
|
||||||
catch (std::exception &ex)
|
|
||||||
{
|
|
||||||
std::cerr << "Error: " << ex.what() << std::endl;
|
|
||||||
perror("Last error");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return rate/sec
|
|
||||||
size_t bench_as(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count)
|
|
||||||
{
|
|
||||||
cout << log->name() << "...\t\t" << flush;
|
|
||||||
std::atomic<int> msg_counter{0};
|
|
||||||
vector<thread> threads;
|
|
||||||
auto start = system_clock::now();
|
|
||||||
for (int t = 0; t < thread_count; ++t)
|
|
||||||
{
|
|
||||||
threads.push_back(std::thread([&]() {
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
int counter = ++msg_counter;
|
|
||||||
if (counter > howmany)
|
|
||||||
break;
|
|
||||||
log->info("Hello logger: msg number {}", counter);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &t : threads)
|
|
||||||
{
|
|
||||||
t.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto delta = system_clock::now() - start;
|
|
||||||
auto delta_d = duration_cast<duration<double>>(delta).count();
|
|
||||||
auto per_sec = size_t(howmany / delta_d);
|
|
||||||
cout << format(per_sec) << "/sec" << endl;
|
|
||||||
return per_sec;
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
CXX = g++
|
CXX = g++
|
||||||
CXX_FLAGS = -Wall -Wextra -pedantic -std=c++11 -pthread -I../include
|
CXX_FLAGS = -Wall -Wextra -pedantic -std=c++11 -pthread -I../include -fmax-errors=1
|
||||||
CXX_RELEASE_FLAGS = -O3 -march=native
|
CXX_RELEASE_FLAGS = -O3 -march=native
|
||||||
CXX_DEBUG_FLAGS= -g
|
CXX_DEBUG_FLAGS= -g
|
||||||
|
|
||||||
|
@ -7,140 +7,149 @@
|
|||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|
||||||
#define SPDLOG_TRACE_ON
|
|
||||||
#define SPDLOG_DEBUG_ON
|
|
||||||
|
|
||||||
#include "spdlog/sinks/daily_file_sink.h"
|
|
||||||
#include "spdlog/sinks/rotating_file_sink.h"
|
|
||||||
#include "spdlog/sinks/simple_file_sink.h"
|
|
||||||
#include "spdlog/sinks/stdout_color_sinks.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
|
void stdout_example();
|
||||||
|
void basic_example();
|
||||||
|
void rotating_example();
|
||||||
|
void daily_example();
|
||||||
void async_example();
|
void async_example();
|
||||||
|
void multi_sink_example();
|
||||||
void user_defined_example();
|
void user_defined_example();
|
||||||
void err_handler_example();
|
void err_handler_example();
|
||||||
void syslog_example();
|
void syslog_example();
|
||||||
|
|
||||||
namespace spd = spdlog;
|
#include "spdlog/spdlog.h"
|
||||||
|
|
||||||
int main(int, char *[])
|
int main(int, char *[])
|
||||||
{
|
{
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto console = spdlog::stdout_color_st("console");
|
// console logging example
|
||||||
console->info("Welcome to spdlog!");
|
stdout_example();
|
||||||
|
|
||||||
console->info("Welcome to spdlog!");
|
// various file loggers
|
||||||
console->error("Some error message with arg: {}", 1);
|
basic_example();
|
||||||
err_handler_example();
|
rotating_example();
|
||||||
// Formatting examples
|
daily_example();
|
||||||
console->warn("Easy padding in numbers like {:08d}", 12);
|
|
||||||
console->critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
|
|
||||||
console->info("Support for floats {:03.2f}", 1.23456);
|
|
||||||
console->info("Positional args are {1} {0}..", "too", "supported");
|
|
||||||
console->info("{:<30}", "left aligned");
|
|
||||||
|
|
||||||
spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function");
|
// async logging using a backing thread pool
|
||||||
|
|
||||||
// Create basic file logger (not rotated)
|
|
||||||
auto my_logger = spd::basic_logger_mt("basic_logger", "logs/basic-log.txt");
|
|
||||||
my_logger->info("Some log message");
|
|
||||||
|
|
||||||
// Create a file rotating logger with 5mb size max and 3 rotated files
|
|
||||||
auto rotating_logger = spd::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3);
|
|
||||||
for (int i = 0; i < 10; ++i)
|
|
||||||
{
|
|
||||||
rotating_logger->info("{} * {} equals {:>10}", i, i, i * i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a daily logger - a new file is created every day on 2:30am
|
|
||||||
auto daily_logger = spd::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
|
|
||||||
// trigger flush if the log severity is error or higher
|
|
||||||
daily_logger->flush_on(spd::level::err);
|
|
||||||
daily_logger->info(123.44);
|
|
||||||
|
|
||||||
// Customize msg format for all messages
|
|
||||||
spd::set_pattern("[%^+++%$] [%H:%M:%S %z] [thread %t] %v");
|
|
||||||
|
|
||||||
console->info("This an info message with custom format");
|
|
||||||
console->error("This an error message with custom format");
|
|
||||||
|
|
||||||
// Change format back to to default
|
|
||||||
spd::set_pattern("%+");
|
|
||||||
|
|
||||||
// Runtime log levels
|
|
||||||
spd::set_level(spd::level::info); // Set global log level to info
|
|
||||||
console->debug("This message should not be displayed!");
|
|
||||||
console->set_level(spd::level::trace); // Set specific logger's log level
|
|
||||||
console->debug("This message should be displayed..");
|
|
||||||
|
|
||||||
// Compile time log levels
|
|
||||||
// define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON
|
|
||||||
SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
|
|
||||||
SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);
|
|
||||||
|
|
||||||
// Asynchronous logging example
|
|
||||||
async_example();
|
async_example();
|
||||||
|
|
||||||
// Log user-defined types example
|
// a logger can have multiple targets with different formats
|
||||||
|
multi_sink_example();
|
||||||
|
|
||||||
|
// user defined types logging by implementing operator<<
|
||||||
user_defined_example();
|
user_defined_example();
|
||||||
|
|
||||||
// Change default log error handler
|
// custom error handler
|
||||||
err_handler_example();
|
err_handler_example();
|
||||||
|
|
||||||
// Apply a function on all registered loggers
|
// apply some function on all registered loggers
|
||||||
spd::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->info("End of example."); });
|
spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->info("End of example."); });
|
||||||
|
|
||||||
// Release and close all loggers
|
// Release and close all loggers
|
||||||
spdlog::drop_all();
|
spdlog::drop_all();
|
||||||
}
|
}
|
||||||
// Exceptions will only be thrown upon failed logger or sink construction (not during logging)
|
// Exceptions will only be thrown upon failed logger or sink construction (not during logging)
|
||||||
catch (const spd::spdlog_ex &ex)
|
catch (const spdlog::spdlog_ex &ex)
|
||||||
{
|
{
|
||||||
std::cout << "Log init failed: " << ex.what() << std::endl;
|
std::cout << "Log init failed: " << ex.what() << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// must be included to use async logger
|
|
||||||
|
#include "spdlog/sinks/stdout_color_sinks.h" // or "/sinks/stdout_sinks.h" if no colors needed
|
||||||
|
void stdout_example()
|
||||||
|
{
|
||||||
|
// create color multi threaded logger
|
||||||
|
auto console = spdlog::stdout_color_mt("console");
|
||||||
|
console->info("Welcome to spdlog!");
|
||||||
|
console->error("Some error message with arg: {}", 1);
|
||||||
|
|
||||||
|
auto err_logger = spdlog::stderr_color_mt("stderr");
|
||||||
|
err_logger->error("Some error message");
|
||||||
|
|
||||||
|
// Formatting examples
|
||||||
|
console->warn("Easy padding in numbers like {:08d}", 12);
|
||||||
|
console->critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
|
||||||
|
console->info("Support for floats {:03.2f}", 1.23456);
|
||||||
|
console->info("Positional args are {1} {0}..", "too", "supported");
|
||||||
|
console->info("{:<30}", "left aligned");
|
||||||
|
|
||||||
|
spdlog::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)");
|
||||||
|
|
||||||
|
// Runtime log levels
|
||||||
|
spdlog::set_level(spdlog::level::info); // Set global log level to info
|
||||||
|
console->debug("This message should not be displayed!");
|
||||||
|
console->set_level(spdlog::level::trace); // Set specific logger's log level
|
||||||
|
console->debug("This message should be displayed..");
|
||||||
|
|
||||||
|
// Customize msg format for all loggers
|
||||||
|
spdlog::set_pattern("[%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v");
|
||||||
|
console->info("This an info message with custom format");
|
||||||
|
|
||||||
|
// Compile time log levels
|
||||||
|
// define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON
|
||||||
|
SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
|
||||||
|
SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "spdlog/sinks/basic_file_sink.h"
|
||||||
|
void basic_example()
|
||||||
|
{
|
||||||
|
// Create basic file logger (not rotated)
|
||||||
|
auto my_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "spdlog/sinks/rotating_file_sink.h"
|
||||||
|
void rotating_example()
|
||||||
|
{
|
||||||
|
// Create a file rotating logger with 5mb size max and 3 rotated files
|
||||||
|
auto rotating_logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "spdlog/sinks/daily_file_sink.h"
|
||||||
|
void daily_example()
|
||||||
|
{
|
||||||
|
// Create a daily logger - a new file is created every day on 2:30am
|
||||||
|
auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
|
||||||
|
}
|
||||||
|
|
||||||
#include "spdlog/async.h"
|
#include "spdlog/async.h"
|
||||||
void async_example()
|
void async_example()
|
||||||
{
|
{
|
||||||
auto async_file = spd::basic_logger_mt<spdlog::create_async>("async_file_logger", "logs/async_log.txt");
|
// default thread pool settings can be modified *before* creating the async logger:
|
||||||
|
// spdlog::init_thread_pool(32768, 1); // queue with max 32k items 1 backing thread.
|
||||||
|
auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");
|
||||||
|
// alternatively:
|
||||||
|
// auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");
|
||||||
|
|
||||||
// thread pool settings can be modified *before* creating the async logger:
|
for (int i = 1; i < 101; ++i)
|
||||||
// spdlog::init_thread_pool(32768, 4); // queue with max 32k items 4 backing threads.
|
|
||||||
for (int i = 0; i < 100; ++i)
|
|
||||||
{
|
{
|
||||||
async_file->info("Async message #{}", i + 1);
|
async_file->info("Async message #{}", i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// syslog example (linux/osx/freebsd)
|
// create logger with 2 targets with different log levels and formats
|
||||||
#ifndef _WIN32
|
// the console will show only warnings or errors, while the file will log all
|
||||||
#include "spdlog/sinks/syslog_sink.h"
|
|
||||||
void syslog_example()
|
void multi_sink_example()
|
||||||
{
|
{
|
||||||
std::string ident = "spdlog-example";
|
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
|
||||||
auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID);
|
console_sink->set_level(spdlog::level::warn);
|
||||||
syslog_logger->warn("This is warning that will end up in syslog.");
|
console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v");
|
||||||
|
|
||||||
|
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/multisink.txt", true);
|
||||||
|
file_sink->set_level(spdlog::level::trace);
|
||||||
|
|
||||||
|
spdlog::logger logger("multi_sink", {console_sink, file_sink});
|
||||||
|
logger.set_level(spdlog::level::debug);
|
||||||
|
logger.warn("this should appear in both console and file");
|
||||||
|
logger.info("this message should not appear in the console, only in the file");
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// Android example
|
|
||||||
#if defined(__ANDROID__)
|
|
||||||
#incude "spdlog/sinks/android_sink.h"
|
|
||||||
void android_example()
|
|
||||||
{
|
|
||||||
std::string tag = "spdlog-android";
|
|
||||||
auto android_logger = spd::android_logger("android", tag);
|
|
||||||
android_logger->critical("Use \"adb shell logcat\" to view this message.");
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// user defined types logging by implementing operator<<
|
// user defined types logging by implementing operator<<
|
||||||
|
#include "spdlog/fmt/ostr.h" // must be included
|
||||||
struct my_type
|
struct my_type
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -151,10 +160,9 @@ struct my_type
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "spdlog/fmt/ostr.h" // must be included
|
|
||||||
void user_defined_example()
|
void user_defined_example()
|
||||||
{
|
{
|
||||||
spd::get("console")->info("user defined type: {}", my_type{14});
|
spdlog::get("console")->info("user defined type: {}", my_type{14});
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -162,8 +170,30 @@ void user_defined_example()
|
|||||||
//
|
//
|
||||||
void err_handler_example()
|
void err_handler_example()
|
||||||
{
|
{
|
||||||
// can be set globaly or per logger(logger->set_error_handler(..))
|
// can be set globally or per logger(logger->set_error_handler(..))
|
||||||
spdlog::set_error_handler([](const std::string &msg) { spd::get("console")->error("*******my err handler: {}", msg); });
|
spdlog::set_error_handler([](const std::string &msg) { spdlog::get("console")->error("*** LOGGER ERROR ***: {}", msg); });
|
||||||
spd::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3);
|
spdlog::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3);
|
||||||
// spd::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// syslog example (linux/osx/freebsd)
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include "spdlog/sinks/syslog_sink.h"
|
||||||
|
void syslog_example()
|
||||||
|
{
|
||||||
|
std::string ident = "spdlog-example";
|
||||||
|
auto syslog_logger = spdlog::syslog_logger("syslog", ident, LOG_PID);
|
||||||
|
syslog_logger->warn("This is warning that will end up in syslog.");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Android example
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
#incude "spdlog/sinks/android_sink.h"
|
||||||
|
void android_example()
|
||||||
|
{
|
||||||
|
std::string tag = "spdlog-android";
|
||||||
|
auto android_logger = spdlog::android_logger("android", tag);
|
||||||
|
android_logger->critical("Use \"adb shell logcat\" to view this message.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -15,8 +15,8 @@ int main(int, char *[])
|
|||||||
// Each sink can have it's own log level and a message will be logged.
|
// Each sink can have it's own log level and a message will be logged.
|
||||||
std::vector<spdlog::sink_ptr> sinks;
|
std::vector<spdlog::sink_ptr> sinks;
|
||||||
sinks.push_back(std::make_shared<spdlog::sinks::stdout_sink_mt>());
|
sinks.push_back(std::make_shared<spdlog::sinks::stdout_sink_mt>());
|
||||||
sinks.push_back(std::make_shared<spdlog::sinks::simple_file_sink_mt>("./log_regular_file.txt"));
|
sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>("./log_regular_file.txt"));
|
||||||
sinks.push_back(std::make_shared<spdlog::sinks::simple_file_sink_mt>("./log_debug_file.txt"));
|
sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>("./log_debug_file.txt"));
|
||||||
|
|
||||||
spdlog::logger console_multisink("multisink", sinks.begin(), sinks.end());
|
spdlog::logger console_multisink("multisink", sinks.begin(), sinks.end());
|
||||||
console_multisink.set_level(spdlog::level::warn);
|
console_multisink.set_level(spdlog::level::warn);
|
||||||
|
@ -23,7 +23,7 @@ namespace spdlog {
|
|||||||
|
|
||||||
// async logger factory - creates async loggers backed with thread pool.
|
// async logger factory - creates async loggers backed with thread pool.
|
||||||
// if a global thread pool doesn't already exist, create it with default queue size of 8192 items and single thread.
|
// if a global thread pool doesn't already exist, create it with default queue size of 8192 items and single thread.
|
||||||
struct create_async
|
struct async_factory
|
||||||
{
|
{
|
||||||
template<typename Sink, typename... SinkArgs>
|
template<typename Sink, typename... SinkArgs>
|
||||||
static std::shared_ptr<async_logger> create(const std::string &logger_name, SinkArgs &&... args)
|
static std::shared_ptr<async_logger> create(const std::string &logger_name, SinkArgs &&... args)
|
||||||
@ -39,16 +39,16 @@ struct create_async
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
|
auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
|
||||||
auto new_logger = std::make_shared<async_logger>(logger_name, std::move(sink), std::move(tp), async_overflow_policy::block_retry);
|
auto new_logger = std::make_shared<async_logger>(logger_name, std::move(sink), std::move(tp), async_overflow_policy::block);
|
||||||
registry::instance().register_and_init(new_logger);
|
registry::instance().register_and_init(new_logger);
|
||||||
return new_logger;
|
return new_logger;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Sink, typename... SinkArgs>
|
template<typename Sink, typename... SinkArgs>
|
||||||
inline std::shared_ptr<spdlog::logger> create_async_logger(const std::string &logger_name, SinkArgs &&... sink_args)
|
inline std::shared_ptr<spdlog::logger> create_async(const std::string &logger_name, SinkArgs &&... sink_args)
|
||||||
{
|
{
|
||||||
return create_async::create<Sink>(logger_name, std::forward<SinkArgs>(sink_args)...);
|
return async_factory::create<Sink>(logger_name, std::forward<SinkArgs>(sink_args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set global thread pool.
|
// set global thread pool.
|
||||||
|
@ -34,13 +34,13 @@ class async_logger SPDLOG_FINAL : public std::enable_shared_from_this<async_logg
|
|||||||
public:
|
public:
|
||||||
template<class It>
|
template<class It>
|
||||||
async_logger(const std::string &logger_name, const It &begin, const It &end, std::weak_ptr<details::thread_pool> tp,
|
async_logger(const std::string &logger_name, const It &begin, const It &end, std::weak_ptr<details::thread_pool> tp,
|
||||||
async_overflow_policy overflow_policy = async_overflow_policy::block_retry);
|
async_overflow_policy overflow_policy = async_overflow_policy::block);
|
||||||
|
|
||||||
async_logger(const std::string &logger_name, sinks_init_list sinks, std::weak_ptr<details::thread_pool> tp,
|
async_logger(const std::string &logger_name, sinks_init_list sinks, std::weak_ptr<details::thread_pool> tp,
|
||||||
async_overflow_policy overflow_policy = async_overflow_policy::block_retry);
|
async_overflow_policy overflow_policy = async_overflow_policy::block);
|
||||||
|
|
||||||
async_logger(const std::string &logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp,
|
async_logger(const std::string &logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp,
|
||||||
async_overflow_policy overflow_policy = async_overflow_policy::block_retry);
|
async_overflow_policy overflow_policy = async_overflow_policy::block);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void sink_it_(details::log_msg &msg) override;
|
void sink_it_(details::log_msg &msg) override;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define SPDLOG_VERSION "0.16.4-rc"
|
#define SPDLOG_VERSION "1.0.0-rc"
|
||||||
|
|
||||||
#include "spdlog/tweakme.h"
|
#include "spdlog/tweakme.h"
|
||||||
|
|
||||||
@ -63,6 +63,7 @@ using log_clock = std::chrono::system_clock;
|
|||||||
using sink_ptr = std::shared_ptr<sinks::sink>;
|
using sink_ptr = std::shared_ptr<sinks::sink>;
|
||||||
using sinks_init_list = std::initializer_list<sink_ptr>;
|
using sinks_init_list = std::initializer_list<sink_ptr>;
|
||||||
using formatter_ptr = std::shared_ptr<spdlog::formatter>;
|
using formatter_ptr = std::shared_ptr<spdlog::formatter>;
|
||||||
|
|
||||||
#if defined(SPDLOG_NO_ATOMIC_LEVELS)
|
#if defined(SPDLOG_NO_ATOMIC_LEVELS)
|
||||||
using level_t = details::null_atomic_int;
|
using level_t = details::null_atomic_int;
|
||||||
#else
|
#else
|
||||||
@ -126,8 +127,8 @@ using level_hasher = std::hash<int>;
|
|||||||
//
|
//
|
||||||
enum class async_overflow_policy
|
enum class async_overflow_policy
|
||||||
{
|
{
|
||||||
block_retry, // Block until message can be enqueued
|
block, // Block until message can be enqueued
|
||||||
overrun_oldeset // Discard oldest message in the queue if full when trying to add new item.
|
overrun_oldest // Discard oldest message in the queue if full when trying to add new item.
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -60,7 +60,7 @@ inline void spdlog::async_logger::flush_()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw spdlog_ex("async flush: thread pool doens't exist anymore");
|
throw spdlog_ex("async flush: thread pool doesn't exist anymore");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#include "stdio.h"
|
#include "stdio.h"
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
namespace details {
|
namespace details {
|
||||||
struct console_stdout_trait
|
struct console_stdout_stream
|
||||||
{
|
{
|
||||||
static FILE *stream()
|
static FILE *stream()
|
||||||
{
|
{
|
||||||
@ -21,7 +21,7 @@ struct console_stdout_trait
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct console_stderr_trait
|
struct console_stderr_stream
|
||||||
{
|
{
|
||||||
static FILE *stream()
|
static FILE *stream()
|
||||||
{
|
{
|
||||||
@ -35,7 +35,7 @@ struct console_stderr_trait
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct console_mutex_trait
|
struct console_global_mutex
|
||||||
{
|
{
|
||||||
using mutex_t = std::mutex;
|
using mutex_t = std::mutex;
|
||||||
static mutex_t &console_mutex()
|
static mutex_t &console_mutex()
|
||||||
@ -45,7 +45,7 @@ struct console_mutex_trait
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct console_null_mutex_trait
|
struct console_global_nullmutex
|
||||||
{
|
{
|
||||||
using mutex_t = null_mutex;
|
using mutex_t = null_mutex;
|
||||||
static mutex_t &console_mutex()
|
static mutex_t &console_mutex()
|
@ -8,13 +8,16 @@
|
|||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
namespace details {
|
namespace details {
|
||||||
namespace fmt_helper {
|
namespace fmt_helper {
|
||||||
inline void append_str(const std::string &str, fmt::memory_buffer &dest)
|
|
||||||
|
template <size_t Buffer_Size>
|
||||||
|
inline void append_str(const std::string &str, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
|
||||||
{
|
{
|
||||||
auto *str_ptr = str.data();
|
auto *str_ptr = str.data();
|
||||||
dest.append(str_ptr, str_ptr + str.size());
|
dest.append(str_ptr, str_ptr + str.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void append_c_str(const char *c_str, fmt::memory_buffer &dest)
|
template <size_t Buffer_Size>
|
||||||
|
inline void append_c_str(const char *c_str, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
|
||||||
{
|
{
|
||||||
char ch;
|
char ch;
|
||||||
while ((ch = *c_str) != '\0')
|
while ((ch = *c_str) != '\0')
|
||||||
@ -24,21 +27,22 @@ inline void append_c_str(const char *c_str, fmt::memory_buffer &dest)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t N1, size_t N2>
|
template<size_t Buffer_Size1, size_t Buffer_Size2>
|
||||||
inline void append_buf(const fmt::basic_memory_buffer<char, N1> &buf, fmt::basic_memory_buffer<char, N2> &dest)
|
inline void append_buf(const fmt::basic_memory_buffer<char, Buffer_Size1> &buf, fmt::basic_memory_buffer<char, Buffer_Size2> &dest)
|
||||||
{
|
{
|
||||||
auto *buf_ptr = buf.data();
|
auto *buf_ptr = buf.data();
|
||||||
dest.append(buf_ptr, buf_ptr + buf.size());
|
dest.append(buf_ptr, buf_ptr + buf.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, size_t Buffer_Size>
|
||||||
inline void append_int(T n, fmt::memory_buffer &dest)
|
inline void append_int(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
|
||||||
{
|
{
|
||||||
fmt::format_int i(n);
|
fmt::format_int i(n);
|
||||||
dest.append(i.data(), i.data() + i.size());
|
dest.append(i.data(), i.data() + i.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void pad2(int n, fmt::memory_buffer &dest)
|
template <size_t Buffer_Size>
|
||||||
|
inline void pad2(int n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
|
||||||
{
|
{
|
||||||
if (n > 99)
|
if (n > 99)
|
||||||
{
|
{
|
||||||
@ -61,7 +65,8 @@ inline void pad2(int n, fmt::memory_buffer &dest)
|
|||||||
fmt::format_to(dest, "{:02}", n);
|
fmt::format_to(dest, "{:02}", n);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void pad3(int n, fmt::memory_buffer &dest)
|
template <size_t Buffer_Size>
|
||||||
|
inline void pad3(int n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
|
||||||
{
|
{
|
||||||
if (n > 99)
|
if (n > 99)
|
||||||
{
|
{
|
||||||
@ -86,8 +91,13 @@ inline void pad3(int n, fmt::memory_buffer &dest)
|
|||||||
fmt::format_to(dest, "{:03}", n);
|
fmt::format_to(dest, "{:03}", n);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void pad6(size_t n, fmt::memory_buffer &dest)
|
template <size_t Buffer_Size>
|
||||||
|
inline void pad6(size_t n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
|
||||||
{
|
{
|
||||||
|
// todo: maybe replace this implementation with
|
||||||
|
// pad3(n / 1000, dest);
|
||||||
|
// pad3(n % 1000, dest);
|
||||||
|
|
||||||
if (n > 99999)
|
if (n > 99999)
|
||||||
{
|
{
|
||||||
append_int(n, dest);
|
append_int(n, dest);
|
||||||
@ -122,7 +132,7 @@ inline void pad6(size_t n, fmt::memory_buffer &dest)
|
|||||||
dest.push_back('0');
|
dest.push_back('0');
|
||||||
dest.push_back('0');
|
dest.push_back('0');
|
||||||
dest.push_back('0');
|
dest.push_back('0');
|
||||||
}
|
}
|
||||||
append_int(n, dest);
|
append_int(n, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,9 +46,9 @@ inline void spdlog::logger::set_formatter(const Args &... args)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void spdlog::logger::set_pattern(const std::string &pattern, pattern_time_type pattern_time)
|
inline void spdlog::logger::set_pattern(const std::string &pattern, pattern_time_type time_type)
|
||||||
{
|
{
|
||||||
set_formatter<spdlog::pattern_formatter>(pattern, pattern_time);
|
set_formatter<spdlog::pattern_formatter>(pattern, time_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
@ -100,40 +100,40 @@ inline void spdlog::logger::log(level::level_enum lvl, const T &msg)
|
|||||||
SPDLOG_CATCH_AND_HANDLE
|
SPDLOG_CATCH_AND_HANDLE
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Arg1, typename... Args>
|
template<typename... Args>
|
||||||
inline void spdlog::logger::trace(const char *fmt, const Arg1 &arg1, const Args &... args)
|
inline void spdlog::logger::trace(const char *fmt, const Args &... args)
|
||||||
{
|
{
|
||||||
log(level::trace, fmt, arg1, args...);
|
log(level::trace, fmt, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Arg1, typename... Args>
|
template<typename... Args>
|
||||||
inline void spdlog::logger::debug(const char *fmt, const Arg1 &arg1, const Args &... args)
|
inline void spdlog::logger::debug(const char *fmt, const Args &... args)
|
||||||
{
|
{
|
||||||
log(level::debug, fmt, arg1, args...);
|
log(level::debug, fmt, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Arg1, typename... Args>
|
template<typename... Args>
|
||||||
inline void spdlog::logger::info(const char *fmt, const Arg1 &arg1, const Args &... args)
|
inline void spdlog::logger::info(const char *fmt, const Args &... args)
|
||||||
{
|
{
|
||||||
log(level::info, fmt, arg1, args...);
|
log(level::info, fmt, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Arg1, typename... Args>
|
template<typename... Args>
|
||||||
inline void spdlog::logger::warn(const char *fmt, const Arg1 &arg1, const Args &... args)
|
inline void spdlog::logger::warn(const char *fmt, const Args &... args)
|
||||||
{
|
{
|
||||||
log(level::warn, fmt, arg1, args...);
|
log(level::warn, fmt, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Arg1, typename... Args>
|
template<typename... Args>
|
||||||
inline void spdlog::logger::error(const char *fmt, const Arg1 &arg1, const Args &... args)
|
inline void spdlog::logger::error(const char *fmt, const Args &... args)
|
||||||
{
|
{
|
||||||
log(level::err, fmt, arg1, args...);
|
log(level::err, fmt, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Arg1, typename... Args>
|
template<typename... Args>
|
||||||
inline void spdlog::logger::critical(const char *fmt, const Arg1 &arg1, const Args &... args)
|
inline void spdlog::logger::critical(const char *fmt, const Args &... args)
|
||||||
{
|
{
|
||||||
log(level::critical, fmt, arg1, args...);
|
log(level::critical, fmt, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -120,7 +120,16 @@ class c_formatter SPDLOG_FINAL : public flag_formatter
|
|||||||
{
|
{
|
||||||
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
|
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
|
||||||
{
|
{
|
||||||
fmt::format_to(dest, "{} {} {} ", days[tm_time.tm_wday], months[tm_time.tm_mon], tm_time.tm_mday); //
|
//fmt::format_to(dest, "{} {} {} ", days[tm_time.tm_wday], months[tm_time.tm_mon], tm_time.tm_mday);
|
||||||
|
// date
|
||||||
|
fmt_helper::append_str(days[tm_time.tm_wday], dest);
|
||||||
|
dest.push_back(' ');
|
||||||
|
fmt_helper::append_str(months[tm_time.tm_mon], dest);
|
||||||
|
dest.push_back(' ');
|
||||||
|
fmt_helper::append_int(tm_time.tm_mday, dest);
|
||||||
|
dest.push_back(' ');
|
||||||
|
// time
|
||||||
|
|
||||||
fmt_helper::pad2(tm_time.tm_hour, dest);
|
fmt_helper::pad2(tm_time.tm_hour, dest);
|
||||||
dest.push_back(':');
|
dest.push_back(':');
|
||||||
fmt_helper::pad2(tm_time.tm_min, dest);
|
fmt_helper::pad2(tm_time.tm_min, dest);
|
||||||
@ -176,7 +185,6 @@ class d_formatter SPDLOG_FINAL : public flag_formatter
|
|||||||
{
|
{
|
||||||
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
|
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
|
||||||
{
|
{
|
||||||
// fmt::format_to(dest, "{:02}", tm_time.tm_mday);
|
|
||||||
fmt_helper::pad2(tm_time.tm_mday, dest);
|
fmt_helper::pad2(tm_time.tm_mday, dest);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -265,7 +273,7 @@ class p_formatter SPDLOG_FINAL : public flag_formatter
|
|||||||
{
|
{
|
||||||
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
|
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
|
||||||
{
|
{
|
||||||
fmt::format_to(dest, "{}", ampm(tm_time));
|
fmt_helper::append_c_str(ampm(tm_time), dest);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -274,13 +282,13 @@ class r_formatter SPDLOG_FINAL : public flag_formatter
|
|||||||
{
|
{
|
||||||
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
|
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
|
||||||
{
|
{
|
||||||
// fmt::format_to(dest, "{:02}:{:02}:{:02} {}", to12h(tm_time), tm_time.tm_min, tm_time.tm_sec, ampm(tm_time));
|
|
||||||
fmt_helper::pad2(to12h(tm_time), dest);
|
fmt_helper::pad2(to12h(tm_time), dest);
|
||||||
dest.push_back(':');
|
dest.push_back(':');
|
||||||
fmt_helper::pad2(tm_time.tm_min, dest);
|
fmt_helper::pad2(tm_time.tm_min, dest);
|
||||||
dest.push_back(':');
|
dest.push_back(':');
|
||||||
fmt_helper::pad2(tm_time.tm_sec, dest);
|
fmt_helper::pad2(tm_time.tm_sec, dest);
|
||||||
fmt::format_to(dest, " {}", ampm(tm_time));
|
dest.push_back(' ');
|
||||||
|
fmt_helper::append_c_str(ampm(tm_time), dest);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -330,23 +338,19 @@ public:
|
|||||||
int total_minutes = os::utc_minutes_offset(tm_time);
|
int total_minutes = os::utc_minutes_offset(tm_time);
|
||||||
#endif
|
#endif
|
||||||
bool is_negative = total_minutes < 0;
|
bool is_negative = total_minutes < 0;
|
||||||
char sign;
|
|
||||||
if (is_negative)
|
if (is_negative)
|
||||||
{
|
{
|
||||||
total_minutes = -total_minutes;
|
total_minutes = -total_minutes;
|
||||||
sign = '-';
|
dest.push_back('-');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sign = '+';
|
dest.push_back('+');
|
||||||
}
|
}
|
||||||
|
|
||||||
int h = total_minutes / 60;
|
fmt_helper::pad2(total_minutes / 60, dest); // hours
|
||||||
int m = total_minutes % 60;
|
|
||||||
dest.push_back(sign);
|
|
||||||
fmt_helper::pad2(h, dest);
|
|
||||||
dest.push_back(':');
|
dest.push_back(':');
|
||||||
fmt_helper::pad2(m, dest);
|
fmt_helper::pad2(total_minutes % 60, dest); // minutes
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -371,7 +375,6 @@ class t_formatter SPDLOG_FINAL : public flag_formatter
|
|||||||
{
|
{
|
||||||
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
|
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
|
||||||
{
|
{
|
||||||
|
|
||||||
fmt_helper::pad6(msg.thread_id, dest);
|
fmt_helper::pad6(msg.thread_id, dest);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -390,7 +393,6 @@ class i_formatter SPDLOG_FINAL : public flag_formatter
|
|||||||
{
|
{
|
||||||
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
|
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
|
||||||
{
|
{
|
||||||
|
|
||||||
fmt_helper::pad6(msg.msg_id, dest);
|
fmt_helper::pad6(msg.msg_id, dest);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -462,39 +464,48 @@ class full_formatter SPDLOG_FINAL : public flag_formatter
|
|||||||
{
|
{
|
||||||
#ifndef SPDLOG_NO_DATETIME
|
#ifndef SPDLOG_NO_DATETIME
|
||||||
|
|
||||||
// each second cache the header
|
// cache the date/time part for the next second.
|
||||||
auto duration = msg.time.time_since_epoch();
|
auto duration = msg.time.time_since_epoch();
|
||||||
auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
|
std::chrono::seconds seconds = std::chrono::duration_cast<std::chrono::seconds>(duration);
|
||||||
if (cached_header_.size() == 0 || cached_seconds_ts_ != seconds)
|
|
||||||
|
if (cache_timestamp_ != seconds || cached_datetime_.size() == 0)
|
||||||
{
|
{
|
||||||
cached_header_ = fmt::memory_buffer();
|
cached_datetime_.resize(0);
|
||||||
cached_header_.push_back('[');
|
cached_datetime_.push_back('[');
|
||||||
fmt_helper::append_int(tm_time.tm_year + 1900, cached_header_);
|
fmt_helper::append_int(tm_time.tm_year + 1900, cached_datetime_);
|
||||||
cached_header_.push_back('-');
|
cached_datetime_.push_back('-');
|
||||||
|
|
||||||
fmt_helper::pad2(tm_time.tm_mon + 1, cached_header_);
|
fmt_helper::pad2(tm_time.tm_mon + 1, cached_datetime_);
|
||||||
cached_header_.push_back('-');
|
cached_datetime_.push_back('-');
|
||||||
|
|
||||||
fmt_helper::pad2(tm_time.tm_mday, cached_header_);
|
fmt_helper::pad2(tm_time.tm_mday, cached_datetime_);
|
||||||
cached_header_.push_back(' ');
|
cached_datetime_.push_back(' ');
|
||||||
|
|
||||||
fmt_helper::pad2(tm_time.tm_hour, cached_header_);
|
fmt_helper::pad2(tm_time.tm_hour, cached_datetime_);
|
||||||
cached_header_.push_back(':');
|
cached_datetime_.push_back(':');
|
||||||
|
|
||||||
fmt_helper::pad2(tm_time.tm_min, cached_header_);
|
fmt_helper::pad2(tm_time.tm_min, cached_datetime_);
|
||||||
cached_header_.push_back(':');
|
cached_datetime_.push_back(':');
|
||||||
|
|
||||||
fmt_helper::pad2(tm_time.tm_sec, cached_header_);
|
fmt_helper::pad2(tm_time.tm_sec, cached_datetime_);
|
||||||
cached_header_.push_back('.');
|
cached_datetime_.push_back('.');
|
||||||
|
|
||||||
cached_seconds_ts_ = seconds;
|
cache_timestamp_ = seconds;
|
||||||
}
|
}
|
||||||
fmt_helper::append_buf(cached_header_, dest);
|
fmt_helper::append_buf(cached_datetime_, dest);
|
||||||
|
|
||||||
|
// cache the millis part for the next milli.
|
||||||
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 1000;
|
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 1000;
|
||||||
fmt_helper::pad3(static_cast<int>(millis), dest);
|
if(millis != millis_cache_timestamp_ || cached_millis_.size() == 0)
|
||||||
dest.push_back(']');
|
{
|
||||||
dest.push_back(' ');
|
cached_millis_.resize(0);
|
||||||
|
fmt_helper::pad3(millis, cached_millis_);
|
||||||
|
cached_millis_.push_back(']');
|
||||||
|
cached_millis_.push_back(' ');
|
||||||
|
millis_cache_timestamp_ = millis;
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt_helper::append_buf(cached_millis_, dest);
|
||||||
#else // no datetime needed
|
#else // no datetime needed
|
||||||
(void)tm_time;
|
(void)tm_time;
|
||||||
#endif
|
#endif
|
||||||
@ -517,8 +528,10 @@ class full_formatter SPDLOG_FINAL : public flag_formatter
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::chrono::seconds::rep cached_seconds_ts_{0};
|
std::chrono::seconds cache_timestamp_ {0};
|
||||||
fmt::memory_buffer cached_header_;
|
std::chrono::milliseconds::rep millis_cache_timestamp_ {0};
|
||||||
|
fmt::basic_memory_buffer<char, 128> cached_datetime_;
|
||||||
|
fmt::basic_memory_buffer<char, 8> cached_millis_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace details
|
} // namespace details
|
||||||
@ -526,14 +539,14 @@ private:
|
|||||||
class pattern_formatter SPDLOG_FINAL : public formatter
|
class pattern_formatter SPDLOG_FINAL : public formatter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit pattern_formatter(const std::string &pattern, pattern_time_type pattern_time = pattern_time_type::local,
|
explicit pattern_formatter(const std::string &pattern, pattern_time_type time_type = pattern_time_type::local,
|
||||||
std::string eol = spdlog::details::os::default_eol)
|
std::string eol = spdlog::details::os::default_eol)
|
||||||
: eol_(std::move(eol))
|
: eol_(std::move(eol))
|
||||||
, pattern_time_(pattern_time)
|
, pattern_time_type_(time_type)
|
||||||
, last_log_secs_(0)
|
, last_log_secs_(0)
|
||||||
{
|
{
|
||||||
std::memset(&cached_tm_, 0, sizeof(cached_tm_));
|
std::memset(&cached_tm_, 0, sizeof(cached_tm_));
|
||||||
compile_pattern(pattern);
|
compile_pattern_(pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
pattern_formatter(const pattern_formatter &) = default;
|
pattern_formatter(const pattern_formatter &) = default;
|
||||||
@ -544,7 +557,7 @@ public:
|
|||||||
auto secs = std::chrono::duration_cast<std::chrono::seconds>(msg.time.time_since_epoch());
|
auto secs = std::chrono::duration_cast<std::chrono::seconds>(msg.time.time_since_epoch());
|
||||||
if (secs != last_log_secs_)
|
if (secs != last_log_secs_)
|
||||||
{
|
{
|
||||||
cached_tm_ = get_time(msg);
|
cached_tm_ = get_time_(msg);
|
||||||
last_log_secs_ = secs;
|
last_log_secs_ = secs;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -558,21 +571,22 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
const std::string eol_;
|
const std::string eol_;
|
||||||
const pattern_time_type pattern_time_;
|
pattern_time_type pattern_time_type_;
|
||||||
std::tm cached_tm_;
|
std::tm cached_tm_;
|
||||||
std::chrono::seconds last_log_secs_;
|
std::chrono::seconds last_log_secs_;
|
||||||
|
|
||||||
std::vector<std::unique_ptr<details::flag_formatter>> formatters_;
|
std::vector<std::unique_ptr<details::flag_formatter>> formatters_;
|
||||||
std::tm get_time(const details::log_msg &msg)
|
|
||||||
|
std::tm get_time_(const details::log_msg &msg)
|
||||||
{
|
{
|
||||||
if (pattern_time_ == pattern_time_type::local)
|
if (pattern_time_type_ == pattern_time_type::local)
|
||||||
{
|
{
|
||||||
return details::os::localtime(log_clock::to_time_t(msg.time));
|
return details::os::localtime(log_clock::to_time_t(msg.time));
|
||||||
}
|
}
|
||||||
return details::os::gmtime(log_clock::to_time_t(msg.time));
|
return details::os::gmtime(log_clock::to_time_t(msg.time));
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_flag(char flag)
|
void handle_flag_(char flag)
|
||||||
{
|
{
|
||||||
switch (flag)
|
switch (flag)
|
||||||
{
|
{
|
||||||
@ -717,7 +731,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void compile_pattern(const std::string &pattern)
|
void compile_pattern_(const std::string &pattern)
|
||||||
{
|
{
|
||||||
auto end = pattern.end();
|
auto end = pattern.end();
|
||||||
std::unique_ptr<details::aggregate_formatter> user_chars;
|
std::unique_ptr<details::aggregate_formatter> user_chars;
|
||||||
@ -732,7 +746,7 @@ private:
|
|||||||
// if(
|
// if(
|
||||||
if (++it != end)
|
if (++it != end)
|
||||||
{
|
{
|
||||||
handle_flag(*it);
|
handle_flag_(*it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
@ -36,7 +36,7 @@ public:
|
|||||||
{
|
{
|
||||||
std::lock_guard<Mutex> lock(mutex_);
|
std::lock_guard<Mutex> lock(mutex_);
|
||||||
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] = new_logger;
|
loggers_[logger_name] = new_logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,11 +44,11 @@ public:
|
|||||||
{
|
{
|
||||||
std::lock_guard<Mutex> lock(mutex_);
|
std::lock_guard<Mutex> lock(mutex_);
|
||||||
auto logger_name = new_logger->name();
|
auto logger_name = new_logger->name();
|
||||||
throw_if_exists(logger_name);
|
throw_if_exists_(logger_name);
|
||||||
|
|
||||||
// create default formatter if not exists
|
// create default formatter if not exists
|
||||||
|
|
||||||
new_logger->set_pattern(formatter_pattern_);
|
new_logger->set_formatter<pattern_formatter>(formatter_pattern_, pattern_time_type_);
|
||||||
|
|
||||||
if (err_handler_)
|
if (err_handler_)
|
||||||
{
|
{
|
||||||
@ -81,13 +81,14 @@ public:
|
|||||||
return tp_;
|
return tp_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_pattern(const std::string &pattern)
|
void set_pattern(const std::string &pattern, pattern_time_type time_type)
|
||||||
{
|
{
|
||||||
std::lock_guard<Mutex> lock(mutex_);
|
std::lock_guard<Mutex> lock(mutex_);
|
||||||
formatter_pattern_ = pattern;
|
formatter_pattern_ = pattern;
|
||||||
|
pattern_time_type_ = time_type;
|
||||||
for (auto &l : loggers_)
|
for (auto &l : loggers_)
|
||||||
{
|
{
|
||||||
l.second->set_pattern(pattern);
|
l.second->set_pattern(pattern, time_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,7 +163,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
registry_t<Mutex>() = default;
|
registry_t<Mutex>() = default;
|
||||||
|
|
||||||
void throw_if_exists(const std::string &logger_name)
|
void throw_if_exists_(const std::string &logger_name)
|
||||||
{
|
{
|
||||||
if (loggers_.find(logger_name) != loggers_.end())
|
if (loggers_.find(logger_name) != loggers_.end())
|
||||||
{
|
{
|
||||||
@ -174,6 +175,7 @@ private:
|
|||||||
Mutex tp_mutex_;
|
Mutex tp_mutex_;
|
||||||
std::unordered_map<std::string, std::shared_ptr<logger>> loggers_;
|
std::unordered_map<std::string, std::shared_ptr<logger>> loggers_;
|
||||||
std::string formatter_pattern_ = "%+";
|
std::string formatter_pattern_ = "%+";
|
||||||
|
pattern_time_type pattern_time_type_ = pattern_time_type::local;
|
||||||
level::level_enum level_ = level::info;
|
level::level_enum level_ = level::info;
|
||||||
level::level_enum flush_level_ = level::off;
|
level::level_enum flush_level_ = level::off;
|
||||||
log_err_handler err_handler_;
|
log_err_handler err_handler_;
|
||||||
|
@ -29,7 +29,7 @@ struct async_msg
|
|||||||
level::level_enum level;
|
level::level_enum level;
|
||||||
log_clock::time_point time;
|
log_clock::time_point time;
|
||||||
size_t thread_id;
|
size_t thread_id;
|
||||||
fmt::basic_memory_buffer<char, 128> raw;
|
fmt::basic_memory_buffer<char, 176> raw;
|
||||||
|
|
||||||
size_t msg_id;
|
size_t msg_id;
|
||||||
async_logger_ptr worker_ptr;
|
async_logger_ptr worker_ptr;
|
||||||
@ -95,7 +95,7 @@ public:
|
|||||||
}
|
}
|
||||||
for (size_t i = 0; i < threads_n; i++)
|
for (size_t i = 0; i < threads_n; i++)
|
||||||
{
|
{
|
||||||
threads_.emplace_back(std::bind(&thread_pool::worker_loop, this));
|
threads_.emplace_back(std::bind(&thread_pool::worker_loop_, this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,14 +106,13 @@ public:
|
|||||||
{
|
{
|
||||||
for (size_t i = 0; i < threads_.size(); i++)
|
for (size_t i = 0; i < threads_.size(); i++)
|
||||||
{
|
{
|
||||||
post_async_msg(async_msg(async_msg_type::terminate), async_overflow_policy::block_retry);
|
post_async_msg_(async_msg(async_msg_type::terminate), async_overflow_policy::block);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &t : threads_)
|
for (auto &t : threads_)
|
||||||
{
|
{
|
||||||
t.join();
|
t.join();
|
||||||
}
|
}
|
||||||
// std::cout << "~thread_pool() msg_counter_: " << msg_counter_ << std::endl;
|
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
@ -123,12 +122,12 @@ public:
|
|||||||
void post_log(async_logger_ptr &&worker_ptr, details::log_msg &&msg, async_overflow_policy overflow_policy)
|
void post_log(async_logger_ptr &&worker_ptr, details::log_msg &&msg, async_overflow_policy overflow_policy)
|
||||||
{
|
{
|
||||||
async_msg async_m(std::forward<async_logger_ptr>(worker_ptr), async_msg_type::log, std::forward<log_msg>(msg));
|
async_msg async_m(std::forward<async_logger_ptr>(worker_ptr), async_msg_type::log, std::forward<log_msg>(msg));
|
||||||
post_async_msg(std::move(async_m), overflow_policy);
|
post_async_msg_(std::move(async_m), overflow_policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
void post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy)
|
void post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy)
|
||||||
{
|
{
|
||||||
post_async_msg(async_msg(std::move(worker_ptr), async_msg_type::flush), overflow_policy);
|
post_async_msg_(async_msg(std::move(worker_ptr), async_msg_type::flush), overflow_policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -136,9 +135,9 @@ private:
|
|||||||
|
|
||||||
std::vector<std::thread> threads_;
|
std::vector<std::thread> threads_;
|
||||||
|
|
||||||
void post_async_msg(async_msg &&new_msg, async_overflow_policy overflow_policy)
|
void post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy)
|
||||||
{
|
{
|
||||||
if (overflow_policy == async_overflow_policy::block_retry)
|
if (overflow_policy == async_overflow_policy::block)
|
||||||
{
|
{
|
||||||
q_.enqueue(std::move(new_msg));
|
q_.enqueue(std::move(new_msg));
|
||||||
}
|
}
|
||||||
@ -148,14 +147,14 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void worker_loop()
|
void worker_loop_()
|
||||||
{
|
{
|
||||||
while (process_next_msg()) {};
|
while (process_next_msg_()) {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// process next message in the queue
|
// process next message in the queue
|
||||||
// return true if this thread should still be active (while no terminate msg was received)
|
// return true if this thread should still be active (while no terminate msg was received)
|
||||||
bool process_next_msg()
|
bool process_next_msg_()
|
||||||
{
|
{
|
||||||
async_msg incoming_async_msg;
|
async_msg incoming_async_msg;
|
||||||
bool dequeued = q_.dequeue_for(incoming_async_msg, std::chrono::seconds(10));
|
bool dequeued = q_.dequeue_for(incoming_async_msg, std::chrono::seconds(10));
|
||||||
|
@ -196,12 +196,22 @@
|
|||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// An implementation of declval for pre-C++11 compilers such as gcc 4.
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
// An implementation of declval for pre-C++11 compilers such as gcc 4.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
typename std::add_rvalue_reference<T>::type declval() FMT_NOEXCEPT;
|
typename std::add_rvalue_reference<T>::type declval() FMT_NOEXCEPT;
|
||||||
|
|
||||||
|
// Casts nonnegative integer to unsigned.
|
||||||
|
template<typename Int>
|
||||||
|
FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value)
|
||||||
|
{
|
||||||
|
FMT_ASSERT(value >= 0, "negative value");
|
||||||
|
return static_cast<typename std::make_unsigned<Int>::type>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
/**
|
/**
|
||||||
An implementation of ``std::basic_string_view`` for pre-C++17. It provides a
|
An implementation of ``std::basic_string_view`` for pre-C++17. It provides a
|
||||||
subset of the API. ``fmt::basic_string_view`` is used for format strings even
|
subset of the API. ``fmt::basic_string_view`` is used for format strings even
|
||||||
@ -242,7 +252,7 @@ public:
|
|||||||
FMT_CONSTEXPR basic_string_view() FMT_NOEXCEPT : data_(FMT_NULL), size_(0) {}
|
FMT_CONSTEXPR basic_string_view() FMT_NOEXCEPT : data_(FMT_NULL), size_(0) {}
|
||||||
|
|
||||||
/** Constructs a string reference object from a C string and a size. */
|
/** Constructs a string reference object from a C string and a size. */
|
||||||
FMT_CONSTEXPR basic_string_view(const Char *s, size_t str_size) FMT_NOEXCEPT : data_(s), size_(str_size) {}
|
FMT_CONSTEXPR basic_string_view(const Char *s, size_t count) FMT_NOEXCEPT : data_(s), size_(count) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
@ -354,11 +364,7 @@ private:
|
|||||||
std::size_t capacity_;
|
std::size_t capacity_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
basic_buffer(T *p = FMT_NULL, std::size_t buf_size = 0, std::size_t buf_capacity = 0) FMT_NOEXCEPT : ptr_(p),
|
basic_buffer(T *p = FMT_NULL, std::size_t sz = 0, std::size_t cap = 0) FMT_NOEXCEPT : ptr_(p), size_(sz), capacity_(cap) {}
|
||||||
size_(buf_size),
|
|
||||||
capacity_(buf_capacity)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sets the buffer data and capacity. */
|
/** Sets the buffer data and capacity. */
|
||||||
void set(T *buf_data, std::size_t buf_capacity) FMT_NOEXCEPT
|
void set(T *buf_data, std::size_t buf_capacity) FMT_NOEXCEPT
|
||||||
@ -418,11 +424,11 @@ public:
|
|||||||
size_ = new_size;
|
size_ = new_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Reserves space to store at least *buf_capacity* elements. */
|
/** Reserves space to store at least *capacity* elements. */
|
||||||
void reserve(std::size_t buf_capacity)
|
void reserve(std::size_t new_capacity)
|
||||||
{
|
{
|
||||||
if (buf_capacity > capacity_)
|
if (new_capacity > capacity_)
|
||||||
grow(buf_capacity);
|
grow(new_capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back(const T &value)
|
void push_back(const T &value)
|
||||||
@ -893,7 +899,7 @@ public:
|
|||||||
// Advances the begin iterator to ``it``.
|
// Advances the begin iterator to ``it``.
|
||||||
FMT_CONSTEXPR void advance_to(iterator it)
|
FMT_CONSTEXPR void advance_to(iterator it)
|
||||||
{
|
{
|
||||||
format_str_.remove_prefix(it - begin());
|
format_str_.remove_prefix(internal::to_unsigned(it - begin()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the next argument index.
|
// Returns the next argument index.
|
||||||
@ -1135,13 +1141,13 @@ struct get_type
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename Context>
|
template<typename Context>
|
||||||
FMT_CONSTEXPR uint64_t get_types()
|
FMT_CONSTEXPR unsigned long long get_types()
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Context, typename Arg, typename... Args>
|
template<typename Context, typename Arg, typename... Args>
|
||||||
FMT_CONSTEXPR uint64_t get_types()
|
FMT_CONSTEXPR unsigned long long get_types()
|
||||||
{
|
{
|
||||||
return get_type<Context, Arg>::value | (get_types<Context, Args...>() << 4);
|
return get_type<Context, Arg>::value | (get_types<Context, Args...>() << 4);
|
||||||
}
|
}
|
||||||
@ -1187,27 +1193,29 @@ private:
|
|||||||
typedef typename std::conditional<IS_PACKED, internal::value<Context>, basic_format_arg<Context>>::type value_type;
|
typedef typename std::conditional<IS_PACKED, internal::value<Context>, basic_format_arg<Context>>::type value_type;
|
||||||
|
|
||||||
// If the arguments are not packed, add one more element to mark the end.
|
// If the arguments are not packed, add one more element to mark the end.
|
||||||
value_type data_[NUM_ARGS + (IS_PACKED && NUM_ARGS != 0 ? 0 : 1)];
|
static const size_t DATA_SIZE = NUM_ARGS + (IS_PACKED && NUM_ARGS != 0 ? 0 : 1);
|
||||||
|
value_type data_[DATA_SIZE];
|
||||||
|
|
||||||
friend class basic_format_args<Context>;
|
friend class basic_format_args<Context>;
|
||||||
|
|
||||||
static FMT_CONSTEXPR int64_t get_types()
|
static FMT_CONSTEXPR long long get_types()
|
||||||
{
|
{
|
||||||
return IS_PACKED ? static_cast<int64_t>(internal::get_types<Context, Args...>()) : -static_cast<int64_t>(NUM_ARGS);
|
return IS_PACKED ? static_cast<long long>(internal::get_types<Context, Args...>()) : -static_cast<long long>(NUM_ARGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
#if FMT_USE_CONSTEXPR
|
#if FMT_USE_CONSTEXPR
|
||||||
static constexpr int64_t TYPES = get_types();
|
static constexpr long long TYPES = get_types();
|
||||||
#else
|
#else
|
||||||
static const int64_t TYPES;
|
static const long long TYPES;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 405
|
#if (FMT_GCC_VERSION && FMT_GCC_VERSION <= 405) || (FMT_MSC_VER && FMT_MSC_VER <= 1800)
|
||||||
// Workaround an array initialization bug in gcc 4.5 and earlier.
|
// Workaround array initialization issues in gcc <= 4.5 and MSVC <= 2013.
|
||||||
format_arg_store(const Args &... args)
|
format_arg_store(const Args &... args)
|
||||||
{
|
{
|
||||||
data_ = {internal::make_arg<IS_PACKED, Context>(args)...};
|
value_type init[DATA_SIZE] = {internal::make_arg<IS_PACKED, Context>(args)...};
|
||||||
|
std::memcpy(data_, init, sizeof(init));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
format_arg_store(const Args &... args)
|
format_arg_store(const Args &... args)
|
||||||
@ -1219,7 +1227,7 @@ public:
|
|||||||
|
|
||||||
#if !FMT_USE_CONSTEXPR
|
#if !FMT_USE_CONSTEXPR
|
||||||
template<typename Context, typename... Args>
|
template<typename Context, typename... Args>
|
||||||
const int64_t format_arg_store<Context, Args...>::TYPES = get_types();
|
const long long format_arg_store<Context, Args...>::TYPES = get_types();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1252,7 +1260,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
// To reduce compiled code size per formatting function call, types of first
|
// To reduce compiled code size per formatting function call, types of first
|
||||||
// max_packed_args arguments are passed in the types_ field.
|
// max_packed_args arguments are passed in the types_ field.
|
||||||
uint64_t types_;
|
unsigned long long types_;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
// If the number of arguments is less than max_packed_args, the argument
|
// If the number of arguments is less than max_packed_args, the argument
|
||||||
@ -1267,7 +1275,7 @@ private:
|
|||||||
typename internal::type type(unsigned index) const
|
typename internal::type type(unsigned index) const
|
||||||
{
|
{
|
||||||
unsigned shift = index * 4;
|
unsigned shift = index * 4;
|
||||||
uint64_t mask = 0xf;
|
unsigned long long mask = 0xf;
|
||||||
return static_cast<typename internal::type>((types_ & (mask << shift)) >> shift);
|
return static_cast<typename internal::type>((types_ & (mask << shift)) >> shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1284,10 +1292,10 @@ private:
|
|||||||
|
|
||||||
format_arg do_get(size_type index) const
|
format_arg do_get(size_type index) const
|
||||||
{
|
{
|
||||||
int64_t signed_types = static_cast<int64_t>(types_);
|
long long signed_types = static_cast<long long>(types_);
|
||||||
if (signed_types < 0)
|
if (signed_types < 0)
|
||||||
{
|
{
|
||||||
uint64_t num_args = -signed_types;
|
unsigned long long num_args = static_cast<unsigned long long>(-signed_types);
|
||||||
return index < num_args ? args_[index] : format_arg();
|
return index < num_args ? args_[index] : format_arg();
|
||||||
}
|
}
|
||||||
format_arg arg;
|
format_arg arg;
|
||||||
@ -1314,7 +1322,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
basic_format_args(const format_arg_store<Context, Args...> &store)
|
basic_format_args(const format_arg_store<Context, Args...> &store)
|
||||||
: types_(store.TYPES)
|
: types_(static_cast<unsigned long long>(store.TYPES))
|
||||||
{
|
{
|
||||||
set_data(store.data_);
|
set_data(store.data_);
|
||||||
}
|
}
|
||||||
@ -1328,8 +1336,8 @@ public:
|
|||||||
|
|
||||||
unsigned max_size() const
|
unsigned max_size() const
|
||||||
{
|
{
|
||||||
int64_t signed_types = static_cast<int64_t>(types_);
|
long long signed_types = static_cast<long long>(types_);
|
||||||
return static_cast<unsigned>(signed_types < 0 ? -signed_types : static_cast<int64_t>(internal::max_packed_args));
|
return static_cast<unsigned>(signed_types < 0 ? -signed_types : static_cast<long long>(internal::max_packed_args));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1414,6 +1422,8 @@ inline internal::named_arg<T, wchar_t> arg(wstring_view name, const T &arg)
|
|||||||
template<typename S, typename T, typename Char>
|
template<typename S, typename T, typename Char>
|
||||||
void arg(S, internal::named_arg<T, Char>) FMT_DELETED;
|
void arg(S, internal::named_arg<T, Char>) FMT_DELETED;
|
||||||
|
|
||||||
|
#ifndef FMT_EXTENDED_COLORS
|
||||||
|
// color and (v)print_colored are deprecated.
|
||||||
enum color
|
enum color
|
||||||
{
|
{
|
||||||
black,
|
black,
|
||||||
@ -1425,27 +1435,19 @@ enum color
|
|||||||
cyan,
|
cyan,
|
||||||
white
|
white
|
||||||
};
|
};
|
||||||
|
|
||||||
FMT_API void vprint_colored(color c, string_view format, format_args args);
|
FMT_API void vprint_colored(color c, string_view format, format_args args);
|
||||||
FMT_API void vprint_colored(color c, wstring_view format, wformat_args args);
|
FMT_API void vprint_colored(color c, wstring_view format, wformat_args args);
|
||||||
|
|
||||||
/**
|
|
||||||
Formats a string and prints it to stdout using ANSI escape sequences to
|
|
||||||
specify color (experimental).
|
|
||||||
Example:
|
|
||||||
fmt::print_colored(fmt::RED, "Elapsed time: {0:.2f} seconds", 1.23);
|
|
||||||
*/
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline void print_colored(color c, string_view format_str, const Args &... args)
|
inline void print_colored(color c, string_view format_str, const Args &... args)
|
||||||
{
|
{
|
||||||
vprint_colored(c, format_str, make_format_args(args...));
|
vprint_colored(c, format_str, make_format_args(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline void print_colored(color c, wstring_view format_str, const Args &... args)
|
inline void print_colored(color c, wstring_view format_str, const Args &... args)
|
||||||
{
|
{
|
||||||
vprint_colored(c, format_str, make_format_args<wformat_context>(args...));
|
vprint_colored(c, format_str, make_format_args<wformat_context>(args...));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
format_context::iterator vformat_to(internal::buffer &buf, string_view format_str, format_args args);
|
format_context::iterator vformat_to(internal::buffer &buf, string_view format_str, format_args args);
|
||||||
wformat_context::iterator vformat_to(internal::wbuffer &buf, wstring_view format_str, wformat_args args);
|
wformat_context::iterator vformat_to(internal::wbuffer &buf, wstring_view format_str, wformat_args args);
|
||||||
|
@ -89,9 +89,6 @@ inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...)
|
|||||||
#define FMT_SWPRINTF swprintf
|
#define FMT_SWPRINTF swprintf
|
||||||
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
|
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
|
||||||
|
|
||||||
const char RESET_COLOR[] = "\x1b[0m";
|
|
||||||
const wchar_t WRESET_COLOR[] = L"\x1b[0m";
|
|
||||||
|
|
||||||
typedef void (*FormatFunc)(internal::buffer &, int, string_view);
|
typedef void (*FormatFunc)(internal::buffer &, int, string_view);
|
||||||
|
|
||||||
// Portable thread-safe version of strerror.
|
// Portable thread-safe version of strerror.
|
||||||
@ -300,6 +297,11 @@ const int16_t basic_data<T>::POW10_EXPONENTS[] = {-1220, -1193, -1166, -1140, -1
|
|||||||
-289, -263, -236, -210, -183, -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, 375,
|
-289, -263, -236, -210, -183, -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, 375,
|
||||||
402, 428, 455, 481, 508, 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066};
|
402, 428, 455, 481, 508, 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const char basic_data<T>::RESET_COLOR[] = "\x1b[0m";
|
||||||
|
template<typename T>
|
||||||
|
const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m";
|
||||||
|
|
||||||
FMT_FUNC fp operator*(fp x, fp y)
|
FMT_FUNC fp operator*(fp x, fp y)
|
||||||
{
|
{
|
||||||
// Multiply 32-bit parts of significands.
|
// Multiply 32-bit parts of significands.
|
||||||
@ -502,13 +504,14 @@ FMT_FUNC void vprint(wstring_view format_str, wformat_args args)
|
|||||||
vprint(stdout, format_str, args);
|
vprint(stdout, format_str, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef FMT_EXTENDED_COLORS
|
||||||
FMT_FUNC void vprint_colored(color c, string_view format, format_args args)
|
FMT_FUNC void vprint_colored(color c, string_view format, format_args args)
|
||||||
{
|
{
|
||||||
char escape[] = "\x1b[30m";
|
char escape[] = "\x1b[30m";
|
||||||
escape[3] = static_cast<char>('0' + c);
|
escape[3] = static_cast<char>('0' + c);
|
||||||
std::fputs(escape, stdout);
|
std::fputs(escape, stdout);
|
||||||
vprint(format, args);
|
vprint(format, args);
|
||||||
std::fputs(RESET_COLOR, stdout);
|
std::fputs(internal::data::RESET_COLOR, stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_FUNC void vprint_colored(color c, wstring_view format, wformat_args args)
|
FMT_FUNC void vprint_colored(color c, wstring_view format, wformat_args args)
|
||||||
@ -517,8 +520,48 @@ FMT_FUNC void vprint_colored(color c, wstring_view format, wformat_args args)
|
|||||||
escape[3] = static_cast<wchar_t>('0' + c);
|
escape[3] = static_cast<wchar_t>('0' + c);
|
||||||
std::fputws(escape, stdout);
|
std::fputws(escape, stdout);
|
||||||
vprint(format, args);
|
vprint(format, args);
|
||||||
std::fputws(WRESET_COLOR, stdout);
|
std::fputws(internal::data::WRESET_COLOR, stdout);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
namespace internal {
|
||||||
|
FMT_CONSTEXPR void to_esc(uint8_t c, char out[], int offset)
|
||||||
|
{
|
||||||
|
out[offset + 0] = static_cast<char>('0' + c / 100);
|
||||||
|
out[offset + 1] = static_cast<char>('0' + c / 10 % 10);
|
||||||
|
out[offset + 2] = static_cast<char>('0' + c % 10);
|
||||||
|
}
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
FMT_FUNC void vprint_rgb(rgb fd, string_view format, format_args args)
|
||||||
|
{
|
||||||
|
char escape_fd[] = "\x1b[38;2;000;000;000m";
|
||||||
|
internal::to_esc(fd.r, escape_fd, 7);
|
||||||
|
internal::to_esc(fd.g, escape_fd, 11);
|
||||||
|
internal::to_esc(fd.b, escape_fd, 15);
|
||||||
|
|
||||||
|
std::fputs(escape_fd, stdout);
|
||||||
|
vprint(format, args);
|
||||||
|
std::fputs(internal::data::RESET_COLOR, stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_FUNC void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args)
|
||||||
|
{
|
||||||
|
char escape_fd[] = "\x1b[38;2;000;000;000m"; // foreground color
|
||||||
|
char escape_bg[] = "\x1b[48;2;000;000;000m"; // background color
|
||||||
|
internal::to_esc(fd.r, escape_fd, 7);
|
||||||
|
internal::to_esc(fd.g, escape_fd, 11);
|
||||||
|
internal::to_esc(fd.b, escape_fd, 15);
|
||||||
|
|
||||||
|
internal::to_esc(bg.r, escape_bg, 7);
|
||||||
|
internal::to_esc(bg.g, escape_bg, 11);
|
||||||
|
internal::to_esc(bg.b, escape_bg, 15);
|
||||||
|
|
||||||
|
std::fputs(escape_fd, stdout);
|
||||||
|
std::fputs(escape_bg, stdout);
|
||||||
|
vprint(format, args);
|
||||||
|
std::fputs(internal::data::RESET_COLOR, stdout);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
FMT_FUNC locale locale_provider::locale()
|
FMT_FUNC locale locale_provider::locale()
|
||||||
{
|
{
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
// Formatting library for C++
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// For the license information refer to format.h.
|
|
||||||
|
|
||||||
#include "fmt/format-inl.h"
|
|
||||||
|
|
||||||
namespace fmt {
|
|
||||||
|
|
||||||
template struct internal::basic_data<void>;
|
|
||||||
|
|
||||||
// Explicit instantiations for char.
|
|
||||||
|
|
||||||
template FMT_API char internal::thousands_sep(locale_provider *lp);
|
|
||||||
|
|
||||||
template void basic_fixed_buffer<char>::grow(std::size_t);
|
|
||||||
|
|
||||||
template void internal::arg_map<format_context>::init(
|
|
||||||
const basic_format_args<format_context> &args);
|
|
||||||
|
|
||||||
template FMT_API int internal::char_traits<char>::format_float(
|
|
||||||
char *buffer, std::size_t size, const char *format,
|
|
||||||
unsigned width, int precision, double value);
|
|
||||||
|
|
||||||
template FMT_API int internal::char_traits<char>::format_float(
|
|
||||||
char *buffer, std::size_t size, const char *format,
|
|
||||||
unsigned width, int precision, long double value);
|
|
||||||
|
|
||||||
// Explicit instantiations for wchar_t.
|
|
||||||
|
|
||||||
template FMT_API wchar_t internal::thousands_sep(locale_provider *lp);
|
|
||||||
|
|
||||||
template void basic_fixed_buffer<wchar_t>::grow(std::size_t);
|
|
||||||
|
|
||||||
template void internal::arg_map<wformat_context>::init(const wformat_args &args);
|
|
||||||
|
|
||||||
template FMT_API int internal::char_traits<wchar_t>::format_float(
|
|
||||||
wchar_t *buffer, std::size_t size, const wchar_t *format,
|
|
||||||
unsigned width, int precision, double value);
|
|
||||||
|
|
||||||
template FMT_API int internal::char_traits<wchar_t>::format_float(
|
|
||||||
wchar_t *buffer, std::size_t size, const wchar_t *format,
|
|
||||||
unsigned width, int precision, long double value);
|
|
||||||
} // namespace fmt
|
|
@ -168,7 +168,7 @@ FMT_END_NAMESPACE
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// A workaround for gcc 4.4 that doesn't support union members with ctors.
|
// A workaround for gcc 4.4 that doesn't support union members with ctors.
|
||||||
#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 404
|
#if (FMT_GCC_VERSION && FMT_GCC_VERSION <= 404) || (FMT_MSC_VER && FMT_MSC_VER <= 1800)
|
||||||
#define FMT_UNION struct
|
#define FMT_UNION struct
|
||||||
#else
|
#else
|
||||||
#define FMT_UNION union
|
#define FMT_UNION union
|
||||||
@ -531,14 +531,6 @@ public:
|
|||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
// Casts nonnegative integer to unsigned.
|
|
||||||
template<typename Int>
|
|
||||||
FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value)
|
|
||||||
{
|
|
||||||
FMT_ASSERT(value >= 0, "negative value");
|
|
||||||
return static_cast<typename std::make_unsigned<Int>::type>(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if FMT_SECURE_SCL
|
#if FMT_SECURE_SCL
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct checked
|
struct checked
|
||||||
@ -1072,6 +1064,8 @@ struct FMT_API basic_data
|
|||||||
static const uint64_t POW10_SIGNIFICANDS[];
|
static const uint64_t POW10_SIGNIFICANDS[];
|
||||||
static const int16_t POW10_EXPONENTS[];
|
static const int16_t POW10_EXPONENTS[];
|
||||||
static const char DIGITS[];
|
static const char DIGITS[];
|
||||||
|
static const char RESET_COLOR[];
|
||||||
|
static const wchar_t WRESET_COLOR[];
|
||||||
};
|
};
|
||||||
|
|
||||||
#if FMT_USE_EXTERN_TEMPLATES
|
#if FMT_USE_EXTERN_TEMPLATES
|
||||||
@ -1172,7 +1166,7 @@ public:
|
|||||||
uint64_t t = ((1ULL << (32 + a)) / data::POWERS_OF_10_32[n] + 1 - n / 9);
|
uint64_t t = ((1ULL << (32 + a)) / data::POWERS_OF_10_32[n] + 1 - n / 9);
|
||||||
t = ((t * u) >> a) + n / 5 * 4;
|
t = ((t * u) >> a) + n / 5 * 4;
|
||||||
write_pair(0, t >> 32);
|
write_pair(0, t >> 32);
|
||||||
for (int i = 2; i < N; i += 2)
|
for (unsigned i = 2; i < N; i += 2)
|
||||||
{
|
{
|
||||||
t = 100ULL * static_cast<uint32_t>(t);
|
t = 100ULL * static_cast<uint32_t>(t);
|
||||||
write_pair(i, t >> 32);
|
write_pair(i, t >> 32);
|
||||||
@ -1561,31 +1555,6 @@ struct align_spec : empty_spec
|
|||||||
template<typename Char>
|
template<typename Char>
|
||||||
class basic_format_specs : public align_spec
|
class basic_format_specs : public align_spec
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
template<typename FillChar>
|
|
||||||
typename std::enable_if<std::is_same<FillChar, Char>::value || std::is_same<FillChar, char>::value, void>::type set(
|
|
||||||
fill_spec<FillChar> fill)
|
|
||||||
{
|
|
||||||
fill_ = fill.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
void set(width_spec width)
|
|
||||||
{
|
|
||||||
width_ = width.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
void set(type_spec type)
|
|
||||||
{
|
|
||||||
type_ = type.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Spec, typename... Specs>
|
|
||||||
void set(Spec spec, Specs... tail)
|
|
||||||
{
|
|
||||||
set(spec);
|
|
||||||
set(tail...);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
unsigned flags_;
|
unsigned flags_;
|
||||||
int precision_;
|
int precision_;
|
||||||
@ -1599,16 +1568,6 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... FormatSpecs>
|
|
||||||
explicit basic_format_specs(FormatSpecs... specs)
|
|
||||||
: align_spec(0, ' ')
|
|
||||||
, flags_(0)
|
|
||||||
, precision_(-1)
|
|
||||||
, type_(0)
|
|
||||||
{
|
|
||||||
set(specs...);
|
|
||||||
}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR bool flag(unsigned f) const
|
FMT_CONSTEXPR bool flag(unsigned f) const
|
||||||
{
|
{
|
||||||
return (flags_ & f) != 0;
|
return (flags_ & f) != 0;
|
||||||
@ -1929,7 +1888,22 @@ public:
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
typename std::enable_if<std::is_integral<T>::value, iterator>::type operator()(T value)
|
typename std::enable_if<std::is_integral<T>::value, iterator>::type operator()(T value)
|
||||||
{
|
{
|
||||||
writer_.write_int(value, specs_);
|
// MSVC2013 fails to compile separate overloads for bool and char_type so
|
||||||
|
// use std::is_same instead.
|
||||||
|
if (std::is_same<T, bool>::value)
|
||||||
|
{
|
||||||
|
if (specs_.type_)
|
||||||
|
return (*this)(value ? 1 : 0);
|
||||||
|
write(value != 0);
|
||||||
|
}
|
||||||
|
else if (std::is_same<T, char_type>::value)
|
||||||
|
{
|
||||||
|
internal::handle_char_specs(specs_, char_spec_handler(*this, static_cast<char_type>(value)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writer_.write_int(value, specs_);
|
||||||
|
}
|
||||||
return out();
|
return out();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1940,14 +1914,6 @@ public:
|
|||||||
return out();
|
return out();
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator operator()(bool value)
|
|
||||||
{
|
|
||||||
if (specs_.type_)
|
|
||||||
return (*this)(value ? 1 : 0);
|
|
||||||
write(value);
|
|
||||||
return out();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct char_spec_handler : internal::error_handler
|
struct char_spec_handler : internal::error_handler
|
||||||
{
|
{
|
||||||
arg_formatter_base &formatter;
|
arg_formatter_base &formatter;
|
||||||
@ -1969,12 +1935,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
iterator operator()(char_type value)
|
|
||||||
{
|
|
||||||
internal::handle_char_specs(specs_, char_spec_handler(*this, value));
|
|
||||||
return out();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct cstring_spec_handler : internal::error_handler
|
struct cstring_spec_handler : internal::error_handler
|
||||||
{
|
{
|
||||||
arg_formatter_base &formatter;
|
arg_formatter_base &formatter;
|
||||||
@ -2047,7 +2007,7 @@ FMT_CONSTEXPR unsigned parse_nonnegative_int(Iterator &it, ErrorHandler &&eh)
|
|||||||
value = max_int + 1;
|
value = max_int + 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
value = value * 10 + (*it - '0');
|
value = value * 10 + unsigned(*it - '0');
|
||||||
// Workaround for MSVC "setup_exception stack overflow" error:
|
// Workaround for MSVC "setup_exception stack overflow" error:
|
||||||
auto next = it;
|
auto next = it;
|
||||||
++next;
|
++next;
|
||||||
@ -2107,7 +2067,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (is_negative(value))
|
if (is_negative(value))
|
||||||
handler_.on_error("negative width");
|
handler_.on_error("negative width");
|
||||||
return value;
|
return static_cast<unsigned long long>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@ -2135,7 +2095,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (is_negative(value))
|
if (is_negative(value))
|
||||||
handler_.on_error("negative precision");
|
handler_.on_error("negative precision");
|
||||||
return value;
|
return static_cast<unsigned long long>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@ -2201,7 +2161,7 @@ public:
|
|||||||
}
|
}
|
||||||
FMT_CONSTEXPR void on_precision(unsigned precision)
|
FMT_CONSTEXPR void on_precision(unsigned precision)
|
||||||
{
|
{
|
||||||
specs_.precision_ = precision;
|
specs_.precision_ = static_cast<int>(precision);
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR void end_precision() {}
|
FMT_CONSTEXPR void end_precision() {}
|
||||||
|
|
||||||
@ -2300,7 +2260,7 @@ FMT_CONSTEXPR void set_dynamic_spec(T &value, basic_format_arg<Context> arg, Err
|
|||||||
unsigned long long big_value = visit(Handler<ErrorHandler>(eh), arg);
|
unsigned long long big_value = visit(Handler<ErrorHandler>(eh), arg);
|
||||||
if (big_value > (std::numeric_limits<int>::max)())
|
if (big_value > (std::numeric_limits<int>::max)())
|
||||||
eh.on_error("number is too big");
|
eh.on_error("number is too big");
|
||||||
value = static_cast<int>(big_value);
|
value = static_cast<T>(big_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct auto_id
|
struct auto_id
|
||||||
@ -2494,7 +2454,7 @@ FMT_CONSTEXPR Iterator parse_arg_id(Iterator it, IDHandler &&handler)
|
|||||||
{
|
{
|
||||||
c = *++it;
|
c = *++it;
|
||||||
} while (is_name_start(c) || ('0' <= c && c <= '9'));
|
} while (is_name_start(c) || ('0' <= c && c <= '9'));
|
||||||
handler(basic_string_view<char_type>(pointer_from(start), it - start));
|
handler(basic_string_view<char_type>(pointer_from(start), to_unsigned(it - start)));
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3063,8 +3023,8 @@ private:
|
|||||||
}
|
}
|
||||||
else if (spec.precision() > static_cast<int>(num_digits))
|
else if (spec.precision() > static_cast<int>(num_digits))
|
||||||
{
|
{
|
||||||
size = prefix.size() + spec.precision();
|
size = prefix.size() + static_cast<std::size_t>(spec.precision());
|
||||||
padding = spec.precision() - num_digits;
|
padding = static_cast<std::size_t>(spec.precision()) - num_digits;
|
||||||
fill = '0';
|
fill = '0';
|
||||||
}
|
}
|
||||||
align_spec as = spec;
|
align_spec as = spec;
|
||||||
@ -3941,8 +3901,7 @@ struct formatter<T, Char, typename std::enable_if<internal::format_type<typename
|
|||||||
internal::handle_dynamic_spec<internal::width_checker>(specs_.width_, specs_.width_ref, ctx);
|
internal::handle_dynamic_spec<internal::width_checker>(specs_.width_, specs_.width_ref, ctx);
|
||||||
internal::handle_dynamic_spec<internal::precision_checker>(specs_.precision_, specs_.precision_ref, ctx);
|
internal::handle_dynamic_spec<internal::precision_checker>(specs_.precision_, specs_.precision_ref, ctx);
|
||||||
typedef output_range<typename FormatContext::iterator, typename FormatContext::char_type> range_type;
|
typedef output_range<typename FormatContext::iterator, typename FormatContext::char_type> range_type;
|
||||||
visit(arg_formatter<range_type>(ctx, specs_), internal::make_arg<FormatContext>(val));
|
return visit(arg_formatter<range_type>(ctx, specs_), internal::make_arg<FormatContext>(val));
|
||||||
return ctx.out();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -4059,7 +4018,7 @@ struct format_handler : internal::error_handler
|
|||||||
|
|
||||||
void on_text(iterator begin, iterator end)
|
void on_text(iterator begin, iterator end)
|
||||||
{
|
{
|
||||||
size_t size = end - begin;
|
auto size = internal::to_unsigned(end - begin);
|
||||||
auto out = context.out();
|
auto out = context.out();
|
||||||
auto &&it = internal::reserve(out, size);
|
auto &&it = internal::reserve(out, size);
|
||||||
it = std::copy_n(begin, size, it);
|
it = std::copy_n(begin, size, it);
|
||||||
@ -4226,10 +4185,10 @@ std::wstring to_wstring(const T &value)
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Char>
|
template<typename Char, std::size_t SIZE>
|
||||||
std::basic_string<Char> to_string(const basic_memory_buffer<Char> &buffer)
|
std::basic_string<Char> to_string(const basic_memory_buffer<Char, SIZE> &buf)
|
||||||
{
|
{
|
||||||
return std::basic_string<Char>(buffer.data(), buffer.size());
|
return std::basic_string<Char>(buf.data(), buf.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline format_context::iterator vformat_to(internal::buffer &buf, string_view format_str, format_args args)
|
inline format_context::iterator vformat_to(internal::buffer &buf, string_view format_str, format_args args)
|
||||||
@ -4244,14 +4203,14 @@ inline wformat_context::iterator vformat_to(internal::wbuffer &buf, wstring_view
|
|||||||
return vformat_to<arg_formatter<range>>(buf, format_str, args);
|
return vformat_to<arg_formatter<range>>(buf, format_str, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args, std::size_t SIZE = inline_buffer_size>
|
||||||
inline format_context::iterator format_to(memory_buffer &buf, string_view format_str, const Args &... args)
|
inline format_context::iterator format_to(basic_memory_buffer<char, SIZE> &buf, string_view format_str, const Args &... args)
|
||||||
{
|
{
|
||||||
return vformat_to(buf, format_str, make_format_args(args...));
|
return vformat_to(buf, format_str, make_format_args(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args, std::size_t SIZE = inline_buffer_size>
|
||||||
inline wformat_context::iterator format_to(wmemory_buffer &buf, wstring_view format_str, const Args &... args)
|
inline wformat_context::iterator format_to(basic_memory_buffer<wchar_t, SIZE> &buf, wstring_view format_str, const Args &... args)
|
||||||
{
|
{
|
||||||
return vformat_to(buf, format_str, make_format_args<wformat_context>(args...));
|
return vformat_to(buf, format_str, make_format_args<wformat_context>(args...));
|
||||||
}
|
}
|
||||||
@ -4276,6 +4235,12 @@ inline OutputIt vformat_to(OutputIt out, string_view format_str, typename format
|
|||||||
typedef output_range<OutputIt, char> range;
|
typedef output_range<OutputIt, char> range;
|
||||||
return vformat_to<arg_formatter<range>>(range(out), format_str, args);
|
return vformat_to<arg_formatter<range>>(range(out), format_str, args);
|
||||||
}
|
}
|
||||||
|
template<typename OutputIt, typename... Args>
|
||||||
|
inline OutputIt vformat_to(OutputIt out, wstring_view format_str, typename format_args_t<OutputIt, wchar_t>::type args)
|
||||||
|
{
|
||||||
|
typedef output_range<OutputIt, wchar_t> range;
|
||||||
|
return vformat_to<arg_formatter<range>>(range(out), format_str, args);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
@ -4317,6 +4282,26 @@ struct format_to_n_result
|
|||||||
std::size_t size;
|
std::size_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename OutputIt>
|
||||||
|
using format_to_n_context = typename fmt::format_context_t<fmt::internal::truncating_iterator<OutputIt>>::type;
|
||||||
|
|
||||||
|
template<typename OutputIt>
|
||||||
|
using format_to_n_args = fmt::basic_format_args<format_to_n_context<OutputIt>>;
|
||||||
|
|
||||||
|
template<typename OutputIt, typename... Args>
|
||||||
|
inline format_arg_store<format_to_n_context<OutputIt>, Args...> make_format_to_n_args(const Args &... args)
|
||||||
|
{
|
||||||
|
return format_arg_store<format_to_n_context<OutputIt>, Args...>(args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename OutputIt, typename... Args>
|
||||||
|
inline format_to_n_result<OutputIt> vformat_to_n(OutputIt out, std::size_t n, string_view format_str, format_to_n_args<OutputIt> args)
|
||||||
|
{
|
||||||
|
typedef internal::truncating_iterator<OutputIt> It;
|
||||||
|
auto it = vformat_to(It(out, n), format_str, args);
|
||||||
|
return {it.base(), it.count()};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
Formats arguments, writes up to ``n`` characters of the result to the output
|
Formats arguments, writes up to ``n`` characters of the result to the output
|
||||||
@ -4326,9 +4311,14 @@ struct format_to_n_result
|
|||||||
*/
|
*/
|
||||||
template<typename OutputIt, typename... Args>
|
template<typename OutputIt, typename... Args>
|
||||||
inline format_to_n_result<OutputIt> format_to_n(OutputIt out, std::size_t n, string_view format_str, const Args &... args)
|
inline format_to_n_result<OutputIt> format_to_n(OutputIt out, std::size_t n, string_view format_str, const Args &... args)
|
||||||
|
{
|
||||||
|
return vformat_to_n<OutputIt>(out, n, format_str, make_format_to_n_args<OutputIt>(args...));
|
||||||
|
}
|
||||||
|
template<typename OutputIt, typename... Args>
|
||||||
|
inline format_to_n_result<OutputIt> format_to_n(OutputIt out, std::size_t n, wstring_view format_str, const Args &... args)
|
||||||
{
|
{
|
||||||
typedef internal::truncating_iterator<OutputIt> It;
|
typedef internal::truncating_iterator<OutputIt> It;
|
||||||
auto it = vformat_to(It(out, n), format_str, make_format_args<typename format_context_t<It>::type>(args...));
|
auto it = vformat_to(It(out, n), format_str, make_format_args<typename format_context_t<It, wchar_t>::type>(args...));
|
||||||
return {it.base(), it.count()};
|
return {it.base(), it.count()};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4361,8 +4351,8 @@ inline typename std::enable_if<internal::is_format_string<String>::value>::type
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns the number of characters in the output of
|
Returns the number of characters in the output of
|
||||||
``format(format_str, args...)``.
|
``format(format_str, args...)``.
|
||||||
*/
|
*/
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline std::size_t formatted_size(string_view format_str, const Args &... args)
|
inline std::size_t formatted_size(string_view format_str, const Args &... args)
|
||||||
@ -4371,6 +4361,215 @@ inline std::size_t formatted_size(string_view format_str, const Args &... args)
|
|||||||
return it.count();
|
return it.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Experimental color support.
|
||||||
|
#ifdef FMT_EXTENDED_COLORS
|
||||||
|
enum class color : uint32_t
|
||||||
|
{
|
||||||
|
alice_blue = 0xF0F8FF, // rgb(240,248,255)
|
||||||
|
antique_white = 0xFAEBD7, // rgb(250,235,215)
|
||||||
|
aqua = 0x00FFFF, // rgb(0,255,255)
|
||||||
|
aquamarine = 0x7FFFD4, // rgb(127,255,212)
|
||||||
|
azure = 0xF0FFFF, // rgb(240,255,255)
|
||||||
|
beige = 0xF5F5DC, // rgb(245,245,220)
|
||||||
|
bisque = 0xFFE4C4, // rgb(255,228,196)
|
||||||
|
black = 0x000000, // rgb(0,0,0)
|
||||||
|
blanched_almond = 0xFFEBCD, // rgb(255,235,205)
|
||||||
|
blue = 0x0000FF, // rgb(0,0,255)
|
||||||
|
blue_violet = 0x8A2BE2, // rgb(138,43,226)
|
||||||
|
brown = 0xA52A2A, // rgb(165,42,42)
|
||||||
|
burly_wood = 0xDEB887, // rgb(222,184,135)
|
||||||
|
cadet_blue = 0x5F9EA0, // rgb(95,158,160)
|
||||||
|
chartreuse = 0x7FFF00, // rgb(127,255,0)
|
||||||
|
chocolate = 0xD2691E, // rgb(210,105,30)
|
||||||
|
coral = 0xFF7F50, // rgb(255,127,80)
|
||||||
|
cornflower_blue = 0x6495ED, // rgb(100,149,237)
|
||||||
|
cornsilk = 0xFFF8DC, // rgb(255,248,220)
|
||||||
|
crimson = 0xDC143C, // rgb(220,20,60)
|
||||||
|
cyan = 0x00FFFF, // rgb(0,255,255)
|
||||||
|
dark_blue = 0x00008B, // rgb(0,0,139)
|
||||||
|
dark_cyan = 0x008B8B, // rgb(0,139,139)
|
||||||
|
dark_golden_rod = 0xB8860B, // rgb(184,134,11)
|
||||||
|
dark_gray = 0xA9A9A9, // rgb(169,169,169)
|
||||||
|
dark_green = 0x006400, // rgb(0,100,0)
|
||||||
|
dark_khaki = 0xBDB76B, // rgb(189,183,107)
|
||||||
|
dark_magenta = 0x8B008B, // rgb(139,0,139)
|
||||||
|
dark_olive_green = 0x556B2F, // rgb(85,107,47)
|
||||||
|
dark_orange = 0xFF8C00, // rgb(255,140,0)
|
||||||
|
dark_orchid = 0x9932CC, // rgb(153,50,204)
|
||||||
|
dark_red = 0x8B0000, // rgb(139,0,0)
|
||||||
|
dark_salmon = 0xE9967A, // rgb(233,150,122)
|
||||||
|
dark_sea_green = 0x8FBC8F, // rgb(143,188,143)
|
||||||
|
dark_slate_blue = 0x483D8B, // rgb(72,61,139)
|
||||||
|
dark_slate_gray = 0x2F4F4F, // rgb(47,79,79)
|
||||||
|
dark_turquoise = 0x00CED1, // rgb(0,206,209)
|
||||||
|
dark_violet = 0x9400D3, // rgb(148,0,211)
|
||||||
|
deep_pink = 0xFF1493, // rgb(255,20,147)
|
||||||
|
deep_sky_blue = 0x00BFFF, // rgb(0,191,255)
|
||||||
|
dim_gray = 0x696969, // rgb(105,105,105)
|
||||||
|
dodger_blue = 0x1E90FF, // rgb(30,144,255)
|
||||||
|
fire_brick = 0xB22222, // rgb(178,34,34)
|
||||||
|
floral_white = 0xFFFAF0, // rgb(255,250,240)
|
||||||
|
forest_green = 0x228B22, // rgb(34,139,34)
|
||||||
|
fuchsia = 0xFF00FF, // rgb(255,0,255)
|
||||||
|
gainsboro = 0xDCDCDC, // rgb(220,220,220)
|
||||||
|
ghost_white = 0xF8F8FF, // rgb(248,248,255)
|
||||||
|
gold = 0xFFD700, // rgb(255,215,0)
|
||||||
|
golden_rod = 0xDAA520, // rgb(218,165,32)
|
||||||
|
gray = 0x808080, // rgb(128,128,128)
|
||||||
|
green = 0x008000, // rgb(0,128,0)
|
||||||
|
green_yellow = 0xADFF2F, // rgb(173,255,47)
|
||||||
|
honey_dew = 0xF0FFF0, // rgb(240,255,240)
|
||||||
|
hot_pink = 0xFF69B4, // rgb(255,105,180)
|
||||||
|
indian_red = 0xCD5C5C, // rgb(205,92,92)
|
||||||
|
indigo = 0x4B0082, // rgb(75,0,130)
|
||||||
|
ivory = 0xFFFFF0, // rgb(255,255,240)
|
||||||
|
khaki = 0xF0E68C, // rgb(240,230,140)
|
||||||
|
lavender = 0xE6E6FA, // rgb(230,230,250)
|
||||||
|
lavender_blush = 0xFFF0F5, // rgb(255,240,245)
|
||||||
|
lawn_green = 0x7CFC00, // rgb(124,252,0)
|
||||||
|
lemon_chiffon = 0xFFFACD, // rgb(255,250,205)
|
||||||
|
light_blue = 0xADD8E6, // rgb(173,216,230)
|
||||||
|
light_coral = 0xF08080, // rgb(240,128,128)
|
||||||
|
light_cyan = 0xE0FFFF, // rgb(224,255,255)
|
||||||
|
light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210)
|
||||||
|
light_gray = 0xD3D3D3, // rgb(211,211,211)
|
||||||
|
light_green = 0x90EE90, // rgb(144,238,144)
|
||||||
|
light_pink = 0xFFB6C1, // rgb(255,182,193)
|
||||||
|
light_salmon = 0xFFA07A, // rgb(255,160,122)
|
||||||
|
light_sea_green = 0x20B2AA, // rgb(32,178,170)
|
||||||
|
light_sky_blue = 0x87CEFA, // rgb(135,206,250)
|
||||||
|
light_slate_gray = 0x778899, // rgb(119,136,153)
|
||||||
|
light_steel_blue = 0xB0C4DE, // rgb(176,196,222)
|
||||||
|
light_yellow = 0xFFFFE0, // rgb(255,255,224)
|
||||||
|
lime = 0x00FF00, // rgb(0,255,0)
|
||||||
|
lime_green = 0x32CD32, // rgb(50,205,50)
|
||||||
|
linen = 0xFAF0E6, // rgb(250,240,230)
|
||||||
|
magenta = 0xFF00FF, // rgb(255,0,255)
|
||||||
|
maroon = 0x800000, // rgb(128,0,0)
|
||||||
|
medium_aquamarine = 0x66CDAA, // rgb(102,205,170)
|
||||||
|
medium_blue = 0x0000CD, // rgb(0,0,205)
|
||||||
|
medium_orchid = 0xBA55D3, // rgb(186,85,211)
|
||||||
|
medium_purple = 0x9370DB, // rgb(147,112,219)
|
||||||
|
medium_sea_green = 0x3CB371, // rgb(60,179,113)
|
||||||
|
medium_slate_blue = 0x7B68EE, // rgb(123,104,238)
|
||||||
|
medium_spring_green = 0x00FA9A, // rgb(0,250,154)
|
||||||
|
medium_turquoise = 0x48D1CC, // rgb(72,209,204)
|
||||||
|
medium_violet_red = 0xC71585, // rgb(199,21,133)
|
||||||
|
midnight_blue = 0x191970, // rgb(25,25,112)
|
||||||
|
mint_cream = 0xF5FFFA, // rgb(245,255,250)
|
||||||
|
misty_rose = 0xFFE4E1, // rgb(255,228,225)
|
||||||
|
moccasin = 0xFFE4B5, // rgb(255,228,181)
|
||||||
|
navajo_white = 0xFFDEAD, // rgb(255,222,173)
|
||||||
|
navy = 0x000080, // rgb(0,0,128)
|
||||||
|
old_lace = 0xFDF5E6, // rgb(253,245,230)
|
||||||
|
olive = 0x808000, // rgb(128,128,0)
|
||||||
|
olive_drab = 0x6B8E23, // rgb(107,142,35)
|
||||||
|
orange = 0xFFA500, // rgb(255,165,0)
|
||||||
|
orange_red = 0xFF4500, // rgb(255,69,0)
|
||||||
|
orchid = 0xDA70D6, // rgb(218,112,214)
|
||||||
|
pale_golden_rod = 0xEEE8AA, // rgb(238,232,170)
|
||||||
|
pale_green = 0x98FB98, // rgb(152,251,152)
|
||||||
|
pale_turquoise = 0xAFEEEE, // rgb(175,238,238)
|
||||||
|
pale_violet_red = 0xDB7093, // rgb(219,112,147)
|
||||||
|
papaya_whip = 0xFFEFD5, // rgb(255,239,213)
|
||||||
|
peach_puff = 0xFFDAB9, // rgb(255,218,185)
|
||||||
|
peru = 0xCD853F, // rgb(205,133,63)
|
||||||
|
pink = 0xFFC0CB, // rgb(255,192,203)
|
||||||
|
plum = 0xDDA0DD, // rgb(221,160,221)
|
||||||
|
powder_blue = 0xB0E0E6, // rgb(176,224,230)
|
||||||
|
purple = 0x800080, // rgb(128,0,128)
|
||||||
|
rebecca_purple = 0x663399, // rgb(102,51,153)
|
||||||
|
red = 0xFF0000, // rgb(255,0,0)
|
||||||
|
rosy_brown = 0xBC8F8F, // rgb(188,143,143)
|
||||||
|
royal_blue = 0x4169E1, // rgb(65,105,225)
|
||||||
|
saddle_brown = 0x8B4513, // rgb(139,69,19)
|
||||||
|
salmon = 0xFA8072, // rgb(250,128,114)
|
||||||
|
sandy_brown = 0xF4A460, // rgb(244,164,96)
|
||||||
|
sea_green = 0x2E8B57, // rgb(46,139,87)
|
||||||
|
sea_shell = 0xFFF5EE, // rgb(255,245,238)
|
||||||
|
sienna = 0xA0522D, // rgb(160,82,45)
|
||||||
|
silver = 0xC0C0C0, // rgb(192,192,192)
|
||||||
|
sky_blue = 0x87CEEB, // rgb(135,206,235)
|
||||||
|
slate_blue = 0x6A5ACD, // rgb(106,90,205)
|
||||||
|
slate_gray = 0x708090, // rgb(112,128,144)
|
||||||
|
snow = 0xFFFAFA, // rgb(255,250,250)
|
||||||
|
spring_green = 0x00FF7F, // rgb(0,255,127)
|
||||||
|
steel_blue = 0x4682B4, // rgb(70,130,180)
|
||||||
|
tan = 0xD2B48C, // rgb(210,180,140)
|
||||||
|
teal = 0x008080, // rgb(0,128,128)
|
||||||
|
thistle = 0xD8BFD8, // rgb(216,191,216)
|
||||||
|
tomato = 0xFF6347, // rgb(255,99,71)
|
||||||
|
turquoise = 0x40E0D0, // rgb(64,224,208)
|
||||||
|
violet = 0xEE82EE, // rgb(238,130,238)
|
||||||
|
wheat = 0xF5DEB3, // rgb(245,222,179)
|
||||||
|
white = 0xFFFFFF, // rgb(255,255,255)
|
||||||
|
white_smoke = 0xF5F5F5, // rgb(245,245,245)
|
||||||
|
yellow = 0xFFFF00, // rgb(255,255,0)
|
||||||
|
yellow_green = 0x9ACD32, // rgb(154,205,50)
|
||||||
|
}; // enum class color
|
||||||
|
|
||||||
|
// rgb is a struct for red, green and blue colors.
|
||||||
|
// We use rgb as name because some editors will show it as color direct in the
|
||||||
|
// editor.
|
||||||
|
struct rgb
|
||||||
|
{
|
||||||
|
FMT_CONSTEXPR_DECL rgb()
|
||||||
|
: r(0)
|
||||||
|
, g(0)
|
||||||
|
, b(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR_DECL rgb(uint8_t r_, uint8_t g_, uint8_t b_)
|
||||||
|
: r(r_)
|
||||||
|
, g(g_)
|
||||||
|
, b(b_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR_DECL rgb(uint32_t hex)
|
||||||
|
: r((hex >> 16) & 0xFF)
|
||||||
|
, g((hex >> 8) & 0xFF)
|
||||||
|
, b((hex)&0xFF)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR_DECL rgb(color hex)
|
||||||
|
: r((uint32_t(hex) >> 16) & 0xFF)
|
||||||
|
, g((uint32_t(hex) >> 8) & 0xFF)
|
||||||
|
, b(uint32_t(hex) & 0xFF)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
uint8_t r;
|
||||||
|
uint8_t g;
|
||||||
|
uint8_t b;
|
||||||
|
};
|
||||||
|
|
||||||
|
void vprint_rgb(rgb fd, string_view format, format_args args);
|
||||||
|
void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Formats a string and prints it to stdout using ANSI escape sequences to
|
||||||
|
specify foreground color 'fd'.
|
||||||
|
Example:
|
||||||
|
fmt::print(fmt::color::red, "Elapsed time: {0:.2f} seconds", 1.23);
|
||||||
|
*/
|
||||||
|
template<typename... Args>
|
||||||
|
inline void print(rgb fd, string_view format_str, const Args &... args)
|
||||||
|
{
|
||||||
|
vprint_rgb(fd, format_str, make_format_args(args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Formats a string and prints it to stdout using ANSI escape sequences to
|
||||||
|
specify foreground color 'fd' and background color 'bg'.
|
||||||
|
Example:
|
||||||
|
fmt::print(fmt::color::red, fmt::color::black, "Elapsed time: {0:.2f} seconds", 1.23);
|
||||||
|
*/
|
||||||
|
template<typename... Args>
|
||||||
|
inline void print(rgb fd, rgb bg, string_view format_str, const Args &... args)
|
||||||
|
{
|
||||||
|
vprint_rgb(fd, bg, format_str, make_format_args(args...));
|
||||||
|
}
|
||||||
|
#endif // FMT_EXTENDED_COLORS
|
||||||
|
|
||||||
#if FMT_USE_USER_DEFINED_LITERALS
|
#if FMT_USE_USER_DEFINED_LITERALS
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
@ -290,27 +290,38 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
using base::operator();
|
template<typename T>
|
||||||
|
typename std::enable_if<std::is_integral<T>::value, iterator>::type operator()(T value)
|
||||||
/** Formats an argument of type ``bool``. */
|
|
||||||
iterator operator()(bool value)
|
|
||||||
{
|
{
|
||||||
format_specs &fmt_spec = this->spec();
|
// MSVC2013 fails to compile separate overloads for bool and char_type so
|
||||||
if (fmt_spec.type_ != 's')
|
// use std::is_same instead.
|
||||||
return (*this)(value ? 1 : 0);
|
if (std::is_same<T, bool>::value)
|
||||||
fmt_spec.type_ = 0;
|
{
|
||||||
this->write(value);
|
format_specs &fmt_spec = this->spec();
|
||||||
|
if (fmt_spec.type_ != 's')
|
||||||
|
return base::operator()(value ? 1 : 0);
|
||||||
|
fmt_spec.type_ = 0;
|
||||||
|
this->write(value != 0);
|
||||||
|
}
|
||||||
|
else if (std::is_same<T, char_type>::value)
|
||||||
|
{
|
||||||
|
format_specs &fmt_spec = this->spec();
|
||||||
|
if (fmt_spec.type_ && fmt_spec.type_ != 'c')
|
||||||
|
return (*this)(static_cast<int>(value));
|
||||||
|
fmt_spec.flags_ = 0;
|
||||||
|
fmt_spec.align_ = ALIGN_RIGHT;
|
||||||
|
return base::operator()(value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return base::operator()(value);
|
||||||
|
}
|
||||||
return this->out();
|
return this->out();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Formats a character. */
|
template<typename T>
|
||||||
iterator operator()(char_type value)
|
typename std::enable_if<std::is_floating_point<T>::value, iterator>::type operator()(T value)
|
||||||
{
|
{
|
||||||
format_specs &fmt_spec = this->spec();
|
|
||||||
if (fmt_spec.type_ && fmt_spec.type_ != 'c')
|
|
||||||
return (*this)(static_cast<int>(value));
|
|
||||||
fmt_spec.flags_ = 0;
|
|
||||||
fmt_spec.align_ = ALIGN_RIGHT;
|
|
||||||
return base::operator()(value);
|
return base::operator()(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,6 +349,16 @@ public:
|
|||||||
return this->out();
|
return this->out();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iterator operator()(basic_string_view<char_type> value)
|
||||||
|
{
|
||||||
|
return base::operator()(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator operator()(monostate value)
|
||||||
|
{
|
||||||
|
return base::operator()(value);
|
||||||
|
}
|
||||||
|
|
||||||
/** Formats a pointer. */
|
/** Formats a pointer. */
|
||||||
iterator operator()(const void *value)
|
iterator operator()(const void *value)
|
||||||
{
|
{
|
||||||
|
@ -114,12 +114,14 @@ struct is_range_ : std::false_type
|
|||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct is_range_<T, typename std::conditional<false,
|
struct is_range_<T, typename std::conditional<false,
|
||||||
conditional_helper<decltype(internal::declval<T>().begin()), decltype(internal::declval<T>().end())>, void>::type>
|
conditional_helper<decltype(internal::declval<T>().begin()), decltype(internal::declval<T>().end())>, void>::type>
|
||||||
: std::true_type
|
: std::true_type
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
/// tuple_size and tuple_element check.
|
/// tuple_size and tuple_element check.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@ -171,7 +173,7 @@ using make_index_sequence = make_integer_sequence<std::size_t, N>;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<class Tuple, class F, size_t... Is>
|
template<class Tuple, class F, size_t... Is>
|
||||||
void for_each(index_sequence<Is...>, Tuple &&tup, F &&f) noexcept
|
void for_each(index_sequence<Is...>, Tuple &&tup, F &&f) FMT_NOEXCEPT
|
||||||
{
|
{
|
||||||
using std::get;
|
using std::get;
|
||||||
// using free function get<I>(T) now.
|
// using free function get<I>(T) now.
|
||||||
|
@ -17,5 +17,3 @@ public:
|
|||||||
virtual void format(const details::log_msg &msg, fmt::memory_buffer &dest) = 0;
|
virtual void format(const details::log_msg &msg, fmt::memory_buffer &dest) = 0;
|
||||||
};
|
};
|
||||||
} // namespace spdlog
|
} // namespace spdlog
|
||||||
|
|
||||||
#include "details/pattern_formatter_impl.h"
|
|
||||||
|
@ -45,23 +45,23 @@ public:
|
|||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void log(level::level_enum lvl, const char *msg);
|
void log(level::level_enum lvl, const char *msg);
|
||||||
|
|
||||||
template<typename Arg1, typename... Args>
|
template<typename... Args>
|
||||||
void trace(const char *fmt, const Arg1 &, const Args &... args);
|
void trace(const char *fmt, const Args &... args);
|
||||||
|
|
||||||
template<typename Arg1, typename... Args>
|
template<typename... Args>
|
||||||
void debug(const char *fmt, const Arg1 &, const Args &... args);
|
void debug(const char *fmt, const Args &... args);
|
||||||
|
|
||||||
template<typename Arg1, typename... Args>
|
template<typename... Args>
|
||||||
void info(const char *fmt, const Arg1 &, const Args &... args);
|
void info(const char *fmt, const Args &... args);
|
||||||
|
|
||||||
template<typename Arg1, typename... Args>
|
template<typename... Args>
|
||||||
void warn(const char *fmt, const Arg1 &, const Args &... args);
|
void warn(const char *fmt, const Args &... args);
|
||||||
|
|
||||||
template<typename Arg1, typename... Args>
|
template<typename... Args>
|
||||||
void error(const char *fmt, const Arg1 &, const Args &... args);
|
void error(const char *fmt, const Args &... args);
|
||||||
|
|
||||||
template<typename Arg1, typename... Args>
|
template<typename... Args>
|
||||||
void critical(const char *fmt, const Arg1 &, const Args &... args);
|
void critical(const char *fmt, const Args &... args);
|
||||||
|
|
||||||
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
|
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
@ -117,10 +117,10 @@ public:
|
|||||||
|
|
||||||
// create a pattern formatter all the sinks in this logger.
|
// create a pattern formatter all the sinks in this logger.
|
||||||
// each sink gets itw own private copy of a formatter object.
|
// each sink gets itw own private copy of a formatter object.
|
||||||
void set_pattern(const std::string &pattern, pattern_time_type pattern_time = pattern_time_type::local);
|
void set_pattern(const std::string &pattern, pattern_time_type time_type = pattern_time_type::local);
|
||||||
|
|
||||||
// create a FormatterT formatter all the sinks in this logger.
|
// create a FormatterT formatter for each sink in this logger.
|
||||||
// each sink gets itw own private copy of a formatter object.
|
// each sink gets its own private copy of a formatter object.
|
||||||
template<class FormatterT, typename... Args>
|
template<class FormatterT, typename... Args>
|
||||||
void set_formatter(const Args &... args);
|
void set_formatter(const Args &... args);
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ public:
|
|||||||
|
|
||||||
void log(const details::log_msg &msg) override
|
void log(const details::log_msg &msg) override
|
||||||
{
|
{
|
||||||
const android_LogPriority priority = convert_to_android(msg.level);
|
const android_LogPriority priority = convert_to_android_(msg.level);
|
||||||
fmt::memory_buffer formatted;
|
fmt::memory_buffer formatted;
|
||||||
if (use_raw_msg_)
|
if (use_raw_msg_)
|
||||||
{
|
{
|
||||||
@ -70,7 +70,7 @@ public:
|
|||||||
void flush() override {}
|
void flush() override {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static android_LogPriority convert_to_android(spdlog::level::level_enum level)
|
static android_LogPriority convert_to_android_(spdlog::level::level_enum level)
|
||||||
{
|
{
|
||||||
switch (level)
|
switch (level)
|
||||||
{
|
{
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "spdlog/details/console_globals.h"
|
||||||
#include "spdlog/details/null_mutex.h"
|
#include "spdlog/details/null_mutex.h"
|
||||||
#include "spdlog/details/os.h"
|
#include "spdlog/details/os.h"
|
||||||
#include "spdlog/details/traits.h"
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@ -22,14 +22,14 @@ namespace sinks {
|
|||||||
* of the message.
|
* of the message.
|
||||||
* If no color terminal detected, omit the escape codes.
|
* If no color terminal detected, omit the escape codes.
|
||||||
*/
|
*/
|
||||||
template<class StreamTrait, class ConsoleMutexTrait>
|
template<class TargetStream, class ConsoleMutex>
|
||||||
class ansicolor_sink : public sink
|
class ansicolor_sink : public sink
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using mutex_t = typename ConsoleMutexTrait::mutex_t;
|
using mutex_t = typename ConsoleMutex::mutex_t;
|
||||||
ansicolor_sink()
|
ansicolor_sink()
|
||||||
: target_file_(StreamTrait::stream())
|
: target_file_(TargetStream::stream())
|
||||||
, mutex_(ConsoleMutexTrait::console_mutex())
|
, mutex_(ConsoleMutex::console_mutex())
|
||||||
|
|
||||||
{
|
{
|
||||||
should_do_colors_ = details::os::in_terminal(target_file_) && details::os::is_color_terminal();
|
should_do_colors_ = details::os::in_terminal(target_file_) && details::os::is_color_terminal();
|
||||||
@ -132,10 +132,11 @@ private:
|
|||||||
std::unordered_map<level::level_enum, std::string, level::level_hasher> colors_;
|
std::unordered_map<level::level_enum, std::string, level::level_hasher> colors_;
|
||||||
};
|
};
|
||||||
|
|
||||||
using ansicolor_stdout_sink_mt = ansicolor_sink<details::console_stdout_trait, details::console_mutex_trait>;
|
using ansicolor_stdout_sink_mt = ansicolor_sink<details::console_stdout_stream, details::console_global_mutex>;
|
||||||
using ansicolor_stdout_sink_st = ansicolor_sink<details::console_stdout_trait, details::console_null_mutex_trait>;
|
using ansicolor_stdout_sink_st = ansicolor_sink<details::console_stdout_stream, details::console_global_nullmutex>;
|
||||||
using ansicolor_stderr_sink_mt = ansicolor_sink<details::console_stderr_trait, details::console_mutex_trait>;
|
|
||||||
using ansicolor_stderr_sink_st = ansicolor_sink<details::console_stderr_trait, details::console_null_mutex_trait>;
|
using ansicolor_stderr_sink_mt = ansicolor_sink<details::console_stderr_stream, details::console_global_mutex>;
|
||||||
|
using ansicolor_stderr_sink_st = ansicolor_sink<details::console_stderr_stream, details::console_global_nullmutex>;
|
||||||
|
|
||||||
} // namespace sinks
|
} // namespace sinks
|
||||||
|
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
//
|
//
|
||||||
// base sink templated over a mutex (either dummy or real)
|
// base sink templated over a mutex (either dummy or real)
|
||||||
// concrete implementation should only override the sink_it_ method.
|
// concrete implementation should override the sink_it_() and flush_() methods.
|
||||||
// all locking is taken care of here so no locking needed by the implementers..
|
// locking is taken care of in this class - no locking needed by the implementers..
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "spdlog/common.h"
|
#include "spdlog/common.h"
|
||||||
@ -26,16 +26,6 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
base_sink(const std::string &formatter_pattern)
|
|
||||||
: sink(formatter_pattern)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
base_sink(std::unique_ptr<spdlog::formatter> sink_formatter)
|
|
||||||
: sink(std::move(sink_formatter))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
base_sink(const base_sink &) = delete;
|
base_sink(const base_sink &) = delete;
|
||||||
base_sink &operator=(const base_sink &) = delete;
|
base_sink &operator=(const base_sink &) = delete;
|
||||||
|
|
||||||
|
@ -18,28 +18,18 @@ namespace sinks {
|
|||||||
* Trivial file sink with single file as target
|
* Trivial file sink with single file as target
|
||||||
*/
|
*/
|
||||||
template<class Mutex>
|
template<class Mutex>
|
||||||
class simple_file_sink SPDLOG_FINAL : public base_sink<Mutex>
|
class basic_file_sink SPDLOG_FINAL : public base_sink<Mutex>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit simple_file_sink(const filename_t &filename, bool truncate = false)
|
explicit basic_file_sink(const filename_t &filename, bool truncate = false)
|
||||||
: force_flush_(false)
|
|
||||||
{
|
{
|
||||||
file_helper_.open(filename, truncate);
|
file_helper_.open(filename, truncate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_force_flush(bool force_flush)
|
|
||||||
{
|
|
||||||
force_flush_ = force_flush;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void sink_it_(const details::log_msg &, const fmt::memory_buffer &formatted) override
|
void sink_it_(const details::log_msg &, const fmt::memory_buffer &formatted) override
|
||||||
{
|
{
|
||||||
file_helper_.write(formatted);
|
file_helper_.write(formatted);
|
||||||
if (force_flush_)
|
|
||||||
{
|
|
||||||
file_helper_.flush();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush_() override
|
void flush_() override
|
||||||
@ -49,11 +39,10 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
details::file_helper file_helper_;
|
details::file_helper file_helper_;
|
||||||
bool force_flush_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using simple_file_sink_mt = simple_file_sink<std::mutex>;
|
using basic_file_sink_mt = basic_file_sink<std::mutex>;
|
||||||
using simple_file_sink_st = simple_file_sink<details::null_mutex>;
|
using basic_file_sink_st = basic_file_sink<details::null_mutex>;
|
||||||
|
|
||||||
} // namespace sinks
|
} // namespace sinks
|
||||||
|
|
||||||
@ -63,13 +52,13 @@ using simple_file_sink_st = simple_file_sink<details::null_mutex>;
|
|||||||
template<typename Factory = default_factory>
|
template<typename Factory = default_factory>
|
||||||
inline std::shared_ptr<logger> basic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false)
|
inline std::shared_ptr<logger> basic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false)
|
||||||
{
|
{
|
||||||
return Factory::template create<sinks::simple_file_sink_mt>(logger_name, filename, truncate);
|
return Factory::template create<sinks::basic_file_sink_mt>(logger_name, filename, truncate);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Factory = default_factory>
|
template<typename Factory = default_factory>
|
||||||
inline std::shared_ptr<logger> basic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false)
|
inline std::shared_ptr<logger> basic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false)
|
||||||
{
|
{
|
||||||
return Factory::template create<sinks::simple_file_sink_st>(logger_name, filename, truncate);
|
return Factory::template create<sinks::basic_file_sink_st>(logger_name, filename, truncate);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace spdlog
|
} // namespace spdlog
|
@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
#include "spdlog/details/log_msg.h"
|
#include "spdlog/details/log_msg.h"
|
||||||
#include "spdlog/details/null_mutex.h"
|
#include "spdlog/details/null_mutex.h"
|
||||||
#include "spdlog/sink/base_sink.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -18,22 +17,18 @@
|
|||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
namespace sinks {
|
namespace sinks {
|
||||||
template<class Mutex>
|
|
||||||
class dist_sink : public base_sink<Mutex>
|
template<typename Mutex>
|
||||||
|
class dist_sink : public sink
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit dist_sink()
|
dist_sink() = default;
|
||||||
: sinks_()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
dist_sink(const dist_sink &) = delete;
|
dist_sink(const dist_sink &) = delete;
|
||||||
dist_sink &operator=(const dist_sink &) = delete;
|
dist_sink &operator=(const dist_sink &) = delete;
|
||||||
|
|
||||||
protected:
|
void log(const details::log_msg &msg) SPDLOG_FINAL override
|
||||||
std::vector<std::shared_ptr<sink>> sinks_;
|
|
||||||
|
|
||||||
void sink_it_(const details::log_msg &msg) override
|
|
||||||
{
|
{
|
||||||
|
std::lock_guard<Mutex> lock(mutex_);
|
||||||
for (auto &sink : sinks_)
|
for (auto &sink : sinks_)
|
||||||
{
|
{
|
||||||
if (sink->should_log(msg.level))
|
if (sink->should_log(msg.level))
|
||||||
@ -43,24 +38,28 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush_() override
|
void flush() SPDLOG_FINAL override
|
||||||
{
|
{
|
||||||
|
std::lock_guard<Mutex> lock(mutex_);
|
||||||
for (auto &sink : sinks_)
|
for (auto &sink : sinks_)
|
||||||
sink->flush();
|
sink->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
void add_sink(std::shared_ptr<sink> sink)
|
void add_sink(std::shared_ptr<sink> sink)
|
||||||
{
|
{
|
||||||
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
|
std::lock_guard<Mutex> lock(mutex_);
|
||||||
sinks_.push_back(sink);
|
sinks_.push_back(sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove_sink(std::shared_ptr<sink> sink)
|
void remove_sink(std::shared_ptr<sink> sink)
|
||||||
{
|
{
|
||||||
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
|
std::lock_guard<Mutex> lock(mutex_);
|
||||||
sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sink), sinks_.end());
|
sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sink), sinks_.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Mutex mutex_;
|
||||||
|
std::vector<std::shared_ptr<sink>> sinks_;
|
||||||
};
|
};
|
||||||
|
|
||||||
using dist_sink_mt = dist_sink<std::mutex>;
|
using dist_sink_mt = dist_sink<std::mutex>;
|
||||||
|
@ -27,9 +27,9 @@ public:
|
|||||||
explicit msvc_sink() {}
|
explicit msvc_sink() {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void sink_it_(const details::log_msg &msg) override
|
void sink_it_(const details::log_msg &, const fmt::memory_buffer &formatted) override
|
||||||
{
|
{
|
||||||
OutputDebugStringA(msg.formatted.c_str());
|
OutputDebugStringA(fmt::to_string(formatted).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush_() override {}
|
void flush_() override {}
|
||||||
@ -38,6 +38,9 @@ protected:
|
|||||||
using msvc_sink_mt = msvc_sink<std::mutex>;
|
using msvc_sink_mt = msvc_sink<std::mutex>;
|
||||||
using msvc_sink_st = msvc_sink<details::null_mutex>;
|
using msvc_sink_st = msvc_sink<details::null_mutex>;
|
||||||
|
|
||||||
|
using windebug_sink_mt = msvc_sink_mt;
|
||||||
|
using windebug_sink_st = msvc_sink_st;
|
||||||
|
|
||||||
} // namespace sinks
|
} // namespace sinks
|
||||||
} // namespace spdlog
|
} // namespace spdlog
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/details/log_msg.h"
|
#include "spdlog/details/log_msg.h"
|
||||||
|
#include "spdlog/details/pattern_formatter.h"
|
||||||
#include "spdlog/formatter.h"
|
#include "spdlog/formatter.h"
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
@ -19,17 +20,6 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit sink(const std::string &formatter_pattern)
|
|
||||||
: formatter_(std::unique_ptr<spdlog::formatter>(new pattern_formatter(formatter_pattern)))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// sink with custom formatter
|
|
||||||
explicit sink(std::unique_ptr<spdlog::formatter> sink_formatter)
|
|
||||||
: formatter_(std::move(sink_formatter))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~sink() = default;
|
virtual ~sink() = default;
|
||||||
|
|
||||||
virtual void log(const details::log_msg &msg) = 0;
|
virtual void log(const details::log_msg &msg) = 0;
|
||||||
@ -39,10 +29,12 @@ public:
|
|||||||
{
|
{
|
||||||
return msg_level >= level_.load(std::memory_order_relaxed);
|
return msg_level >= level_.load(std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_level(level::level_enum log_level)
|
void set_level(level::level_enum log_level)
|
||||||
{
|
{
|
||||||
level_.store(log_level);
|
level_.store(log_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
level::level_enum level() const
|
level::level_enum level() const
|
||||||
{
|
{
|
||||||
return static_cast<spdlog::level::level_enum>(level_.load(std::memory_order_relaxed));
|
return static_cast<spdlog::level::level_enum>(level_.load(std::memory_order_relaxed));
|
||||||
@ -58,11 +50,6 @@ public:
|
|||||||
formatter_ = std::move(sink_formatter);
|
formatter_ = std::move(sink_formatter);
|
||||||
}
|
}
|
||||||
|
|
||||||
spdlog::formatter *formatter()
|
|
||||||
{
|
|
||||||
return formatter_.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
level_t level_{level::trace};
|
level_t level_{level::trace};
|
||||||
std::unique_ptr<spdlog::formatter> formatter_;
|
std::unique_ptr<spdlog::formatter> formatter_;
|
||||||
|
@ -5,26 +5,27 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "spdlog/details/console_globals.h"
|
||||||
#include "spdlog/details/null_mutex.h"
|
#include "spdlog/details/null_mutex.h"
|
||||||
#include "spdlog/details/traits.h"
|
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <spdlog/details/console_globals.h>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
|
|
||||||
namespace sinks {
|
namespace sinks {
|
||||||
|
|
||||||
template<class StdoutTrait, class ConsoleMutexTrait>
|
template<class TargetStream, class ConsoleMutex>
|
||||||
class stdout_sink : public sink
|
class stdout_sink : public sink
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using mutex_t = typename ConsoleMutexTrait::mutex_t;
|
using mutex_t = typename ConsoleMutex::mutex_t;
|
||||||
stdout_sink()
|
stdout_sink()
|
||||||
: mutex_(ConsoleMutexTrait::console_mutex())
|
: mutex_(ConsoleMutex::console_mutex())
|
||||||
, file_(StdoutTrait::stream())
|
, file_(TargetStream::stream())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
~stdout_sink() = default;
|
~stdout_sink() = default;
|
||||||
@ -35,14 +36,16 @@ public:
|
|||||||
void log(const details::log_msg &msg) override
|
void log(const details::log_msg &msg) override
|
||||||
{
|
{
|
||||||
std::lock_guard<mutex_t> lock(mutex_);
|
std::lock_guard<mutex_t> lock(mutex_);
|
||||||
fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), file_);
|
fmt::memory_buffer formatted;
|
||||||
fflush(StdoutTrait::stream());
|
formatter_->format(msg, formatted);
|
||||||
|
fwrite(formatted.data(), sizeof(char), formatted.size(), file_);
|
||||||
|
fflush(TargetStream::stream());
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush() override
|
void flush() override
|
||||||
{
|
{
|
||||||
std::lock_guard<mutex_t> lock(mutex_);
|
std::lock_guard<mutex_t> lock(mutex_);
|
||||||
fflush(StdoutTrait::stream());
|
fflush(TargetStream::stream());
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -50,10 +53,11 @@ private:
|
|||||||
FILE *file_;
|
FILE *file_;
|
||||||
};
|
};
|
||||||
|
|
||||||
using stdout_sink_mt = stdout_sink<details::console_stdout_trait, details::console_mutex_trait>;
|
using stdout_sink_mt = stdout_sink<details::console_stdout_stream, details::console_global_mutex>;
|
||||||
using stdout_sink_st = stdout_sink<details::console_stdout_trait, details::console_null_mutex_trait>;
|
using stdout_sink_st = stdout_sink<details::console_stdout_stream, details::console_global_nullmutex>;
|
||||||
using stderr_sink_mt = stdout_sink<details::console_stderr_trait, details::console_mutex_trait>;
|
|
||||||
using stderr_sink_st = stdout_sink<details::console_stderr_trait, details::console_null_mutex_trait>;
|
using stderr_sink_mt = stdout_sink<details::console_stderr_stream, details::console_global_mutex>;
|
||||||
|
using stderr_sink_st = stdout_sink<details::console_stderr_stream, details::console_global_nullmutex>;
|
||||||
|
|
||||||
} // namespace sinks
|
} // namespace sinks
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
|
|
||||||
#include "../fmt/fmt.h"
|
#include "../fmt/fmt.h"
|
||||||
#include "spdlog/common.h"
|
#include "spdlog/common.h"
|
||||||
|
#include "spdlog/details/console_globals.h"
|
||||||
#include "spdlog/details/null_mutex.h"
|
#include "spdlog/details/null_mutex.h"
|
||||||
#include "spdlog/details/traits.h"
|
|
||||||
#include "spdlog/sinks/sink.h"
|
#include "spdlog/sinks/sink.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -22,7 +22,7 @@ namespace sinks {
|
|||||||
/*
|
/*
|
||||||
* Windows color console sink. Uses WriteConsoleA to write to the console with colors
|
* Windows color console sink. Uses WriteConsoleA to write to the console with colors
|
||||||
*/
|
*/
|
||||||
template<class HandleTrait, class ConsoleMutexTrait>
|
template<class OutHandle, class ConsoleMutex>
|
||||||
class wincolor_sink : public sink
|
class wincolor_sink : public sink
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -34,8 +34,8 @@ public:
|
|||||||
const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN;
|
const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN;
|
||||||
|
|
||||||
wincolor_sink()
|
wincolor_sink()
|
||||||
: out_handle_(HandleTrait::handle())
|
: out_handle_(OutHandle::handle())
|
||||||
, mutex_(ConsoleMutexTrait::console_mutex())
|
, mutex_(ConsoleMutex::console_mutex())
|
||||||
{
|
{
|
||||||
colors_[level::trace] = WHITE;
|
colors_[level::trace] = WHITE;
|
||||||
colors_[level::debug] = CYAN;
|
colors_[level::debug] = CYAN;
|
||||||
@ -90,7 +90,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using mutex_t = typename ConsoleMutexTrait::mutex_t;
|
using mutex_t = typename ConsoleMutex::mutex_t;
|
||||||
// set color and return the orig console attributes (for resetting later)
|
// set color and return the orig console attributes (for resetting later)
|
||||||
WORD set_console_attribs(WORD attribs)
|
WORD set_console_attribs(WORD attribs)
|
||||||
{
|
{
|
||||||
@ -116,11 +116,11 @@ private:
|
|||||||
std::unordered_map<level::level_enum, WORD, level::level_hasher> colors_;
|
std::unordered_map<level::level_enum, WORD, level::level_hasher> colors_;
|
||||||
};
|
};
|
||||||
|
|
||||||
using wincolor_stdout_sink_mt = wincolor_sink<details::console_stdout_trait, details::console_mutex_trait>;
|
using wincolor_stdout_sink_mt = wincolor_sink<details::console_stdout_stream, details::console_global_mutex>;
|
||||||
using wincolor_stdout_sink_st = wincolor_sink<details::console_stdout_trait, details::console_null_mutex_trait>;
|
using wincolor_stdout_sink_st = wincolor_sink<details::console_stdout_stream, details::console_global_nullmutex>;
|
||||||
|
|
||||||
using wincolor_stderr_sink_mt = wincolor_sink<details::console_stderr_trait, details::console_mutex_trait>;
|
using wincolor_stderr_sink_mt = wincolor_sink<details::console_stderr_stream, details::console_global_mutex>;
|
||||||
using wincolor_stderr_sink_st = wincolor_sink<details::console_stderr_trait, details::console_null_mutex_trait>;
|
using wincolor_stderr_sink_st = wincolor_sink<details::console_stderr_stream, details::console_global_nullmutex>;
|
||||||
|
|
||||||
} // namespace sinks
|
} // namespace sinks
|
||||||
} // namespace spdlog
|
} // namespace spdlog
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright(c) 2017 Alexander Dalshov.
|
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
|
|
||||||
#include "spdlog/sinks/msvc_sink.h"
|
|
||||||
|
|
||||||
namespace spdlog {
|
|
||||||
namespace sinks {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Windows debug sink (logging using OutputDebugStringA, synonym for msvc_sink)
|
|
||||||
*/
|
|
||||||
template<class Mutex>
|
|
||||||
using windebug_sink = msvc_sink<Mutex>;
|
|
||||||
|
|
||||||
using windebug_sink_mt = msvc_sink_mt;
|
|
||||||
using windebug_sink_st = msvc_sink_st;
|
|
||||||
|
|
||||||
} // namespace sinks
|
|
||||||
} // namespace spdlog
|
|
||||||
|
|
||||||
#endif
|
|
@ -19,7 +19,7 @@
|
|||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
|
|
||||||
// Default logger factory- creates synchronous loggers
|
// Default logger factory- creates synchronous loggers
|
||||||
struct create_synchronous
|
struct synchronous_factory
|
||||||
{
|
{
|
||||||
template<typename Sink, typename... SinkArgs>
|
template<typename Sink, typename... SinkArgs>
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ struct create_synchronous
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using default_factory = create_synchronous;
|
using default_factory = synchronous_factory;
|
||||||
|
|
||||||
// Create and register a logger with a templated sink type
|
// Create and register a logger with a templated sink type
|
||||||
// The logger's level, formatter and flush level will be set according the global settings.
|
// The logger's level, formatter and flush level will be set according the global settings.
|
||||||
@ -57,9 +57,9 @@ inline std::shared_ptr<logger> get(const std::string &name)
|
|||||||
// Set global formatting
|
// Set global formatting
|
||||||
// example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v");
|
// example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v");
|
||||||
//
|
//
|
||||||
inline void set_pattern(const std::string &format_string)
|
inline void set_pattern(const std::string &format_string, pattern_time_type time_type = pattern_time_type::local)
|
||||||
{
|
{
|
||||||
details::registry::instance().set_pattern(format_string);
|
details::registry::instance().set_pattern(format_string, time_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -24,7 +24,7 @@ TEST_CASE("default_error_handler", "[errors]]")
|
|||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
std::string filename = "logs/simple_log.txt";
|
std::string filename = "logs/simple_log.txt";
|
||||||
|
|
||||||
auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("test-error", filename, true);
|
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("test-error", filename, true);
|
||||||
logger->set_pattern("%v");
|
logger->set_pattern("%v");
|
||||||
logger->info("Test message {} {}", 1);
|
logger->info("Test message {} {}", 1);
|
||||||
logger->info("Test message {}", 2);
|
logger->info("Test message {}", 2);
|
||||||
@ -41,7 +41,7 @@ TEST_CASE("custom_error_handler", "[errors]]")
|
|||||||
{
|
{
|
||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
std::string filename = "logs/simple_log.txt";
|
std::string filename = "logs/simple_log.txt";
|
||||||
auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename, true);
|
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename, true);
|
||||||
logger->flush_on(spdlog::level::info);
|
logger->flush_on(spdlog::level::info);
|
||||||
logger->set_error_handler([=](const std::string &) { throw custom_ex(); });
|
logger->set_error_handler([=](const std::string &) { throw custom_ex(); });
|
||||||
logger->info("Good message #1");
|
logger->info("Good message #1");
|
||||||
@ -75,7 +75,7 @@ TEST_CASE("async_error_handler", "[errors]]")
|
|||||||
std::string filename = "logs/simple_async_log.txt";
|
std::string filename = "logs/simple_async_log.txt";
|
||||||
{
|
{
|
||||||
spdlog::init_thread_pool(128, 1);
|
spdlog::init_thread_pool(128, 1);
|
||||||
auto logger = spdlog::create_async_logger<spdlog::sinks::simple_file_sink_mt>("logger", filename, true);
|
auto logger = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("logger", filename, true);
|
||||||
logger->set_error_handler([=](const std::string &) {
|
logger->set_error_handler([=](const std::string &) {
|
||||||
std::ofstream ofs("logs/custom_err.txt");
|
std::ofstream ofs("logs/custom_err.txt");
|
||||||
if (!ofs)
|
if (!ofs)
|
||||||
@ -99,7 +99,7 @@ TEST_CASE("async_error_handler2", "[errors]]")
|
|||||||
std::string err_msg("This is async handler error message");
|
std::string err_msg("This is async handler error message");
|
||||||
{
|
{
|
||||||
spdlog::init_thread_pool(128, 1);
|
spdlog::init_thread_pool(128, 1);
|
||||||
auto logger = spdlog::create_async_logger<failing_sink>("failed_logger");
|
auto logger = spdlog::create_async<failing_sink>("failed_logger");
|
||||||
logger->set_error_handler([=](const std::string &) {
|
logger->set_error_handler([=](const std::string &) {
|
||||||
std::ofstream ofs("logs/custom_err2.txt");
|
std::ofstream ofs("logs/custom_err2.txt");
|
||||||
if (!ofs)
|
if (!ofs)
|
||||||
|
@ -8,7 +8,7 @@ TEST_CASE("simple_file_logger", "[simple_logger]]")
|
|||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
std::string filename = "logs/simple_log";
|
std::string filename = "logs/simple_log";
|
||||||
|
|
||||||
auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename);
|
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename);
|
||||||
logger->set_pattern("%v");
|
logger->set_pattern("%v");
|
||||||
|
|
||||||
logger->info("Test message {}", 1);
|
logger->info("Test message {}", 1);
|
||||||
@ -24,7 +24,7 @@ TEST_CASE("flush_on", "[flush_on]]")
|
|||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
std::string filename = "logs/simple_log";
|
std::string filename = "logs/simple_log";
|
||||||
|
|
||||||
auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename);
|
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename);
|
||||||
logger->set_pattern("%v");
|
logger->set_pattern("%v");
|
||||||
logger->set_level(spdlog::level::trace);
|
logger->set_level(spdlog::level::trace);
|
||||||
logger->flush_on(spdlog::level::info);
|
logger->flush_on(spdlog::level::info);
|
||||||
|
@ -13,10 +13,10 @@
|
|||||||
#define SPDLOG_DEBUG_ON
|
#define SPDLOG_DEBUG_ON
|
||||||
|
|
||||||
#include "spdlog/async.h"
|
#include "spdlog/async.h"
|
||||||
|
#include "spdlog/sinks/basic_file_sink.h"
|
||||||
#include "spdlog/sinks/daily_file_sink.h"
|
#include "spdlog/sinks/daily_file_sink.h"
|
||||||
#include "spdlog/sinks/null_sink.h"
|
#include "spdlog/sinks/null_sink.h"
|
||||||
#include "spdlog/sinks/ostream_sink.h"
|
#include "spdlog/sinks/ostream_sink.h"
|
||||||
#include "spdlog/sinks/rotating_file_sink.h"
|
#include "spdlog/sinks/rotating_file_sink.h"
|
||||||
#include "spdlog/sinks/simple_file_sink.h"
|
|
||||||
#include "spdlog/sinks/stdout_color_sinks.h"
|
#include "spdlog/sinks/stdout_color_sinks.h"
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
#include "spdlog/async.h"
|
#include "spdlog/async.h"
|
||||||
#include "spdlog/sinks/simple_file_sink.h"
|
#include "spdlog/sinks/basic_file_sink.h"
|
||||||
#include "test_sink.h"
|
#include "test_sink.h"
|
||||||
|
|
||||||
TEST_CASE("basic async test ", "[async]")
|
TEST_CASE("basic async test ", "[async]")
|
||||||
@ -11,7 +11,7 @@ TEST_CASE("basic async test ", "[async]")
|
|||||||
size_t messages = 256;
|
size_t messages = 256;
|
||||||
{
|
{
|
||||||
auto tp = std::make_shared<details::thread_pool>(queue_size, 1);
|
auto tp = std::make_shared<details::thread_pool>(queue_size, 1);
|
||||||
auto logger = std::make_shared<async_logger>("as", test_sink, tp, async_overflow_policy::block_retry);
|
auto logger = std::make_shared<async_logger>("as", test_sink, tp, async_overflow_policy::block);
|
||||||
for (size_t i = 0; i < messages; i++)
|
for (size_t i = 0; i < messages; i++)
|
||||||
{
|
{
|
||||||
logger->info("Hello message #{}", i);
|
logger->info("Hello message #{}", i);
|
||||||
@ -30,7 +30,7 @@ TEST_CASE("discard policy ", "[async]")
|
|||||||
size_t messages = 1024;
|
size_t messages = 1024;
|
||||||
{
|
{
|
||||||
auto tp = std::make_shared<details::thread_pool>(queue_size, 1);
|
auto tp = std::make_shared<details::thread_pool>(queue_size, 1);
|
||||||
auto logger = std::make_shared<async_logger>("as", test_sink, tp, async_overflow_policy::overrun_oldeset);
|
auto logger = std::make_shared<async_logger>("as", test_sink, tp, async_overflow_policy::overrun_oldest);
|
||||||
for (size_t i = 0; i < messages; i++)
|
for (size_t i = 0; i < messages; i++)
|
||||||
{
|
{
|
||||||
logger->info("Hello message #{}", i);
|
logger->info("Hello message #{}", i);
|
||||||
@ -48,7 +48,7 @@ TEST_CASE("flush", "[async]")
|
|||||||
size_t messages = 256;
|
size_t messages = 256;
|
||||||
{
|
{
|
||||||
auto tp = std::make_shared<details::thread_pool>(queue_size, 1);
|
auto tp = std::make_shared<details::thread_pool>(queue_size, 1);
|
||||||
auto logger = std::make_shared<async_logger>("as", test_sink, tp, async_overflow_policy::block_retry);
|
auto logger = std::make_shared<async_logger>("as", test_sink, tp, async_overflow_policy::block);
|
||||||
for (size_t i = 0; i < messages; i++)
|
for (size_t i = 0; i < messages; i++)
|
||||||
{
|
{
|
||||||
logger->info("Hello message #{}", i);
|
logger->info("Hello message #{}", i);
|
||||||
@ -69,7 +69,7 @@ TEST_CASE("tp->wait_empty() ", "[async]")
|
|||||||
size_t messages = 100;
|
size_t messages = 100;
|
||||||
|
|
||||||
auto tp = std::make_shared<details::thread_pool>(messages, 2);
|
auto tp = std::make_shared<details::thread_pool>(messages, 2);
|
||||||
auto logger = std::make_shared<async_logger>("as", test_sink, tp, async_overflow_policy::block_retry);
|
auto logger = std::make_shared<async_logger>("as", test_sink, tp, async_overflow_policy::block);
|
||||||
for (size_t i = 0; i < messages; i++)
|
for (size_t i = 0; i < messages; i++)
|
||||||
{
|
{
|
||||||
logger->info("Hello message #{}", i);
|
logger->info("Hello message #{}", i);
|
||||||
@ -90,7 +90,7 @@ TEST_CASE("multi threads", "[async]")
|
|||||||
size_t n_threads = 10;
|
size_t n_threads = 10;
|
||||||
{
|
{
|
||||||
auto tp = std::make_shared<details::thread_pool>(queue_size, 1);
|
auto tp = std::make_shared<details::thread_pool>(queue_size, 1);
|
||||||
auto logger = std::make_shared<async_logger>("as", test_sink, tp, async_overflow_policy::block_retry);
|
auto logger = std::make_shared<async_logger>("as", test_sink, tp, async_overflow_policy::block);
|
||||||
|
|
||||||
std::vector<std::thread> threads;
|
std::vector<std::thread> threads;
|
||||||
for (size_t i = 0; i < n_threads; i++)
|
for (size_t i = 0; i < n_threads; i++)
|
||||||
@ -121,7 +121,7 @@ TEST_CASE("to_file", "[async]")
|
|||||||
size_t tp_threads = 1;
|
size_t tp_threads = 1;
|
||||||
std::string filename = "logs/async_test.log";
|
std::string filename = "logs/async_test.log";
|
||||||
{
|
{
|
||||||
auto file_sink = std::make_shared<spdlog::sinks::simple_file_sink_mt>(filename, true);
|
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true);
|
||||||
auto tp = std::make_shared<spdlog::details::thread_pool>(messages, tp_threads);
|
auto tp = std::make_shared<spdlog::details::thread_pool>(messages, tp_threads);
|
||||||
auto logger = std::make_shared<spdlog::async_logger>("as", std::move(file_sink), std::move(tp));
|
auto logger = std::make_shared<spdlog::async_logger>("as", std::move(file_sink), std::move(tp));
|
||||||
|
|
||||||
@ -143,7 +143,7 @@ TEST_CASE("to_file multi-workers", "[async]")
|
|||||||
size_t tp_threads = 10;
|
size_t tp_threads = 10;
|
||||||
std::string filename = "logs/async_test.log";
|
std::string filename = "logs/async_test.log";
|
||||||
{
|
{
|
||||||
auto file_sink = std::make_shared<spdlog::sinks::simple_file_sink_mt>(filename, true);
|
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true);
|
||||||
auto tp = std::make_shared<spdlog::details::thread_pool>(messages, tp_threads);
|
auto tp = std::make_shared<spdlog::details::thread_pool>(messages, tp_threads);
|
||||||
auto logger = std::make_shared<spdlog::async_logger>("as", std::move(file_sink), std::move(tp));
|
auto logger = std::make_shared<spdlog::async_logger>("as", std::move(file_sink), std::move(tp));
|
||||||
|
|
||||||
|
@ -9,12 +9,11 @@ TEST_CASE("debug and trace w/o format string", "[macros]]")
|
|||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
std::string filename = "logs/simple_log";
|
std::string filename = "logs/simple_log";
|
||||||
|
|
||||||
auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename);
|
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename);
|
||||||
logger->set_pattern("%v");
|
logger->set_pattern("%v");
|
||||||
logger->set_level(spdlog::level::trace);
|
logger->set_level(spdlog::level::trace);
|
||||||
|
|
||||||
SPDLOG_TRACE(logger, "Test message 1");
|
SPDLOG_TRACE(logger, "Test message 1");
|
||||||
// SPDLOG_DEBUG(logger, "Test message 2");
|
|
||||||
SPDLOG_DEBUG(logger, "Test message 2");
|
SPDLOG_DEBUG(logger, "Test message 2");
|
||||||
logger->flush();
|
logger->flush();
|
||||||
|
|
||||||
@ -27,7 +26,7 @@ TEST_CASE("debug and trace with format strings", "[macros]]")
|
|||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
std::string filename = "logs/simple_log";
|
std::string filename = "logs/simple_log";
|
||||||
|
|
||||||
auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename);
|
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename);
|
||||||
logger->set_pattern("%v");
|
logger->set_pattern("%v");
|
||||||
logger->set_level(spdlog::level::trace);
|
logger->set_level(spdlog::level::trace);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user