Asink sink (#3309)
Some checks failed
linux / ${{ matrix.config.compiler}} ${{ matrix.config.version }} (C++${{ matrix.config.cppstd }} ${{ matrix.config.build_type }} ${{ matrix.config.asan == 'ON' && 'ASAN' || '' }}${{ matrix.config.tsan == 'ON' && 'TSAN' || '' }}) (map[asan:ON build_type:Debug … (push) Has been cancelled
linux / ${{ matrix.config.compiler}} ${{ matrix.config.version }} (C++${{ matrix.config.cppstd }} ${{ matrix.config.build_type }} ${{ matrix.config.asan == 'ON' && 'ASAN' || '' }}${{ matrix.config.tsan == 'ON' && 'TSAN' || '' }}) (map[build_type:Debug compiler… (push) Has been cancelled
linux / ${{ matrix.config.compiler}} ${{ matrix.config.version }} (C++${{ matrix.config.cppstd }} ${{ matrix.config.build_type }} ${{ matrix.config.asan == 'ON' && 'ASAN' || '' }}${{ matrix.config.tsan == 'ON' && 'TSAN' || '' }}) (map[build_type:Release compil… (push) Has been cancelled
macos / macOS Clang (C++17, Release) (push) Has been cancelled
windows / build (map[BUILD_EXAMPLE:OFF BUILD_SHARED:ON BUILD_TYPE:Release CXX_STANDARD:17 FATAL_ERRORS:ON GENERATOR:Visual Studio 17 2022]) (push) Has been cancelled
windows / build (map[BUILD_EXAMPLE:OFF BUILD_SHARED:ON BUILD_TYPE:Release CXX_STANDARD:20 FATAL_ERRORS:ON GENERATOR:Visual Studio 17 2022]) (push) Has been cancelled
windows / build (map[BUILD_EXAMPLE:ON BUILD_SHARED:OFF BUILD_TYPE:Release CXX_STANDARD:17 FATAL_ERRORS:ON GENERATOR:Visual Studio 17 2022]) (push) Has been cancelled
windows / build_2019 (map[BUILD_EXAMPLE:ON BUILD_SHARED:ON BUILD_TYPE:Release CXX_STANDARD:17 FATAL_ERRORS:ON GENERATOR:Visual Studio 16 2019]) (push) Has been cancelled
windows / build_2019 (map[BUILD_EXAMPLE:ON BUILD_SHARED:ON BUILD_TYPE:Release CXX_STANDARD:20 FATAL_ERRORS:ON GENERATOR:Visual Studio 16 2019]) (push) Has been cancelled

Replace async logger with async sink
This commit is contained in:
Gabi Melman 2025-01-05 02:17:31 +02:00 committed by GitHub
parent 166843ff3a
commit 83c9ede9e6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
82 changed files with 986 additions and 1789 deletions

View File

@ -139,8 +139,6 @@ find_package(Threads REQUIRED)
# Library sources # Library sources
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
set(SPDLOG_HEADERS set(SPDLOG_HEADERS
"include/spdlog/async.h"
"include/spdlog/async_logger.h"
"include/spdlog/common.h" "include/spdlog/common.h"
"include/spdlog/formatter.h" "include/spdlog/formatter.h"
"include/spdlog/fwd.h" "include/spdlog/fwd.h"
@ -154,16 +152,12 @@ set(SPDLOG_HEADERS
"include/spdlog/details/file_helper.h" "include/spdlog/details/file_helper.h"
"include/spdlog/details/fmt_helper.h" "include/spdlog/details/fmt_helper.h"
"include/spdlog/details/log_msg.h" "include/spdlog/details/log_msg.h"
"include/spdlog/details/log_msg_buffer.h" "include/spdlog/details/async_log_msg.h"
"include/spdlog/details/mpmc_blocking_q.h" "include/spdlog/details/mpmc_blocking_q.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/periodic_worker.h" "include/spdlog/details/err_helper.h"
"include/spdlog/details/context.h" "include/spdlog/bin_to_hex.h"
"include/spdlog/details/synchronous_factory.h"
"include/spdlog/details/thread_pool.h"
"include/spdlog/fmt/bin_to_hex.h"
"include/spdlog/fmt/fmt.h"
"include/spdlog/sinks/android_sink.h" "include/spdlog/sinks/android_sink.h"
"include/spdlog/sinks/base_sink.h" "include/spdlog/sinks/base_sink.h"
"include/spdlog/sinks/basic_file_sink.h" "include/spdlog/sinks/basic_file_sink.h"
@ -186,10 +180,10 @@ set(SPDLOG_HEADERS
"include/spdlog/sinks/syslog_sink.h" "include/spdlog/sinks/syslog_sink.h"
"include/spdlog/sinks/systemd_sink.h" "include/spdlog/sinks/systemd_sink.h"
"include/spdlog/sinks/tcp_sink.h" "include/spdlog/sinks/tcp_sink.h"
"include/spdlog/sinks/udp_sink.h") "include/spdlog/sinks/udp_sink.h"
"include/spdlog/sinks/async_sink.h")
set(SPDLOG_SRCS set(SPDLOG_SRCS
"src/async_logger.cpp"
"src/common.cpp" "src/common.cpp"
"src/logger.cpp" "src/logger.cpp"
"src/pattern_formatter.cpp" "src/pattern_formatter.cpp"
@ -197,22 +191,19 @@ set(SPDLOG_SRCS
"src/details/file_helper.cpp" "src/details/file_helper.cpp"
"src/details/os_filesystem.cpp" "src/details/os_filesystem.cpp"
"src/details/log_msg.cpp" "src/details/log_msg.cpp"
"src/details/log_msg_buffer.cpp" "src/details/async_log_msg.cpp"
"src/details/context.cpp" "src/details/err_helper.cpp"
"src/details/thread_pool.cpp"
"src/sinks/base_sink.cpp" "src/sinks/base_sink.cpp"
"src/sinks/basic_file_sink.cpp" "src/sinks/basic_file_sink.cpp"
"src/sinks/rotating_file_sink.cpp" "src/sinks/rotating_file_sink.cpp"
"src/sinks/sink.cpp" "src/sinks/stdout_sinks.cpp"
"src/sinks/stdout_color_sinks.cpp" "src/sinks/async_sink.cpp")
"src/sinks/stdout_sinks.cpp")
if (WIN32) if (WIN32)
list(APPEND SPDLOG_SRCS list(APPEND SPDLOG_SRCS
"src/details/os_windows.cpp" "src/details/os_windows.cpp"
"src/sinks/wincolor_sink.cpp") "src/sinks/wincolor_sink.cpp")
list( list(APPEND SPDLOG_HEADERS
APPEND SPDLOG_HEADERS
"include/spdlog/sinks/wincolor_sink.h" "include/spdlog/sinks/wincolor_sink.h"
"include/spdlog/details/tcp_client_windows.h" "include/spdlog/details/tcp_client_windows.h"
"include/spdlog/details/udp_client_windows.h" "include/spdlog/details/udp_client_windows.h"

View File

@ -245,33 +245,11 @@ void callback_example()
#include "spdlog/sinks/basic_file_sink.h" #include "spdlog/sinks/basic_file_sink.h"
void async_example() void async_example()
{ {
// default thread pool settings can be modified *before* creating the async logger: // TODO
// spdlog::init_thread_pool(8192, 1); // queue with 8k 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");
} }
``` ```
---
#### Asynchronous logger with multi sinks
```c++
#include "spdlog/async.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/rotating_file_sink.h"
void multi_sink_example2()
{
spdlog::init_thread_pool(8192, 1);
auto stdout_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt >();
auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>("mylog.txt", 1024*1024*10, 3);
std::vector<spdlog::sink_ptr> sinks {stdout_sink, rotating_sink};
auto logger = std::make_shared<spdlog::async_logger>("loggername", sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block);
spdlog::register_logger(logger);
}
```
--- ---
#### User-defined types #### User-defined types
```c++ ```c++

View File

@ -8,11 +8,14 @@
// //
#include <atomic> #include <atomic>
#include <iostream> #include <iostream>
#include <fstream>
#include <memory> #include <memory>
#include <string> #include <string>
#include <thread> #include <thread>
#include <locale>
#include <algorithm>
#include "spdlog/async.h" #include "spdlog/sinks/async_sink.h"
#include "spdlog/sinks/basic_file_sink.h" #include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
@ -23,21 +26,9 @@ using namespace spdlog::sinks;
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);
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4996) // disable fopen warning under msvc
#endif // _MSC_VER
int count_lines(const char *filename) { int count_lines(const char *filename) {
int counter = 0; std::ifstream ifs(filename);
auto *infile = fopen(filename, "r"); return std::count(std::istreambuf_iterator(ifs), std::istreambuf_iterator<char>(), '\n');
int ch;
while (EOF != (ch = getc(infile))) {
if ('\n' == ch) counter++;
}
fclose(infile);
return counter;
} }
void verify_file(const char *filename, int expected_count) { void verify_file(const char *filename, int expected_count) {
@ -54,7 +45,11 @@ void verify_file(const char *filename, int expected_count) {
#pragma warning(pop) #pragma warning(pop)
#endif #endif
using namespace spdlog::sinks;
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
// setlocale to show thousands separators
std::locale::global(std::locale("en_US.UTF-8"));
int howmany = 1000000; int howmany = 1000000;
int queue_size = std::min(howmany + 2, 8192); int queue_size = std::min(howmany + 2, 8192);
int threads = 10; int threads = 10;
@ -62,7 +57,7 @@ int main(int argc, char *argv[]) {
try { try {
spdlog::set_pattern("[%^%l%$] %v"); spdlog::set_pattern("[%^%l%$] %v");
if (argc == 1) { if (argc > 1 && (std::string(argv[1]) == "-h" || std::string(argv[1]) == "--help")) {
spdlog::info("Usage: {} <message_count> <threads> <q_size> <iterations>", argv[0]); spdlog::info("Usage: {} <message_count> <threads> <q_size> <iterations>", argv[0]);
return 0; return 0;
} }
@ -78,8 +73,13 @@ int main(int argc, char *argv[]) {
} }
if (argc > 4) iters = atoi(argv[4]); if (argc > 4) iters = atoi(argv[4]);
// validate all argc values
if (howmany < 1 || threads < 1 || queue_size < 1 || iters < 1) {
spdlog::error("Invalid input values");
exit(1);
}
auto slot_size = sizeof(spdlog::details::async_msg); auto slot_size = sizeof(details::async_log_msg);
spdlog::info("-------------------------------------------------"); spdlog::info("-------------------------------------------------");
spdlog::info("Messages : {:L}", howmany); spdlog::info("Messages : {:L}", howmany);
spdlog::info("Threads : {:L}", threads); spdlog::info("Threads : {:L}", threads);
@ -94,14 +94,17 @@ int main(int argc, char *argv[]) {
spdlog::info("Queue Overflow Policy: block"); spdlog::info("Queue Overflow Policy: block");
spdlog::info("*********************************"); spdlog::info("*********************************");
for (int i = 0; i < iters; i++) { for (int i = 0; i < iters; i++) {
auto tp = std::make_shared<details::thread_pool>(queue_size, 1); {
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true); auto file_sink = std::make_shared<basic_file_sink_mt>(filename, true);
auto logger = auto cfg = async_sink::config();
std::make_shared<async_logger>("async_logger", std::move(file_sink), std::move(tp), async_overflow_policy::block); cfg.queue_size = queue_size;
cfg.sinks.push_back(std::move(file_sink));
auto async_sink = std::make_shared<sinks::async_sink>(cfg);
auto logger = std::make_shared<spdlog::logger>("async_logger", std::move(async_sink));
bench_mt(howmany, std::move(logger), threads); bench_mt(howmany, std::move(logger), threads);
// verify_file(filename, howmany);
} }
//verify_file(filename, howmany); // in separate scope to ensure logger is destroyed and all logs were written
}
spdlog::info(""); spdlog::info("");
spdlog::info("*********************************"); spdlog::info("*********************************");
spdlog::info("Queue Overflow Policy: overrun"); spdlog::info("Queue Overflow Policy: overrun");
@ -109,10 +112,13 @@ int main(int argc, char *argv[]) {
// do same test but discard the oldest if queue is full instead of blocking // do same test but discard the oldest if queue is full instead of blocking
filename = "logs/basic_async-overrun.log"; filename = "logs/basic_async-overrun.log";
for (int i = 0; i < iters; i++) { for (int i = 0; i < iters; i++) {
auto tp = std::make_shared<details::thread_pool>(queue_size, 1); async_sink::config cfg;
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true); cfg.policy = async_sink::overflow_policy::overrun_oldest;
auto logger = std::make_shared<async_logger>("async_logger", std::move(file_sink), std::move(tp), cfg.queue_size = queue_size;
async_overflow_policy::overrun_oldest); auto file_sink = std::make_shared<basic_file_sink_mt>(filename, true);
cfg.sinks.push_back(std::move(file_sink));
auto async_sink = std::make_shared<sinks::async_sink>(cfg);
auto logger = std::make_shared<spdlog::logger>("async_logger", std::move(async_sink));
bench_mt(howmany, std::move(logger), threads); bench_mt(howmany, std::move(logger), threads);
} }
spdlog::shutdown(); spdlog::shutdown();

View File

@ -31,21 +31,22 @@ static const size_t file_size = 30 * 1024 * 1024;
static const size_t rotating_files = 5; static const size_t rotating_files = 5;
static const int max_threads = 1000; static const int max_threads = 1000;
using namespace spdlog::sinks;
void bench_threaded_logging(size_t threads, int iters) { void bench_threaded_logging(size_t threads, int iters) {
spdlog::info("**************************************************************"); spdlog::info("**************************************************************");
spdlog::info( spdlog::info(
spdlog::fmt_lib::format(std::locale("en_US.UTF-8"), "Multi threaded: {:L} threads, {:L} messages", threads, iters)); spdlog::fmt_lib::format(std::locale("en_US.UTF-8"), "Multi threaded: {:L} threads, {:L} messages", threads, iters));
spdlog::info("**************************************************************"); spdlog::info("**************************************************************");
auto basic_mt = spdlog::basic_logger_mt("basic_mt", "logs/basic_mt.log", true); auto basic_mt = spdlog::create<basic_file_sink_mt>("basic_mt", "logs/basic_mt.log", true);
bench_mt(iters, std::move(basic_mt), threads); bench_mt(iters, std::move(basic_mt), threads);
spdlog::info(""); spdlog::info("");
auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt.log", file_size, rotating_files); auto rotating_mt = spdlog::create<rotating_file_sink_mt>("rotating_mt", "logs/rotating_mt.log", file_size, rotating_files);
bench_mt(iters, std::move(rotating_mt), threads); bench_mt(iters, std::move(rotating_mt), threads);
spdlog::info(""); spdlog::info("");
auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt.log"); auto daily_mt = spdlog::create<daily_file_sink_mt>("daily_mt", "logs/daily_mt.log", 0, 1);
bench_mt(iters, std::move(daily_mt), threads); bench_mt(iters, std::move(daily_mt), threads);
spdlog::info(""); spdlog::info("");
@ -59,15 +60,15 @@ void bench_single_threaded(int iters) {
spdlog::info(spdlog::fmt_lib::format(std::locale("en_US.UTF-8"), "Single threaded: {} messages", iters)); spdlog::info(spdlog::fmt_lib::format(std::locale("en_US.UTF-8"), "Single threaded: {} messages", iters));
spdlog::info("**************************************************************"); spdlog::info("**************************************************************");
auto basic_st = spdlog::basic_logger_st("basic_st", "logs/basic_st.log", true); auto basic_st = spdlog::create<basic_file_sink_st>("basic_st", "logs/basic_st.log", true);
bench(iters, std::move(basic_st)); bench(iters, std::move(basic_st));
spdlog::info(""); spdlog::info("");
auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st.log", file_size, rotating_files); auto rotating_st = spdlog::create<rotating_file_sink_st>("rotating_st", "logs/rotating_st.log", file_size, rotating_files);
bench(iters, std::move(rotating_st)); bench(iters, std::move(rotating_st));
spdlog::info(""); spdlog::info("");
auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st.log"); auto daily_st = spdlog::create<daily_file_sink_st>("daily_st", "logs/daily_st.log", 0, 1);
bench(iters, std::move(daily_st)); bench(iters, std::move(daily_st));
spdlog::info(""); spdlog::info("");

View File

@ -8,13 +8,14 @@
// //
#include "benchmark/benchmark.h" #include "benchmark/benchmark.h"
#include "spdlog/async.h" #include "spdlog/sinks/async_sink.h"
#include "spdlog/sinks/basic_file_sink.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/spdlog.h" #include "spdlog/spdlog.h"
using namespace spdlog::sinks;
void bench_c_string(benchmark::State &state, std::shared_ptr<spdlog::logger> logger) { void bench_c_string(benchmark::State &state, std::shared_ptr<spdlog::logger> logger) {
const char *msg = const char *msg =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pharetra metus cursus " "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pharetra metus cursus "
@ -69,10 +70,10 @@ void bench_disabled_macro_global_logger(benchmark::State &state, std::shared_ptr
#ifdef __linux__ #ifdef __linux__
void bench_dev_null() { void bench_dev_null() {
auto dev_null_st = spdlog::basic_logger_st("/dev/null_st", "/dev/null"); auto dev_null_st = spdlog::create<basic_file_sink_st>("/dev/null_st", "/dev/null");
benchmark::RegisterBenchmark("/dev/null_st", bench_logger, std::move(dev_null_st))->UseRealTime(); benchmark::RegisterBenchmark("/dev/null_st", bench_logger, std::move(dev_null_st))->UseRealTime();
auto dev_null_mt = spdlog::basic_logger_mt("/dev/null_mt", "/dev/null"); auto dev_null_mt = spdlog::create<basic_file_sink_mt>("/dev/null_mt", "/dev/null");
benchmark::RegisterBenchmark("/dev/null_mt", bench_logger, std::move(dev_null_mt))->UseRealTime(); benchmark::RegisterBenchmark("/dev/null_mt", bench_logger, std::move(dev_null_mt))->UseRealTime();
} }
@ -85,7 +86,7 @@ static std::string prepare_null_loggers() {
const std::string some_logger_name = "Some logger name"; const std::string some_logger_name = "Some logger name";
const int null_logger_count = 9; const int null_logger_count = 9;
for (int i = 0; i < null_logger_count; i++) { for (int i = 0; i < null_logger_count; i++) {
spdlog::create<spdlog::sinks::null_sink_mt>(some_logger_name + std::to_string(i)); spdlog::create<null_sink_mt>(some_logger_name + std::to_string(i));
} }
return some_logger_name + std::to_string(null_logger_count / 2); return some_logger_name + std::to_string(null_logger_count / 2);
} }
@ -119,15 +120,15 @@ int main(int argc, char *argv[]) {
if (full_bench) { if (full_bench) {
// basic_st // basic_st
auto basic_st = spdlog::basic_logger_st("basic_st", "latency_logs/basic_st.log", true); auto basic_st = spdlog::create<basic_file_sink_st>("basic_st", "latency_logs/basic_st.log", true);
benchmark::RegisterBenchmark("basic_st", bench_logger, std::move(basic_st))->UseRealTime(); benchmark::RegisterBenchmark("basic_st", bench_logger, std::move(basic_st))->UseRealTime();
// rotating st // rotating st
auto rotating_st = spdlog::rotating_logger_st("rotating_st", "latency_logs/rotating_st.log", file_size, rotating_files); auto rotating_st = spdlog::create<rotating_file_sink_st>("rotating_st", "latency_logs/rotating_st.log", file_size, rotating_files);
benchmark::RegisterBenchmark("rotating_st", bench_logger, std::move(rotating_st))->UseRealTime(); benchmark::RegisterBenchmark("rotating_st", bench_logger, std::move(rotating_st))->UseRealTime();
// daily st // daily st
auto daily_st = spdlog::daily_logger_mt("daily_st", "latency_logs/daily_st.log"); auto daily_st = spdlog::create<daily_file_sink_st>("daily_st", "latency_logs/daily_st.log", 0, 1);
benchmark::RegisterBenchmark("daily_st", bench_logger, std::move(daily_st))->UseRealTime(); benchmark::RegisterBenchmark("daily_st", bench_logger, std::move(daily_st))->UseRealTime();
// //
@ -137,23 +138,23 @@ int main(int argc, char *argv[]) {
benchmark::RegisterBenchmark("null_sink_mt", bench_logger, null_logger_mt)->Threads(n_threads)->UseRealTime(); benchmark::RegisterBenchmark("null_sink_mt", bench_logger, null_logger_mt)->Threads(n_threads)->UseRealTime();
// basic_mt // basic_mt
auto basic_mt = spdlog::basic_logger_mt("basic_mt", "latency_logs/basic_mt.log", true); auto basic_mt = spdlog::create<basic_file_sink_mt>("basic_mt", "latency_logs/basic_mt.log", true);
benchmark::RegisterBenchmark("basic_mt", bench_logger, std::move(basic_mt))->Threads(n_threads)->UseRealTime(); benchmark::RegisterBenchmark("basic_mt", bench_logger, std::move(basic_mt))->Threads(n_threads)->UseRealTime();
// rotating mt // rotating mt
auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "latency_logs/rotating_mt.log", file_size, rotating_files); auto rotating_mt = spdlog::create<rotating_file_sink_mt>("rotating_mt", "latency_logs/rotating_mt.log", file_size, rotating_files);
benchmark::RegisterBenchmark("rotating_mt", bench_logger, std::move(rotating_mt))->Threads(n_threads)->UseRealTime(); benchmark::RegisterBenchmark("rotating_mt", bench_logger, std::move(rotating_mt))->Threads(n_threads)->UseRealTime();
// daily mt // daily mt
auto daily_mt = spdlog::daily_logger_mt("daily_mt", "latency_logs/daily_mt.log"); auto daily_mt = spdlog::create<daily_file_sink_mt>("daily_mt", "latency_logs/daily_mt.log", 0, 1);
benchmark::RegisterBenchmark("daily_mt", bench_logger, std::move(daily_mt))->Threads(n_threads)->UseRealTime(); benchmark::RegisterBenchmark("daily_mt", bench_logger, std::move(daily_mt))->Threads(n_threads)->UseRealTime();
} }
using spdlog::sinks::async_sink;
// async async_sink::config config;
auto queue_size = 1024 * 1024 * 3; config.queue_size = 3 * 1024 * 1024;;
auto tp = std::make_shared<spdlog::details::thread_pool>(queue_size, 1); config.sinks.push_back(std::make_shared<null_sink_st>());
auto async_logger = std::make_shared<spdlog::async_logger>("async_logger", std::make_shared<null_sink_mt>(), std::move(tp), config.policy = async_sink::overflow_policy::overrun_oldest;
spdlog::async_overflow_policy::overrun_oldest); auto async_logger = std::make_shared<spdlog::logger>("async_logger", std::make_shared<async_sink>(config));
benchmark::RegisterBenchmark("async_logger", bench_logger, async_logger)->Threads(n_threads)->UseRealTime(); benchmark::RegisterBenchmark("async_logger", bench_logger, async_logger)->Threads(n_threads)->UseRealTime();
benchmark::Initialize(&argc, argv); benchmark::Initialize(&argc, argv);

View File

@ -29,6 +29,8 @@ void replace_global_logger_example();
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
#include "spdlog/version.h" #include "spdlog/version.h"
using namespace spdlog::sinks;
int main(int, char *[]) { int main(int, char *[]) {
spdlog::info("Welcome to spdlog version {}.{}.{} !", SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH); spdlog::info("Welcome to spdlog version {}.{}.{} !", SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH);
spdlog::warn("Easy padding in numbers like {:08d}", 12); spdlog::warn("Easy padding in numbers like {:08d}", 12);
@ -84,49 +86,44 @@ int main(int, char *[]) {
// or #include "spdlog/sinks/stdout_sinks.h" if no colors needed. // or #include "spdlog/sinks/stdout_sinks.h" if no colors needed.
void stdout_logger_example() { void stdout_logger_example() {
// Create color multithreading logger. // Create color multithreading logger.
auto console = spdlog::stdout_color_mt("console"); auto console = spdlog::create<stdout_color_sink_mt>("console");
// or for stderr: // or for stderr:
// auto console = spdlog::stderr_color_mt("error-logger"); //auto console = spdlog::create<stderr_color_sink_mt>("console");
} }
#include "spdlog/sinks/basic_file_sink.h" #include "spdlog/sinks/basic_file_sink.h"
void basic_example() { void basic_example() {
// Create basic file logger (not rotated). // Create basic file logger (not rotated).
auto my_logger = spdlog::basic_logger_mt("file_logger", "logs/basic-log.txt", true); auto my_logger = spdlog::create<basic_file_sink_mt>("file_logger", "logs/basic-log.txt", true);
} }
#include "spdlog/sinks/rotating_file_sink.h" #include "spdlog/sinks/rotating_file_sink.h"
void rotating_example() { void rotating_example() {
// Create a file rotating logger with 5mb size max and 3 rotated files. // Create a file rotating logger with 5mb size max and 3 rotated files.
auto rotating_logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3); auto rotating_logger = spdlog::create<rotating_file_sink_mt>("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3);
} }
#include "spdlog/sinks/daily_file_sink.h" #include "spdlog/sinks/daily_file_sink.h"
void daily_example() { void daily_example() {
// Create a daily logger - a new file is created every day on 2:30am. // Create a daily logger - a new file is created every day on 2:30am.
auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30); auto daily_logger = spdlog::create<daily_file_format_sink_mt>("daily_logger", "logs/daily.txt", 2, 30);
} }
#include "spdlog/sinks/callback_sink.h" #include "spdlog/sinks/callback_sink.h"
void callback_example() { void callback_example() {
// Create the logger // Create the logger
auto logger = spdlog::callback_logger_mt("custom_callback_logger", [](const spdlog::details::log_msg & /*msg*/) { auto logger = spdlog::create<callback_sink_mt>("custom_callback_logger", [](const spdlog::details::log_msg & /*msg*/) {
// do what you need to do with msg // do what you need to do with msg
}); });
} }
#include "spdlog/async.h" #include "spdlog/sinks/async_sink.h"
void async_example() { void async_example() {
// Default thread pool settings can be modified *before* creating the async logger: using spdlog::sinks::async_sink;
// spdlog::init_thread_pool(32768, 1); // queue with max 32k items 1 backing thread. auto sink = async_sink::with<basic_file_sink_mt>("logs/async_log.txt", true);
auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt"); auto logger = std::make_shared<spdlog::logger>("async_logger", sink);
// 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) { for (int i = 1; i < 101; ++i) {
async_file->info("Async message #{}", i); logger->info("Async message #{}", i);
} }
} }
@ -139,7 +136,7 @@ void async_example() {
// {:p} - don't print the position on each line start. // {:p} - don't print the position on each line start.
// {:n} - don't split the output to lines. // {:n} - don't split the output to lines.
#include "spdlog/fmt/bin_to_hex.h" #include "spdlog/bin_to_hex.h"
void binary_example() { void binary_example() {
std::vector<char> buf; std::vector<char> buf;
for (int i = 0; i < 80; i++) { for (int i = 0; i < 80; i++) {
@ -183,19 +180,19 @@ void stopwatch_example() {
#include "spdlog/sinks/udp_sink.h" #include "spdlog/sinks/udp_sink.h"
void udp_example() { void udp_example() {
spdlog::sinks::udp_sink_config cfg("127.0.0.1", 11091); udp_sink_config cfg("127.0.0.1", 11091);
auto my_logger = spdlog::udp_logger_mt("udplog", cfg); auto my_logger = spdlog::create<udp_sink_mt>("udplog", cfg);
my_logger->set_level(spdlog::level::debug); my_logger->set_level(spdlog::level::debug);
my_logger->info("hello world"); my_logger->info("hello world");
} }
// A logger with multiple sinks (stdout and file) - each with a different format and log level. // A logger with multiple sinks (stdout and file) - each with a different format and log level.
void multi_sink_example() { void multi_sink_example() {
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>(); auto console_sink = std::make_shared<stdout_color_sink_mt>();
console_sink->set_level(spdlog::level::warn); console_sink->set_level(spdlog::level::warn);
console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v"); 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); auto file_sink = std::make_shared<basic_file_sink_mt>("logs/multisink.txt", true);
file_sink->set_level(spdlog::level::trace); file_sink->set_level(spdlog::level::trace);
spdlog::logger logger("multi_sink", {console_sink, file_sink}); spdlog::logger logger("multi_sink", {console_sink, file_sink});
@ -231,7 +228,7 @@ void err_handler_example() {
#include "spdlog/sinks/syslog_sink.h" #include "spdlog/sinks/syslog_sink.h"
void syslog_example() { void syslog_example() {
std::string ident = "spdlog-example"; std::string ident = "spdlog-example";
auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID); auto syslog_logger = spdlog::create<syslog_sink_mt>("syslog", ident, LOG_PID);
syslog_logger->warn("This is warning that will end up in syslog."); syslog_logger->warn("This is warning that will end up in syslog.");
} }
#endif #endif
@ -291,7 +288,7 @@ void replace_global_logger_example() {
// store the old logger so we don't break other examples. // store the old logger so we don't break other examples.
auto old_logger = spdlog::global_logger(); auto old_logger = spdlog::global_logger();
auto new_logger = spdlog::basic_logger_mt("new_global_logger", "logs/new-default-log.txt", true); auto new_logger = spdlog::create<basic_file_sink_mt>("new_global_logger", "logs/new-default-log.txt", true);
spdlog::set_global_logger(new_logger); spdlog::set_global_logger(new_logger);
spdlog::set_level(spdlog::level::info); spdlog::set_level(spdlog::level::info);
spdlog::debug("This message should not be displayed!"); spdlog::debug("This message should not be displayed!");

View File

@ -1,85 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
//
// Async logging using global thread pool
// All loggers created here share same global thread pool.
// Each log message is pushed to a queue along with a shared pointer to the
// logger.
// If a logger deleted while having pending messages in the queue, it's actual
// destruction will defer
// until all its messages are processed by the thread pool.
// This is because each message in the queue holds a shared_ptr to the
// originating logger.
#include <functional>
#include <memory>
#include <mutex>
#include "./async_logger.h"
#include "./details/context.h"
#include "./details/thread_pool.h"
#include "spdlog.h"
namespace spdlog {
namespace details {
static constexpr size_t default_async_q_size = 8192;
}
// 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.
template <async_overflow_policy OverflowPolicy = async_overflow_policy::block>
struct async_factory_impl {
template <typename Sink, typename... SinkArgs>
static std::shared_ptr<async_logger> create(std::string logger_name, SinkArgs &&...args) {
auto context = spdlog::context();
// create global thread pool if not already exists
auto &mutex = context->tp_mutex();
std::lock_guard<std::recursive_mutex> tp_lock(mutex);
auto tp = context->get_tp();
if (tp == nullptr) {
tp = std::make_shared<details::thread_pool>(details::default_async_q_size, 1U);
context->set_tp(tp);
}
auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
auto new_logger = std::make_shared<async_logger>(std::move(logger_name), std::move(sink), std::move(tp), OverflowPolicy);
return new_logger;
}
};
using async_factory = async_factory_impl<async_overflow_policy::block>;
using async_factory_nonblock = async_factory_impl<async_overflow_policy::overrun_oldest>;
template <typename Sink, typename... SinkArgs>
std::shared_ptr<spdlog::logger> create_async(std::string logger_name, SinkArgs &&...sink_args) {
return async_factory::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...);
}
template <typename Sink, typename... SinkArgs>
std::shared_ptr<spdlog::logger> create_async_nb(std::string logger_name, SinkArgs &&...sink_args) {
return async_factory_nonblock::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...);
}
// set global thread pool.
inline void init_thread_pool(size_t q_size,
size_t thread_count,
std::function<void()> on_thread_start,
std::function<void()> on_thread_stop) {
auto tp = std::make_shared<details::thread_pool>(q_size, thread_count, on_thread_start, on_thread_stop);
spdlog::context()->set_tp(std::move(tp));
}
inline void init_thread_pool(size_t q_size, size_t thread_count, std::function<void()> on_thread_start) {
init_thread_pool(q_size, thread_count, on_thread_start, [] {});
}
inline void init_thread_pool(size_t q_size, size_t thread_count) {
init_thread_pool(q_size, thread_count, [] {}, [] {});
}
// get the global thread pool.
inline std::shared_ptr<spdlog::details::thread_pool> thread_pool() { return spdlog::context()->get_tp(); }
} // namespace spdlog

View File

@ -1,69 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
// Fast asynchronous logger.
// Uses pre allocated queue.
// Creates a single back thread to pop messages from the queue and log them.
//
// Upon each log write the logger:
// 1. Checks if its log level is enough to log the message
// 2. Push a new copy of the message to a queue (or block the caller until
// space is available in the queue)
// Upon destruction, logs all remaining messages in the queue before
// destructing
#include "./logger.h"
namespace spdlog {
// Async overflow policy - block by default.
enum class async_overflow_policy {
block, // Block until message can be enqueued
overrun_oldest, // Discard the oldest message in the queue if full when trying to
// add new item.
discard_new // Discard new message if the queue is full when trying to add new item.
};
namespace details {
class thread_pool;
}
class SPDLOG_API async_logger final : public std::enable_shared_from_this<async_logger>, public logger {
friend class details::thread_pool;
public:
template <typename It>
async_logger(std::string logger_name,
It begin,
It end,
std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy = async_overflow_policy::block)
: logger(std::move(logger_name), begin, end),
thread_pool_(std::move(tp)),
overflow_policy_(overflow_policy) {}
async_logger(std::string logger_name,
sinks_init_list sinks_list,
std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy = async_overflow_policy::block);
async_logger(std::string logger_name,
sink_ptr single_sink,
std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy = async_overflow_policy::block);
std::shared_ptr<logger> clone(std::string new_name) override;
protected:
void sink_it_(const details::log_msg &msg) override;
void flush_() override;
void backend_sink_it_(const details::log_msg &incoming_log_msg);
void backend_flush_();
private:
std::weak_ptr<details::thread_pool> thread_pool_;
async_overflow_policy overflow_policy_;
};
} // namespace spdlog

View File

@ -7,7 +7,7 @@
#include <cctype> #include <cctype>
#include "../common.h" #include "common.h"
#if defined(__has_include) #if defined(__has_include)
#if __has_include(<version>) #if __has_include(<version>)

View File

@ -12,8 +12,11 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <cstdint>
#include "./source_loc.h" #include "./source_loc.h"
#include "fmt/base.h"
#include "fmt/xchar.h"
#if defined(SPDLOG_SHARED_LIB) #if defined(SPDLOG_SHARED_LIB)
#if defined(_WIN32) #if defined(_WIN32)
@ -29,8 +32,6 @@
#define SPDLOG_API #define SPDLOG_API
#endif #endif
#include "fmt/fmt.h"
#define SPDLOG_FMT_RUNTIME(format_string) fmt::runtime(format_string) #define SPDLOG_FMT_RUNTIME(format_string) fmt::runtime(format_string)
#define SPDLOG_FMT_STRING(format_string) FMT_STRING(format_string) #define SPDLOG_FMT_STRING(format_string) FMT_STRING(format_string)
@ -73,7 +74,7 @@ using format_string_t = fmt::format_string<Args...>;
#endif #endif
// Log level enum // Log level enum
enum class level { enum class level : std::uint8_t {
trace = SPDLOG_LEVEL_TRACE, trace = SPDLOG_LEVEL_TRACE,
debug = SPDLOG_LEVEL_DEBUG, debug = SPDLOG_LEVEL_DEBUG,
info = SPDLOG_LEVEL_INFO, info = SPDLOG_LEVEL_INFO,
@ -81,7 +82,7 @@ enum class level {
err = SPDLOG_LEVEL_ERROR, err = SPDLOG_LEVEL_ERROR,
critical = SPDLOG_LEVEL_CRITICAL, critical = SPDLOG_LEVEL_CRITICAL,
off = SPDLOG_LEVEL_OFF, off = SPDLOG_LEVEL_OFF,
n_levels n_levels = SPDLOG_LEVEL_OFF + 1
}; };
using atomic_level_t = std::atomic<level>; using atomic_level_t = std::atomic<level>;

View File

@ -0,0 +1,37 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <cstdint>
#include "./log_msg.h"
namespace spdlog {
namespace details {
// Extend log_msg with internal buffer to store its payload.
// This is needed since log_msg holds string_views that points to stack data.
class SPDLOG_API async_log_msg : public log_msg {
public:
enum class type:std::uint8_t { log, flush, terminate };
async_log_msg() = default;
explicit async_log_msg(type type);
async_log_msg(type type, const log_msg &orig_msg);
~async_log_msg() = default;
async_log_msg(const async_log_msg &other);
async_log_msg(async_log_msg &&other) noexcept;
async_log_msg &operator=(const async_log_msg &other);
async_log_msg &operator=(async_log_msg &&other) noexcept;
type message_type() const {return msg_type_;}
private:
type msg_type_{type::log};
memory_buf_t buffer_;
void update_string_views();
};
} // namespace details
} // namespace spdlog

View File

@ -7,8 +7,6 @@
#include <cassert> #include <cassert>
#include <vector> #include <vector>
#include "spdlog/common.h"
namespace spdlog { namespace spdlog {
namespace details { namespace details {
template <typename T> template <typename T>

View File

@ -1,59 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
// Loggers registry of unique name->logger pointer
// An attempt to create a logger with an already existing name will result with spdlog_ex exception.
// If user requests a non-existing logger, nullptr will be returned
// This class is thread safe
#include <memory>
#include <mutex>
#include <string>
#include "../common.h"
#include "./periodic_worker.h"
namespace spdlog {
class logger;
namespace details {
class thread_pool;
class SPDLOG_API context {
public:
context() = default;
explicit context(std::unique_ptr<logger> global_logger);
~context() = default;
context(const context &) = delete;
context &operator=(const context &) = delete;
[[nodiscard]] std::shared_ptr<logger> global_logger();
// Return raw ptr to the global logger.
// To be used directly by the spdlog global api (e.g. spdlog::info)
// This make the global API faster, but cannot be used concurrently with set_global_logger().
// e.g do not call set_global_logger() from one thread while calling spdlog::info() from
// another.
[[nodiscard]] logger *global_logger_raw() const noexcept;
// set logger instance.
void set_logger(std::shared_ptr<logger> new_logger);
void set_tp(std::shared_ptr<thread_pool> tp);
[[nodiscard]] std::shared_ptr<thread_pool> get_tp();
// clean all resources
void shutdown();
[[nodiscard]] std::recursive_mutex &tp_mutex();
private:
std::recursive_mutex tp_mutex_;
std::shared_ptr<thread_pool> tp_;
std::shared_ptr<logger> global_logger_;
};
} // namespace details
} // namespace spdlog

View File

@ -0,0 +1,23 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <string>
#include <mutex>
#include <exception>
#include "spdlog/common.h"
// by default, prints the error to stderr, thread safe
namespace spdlog {
namespace details {
class SPDLOG_API err_helper {
err_handler custom_err_handler_;
public:
void handle_ex(const std::string& origin, const source_loc& loc, const std::exception& ex) const;
void handle_unknown_ex(const std::string& origin, const source_loc& loc) const;
void set_err_handler(err_handler handler);
};
}} // namespace spdlog::details

View File

@ -7,7 +7,6 @@
#include <type_traits> #include <type_traits>
#include "../common.h" #include "../common.h"
#include "../fmt/fmt.h"
// Some fmt helpers to efficiently format and pad ints and strings // Some fmt helpers to efficiently format and pad ints and strings
namespace spdlog { namespace spdlog {

View File

@ -1,28 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include "./log_msg.h"
namespace spdlog {
namespace details {
// Extend log_msg with internal buffer to store its payload.
// This is needed since log_msg holds string_views that points to stack data.
class SPDLOG_API log_msg_buffer : public log_msg {
memory_buf_t buffer;
void update_string_views();
public:
log_msg_buffer() = default;
explicit log_msg_buffer(const log_msg &orig_msg);
log_msg_buffer(const log_msg_buffer &other);
log_msg_buffer(log_msg_buffer &&other) noexcept;
log_msg_buffer &operator=(const log_msg_buffer &other);
log_msg_buffer &operator=(log_msg_buffer &&other) noexcept;
};
} // namespace details
} // namespace spdlog

View File

@ -37,7 +37,7 @@ public:
push_cv_.notify_one(); push_cv_.notify_one();
} }
// enqueue immediately. overrun oldest message in the queue if no room left. // enqueue immediately. overrun the oldest message in the queue if no room left.
void enqueue_nowait(T &&item) { void enqueue_nowait(T &&item) {
{ {
std::unique_lock<std::mutex> lock(queue_mutex_); std::unique_lock<std::mutex> lock(queue_mutex_);

View File

@ -1,57 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
// periodic worker thread - periodically executes the given callback function.
//
// RAII over the owned thread:
// creates the thread on construction.
// stops and joins the thread on destruction (if the thread is executing a callback, wait for it
// to finish first).
#include <chrono>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <thread>
#include "../common.h"
namespace spdlog {
namespace details {
class SPDLOG_API periodic_worker {
public:
template <typename Rep, typename Period>
periodic_worker(const std::function<void()> &callback_fun, std::chrono::duration<Rep, Period> interval) {
active_ = (interval > std::chrono::duration<Rep, Period>::zero());
if (!active_) {
return;
}
worker_thread_ = std::thread([this, callback_fun, interval]() {
for (;;) {
std::unique_lock<std::mutex> lock(this->mutex_);
if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; })) {
return; // active_ == false, so exit this thread
}
callback_fun();
}
});
}
std::thread &get_thread() { return worker_thread_; }
periodic_worker(const periodic_worker &) = delete;
periodic_worker &operator=(const periodic_worker &) = delete;
// stop the worker thread and join it
~periodic_worker();
private:
bool active_;
std::thread worker_thread_;
std::mutex mutex_;
std::condition_variable cv_;
};
} // namespace details
} // namespace spdlog

View File

@ -1,21 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include "./context.h"
namespace spdlog {
// Default logger factory- creates synchronous loggers
class logger;
struct synchronous_factory {
template <typename Sink, typename... SinkArgs>
static std::shared_ptr<spdlog::logger> create(std::string logger_name, SinkArgs &&...args) {
auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
auto new_logger = std::make_shared<spdlog::logger>(std::move(logger_name), std::move(sink));
return new_logger;
}
};
} // namespace spdlog

View File

@ -1,112 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <chrono>
#include <functional>
#include <memory>
#include <thread>
#include <vector>
#include "../async.h"
#include "./log_msg_buffer.h"
#include "./mpmc_blocking_q.h"
#include "./os.h"
namespace spdlog {
class async_logger;
namespace details {
using async_logger_ptr = std::shared_ptr<spdlog::async_logger>;
enum class async_msg_type { log, flush, terminate };
// Async msg to move to/from the queue
// Movable only. should never be copied
struct async_msg : log_msg_buffer {
async_msg_type msg_type{async_msg_type::log};
async_logger_ptr worker_ptr;
async_msg() = default;
~async_msg() = default;
// should only be moved in or out of the queue..
async_msg(const async_msg &) = delete;
// support for vs2013 move
#if defined(_MSC_VER) && _MSC_VER <= 1800
async_msg(async_msg &&other)
: log_msg_buffer(std::move(other)),
msg_type(other.msg_type),
worker_ptr(std::move(other.worker_ptr)) {}
async_msg &operator=(async_msg &&other) {
*static_cast<log_msg_buffer *>(this) = std::move(other);
msg_type = other.msg_type;
worker_ptr = std::move(other.worker_ptr);
return *this;
}
#else // (_MSC_VER) && _MSC_VER <= 1800
async_msg(async_msg &&) = default;
async_msg &operator=(async_msg &&) = default;
#endif
// construct from log_msg with given type
async_msg(async_logger_ptr &&worker, async_msg_type the_type, const details::log_msg &m)
: log_msg_buffer{m},
msg_type{the_type},
worker_ptr{std::move(worker)} {}
async_msg(async_logger_ptr &&worker, async_msg_type the_type)
: log_msg_buffer{},
msg_type{the_type},
worker_ptr{std::move(worker)} {}
explicit async_msg(async_msg_type the_type)
: async_msg{nullptr, the_type} {}
};
class SPDLOG_API thread_pool {
public:
using item_type = async_msg;
using q_type = details::mpmc_blocking_queue<item_type>;
thread_pool(size_t q_max_items,
size_t threads_n,
std::function<void()> on_thread_start,
std::function<void()> on_thread_stop);
thread_pool(size_t q_max_items, size_t threads_n, std::function<void()> on_thread_start);
thread_pool(size_t q_max_items, size_t threads_n);
// message all threads to terminate gracefully and join them
~thread_pool();
thread_pool(const thread_pool &) = delete;
thread_pool &operator=(thread_pool &&) = delete;
void post_log(async_logger_ptr &&worker_ptr, const details::log_msg &msg, async_overflow_policy overflow_policy);
void post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy);
size_t overrun_counter();
void reset_overrun_counter();
size_t discard_counter();
void reset_discard_counter();
size_t queue_size();
private:
q_type q_;
std::vector<std::thread> threads_;
void post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy);
void worker_loop_();
// process next message in the queue
// return true if this thread should still be active (while no terminate msg
// was received)
bool process_next_msg_();
};
} // namespace details
} // namespace spdlog

View File

@ -1,9 +0,0 @@
//
// Copyright(c) 2016-2018 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include "fmt/format.h"
#include "fmt/xchar.h"

View File

@ -3,37 +3,22 @@
#pragma once #pragma once
// Thread safe logger (except for set_error_handler()) // Thread-safe logger, with exceptions for these non-thread-safe methods:
// Has name, log level, vector of std::shared sink pointers and formatter // set_pattern() - Modifies the log pattern.
// Upon each log write the logger: // set_formatter() - Sets a new formatter.
// 1. Checks if its log level is enough to log the message and if yes: // set_error_handler() - Assigns a new error handler.
// 2. Call the underlying sinks to do the job. // sinks() (non-const) - Accesses and potentially modifies the sinks directly.
// 3. Each sink use its own private copy of a formatter to format the message // By default, the logger does not throw exceptions during logging.
// and send to its destination. // To enable exception throwing for logging errors, set a custom error handler.
//
// The use of private formatter per sink provides the opportunity to cache some
// formatted data, and support for different format per sink.
#include <cassert> #include <cassert>
#include <iterator> #include <iterator>
#include <vector> #include <vector>
#include "./common.h" #include "common.h"
#include "./details/log_msg.h" #include "details/err_helper.h"
#include "./sinks/sink.h" #include "details/log_msg.h"
#include "sinks/sink.h"
#define SPDLOG_LOGGER_CATCH(location) \
catch (const std::exception &ex) { \
if (!location.empty()) { \
err_handler_(fmt_lib::format(SPDLOG_FMT_STRING("{} [{}({})]"), ex.what(), location.filename, location.line)); \
} else { \
err_handler_(ex.what()); \
} \
} \
catch (...) { \
err_handler_("Rethrowing unknown exception in logger"); \
throw; \
}
namespace spdlog { namespace spdlog {
@ -60,7 +45,7 @@ public:
logger(const logger &other) noexcept; logger(const logger &other) noexcept;
logger(logger &&other) noexcept; logger(logger &&other) noexcept;
virtual ~logger() = default; ~logger() = default;
template <typename... Args> template <typename... Args>
void log(source_loc loc, level lvl, format_string_t<Args...> fmt, Args &&...args) { void log(source_loc loc, level lvl, format_string_t<Args...> fmt, Args &&...args) {
@ -168,14 +153,14 @@ public:
void set_error_handler(err_handler); void set_error_handler(err_handler);
// create new logger with same sinks and configuration. // create new logger with same sinks and configuration.
virtual std::shared_ptr<logger> clone(std::string logger_name); std::shared_ptr<logger> clone(std::string logger_name);
protected: private:
std::string name_; std::string name_;
std::vector<sink_ptr> sinks_; std::vector<sink_ptr> sinks_;
spdlog::atomic_level_t level_{level::info}; atomic_level_t level_{level::info};
spdlog::atomic_level_t flush_level_{level::off}; atomic_level_t flush_level_{level::off};
err_handler custom_err_handler_{nullptr}; details::err_helper err_helper_;
// common implementation for after templated public api has been resolved to format string and // common implementation for after templated public api has been resolved to format string and
// args // args
@ -186,19 +171,25 @@ protected:
memory_buf_t buf; memory_buf_t buf;
fmt::vformat_to(std::back_inserter(buf), format_string, fmt::make_format_args(args...)); fmt::vformat_to(std::back_inserter(buf), format_string, fmt::make_format_args(args...));
sink_it_(details::log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()))); sink_it_(details::log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())));
} catch (const std::exception &ex) {
err_helper_.handle_ex(name_, loc, ex);
} catch (...) {
err_helper_.handle_unknown_ex(name_, loc);
} }
SPDLOG_LOGGER_CATCH(loc)
} }
// log the given message (if the given log level is high enough) // log the given message (if the given log level is high enough)
virtual void sink_it_(const details::log_msg &msg) { void sink_it_(const details::log_msg &msg) {
assert(should_log(msg.log_level)); assert(should_log(msg.log_level));
for (auto &sink : sinks_) { for (auto &sink : sinks_) {
if (sink->should_log(msg.log_level)) { if (sink->should_log(msg.log_level)) {
try { try {
sink->log(msg); sink->log(msg);
} catch (const std::exception &ex) {
err_helper_.handle_ex(name_, msg.source, ex);
} catch (...) {
err_helper_.handle_unknown_ex(name_, msg.source);
} }
SPDLOG_LOGGER_CATCH(msg.source)
} }
} }
@ -206,12 +197,8 @@ protected:
flush_(); flush_();
} }
} }
virtual void flush_(); void flush_();
[[nodiscard]] bool should_flush_(const details::log_msg &msg) const; [[nodiscard]] bool should_flush_(const details::log_msg &msg) const;
// handle errors during logging.
// default handler prints the error to stderr at max rate of 1 message/sec.
void err_handler_(const std::string &msg);
}; };
} // namespace spdlog } // namespace spdlog

View File

@ -16,7 +16,6 @@
#include "../details/fmt_helper.h" #include "../details/fmt_helper.h"
#include "../details/null_mutex.h" #include "../details/null_mutex.h"
#include "../details/os.h" #include "../details/os.h"
#include "../details/synchronous_factory.h"
#include "./base_sink.h" #include "./base_sink.h"
#if !defined(SPDLOG_ANDROID_RETRIES) #if !defined(SPDLOG_ANDROID_RETRIES)
@ -120,19 +119,6 @@ template <int BufferId = log_id::LOG_ID_MAIN>
using android_sink_buf_st = android_sink<details::null_mutex, BufferId>; using android_sink_buf_st = android_sink<details::null_mutex, BufferId>;
} // namespace sinks } // namespace sinks
// Create and register android syslog logger
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> android_logger_mt(const std::string &logger_name, const std::string &tag = "spdlog") {
return Factory::template create<sinks::android_sink_mt>(logger_name, tag);
}
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> android_logger_st(const std::string &logger_name, const std::string &tag = "spdlog") {
return Factory::template create<sinks::android_sink_st>(logger_name, tag);
}
} // namespace spdlog } // namespace spdlog
#endif // __ANDROID__ #endif // __ANDROID__

View File

@ -94,7 +94,6 @@ public:
using ansicolor_stdout_sink_mt = ansicolor_stdout_sink<std::mutex>; using ansicolor_stdout_sink_mt = ansicolor_stdout_sink<std::mutex>;
using ansicolor_stdout_sink_st = ansicolor_stdout_sink<details::null_mutex>; using ansicolor_stdout_sink_st = ansicolor_stdout_sink<details::null_mutex>;
using ansicolor_stderr_sink_mt = ansicolor_stderr_sink<std::mutex>; using ansicolor_stderr_sink_mt = ansicolor_stderr_sink<std::mutex>;
using ansicolor_stderr_sink_st = ansicolor_stderr_sink<details::null_mutex>; using ansicolor_stderr_sink_st = ansicolor_stderr_sink<details::null_mutex>;

View File

@ -0,0 +1,86 @@
#pragma once
#include <atomic>
#include <cstdint>
#include <functional>
#include <memory>
#include <thread>
#include <vector>
#include "../details/async_log_msg.h"
#include "../details/err_helper.h"
#include "sink.h"
// async_sink is a sink that sends log messages to a dist_sink in a separate thread using a queue.
// The worker thread dequeues the messages and sends them to the dist_sink to perform the actual logging.
// Once the sink is destroyed, the worker thread empties the queue and exits.
namespace spdlog::details { // forward declaration
template <typename T>
class mpmc_blocking_queue;
}
namespace spdlog {
namespace sinks {
class SPDLOG_API async_sink final : public sink {
public:
enum class overflow_policy : std::uint8_t {
block, // Block until the log message can be enqueued (default).
overrun_oldest, // Overrun the oldest message in the queue if full.
discard_new // Discard the log message if the queue is full
};
enum { default_queue_size = 8192, max_queue_size = 10 * 1024 * 1024 };
struct config {
size_t queue_size = default_queue_size;
overflow_policy policy = overflow_policy::block;
std::vector<std::shared_ptr<sink>> sinks;
std::function<void()> on_thread_start = nullptr;
std::function<void()> on_thread_stop = nullptr;
err_handler custom_err_handler = nullptr;
};
explicit async_sink(config async_config);
// create an async_sink with one backend sink
template <typename Sink, typename... SinkArgs>
static std::shared_ptr<async_sink> with(SinkArgs &&...sink_args) {
config cfg{};
cfg.sinks.emplace_back(std::make_shared<Sink>(std::forward<SinkArgs>(sink_args)...));
return std::make_shared<async_sink>(cfg);
}
~async_sink() override;
// sink interface implementation
void log(const details::log_msg &msg) override;
void flush() override;
void set_pattern(const std::string &pattern) override;
void set_formatter(std::unique_ptr<formatter> sink_formatter) override;
// async sink specific methods
[[nodiscard]] size_t get_overrun_counter() const;
void reset_overrun_counter() const;
[[nodiscard]] size_t get_discard_counter() const;
void reset_discard_counter() const;
[[nodiscard]] const config &get_config() const;
private:
using async_log_msg = details::async_log_msg;
using queue_t = details::mpmc_blocking_queue<async_log_msg>;
void send_message_(async_log_msg::type msg_type, const details::log_msg &msg) const;
void backend_loop_();
void backend_log_(const details::log_msg &msg) ;
void backend_flush_();
config config_;
std::unique_ptr<queue_t> q_;
std::thread worker_thread_;
details::err_helper err_helper_;
};
} // namespace sinks
} // namespace spdlog

View File

@ -43,5 +43,6 @@ protected:
virtual void set_pattern_(const std::string &pattern); virtual void set_pattern_(const std::string &pattern);
virtual void set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter); virtual void set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter);
}; };
} // namespace sinks } // namespace sinks
} // namespace spdlog } // namespace spdlog

View File

@ -8,7 +8,6 @@
#include "../details/file_helper.h" #include "../details/file_helper.h"
#include "../details/null_mutex.h" #include "../details/null_mutex.h"
#include "../details/synchronous_factory.h"
#include "./base_sink.h" #include "./base_sink.h"
namespace spdlog { namespace spdlog {
@ -34,24 +33,4 @@ using basic_file_sink_mt = basic_file_sink<std::mutex>;
using basic_file_sink_st = basic_file_sink<details::null_mutex>; using basic_file_sink_st = basic_file_sink<details::null_mutex>;
} // namespace sinks } // namespace sinks
//
// factory functions
//
template <typename Factory = spdlog::synchronous_factory>
std::shared_ptr<logger> basic_logger_mt(const std::string &logger_name,
const filename_t &filename,
bool truncate = false,
const file_event_handlers &event_handlers = {}) {
return Factory::template create<sinks::basic_file_sink_mt>(logger_name, filename, truncate, event_handlers);
}
template <typename Factory = spdlog::synchronous_factory>
std::shared_ptr<logger> basic_logger_st(const std::string &logger_name,
const filename_t &filename,
bool truncate = false,
const file_event_handlers &event_handlers = {}) {
return Factory::template create<sinks::basic_file_sink_st>(logger_name, filename, truncate, event_handlers);
}
} // namespace spdlog } // namespace spdlog

View File

@ -7,7 +7,6 @@
#include <string> #include <string>
#include "../details/null_mutex.h" #include "../details/null_mutex.h"
#include "../details/synchronous_factory.h"
#include "./base_sink.h" #include "./base_sink.h"
namespace spdlog { namespace spdlog {
@ -37,18 +36,4 @@ using callback_sink_mt = callback_sink<std::mutex>;
using callback_sink_st = callback_sink<details::null_mutex>; using callback_sink_st = callback_sink<details::null_mutex>;
} // namespace sinks } // namespace sinks
//
// factory functions
//
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> callback_logger_mt(const std::string &logger_name, const custom_log_callback &callback) {
return Factory::template create<sinks::callback_sink_mt>(logger_name, callback);
}
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> callback_logger_st(const std::string &logger_name, const custom_log_callback &callback) {
return Factory::template create<sinks::callback_sink_st>(logger_name, callback);
}
} // namespace spdlog } // namespace spdlog

View File

@ -15,7 +15,6 @@
#include "../details/file_helper.h" #include "../details/file_helper.h"
#include "../details/null_mutex.h" #include "../details/null_mutex.h"
#include "../details/os.h" #include "../details/os.h"
#include "../details/synchronous_factory.h"
#include "./base_sink.h" #include "./base_sink.h"
namespace spdlog { namespace spdlog {
@ -190,55 +189,4 @@ using daily_file_format_sink_mt = daily_file_sink<std::mutex, daily_filename_for
using daily_file_format_sink_st = daily_file_sink<details::null_mutex, daily_filename_format_calculator>; using daily_file_format_sink_st = daily_file_sink<details::null_mutex, daily_filename_format_calculator>;
} // namespace sinks } // namespace sinks
//
// factory functions
//
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> daily_logger_mt(const std::string &logger_name,
const filename_t &filename,
int hour = 0,
int minute = 0,
bool truncate = false,
uint16_t max_files = 0,
const file_event_handlers &event_handlers = {}) {
return Factory::template create<sinks::daily_file_sink_mt>(logger_name, filename, hour, minute, truncate, max_files,
event_handlers);
}
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> daily_logger_format_mt(const std::string &logger_name,
const filename_t &filename,
int hour = 0,
int minute = 0,
bool truncate = false,
uint16_t max_files = 0,
const file_event_handlers &event_handlers = {}) {
return Factory::template create<sinks::daily_file_format_sink_mt>(logger_name, filename, hour, minute, truncate, max_files,
event_handlers);
}
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> daily_logger_st(const std::string &logger_name,
const filename_t &filename,
int hour = 0,
int minute = 0,
bool truncate = false,
uint16_t max_files = 0,
const file_event_handlers &event_handlers = {}) {
return Factory::template create<sinks::daily_file_sink_st>(logger_name, filename, hour, minute, truncate, max_files,
event_handlers);
}
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> daily_logger_format_st(const std::string &logger_name,
const filename_t &filename,
int hour = 0,
int minute = 0,
bool truncate = false,
uint16_t max_files = 0,
const file_event_handlers &event_handlers = {}) {
return Factory::template create<sinks::daily_file_format_sink_st>(logger_name, filename, hour, minute, truncate, max_files,
event_handlers);
}
} // namespace spdlog } // namespace spdlog

View File

@ -24,14 +24,14 @@ class dist_sink : public base_sink<Mutex> {
public: public:
dist_sink() = default; dist_sink() = default;
explicit dist_sink(std::vector<std::shared_ptr<sink>> sinks) explicit dist_sink(std::vector<std::shared_ptr<sink>> sinks)
: sinks_(sinks) {} : sinks_(std::move(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;
void add_sink(std::shared_ptr<sink> sub_sink) { void add_sink(std::shared_ptr<sink> sub_sink) {
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_); std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
sinks_.push_back(sub_sink); sinks_.push_back(std::move(sub_sink));
} }
void remove_sink(std::shared_ptr<sink> sub_sink) { void remove_sink(std::shared_ptr<sink> sub_sink) {
@ -48,7 +48,7 @@ public:
protected: protected:
void sink_it_(const details::log_msg &msg) override { void sink_it_(const details::log_msg &msg) override {
for (auto &sub_sink : sinks_) { for (const auto &sub_sink : sinks_) {
if (sub_sink->should_log(msg.log_level)) { if (sub_sink->should_log(msg.log_level)) {
sub_sink->log(msg); sub_sink->log(msg);
} }

View File

@ -14,8 +14,6 @@
#include "../details/file_helper.h" #include "../details/file_helper.h"
#include "../details/null_mutex.h" #include "../details/null_mutex.h"
#include "../details/os.h" #include "../details/os.h"
#include "../details/synchronous_factory.h"
#include "../fmt/fmt.h"
#include "./base_sink.h" #include "./base_sink.h"
namespace spdlog { namespace spdlog {
@ -167,25 +165,4 @@ using hourly_file_sink_mt = hourly_file_sink<std::mutex>;
using hourly_file_sink_st = hourly_file_sink<details::null_mutex>; using hourly_file_sink_st = hourly_file_sink<details::null_mutex>;
} // namespace sinks } // namespace sinks
//
// factory functions
//
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> hourly_logger_mt(const std::string &logger_name,
const filename_t &filename,
bool truncate = false,
uint16_t max_files = 0,
const file_event_handlers &event_handlers = {}) {
return Factory::template create<sinks::hourly_file_sink_mt>(logger_name, filename, truncate, max_files, event_handlers);
}
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> hourly_logger_st(const std::string &logger_name,
const filename_t &filename,
bool truncate = false,
uint16_t max_files = 0,
const file_event_handlers &event_handlers = {}) {
return Factory::template create<sinks::hourly_file_sink_st>(logger_name, filename, truncate, max_files, event_handlers);
}
} // namespace spdlog } // namespace spdlog

View File

@ -12,11 +12,9 @@
#include <mutex> #include <mutex>
#include "../async.h"
#include "../common.h" #include "../common.h"
#include "../details/log_msg.h" #include "../details/log_msg.h"
#include "../details/null_mutex.h" #include "../details/null_mutex.h"
#include "../details/synchronous_factory.h"
#include "./base_sink.h" #include "./base_sink.h"
// kafka header // kafka header
@ -89,25 +87,4 @@ using kafka_sink_mt = kafka_sink<std::mutex>;
using kafka_sink_st = kafka_sink<spdlog::details::null_mutex>; using kafka_sink_st = kafka_sink<spdlog::details::null_mutex>;
} // namespace sinks } // namespace sinks
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> kafka_logger_mt(const std::string &logger_name, spdlog::sinks::kafka_sink_config config) {
return Factory::template create<sinks::kafka_sink_mt>(logger_name, config);
}
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> kafka_logger_st(const std::string &logger_name, spdlog::sinks::kafka_sink_config config) {
return Factory::template create<sinks::kafka_sink_st>(logger_name, config);
}
template <typename Factory = spdlog::async_factory>
inline std::shared_ptr<spdlog::logger> kafka_logger_async_mt(std::string logger_name, spdlog::sinks::kafka_sink_config config) {
return Factory::template create<sinks::kafka_sink_mt>(logger_name, config);
}
template <typename Factory = spdlog::async_factory>
inline std::shared_ptr<spdlog::logger> kafka_logger_async_st(std::string logger_name, spdlog::sinks::kafka_sink_config config) {
return Factory::template create<sinks::kafka_sink_st>(logger_name, config);
}
} // namespace spdlog } // namespace spdlog

View File

@ -17,9 +17,10 @@
#include <mongocxx/instance.hpp> #include <mongocxx/instance.hpp>
#include <mongocxx/uri.hpp> #include <mongocxx/uri.hpp>
#include <mutex>
#include "../details/null_mutex.h"
#include "../common.h" #include "../common.h"
#include "../details/log_msg.h" #include "../details/log_msg.h"
#include "../details/synchronous_factory.h"
#include "./base_sink.h" #include "./base_sink.h"
namespace spdlog { namespace spdlog {
@ -75,28 +76,8 @@ private:
std::unique_ptr<mongocxx::client> client_ = nullptr; std::unique_ptr<mongocxx::client> client_ = nullptr;
}; };
#include <mutex>
#include "../details/null_mutex.h"
using mongo_sink_mt = mongo_sink<std::mutex>; using mongo_sink_mt = mongo_sink<std::mutex>;
using mongo_sink_st = mongo_sink<spdlog::details::null_mutex>; using mongo_sink_st = mongo_sink<details::null_mutex>;
} // namespace sinks } // namespace sinks
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> mongo_logger_mt(const std::string &logger_name,
const std::string &db_name,
const std::string &collection_name,
const std::string &uri = "mongodb://localhost:27017") {
return Factory::template create<sinks::mongo_sink_mt>(logger_name, db_name, collection_name, uri);
}
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> mongo_logger_st(const std::string &logger_name,
const std::string &db_name,
const std::string &collection_name,
const std::string &uri = "mongodb://localhost:27017") {
return Factory::template create<sinks::mongo_sink_st>(logger_name, db_name, collection_name, uri);
}
} // namespace spdlog } // namespace spdlog

View File

@ -4,7 +4,6 @@
#pragma once #pragma once
#include <mutex> #include <mutex>
#include "../details/null_mutex.h" #include "../details/null_mutex.h"
#include "./base_sink.h" #include "./base_sink.h"

View File

@ -4,7 +4,6 @@
#pragma once #pragma once
#include "../details/null_mutex.h" #include "../details/null_mutex.h"
#include "../details/synchronous_factory.h"
#include "./base_sink.h" #include "./base_sink.h"
namespace spdlog { namespace spdlog {
@ -21,19 +20,4 @@ using null_sink_mt = null_sink<details::null_mutex>;
using null_sink_st = null_sink<details::null_mutex>; using null_sink_st = null_sink<details::null_mutex>;
} // namespace sinks } // namespace sinks
template <typename Factory = spdlog::synchronous_factory>
std::shared_ptr<logger> null_logger_mt(const std::string &logger_name) {
auto null_logger = Factory::template create<sinks::null_sink_mt>(logger_name);
null_logger->set_level(level::off);
return null_logger;
}
template <typename Factory = spdlog::synchronous_factory>
std::shared_ptr<logger> null_logger_st(const std::string &logger_name) {
auto null_logger = Factory::template create<sinks::null_sink_st>(logger_name);
null_logger->set_level(level::off);
return null_logger;
}
} // namespace spdlog } // namespace spdlog

View File

@ -17,7 +17,6 @@
#include "../common.h" #include "../common.h"
#include "../details/log_msg.h" #include "../details/log_msg.h"
#include "../details/synchronous_factory.h"
#include "./base_sink.h" #include "./base_sink.h"
// //
@ -218,75 +217,10 @@ protected:
std::array<QTextCharFormat, level::n_levels> colors_; std::array<QTextCharFormat, level::n_levels> colors_;
}; };
#include <mutex>
#include "../details/null_mutex.h"
using qt_sink_mt = qt_sink<std::mutex>; using qt_sink_mt = qt_sink<std::mutex>;
using qt_sink_st = qt_sink<details::null_mutex>; using qt_sink_st = qt_sink<details::null_mutex>;
using qt_color_sink_mt = qt_color_sink<std::mutex>; using qt_color_sink_mt = qt_color_sink<std::mutex>;
using qt_color_sink_st = qt_color_sink<details::null_mutex>; using qt_color_sink_st = qt_color_sink<details::null_mutex>;
} // namespace sinks } // namespace sinks
//
// Factory functions
//
// log to QTextEdit
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> qt_logger_mt(const std::string &logger_name,
QTextEdit *qt_object,
const std::string &meta_method = "append") {
return Factory::template create<sinks::qt_sink_mt>(logger_name, qt_object, meta_method);
}
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> qt_logger_st(const std::string &logger_name,
QTextEdit *qt_object,
const std::string &meta_method = "append") {
return Factory::template create<sinks::qt_sink_st>(logger_name, qt_object, meta_method);
}
// log to QPlainTextEdit
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> qt_logger_mt(const std::string &logger_name,
QPlainTextEdit *qt_object,
const std::string &meta_method = "appendPlainText") {
return Factory::template create<sinks::qt_sink_mt>(logger_name, qt_object, meta_method);
}
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> qt_logger_st(const std::string &logger_name,
QPlainTextEdit *qt_object,
const std::string &meta_method = "appendPlainText") {
return Factory::template create<sinks::qt_sink_st>(logger_name, qt_object, meta_method);
}
// log to QObject
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> qt_logger_mt(const std::string &logger_name, QObject *qt_object, const std::string &meta_method) {
return Factory::template create<sinks::qt_sink_mt>(logger_name, qt_object, meta_method);
}
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> qt_logger_st(const std::string &logger_name, QObject *qt_object, const std::string &meta_method) {
return Factory::template create<sinks::qt_sink_st>(logger_name, qt_object, meta_method);
}
// log to QTextEdit with colorized output
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> qt_color_logger_mt(const std::string &logger_name,
QTextEdit *qt_text_edit,
int max_lines,
bool is_utf8 = false) {
return Factory::template create<sinks::qt_color_sink_mt>(logger_name, qt_text_edit, max_lines, false, is_utf8);
}
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> qt_color_logger_st(const std::string &logger_name,
QTextEdit *qt_text_edit,
int max_lines,
bool is_utf8 = false) {
return Factory::template create<sinks::qt_color_sink_st>(logger_name, qt_text_edit, max_lines, false, is_utf8);
}
} // namespace spdlog } // namespace spdlog

View File

@ -7,10 +7,10 @@
#include <mutex> #include <mutex>
#include <string_view> #include <string_view>
#include "../details/async_log_msg.h"
#include "../details/circular_q.h" #include "../details/circular_q.h"
#include "../details/log_msg_buffer.h"
#include "../details/null_mutex.h" #include "../details/null_mutex.h"
#include "./base_sink.h" #include "base_sink.h"
namespace spdlog { namespace spdlog {
namespace sinks { namespace sinks {
@ -26,7 +26,7 @@ public:
explicit ringbuffer_sink(size_t n_items) explicit ringbuffer_sink(size_t n_items)
: q_{n_items} {} : q_{n_items} {}
void drain_raw(std::function<void(const details::log_msg_buffer &)> callback) { void drain_raw(std::function<void(const details::async_log_msg &)> callback) {
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_); std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
while (!q_.empty()) { while (!q_.empty()) {
callback(q_.front()); callback(q_.front());
@ -46,11 +46,11 @@ public:
} }
protected: protected:
void sink_it_(const details::log_msg &msg) override { q_.push_back(details::log_msg_buffer{msg}); } void sink_it_(const details::log_msg &msg) override { q_.push_back(details::async_log_msg{details::async_log_msg::type::log, msg}); }
void flush_() override {} void flush_() override {}
private: private:
details::circular_q<details::log_msg_buffer> q_; details::circular_q<details::async_log_msg> q_;
}; };
using ringbuffer_sink_mt = ringbuffer_sink<std::mutex>; using ringbuffer_sink_mt = ringbuffer_sink<std::mutex>;

View File

@ -8,14 +8,12 @@
#include "../details/file_helper.h" #include "../details/file_helper.h"
#include "../details/null_mutex.h" #include "../details/null_mutex.h"
#include "../details/synchronous_factory.h"
#include "./base_sink.h" #include "./base_sink.h"
// Rotating file sink based on size
namespace spdlog { namespace spdlog {
namespace sinks { namespace sinks {
//
// Rotating file sink based on size
//
template <typename Mutex> template <typename Mutex>
class rotating_file_sink final : public base_sink<Mutex> { class rotating_file_sink final : public base_sink<Mutex> {
public: public:
@ -56,30 +54,4 @@ using rotating_file_sink_mt = rotating_file_sink<std::mutex>;
using rotating_file_sink_st = rotating_file_sink<details::null_mutex>; using rotating_file_sink_st = rotating_file_sink<details::null_mutex>;
} // namespace sinks } // namespace sinks
//
// factory functions
//
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> rotating_logger_mt(const std::string &logger_name,
const filename_t &filename,
size_t max_file_size,
size_t max_files,
bool rotate_on_open = false,
const file_event_handlers &event_handlers = {}) {
return Factory::template create<sinks::rotating_file_sink_mt>(logger_name, filename, max_file_size, max_files, rotate_on_open,
event_handlers);
}
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> rotating_logger_st(const std::string &logger_name,
const filename_t &filename,
size_t max_file_size,
size_t max_files,
bool rotate_on_open = false,
const file_event_handlers &event_handlers = {}) {
return Factory::template create<sinks::rotating_file_sink_st>(logger_name, filename, max_file_size, max_files, rotate_on_open,
event_handlers);
}
} // namespace spdlog } // namespace spdlog

View File

@ -16,9 +16,9 @@ public:
virtual void set_pattern(const std::string &pattern) = 0; virtual void set_pattern(const std::string &pattern) = 0;
virtual void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) = 0; virtual void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) = 0;
void set_level(level level); void set_level(level level) { level_.store(level, std::memory_order_relaxed); }
level log_level() const; level log_level() const { return level_.load(std::memory_order_relaxed);}
bool should_log(level msg_level) const; bool should_log(level msg_level) const {return msg_level >= level_.load(std::memory_order_relaxed);}
protected: protected:
// sink log level - default is all // sink log level - default is all

View File

@ -9,9 +9,6 @@
#include "./ansicolor_sink.h" #include "./ansicolor_sink.h"
#endif #endif
#include "../async.h"
#include "../details/synchronous_factory.h"
namespace spdlog { namespace spdlog {
namespace sinks { namespace sinks {
#ifdef _WIN32 #ifdef _WIN32
@ -25,19 +22,6 @@ using stdout_color_sink_st = ansicolor_stdout_sink_st;
using stderr_color_sink_mt = ansicolor_stderr_sink_mt; using stderr_color_sink_mt = ansicolor_stderr_sink_mt;
using stderr_color_sink_st = ansicolor_stderr_sink_st; using stderr_color_sink_st = ansicolor_stderr_sink_st;
#endif #endif
} // namespace sinks } // namespace sinks
// logger factory functions
template <typename Factory = spdlog::synchronous_factory>
std::shared_ptr<logger> stdout_color_mt(const std::string &logger_name, color_mode mode = color_mode::automatic);
template <typename Factory = spdlog::synchronous_factory>
std::shared_ptr<logger> stdout_color_st(const std::string &logger_name, color_mode mode = color_mode::automatic);
template <typename Factory = spdlog::synchronous_factory>
std::shared_ptr<logger> stderr_color_mt(const std::string &logger_name, color_mode mode = color_mode::automatic);
template <typename Factory = spdlog::synchronous_factory>
std::shared_ptr<logger> stderr_color_st(const std::string &logger_name, color_mode mode = color_mode::automatic);
} // namespace spdlog } // namespace spdlog

View File

@ -4,9 +4,9 @@
#pragma once #pragma once
#include <cstdio> #include <cstdio>
#include <mutex>
#include "../details/null_mutex.h" #include "../details/null_mutex.h"
#include "../details/synchronous_factory.h"
#include "./base_sink.h" #include "./base_sink.h"
#include "./sink.h" #include "./sink.h"
@ -58,18 +58,4 @@ using stderr_sink_mt = stderr_sink<std::mutex>;
using stderr_sink_st = stderr_sink<details::null_mutex>; using stderr_sink_st = stderr_sink<details::null_mutex>;
} // namespace sinks } // namespace sinks
// factory methods
template <typename Factory = spdlog::synchronous_factory>
std::shared_ptr<logger> stdout_logger_mt(const std::string &logger_name);
template <typename Factory = spdlog::synchronous_factory>
std::shared_ptr<logger> stdout_logger_st(const std::string &logger_name);
template <typename Factory = spdlog::synchronous_factory>
std::shared_ptr<logger> stderr_logger_mt(const std::string &logger_name);
template <typename Factory = spdlog::synchronous_factory>
std::shared_ptr<logger> stderr_logger_st(const std::string &logger_name);
} // namespace spdlog } // namespace spdlog

View File

@ -4,12 +4,12 @@
#pragma once #pragma once
#include <spdlog/details/null_mutex.h> #include <spdlog/details/null_mutex.h>
#include <spdlog/details/synchronous_factory.h>
#include <spdlog/sinks/base_sink.h> #include <spdlog/sinks/base_sink.h>
#include <syslog.h> #include <syslog.h>
#include <array> #include <array>
#include <string> #include <string>
#include <mutex>
namespace spdlog { namespace spdlog {
namespace sinks { namespace sinks {
@ -19,7 +19,7 @@ namespace sinks {
template <typename Mutex> template <typename Mutex>
class syslog_sink final : public base_sink<Mutex> { class syslog_sink final : public base_sink<Mutex> {
public: public:
syslog_sink(std::string ident, int syslog_option, int syslog_facility, bool enable_formatting) syslog_sink(std::string ident = "", int syslog_option = 0, int syslog_facility = LOG_USER, bool enable_formatting=false)
: enable_formatting_{enable_formatting}, : enable_formatting_{enable_formatting},
syslog_levels_{{/* spdlog::level::trace */ LOG_DEBUG, syslog_levels_{{/* spdlog::level::trace */ LOG_DEBUG,
/* spdlog::level::debug */ LOG_DEBUG, /* spdlog::level::debug */ LOG_DEBUG,
@ -79,26 +79,6 @@ private:
using syslog_sink_mt = syslog_sink<std::mutex>; using syslog_sink_mt = syslog_sink<std::mutex>;
using syslog_sink_st = syslog_sink<details::null_mutex>; using syslog_sink_st = syslog_sink<details::null_mutex>;
} // namespace sinks } // namespace sinks
// Create and register a syslog logger
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> syslog_logger_mt(const std::string &logger_name,
const std::string &syslog_ident = "",
int syslog_option = 0,
int syslog_facility = LOG_USER,
bool enable_formatting = false) {
return Factory::template create<sinks::syslog_sink_mt>(logger_name, syslog_ident, syslog_option, syslog_facility,
enable_formatting);
}
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> syslog_logger_st(const std::string &logger_name,
const std::string &syslog_ident = "",
int syslog_option = 0,
int syslog_facility = LOG_USER,
bool enable_formatting = false) {
return Factory::template create<sinks::syslog_sink_st>(logger_name, syslog_ident, syslog_option, syslog_facility,
enable_formatting);
}
} // namespace spdlog } // namespace spdlog

View File

@ -7,7 +7,6 @@
#include "../details/null_mutex.h" #include "../details/null_mutex.h"
#include "../details/os.h" #include "../details/os.h"
#include "../details/synchronous_factory.h"
#include "./base_sink.h" #include "./base_sink.h"
#ifndef SD_JOURNAL_SUPPRESS_LOCATION #ifndef SD_JOURNAL_SUPPRESS_LOCATION
#define SD_JOURNAL_SUPPRESS_LOCATION #define SD_JOURNAL_SUPPRESS_LOCATION
@ -90,20 +89,6 @@ protected:
using systemd_sink_mt = systemd_sink<std::mutex>; using systemd_sink_mt = systemd_sink<std::mutex>;
using systemd_sink_st = systemd_sink<details::null_mutex>; using systemd_sink_st = systemd_sink<details::null_mutex>;
} // namespace sinks } // namespace sinks
// Create and register a syslog logger
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> systemd_logger_mt(const std::string &logger_name,
const std::string &ident = "",
bool enable_formatting = false) {
return Factory::template create<sinks::systemd_sink_mt>(logger_name, ident, enable_formatting);
}
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> systemd_logger_st(const std::string &logger_name,
const std::string &ident = "",
bool enable_formatting = false) {
return Factory::template create<sinks::systemd_sink_st>(logger_name, ident, enable_formatting);
}
} // namespace spdlog } // namespace spdlog

View File

@ -69,7 +69,7 @@ protected:
}; };
using tcp_sink_mt = tcp_sink<std::mutex>; using tcp_sink_mt = tcp_sink<std::mutex>;
using tcp_sink_st = tcp_sink<spdlog::details::null_mutex>; using tcp_sink_st = tcp_sink<details::null_mutex>;
} // namespace sinks } // namespace sinks
} // namespace spdlog } // namespace spdlog

View File

@ -33,7 +33,7 @@ struct udp_sink_config {
}; };
template <typename Mutex> template <typename Mutex>
class udp_sink final : public spdlog::sinks::base_sink<Mutex> { class udp_sink final : public base_sink<Mutex> {
public: public:
// host can be hostname or ip address // host can be hostname or ip address
explicit udp_sink(udp_sink_config sink_config) explicit udp_sink(udp_sink_config sink_config)
@ -53,16 +53,7 @@ protected:
}; };
using udp_sink_mt = udp_sink<std::mutex>; using udp_sink_mt = udp_sink<std::mutex>;
using udp_sink_st = udp_sink<spdlog::details::null_mutex>; using udp_sink_st = udp_sink<details::null_mutex>;
} // namespace sinks } // namespace sinks
//
// factory functions
//
template <typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> udp_logger_mt(const std::string &logger_name, sinks::udp_sink_config skin_config) {
return Factory::template create<sinks::udp_sink_mt>(logger_name, skin_config);
}
} // namespace spdlog } // namespace spdlog

View File

@ -66,8 +66,8 @@ public:
using wincolor_stdout_sink_mt = wincolor_stdout_sink<std::mutex>; using wincolor_stdout_sink_mt = wincolor_stdout_sink<std::mutex>;
using wincolor_stdout_sink_st = wincolor_stdout_sink<details::null_mutex>; using wincolor_stdout_sink_st = wincolor_stdout_sink<details::null_mutex>;
using wincolor_stderr_sink_mt = wincolor_stderr_sink<std::mutex>; using wincolor_stderr_sink_mt = wincolor_stderr_sink<std::mutex>;
using wincolor_stderr_sink_st = wincolor_stderr_sink<details::null_mutex>; using wincolor_stderr_sink_st = wincolor_stderr_sink<details::null_mutex>;
} // namespace sinks } // namespace sinks
} // namespace spdlog } // namespace spdlog

View File

@ -14,24 +14,16 @@
#include <string_view> #include <string_view>
#include "./common.h" #include "./common.h"
#include "./details/context.h"
#include "./details/synchronous_factory.h"
#include "./logger.h" #include "./logger.h"
namespace spdlog { namespace spdlog {
using default_factory = synchronous_factory;
SPDLOG_API void set_context(std::shared_ptr<details::context> context);
SPDLOG_API std::shared_ptr<details::context> context();
SPDLOG_API const std::shared_ptr<details::context> &context_ref();
// Create a logger with a templated sink type // Create a logger with a templated sink type
// Example: // Example:
// spdlog::create<daily_file_sink_st>("logger_name", "dailylog_filename", 11, 59); // spdlog::create<daily_file_sink_st>("logger_name", "dailylog_filename", 11, 59);
template <typename Sink, typename... SinkArgs> template <typename Sink, typename... SinkArgs>
std::shared_ptr<logger> create(std::string logger_name, SinkArgs &&...sink_args) { std::shared_ptr<logger> create(std::string logger_name, SinkArgs &&...sink_args) {
return default_factory::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...); return std::make_shared<logger>(std::move(logger_name), std::make_shared<Sink>(std::forward<SinkArgs>(sink_args)...));
} }
// Set formatter of the global logger. Each sink in each logger will get a clone of this object // Set formatter of the global logger. Each sink in each logger will get a clone of this object

View File

@ -5,7 +5,7 @@
#include <chrono> #include <chrono>
#include "fmt/fmt.h" #include "fmt/base.h"
// Stopwatch support for spdlog (using std::chrono::steady_clock). // Stopwatch support for spdlog (using std::chrono::steady_clock).
// Displays elapsed seconds since construction as double. // Displays elapsed seconds since construction as double.

View File

@ -1,79 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#include "spdlog/async_logger.h"
#include <memory>
#include <string>
#include "spdlog/details/thread_pool.h"
#include "spdlog/sinks/sink.h"
spdlog::async_logger::async_logger(std::string logger_name,
sinks_init_list sinks_list,
std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy)
: async_logger(std::move(logger_name), sinks_list.begin(), sinks_list.end(), std::move(tp), overflow_policy) {}
spdlog::async_logger::async_logger(std::string logger_name,
sink_ptr single_sink,
std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy)
: async_logger(std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy) {}
// send the log message to the thread pool
void spdlog::async_logger::sink_it_(const details::log_msg &msg) {
try {
if (auto pool_ptr = thread_pool_.lock()) {
pool_ptr->post_log(shared_from_this(), msg, overflow_policy_);
} else {
throw_spdlog_ex("async log: thread pool doesn't exist anymore");
}
}
SPDLOG_LOGGER_CATCH(msg.source)
}
// send flush request to the thread pool
void spdlog::async_logger::flush_() {
try {
if (auto pool_ptr = thread_pool_.lock()) {
pool_ptr->post_flush(shared_from_this(), overflow_policy_);
} else {
throw_spdlog_ex("async flush: thread pool doesn't exist anymore");
}
}
SPDLOG_LOGGER_CATCH(source_loc())
}
//
// backend functions - called from the thread pool to do the actual job
//
void spdlog::async_logger::backend_sink_it_(const details::log_msg &msg) {
for (auto &sink : sinks_) {
if (sink->should_log(msg.log_level)) {
try {
sink->log(msg);
}
SPDLOG_LOGGER_CATCH(msg.source)
}
}
if (should_flush_(msg)) {
backend_flush_();
}
}
void spdlog::async_logger::backend_flush_() {
for (auto &sink : sinks_) {
try {
sink->flush();
}
SPDLOG_LOGGER_CATCH(source_loc())
}
}
std::shared_ptr<spdlog::logger> spdlog::async_logger::clone(std::string new_name) {
auto cloned = std::make_shared<spdlog::async_logger>(*this);
cloned->name_ = std::move(new_name);
return cloned;
}

View File

@ -0,0 +1,61 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#include "spdlog/details/async_log_msg.h"
namespace spdlog {
namespace details {
async_log_msg::async_log_msg(const type type)
: msg_type_{type} {}
// copy logger name and payload to buffer so can be used asynchronously
// note: source location pointers are copied without allocation since they
// are compiler generated const chars* (__FILE__, __LINE__, __FUNCTION__)
// if you pass custom strings to source location, make sure they outlive the async_log_msg
async_log_msg::async_log_msg(const type type, const log_msg &orig_msg)
: log_msg{orig_msg}, msg_type_(type) {
buffer_.append(logger_name);
buffer_.append(payload);
update_string_views();
}
async_log_msg::async_log_msg(const async_log_msg &other)
: log_msg{other}, msg_type_{other.msg_type_} {
buffer_.append(logger_name);
buffer_.append(payload);
update_string_views();
}
async_log_msg::async_log_msg(async_log_msg &&other) noexcept
: log_msg{other}, msg_type_{other.msg_type_}, buffer_{std::move(other.buffer_)} {
update_string_views();
}
async_log_msg &async_log_msg::operator=(const async_log_msg &other) {
if (this == &other) return *this;
log_msg::operator=(other);
msg_type_ = other.msg_type_;
buffer_.clear();
buffer_.append(other.buffer_.data(), other.buffer_.data() + other.buffer_.size());
update_string_views();
return *this;
}
async_log_msg &async_log_msg::operator=(async_log_msg &&other) noexcept {
if (this == &other) return *this;
log_msg::operator=(other);
msg_type_ = other.msg_type_;
buffer_ = std::move(other.buffer_);
update_string_views();
return *this;
}
void async_log_msg::update_string_views() {
logger_name = string_view_t{buffer_.data(), logger_name.size()};
payload = string_view_t{buffer_.data() + logger_name.size(), payload.size()};
}
} // namespace details
} // namespace spdlog

View File

@ -1,49 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#include "spdlog/details/context.h"
#include "spdlog/logger.h"
#ifndef SPDLOG_DISABLE_GLOBAL_LOGGER
#include "spdlog/sinks/stdout_color_sinks.h"
#endif // SPDLOG_DISABLE_GLOBAL_LOGGER
#include <memory>
namespace spdlog {
namespace details {
context::context(std::unique_ptr<logger> global_logger) { global_logger_ = std::move(global_logger); }
std::shared_ptr<logger> context::global_logger() { return global_logger_; }
// Return raw ptr to the global logger.
// To be used directly by the spdlog default api (e.g. spdlog::info)
// This make the default API faster, but cannot be used concurrently with set_global_logger().
// e.g do not call set_global_logger() from one thread while calling spdlog::info() from another.
logger *context::global_logger_raw() const noexcept { return global_logger_.get(); }
// set global logger
void context::set_logger(std::shared_ptr<logger> new_global_logger) { global_logger_ = std::move(new_global_logger); }
void context::set_tp(std::shared_ptr<thread_pool> tp) {
std::lock_guard lock(tp_mutex_);
tp_ = std::move(tp);
}
std::shared_ptr<thread_pool> context::get_tp() {
std::lock_guard lock(tp_mutex_);
return tp_;
}
// clean all resources and threads started by the registry
void context::shutdown() {
std::lock_guard lock(tp_mutex_);
tp_.reset();
}
std::recursive_mutex &context::tp_mutex() { return tp_mutex_; }
} // namespace details
} // namespace spdlog

View File

@ -0,0 +1,40 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#include "iostream"
#include "spdlog/details/err_helper.h"
#include "spdlog/details/os.h"
namespace spdlog {
namespace details {
// Prints error to stderr with source location (if available). A stderr sink is not used because reaching
// this point might indicate a problem with the logging system itself so we use fputs() directly.
void err_helper::handle_ex(const std::string &origin, const source_loc &loc, const std::exception &ex) const {
if (custom_err_handler_) {
custom_err_handler_(ex.what());
return;
}
const auto tm_time = os::localtime();
char date_buf[32];
std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time);
std::string msg;
if (loc.empty()) {
msg = fmt_lib::format("[*** LOG ERROR ***] [{}] [{}] {}\n", date_buf, origin, ex.what());
} else {
msg = fmt_lib::format("[*** LOG ERROR ***] [{}({})] [{}] [{}] {}\n", loc.filename, loc.line, date_buf, origin,
ex.what());
}
std::fputs(msg.c_str(), stderr);
}
void err_helper::handle_unknown_ex(const std::string &origin, const source_loc &loc) const {
handle_ex(origin, loc, std::runtime_error("unknown exception"));
}
void err_helper::set_err_handler(err_handler handler) {
custom_err_handler_ = std::move(handler);
}
} // namespace details
} // namespace spdlog

View File

@ -1,54 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#include "spdlog/details/log_msg_buffer.h"
namespace spdlog {
namespace details {
// copy logger name and payload to buffer so can be used asynchronously
// note: source location pointers are copied without allocation since they
// are compiler generated const chars* (__FILE__, __LINE__, __FUNCTION__)
// if you pass custom strings to source location, make sure they outlive the log_msg_buffer
log_msg_buffer::log_msg_buffer(const log_msg &orig_msg)
: log_msg{orig_msg} {
buffer.append(logger_name);
buffer.append(payload);
update_string_views();
}
log_msg_buffer::log_msg_buffer(const log_msg_buffer &other)
: log_msg{other} {
buffer.append(logger_name);
buffer.append(payload);
update_string_views();
}
log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) noexcept
: log_msg{other},
buffer{std::move(other.buffer)} {
update_string_views();
}
log_msg_buffer &log_msg_buffer::operator=(const log_msg_buffer &other) {
log_msg::operator=(other);
buffer.clear();
buffer.append(other.buffer.data(), other.buffer.data() + other.buffer.size());
update_string_views();
return *this;
}
log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other) noexcept {
log_msg::operator=(other);
buffer = std::move(other.buffer);
update_string_views();
return *this;
}
void log_msg_buffer::update_string_views() {
logger_name = string_view_t{buffer.data(), logger_name.size()};
payload = string_view_t{buffer.data() + logger_name.size(), payload.size()};
}
} // namespace details
} // namespace spdlog

View File

@ -1,117 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#include "spdlog/details/thread_pool.h"
#include <cassert>
#include "spdlog/common.h"
namespace spdlog {
namespace details {
thread_pool::thread_pool(size_t q_max_items,
size_t threads_n,
std::function<void()> on_thread_start,
std::function<void()> on_thread_stop)
: q_(q_max_items) {
if (threads_n == 0 || threads_n > 1000) {
throw_spdlog_ex(
"spdlog::thread_pool(): invalid threads_n param (valid "
"range is 1-1000)");
}
for (size_t i = 0; i < threads_n; i++) {
threads_.emplace_back([this, on_thread_start, on_thread_stop] {
on_thread_start();
this->thread_pool::worker_loop_();
on_thread_stop();
});
}
}
thread_pool::thread_pool(size_t q_max_items, size_t threads_n, std::function<void()> on_thread_start)
: thread_pool(q_max_items, threads_n, on_thread_start, [] {}) {}
thread_pool::thread_pool(size_t q_max_items, size_t threads_n)
: thread_pool(q_max_items, threads_n, [] {}, [] {}) {}
// message all threads to terminate gracefully join them
thread_pool::~thread_pool() {
try {
for (size_t i = 0; i < threads_.size(); i++) {
post_async_msg_(async_msg(async_msg_type::terminate), async_overflow_policy::block);
}
for (auto &t : threads_) {
t.join();
}
} catch (...) {
}
}
void thread_pool::post_log(async_logger_ptr &&worker_ptr, const details::log_msg &msg, async_overflow_policy overflow_policy) {
async_msg async_m(std::move(worker_ptr), async_msg_type::log, msg);
post_async_msg_(std::move(async_m), overflow_policy);
}
void thread_pool::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);
}
size_t thread_pool::overrun_counter() { return q_.overrun_counter(); }
void thread_pool::reset_overrun_counter() { q_.reset_overrun_counter(); }
size_t thread_pool::discard_counter() { return q_.discard_counter(); }
void thread_pool::reset_discard_counter() { q_.reset_discard_counter(); }
size_t thread_pool::queue_size() { return q_.size(); }
void thread_pool::post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy) {
if (overflow_policy == async_overflow_policy::block) {
q_.enqueue(std::move(new_msg));
} else if (overflow_policy == async_overflow_policy::overrun_oldest) {
q_.enqueue_nowait(std::move(new_msg));
} else {
assert(overflow_policy == async_overflow_policy::discard_new);
q_.enqueue_if_have_room(std::move(new_msg));
}
}
void thread_pool::worker_loop_() {
while (process_next_msg_()) {
}
}
// process next message in the queue
// return true if this thread should still be active (while no terminate msg
// was received)
bool thread_pool::process_next_msg_() {
async_msg incoming_async_msg;
q_.dequeue(incoming_async_msg);
switch (incoming_async_msg.msg_type) {
case async_msg_type::log: {
incoming_async_msg.worker_ptr->backend_sink_it_(incoming_async_msg);
return true;
}
case async_msg_type::flush: {
incoming_async_msg.worker_ptr->backend_flush_();
return true;
}
case async_msg_type::terminate: {
return false;
}
default: {
assert(false);
}
}
return true;
}
} // namespace details
} // namespace spdlog

View File

@ -3,9 +3,6 @@
#include "spdlog/logger.h" #include "spdlog/logger.h"
#include <cstdio>
#include <mutex>
#include "spdlog/pattern_formatter.h" #include "spdlog/pattern_formatter.h"
#include "spdlog/sinks/sink.h" #include "spdlog/sinks/sink.h"
@ -17,14 +14,14 @@ logger::logger(const logger &other) noexcept
sinks_(other.sinks_), sinks_(other.sinks_),
level_(other.level_.load(std::memory_order_relaxed)), level_(other.level_.load(std::memory_order_relaxed)),
flush_level_(other.flush_level_.load(std::memory_order_relaxed)), flush_level_(other.flush_level_.load(std::memory_order_relaxed)),
custom_err_handler_(other.custom_err_handler_) {} err_helper_(other.err_helper_) {}
logger::logger(logger &&other) noexcept logger::logger(logger &&other) noexcept
: name_(std::move(other.name_)), : name_(std::move(other.name_)),
sinks_(std::move(other.sinks_)), sinks_(std::move(other.sinks_)),
level_(other.level_.load(std::memory_order_relaxed)), level_(other.level_.load(std::memory_order_relaxed)),
flush_level_(other.flush_level_.load(std::memory_order_relaxed)), flush_level_(other.flush_level_.load(std::memory_order_relaxed)),
custom_err_handler_(std::move(other.custom_err_handler_)) {} err_helper_(std::move(other.err_helper_)) {}
void logger::set_level(level level) { level_.store(level); } void logger::set_level(level level) { level_.store(level); }
@ -62,8 +59,8 @@ const std::vector<sink_ptr> &logger::sinks() const { return sinks_; }
std::vector<sink_ptr> &logger::sinks() { return sinks_; } std::vector<sink_ptr> &logger::sinks() { return sinks_; }
// error handler // custom error handler
void logger::set_error_handler(err_handler handler) { custom_err_handler_ = std::move(handler); } void logger::set_error_handler(err_handler handler) { err_helper_.set_err_handler(std::move(handler)); }
// create new logger with same sinks and configuration. // create new logger with same sinks and configuration.
std::shared_ptr<logger> logger::clone(std::string logger_name) { std::shared_ptr<logger> logger::clone(std::string logger_name) {
@ -77,30 +74,17 @@ void logger::flush_() {
for (auto &sink : sinks_) { for (auto &sink : sinks_) {
try { try {
sink->flush(); sink->flush();
} catch (const std::exception &ex) {
err_helper_.handle_ex(name_, source_loc{}, ex);
} catch (...) {
err_helper_.handle_unknown_ex(name_, source_loc{});
} }
SPDLOG_LOGGER_CATCH(source_loc())
} }
} }
bool logger::should_flush_(const details::log_msg &msg) const { bool logger::should_flush_(const details::log_msg &msg) const {
auto flush_level = flush_level_.load(std::memory_order_relaxed); const auto flush_level = flush_level_.load(std::memory_order_relaxed);
return (msg.log_level >= flush_level) && (msg.log_level != level::off); return (msg.log_level >= flush_level) && (msg.log_level != level::off);
} }
void logger::err_handler_(const std::string &msg) {
if (custom_err_handler_) {
custom_err_handler_(msg);
} else {
using std::chrono::system_clock;
auto now = system_clock::now();
auto tm_time = details::os::localtime(system_clock::to_time_t(now));
char date_buf[64];
std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time);
#if defined(USING_R) && defined(R_R_H) // if in R environment
REprintf("[*** LOG ERROR ***] [%s] [%s] %s\n", date_buf, name().c_str(), msg.c_str());
#else
std::fprintf(stderr, "[*** LOG ERROR ***] [%s] [%s] %s\n", date_buf, name().c_str(), msg.c_str());
#endif
}
}
} // namespace spdlog } // namespace spdlog

View File

@ -16,7 +16,6 @@
#include "spdlog/details/fmt_helper.h" #include "spdlog/details/fmt_helper.h"
#include "spdlog/details/log_msg.h" #include "spdlog/details/log_msg.h"
#include "spdlog/details/os.h" #include "spdlog/details/os.h"
#include "spdlog/fmt/fmt.h"
#include "spdlog/formatter.h" #include "spdlog/formatter.h"
namespace spdlog { namespace spdlog {

View File

@ -5,7 +5,6 @@
#include <mutex> #include <mutex>
#include "spdlog/details/null_mutex.h"
#include "spdlog/details/os.h" #include "spdlog/details/os.h"
#include "spdlog/pattern_formatter.h" #include "spdlog/pattern_formatter.h"
@ -110,12 +109,13 @@ template <typename Mutex>
ansicolor_stderr_sink<Mutex>::ansicolor_stderr_sink(color_mode mode) ansicolor_stderr_sink<Mutex>::ansicolor_stderr_sink(color_mode mode)
: ansicolor_sink<Mutex>(stderr, mode) {} : ansicolor_sink<Mutex>(stderr, mode) {}
} // namespace sinks } // namespace sinks
} // namespace spdlog } // namespace spdlog
// template instantiations // template instantiations
#include "spdlog/details/null_mutex.h"
template class SPDLOG_API spdlog::sinks::ansicolor_stdout_sink<std::mutex>; template class SPDLOG_API spdlog::sinks::ansicolor_stdout_sink<std::mutex>;
template class SPDLOG_API spdlog::sinks::ansicolor_stdout_sink<spdlog::details::null_mutex>; template class SPDLOG_API spdlog::sinks::ansicolor_stdout_sink<spdlog::details::null_mutex>;
template class SPDLOG_API spdlog::sinks::ansicolor_stderr_sink<std::mutex>; template class SPDLOG_API spdlog::sinks::ansicolor_stderr_sink<std::mutex>;
template class SPDLOG_API spdlog::sinks::ansicolor_stderr_sink<spdlog::details::null_mutex>; template class SPDLOG_API spdlog::sinks::ansicolor_stderr_sink<spdlog::details::null_mutex>;

130
src/sinks/async_sink.cpp Normal file
View File

@ -0,0 +1,130 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#include "spdlog/sinks/async_sink.h"
#include <cassert>
#include <memory>
#include "spdlog/common.h"
#include "spdlog/details/mpmc_blocking_q.h"
#include "spdlog/pattern_formatter.h"
#include "spdlog/spdlog.h"
namespace spdlog {
namespace sinks {
async_sink::async_sink(config async_config)
: config_(std::move(async_config)) {
if (config_.queue_size == 0 || config_.queue_size > max_queue_size) {
throw spdlog_ex("async_sink: invalid queue size");
}
q_ = std::make_unique<queue_t>(config_.queue_size);
worker_thread_ = std::thread([this] {
if (config_.on_thread_start) config_.on_thread_start();
this->backend_loop_();
if (config_.on_thread_stop) config_.on_thread_stop();
});
}
async_sink::~async_sink() {
try {
q_->enqueue(async_log_msg(async_log_msg::type::terminate));
worker_thread_.join();
} catch (...) {
printf("Exception in ~async_sink()\n");
}
}
void async_sink::log(const details::log_msg &msg) { send_message_(async_log_msg::type::log, msg); }
void async_sink::flush() { send_message_(async_log_msg::type::flush, details::log_msg()); }
void async_sink::set_pattern(const std::string &pattern) { set_formatter(std::make_unique<pattern_formatter>(pattern)); }
void async_sink::set_formatter(std::unique_ptr<formatter> formatter) {
const auto &sinks = config_.sinks;
for (auto it = sinks.begin(); it != sinks.end(); ++it) {
if (std::next(it) == sinks.end()) {
// last element - we can move it.
(*it)->set_formatter(std::move(formatter));
break; // to prevent clang-tidy warning
}
(*it)->set_formatter(formatter->clone());
}
}
size_t async_sink::get_overrun_counter() const { return q_->overrun_counter(); }
void async_sink::reset_overrun_counter() const { q_->reset_overrun_counter(); }
size_t async_sink::get_discard_counter() const { return q_->discard_counter(); }
void async_sink::reset_discard_counter() const { q_->reset_discard_counter(); }
const async_sink::config &async_sink::get_config() const { return config_; }
// private methods
void async_sink::send_message_(async_log_msg::type msg_type, const details::log_msg &msg) const {
switch (config_.policy) {
case overflow_policy::block:
q_->enqueue(async_log_msg(msg_type, msg));
break;
case overflow_policy::overrun_oldest:
q_->enqueue_nowait(async_log_msg(msg_type, msg));
break;
case overflow_policy::discard_new:
q_->enqueue_if_have_room(async_log_msg(msg_type, msg));
break;
default:
assert(false);
throw spdlog_ex("async_sink: invalid overflow policy");
}
}
void async_sink::backend_loop_() {
details::async_log_msg incoming_msg;
for (;;) {
q_->dequeue(incoming_msg);
switch (incoming_msg.message_type()) {
case async_log_msg::type::log:
backend_log_(incoming_msg);
break;
case async_log_msg::type::flush:
backend_flush_();
break;
case async_log_msg::type::terminate:
return;
default:
assert(false);
}
}
}
void async_sink::backend_log_(const details::log_msg &msg) {
for (const auto &sink : config_.sinks) {
if (sink->should_log(msg.log_level)) {
try {
sink->log(msg);
} catch (const std::exception &ex) {
err_helper_.handle_ex("async log", msg.source, ex);
} catch (...) {
err_helper_.handle_unknown_ex("async log", source_loc{});
}
}
}
}
void async_sink::backend_flush_() {
for (const auto &sink : config_.sinks) {
try {
sink->flush();
} catch (const std::exception &ex) {
err_helper_.handle_ex("async flush", source_loc{}, ex);
} catch (...) {
err_helper_.handle_unknown_ex("async flush", source_loc{});
}
}
}
} // namespace sinks
} // namespace spdlog

View File

@ -5,53 +5,58 @@
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include "spdlog/common.h" #include "spdlog/common.h"
#include "spdlog/details/null_mutex.h"
#include "spdlog/pattern_formatter.h" #include "spdlog/pattern_formatter.h"
namespace spdlog {
namespace sinks {
template <typename Mutex> template <typename Mutex>
spdlog::sinks::base_sink<Mutex>::base_sink() base_sink<Mutex>::base_sink()
: formatter_{std::make_unique<spdlog::pattern_formatter>()} {} : formatter_{std::make_unique<spdlog::pattern_formatter>()} {}
template <typename Mutex> template <typename Mutex>
spdlog::sinks::base_sink<Mutex>::base_sink(std::unique_ptr<spdlog::formatter> formatter) base_sink<Mutex>::base_sink(std::unique_ptr<spdlog::formatter> formatter)
: formatter_{std::move(formatter)} {} : formatter_{std::move(formatter)} {}
template <typename Mutex> template <typename Mutex>
void spdlog::sinks::base_sink<Mutex>::log(const details::log_msg &msg) { void base_sink<Mutex>::log(const details::log_msg &msg) {
std::lock_guard<Mutex> lock(mutex_); std::lock_guard<Mutex> lock(mutex_);
sink_it_(msg); sink_it_(msg);
} }
template <typename Mutex> template <typename Mutex>
void spdlog::sinks::base_sink<Mutex>::flush() { void base_sink<Mutex>::flush() {
std::lock_guard<Mutex> lock(mutex_); std::lock_guard<Mutex> lock(mutex_);
flush_(); flush_();
} }
template <typename Mutex> template <typename Mutex>
void spdlog::sinks::base_sink<Mutex>::set_pattern(const std::string &pattern) { void base_sink<Mutex>::set_pattern(const std::string &pattern) {
std::lock_guard<Mutex> lock(mutex_); std::lock_guard<Mutex> lock(mutex_);
set_pattern_(pattern); set_pattern_(pattern);
} }
template <typename Mutex> template <typename Mutex>
void spdlog::sinks::base_sink<Mutex>::set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) { void base_sink<Mutex>::set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) {
std::lock_guard<Mutex> lock(mutex_); std::lock_guard<Mutex> lock(mutex_);
set_formatter_(std::move(sink_formatter)); set_formatter_(std::move(sink_formatter));
} }
template <typename Mutex> template <typename Mutex>
void spdlog::sinks::base_sink<Mutex>::set_pattern_(const std::string &pattern) { void base_sink<Mutex>::set_pattern_(const std::string &pattern) {
set_formatter_(std::make_unique<spdlog::pattern_formatter>(pattern)); set_formatter_(std::make_unique<pattern_formatter>(pattern));
} }
template <typename Mutex> template <typename Mutex>
void spdlog::sinks::base_sink<Mutex>::set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter) { void base_sink<Mutex>::set_formatter_(std::unique_ptr<formatter> sink_formatter) {
formatter_ = std::move(sink_formatter); formatter_ = std::move(sink_formatter);
} }
} // namespace sinks
} // namespace spdlog
// template instantiations // template instantiations
#include "spdlog/details/null_mutex.h"
template class SPDLOG_API spdlog::sinks::base_sink<std::mutex>; template class SPDLOG_API spdlog::sinks::base_sink<std::mutex>;
template class SPDLOG_API spdlog::sinks::base_sink<spdlog::details::null_mutex>; template class SPDLOG_API spdlog::sinks::base_sink<spdlog::details::null_mutex>;

View File

@ -2,8 +2,8 @@
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
#include "spdlog/sinks/basic_file_sink.h" #include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/common.h" #include "spdlog/common.h"
#include <mutex>
namespace spdlog { namespace spdlog {
namespace sinks { namespace sinks {
@ -34,6 +34,8 @@ void basic_file_sink<Mutex>::flush_() {
} // namespace sinks } // namespace sinks
} // namespace spdlog } // namespace spdlog
// template instantiations // template instantiations
#include "spdlog/details/null_mutex.h"
template class SPDLOG_API spdlog::sinks::basic_file_sink<std::mutex>; template class SPDLOG_API spdlog::sinks::basic_file_sink<std::mutex>;
template class SPDLOG_API spdlog::sinks::basic_file_sink<spdlog::details::null_mutex>; template class SPDLOG_API spdlog::sinks::basic_file_sink<spdlog::details::null_mutex>;

View File

@ -140,5 +140,6 @@ bool rotating_file_sink<Mutex>::rename_file_(const filename_t &src_filename, con
} // namespace spdlog } // namespace spdlog
// template instantiations // template instantiations
#include "spdlog/details/null_mutex.h"
template class SPDLOG_API spdlog::sinks::rotating_file_sink<std::mutex>; template class SPDLOG_API spdlog::sinks::rotating_file_sink<std::mutex>;
template class SPDLOG_API spdlog::sinks::rotating_file_sink<spdlog::details::null_mutex>; template class SPDLOG_API spdlog::sinks::rotating_file_sink<spdlog::details::null_mutex>;

View File

@ -1,14 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#include "spdlog/sinks/sink.h"
#include "spdlog/common.h"
bool spdlog::sinks::sink::should_log(spdlog::level msg_level) const {
return msg_level >= level_.load(std::memory_order_relaxed);
}
void spdlog::sinks::sink::set_level(level level) { level_.store(level, std::memory_order_relaxed); }
spdlog::level spdlog::sinks::sink::log_level() const { return level_.load(std::memory_order_relaxed); }

View File

@ -1,57 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/async.h"
#include "spdlog/common.h"
#include "spdlog/details/synchronous_factory.h"
#include "spdlog/logger.h"
namespace spdlog {
template <typename Factory>
std::shared_ptr<logger> stdout_color_mt(const std::string &logger_name, color_mode mode) {
return Factory::template create<sinks::stdout_color_sink_mt>(logger_name, mode);
}
template <typename Factory>
std::shared_ptr<logger> stdout_color_st(const std::string &logger_name, color_mode mode) {
return Factory::template create<sinks::stdout_color_sink_st>(logger_name, mode);
}
template <typename Factory>
std::shared_ptr<logger> stderr_color_mt(const std::string &logger_name, color_mode mode) {
return Factory::template create<sinks::stderr_color_sink_mt>(logger_name, mode);
}
template <typename Factory>
std::shared_ptr<logger> stderr_color_st(const std::string &logger_name, color_mode mode) {
return Factory::template create<sinks::stderr_color_sink_st>(logger_name, mode);
}
} // namespace spdlog
// template instantiations
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt<spdlog::synchronous_factory>(
const std::string &logger_name, color_mode mode);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_color_st<spdlog::synchronous_factory>(
const std::string &logger_name, color_mode mode);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt<spdlog::synchronous_factory>(
const std::string &logger_name, color_mode mode);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_color_st<spdlog::synchronous_factory>(
const std::string &logger_name, color_mode mode);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt<spdlog::async_factory>(const std::string &logger_name,
color_mode mode);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_color_st<spdlog::async_factory>(const std::string &logger_name,
color_mode mode);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt<spdlog::async_factory>(const std::string &logger_name,
color_mode mode);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_color_st<spdlog::async_factory>(const std::string &logger_name,
color_mode mode);

View File

@ -4,6 +4,7 @@
#include "spdlog/sinks/stdout_sinks.h" #include "spdlog/sinks/stdout_sinks.h"
#include <memory> #include <memory>
#include <mutex>
#include "spdlog/details/os.h" #include "spdlog/details/os.h"
#include "spdlog/pattern_formatter.h" #include "spdlog/pattern_formatter.h"
@ -82,55 +83,11 @@ stderr_sink<Mutex>::stderr_sink()
: stdout_sink_base<Mutex>(stderr) {} : stdout_sink_base<Mutex>(stderr) {}
} // namespace sinks } // namespace sinks
// factory methods
template <typename Factory>
std::shared_ptr<logger> stdout_logger_mt(const std::string &logger_name) {
return Factory::template create<sinks::stdout_sink_mt>(logger_name);
}
template <typename Factory>
std::shared_ptr<logger> stdout_logger_st(const std::string &logger_name) {
return Factory::template create<sinks::stdout_sink_st>(logger_name);
}
template <typename Factory>
std::shared_ptr<logger> stderr_logger_mt(const std::string &logger_name) {
return Factory::template create<sinks::stderr_sink_mt>(logger_name);
}
template <typename Factory>
std::shared_ptr<logger> stderr_logger_st(const std::string &logger_name) {
return Factory::template create<sinks::stderr_sink_st>(logger_name);
}
} // namespace spdlog } // namespace spdlog
// template instantiations for stdout/stderr loggers // template instantiations
template class SPDLOG_API spdlog::sinks::stdout_sink_base<std::mutex>; #include "spdlog/details/null_mutex.h"
template class SPDLOG_API spdlog::sinks::stdout_sink_base<spdlog::details::null_mutex>;
template class SPDLOG_API spdlog::sinks::stdout_sink<std::mutex>; template class SPDLOG_API spdlog::sinks::stdout_sink<std::mutex>;
template class SPDLOG_API spdlog::sinks::stdout_sink<spdlog::details::null_mutex>; template class SPDLOG_API spdlog::sinks::stdout_sink<spdlog::details::null_mutex>;
template class SPDLOG_API spdlog::sinks::stderr_sink<std::mutex>; template class SPDLOG_API spdlog::sinks::stderr_sink<std::mutex>;
template class SPDLOG_API spdlog::sinks::stderr_sink<spdlog::details::null_mutex>; template class SPDLOG_API spdlog::sinks::stderr_sink<spdlog::details::null_mutex>;
// template instantiations for stdout/stderr factory functions
#include "spdlog/async.h"
#include "spdlog/details/synchronous_factory.h"
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt<spdlog::synchronous_factory>(
const std::string &logger_name);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st<spdlog::synchronous_factory>(
const std::string &logger_name);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt<spdlog::synchronous_factory>(
const std::string &logger_name);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st<spdlog::synchronous_factory>(
const std::string &logger_name);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt<spdlog::async_factory>(
const std::string &logger_name);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st<spdlog::async_factory>(
const std::string &logger_name);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt<spdlog::async_factory>(
const std::string &logger_name);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st<spdlog::async_factory>(
const std::string &logger_name);

View File

@ -5,12 +5,10 @@
#include "spdlog/details/windows_include.h" #include "spdlog/details/windows_include.h"
#include <wincon.h> #include <wincon.h>
#include <mutex> #include <mutex>
// clang-format on // clang-format on
#include "spdlog/sinks/wincolor_sink.h" #include "spdlog/sinks/wincolor_sink.h"
#include "spdlog/common.h" #include "spdlog/common.h"
#include "spdlog/details/null_mutex.h"
namespace spdlog { namespace spdlog {
namespace sinks { namespace sinks {
@ -132,15 +130,14 @@ wincolor_stdout_sink<Mutex>::wincolor_stdout_sink(color_mode mode)
template <typename Mutex> template <typename Mutex>
wincolor_stderr_sink<Mutex>::wincolor_stderr_sink(color_mode mode) wincolor_stderr_sink<Mutex>::wincolor_stderr_sink(color_mode mode)
: wincolor_sink<Mutex>(::GetStdHandle(STD_ERROR_HANDLE), mode) {} : wincolor_sink<Mutex>(::GetStdHandle(STD_ERROR_HANDLE), mode) {}
} // namespace sinks } // namespace sinks
} // namespace spdlog } // namespace spdlog
// template instantiations // template instantiations
template class SPDLOG_API spdlog::sinks::wincolor_sink<std::mutex>; #include "spdlog/details/null_mutex.h"
template class SPDLOG_API spdlog::sinks::wincolor_sink<spdlog::details::null_mutex>;
template class SPDLOG_API spdlog::sinks::wincolor_stdout_sink<std::mutex>; template class SPDLOG_API spdlog::sinks::wincolor_stdout_sink<std::mutex>;
template class SPDLOG_API spdlog::sinks::wincolor_stdout_sink<spdlog::details::null_mutex>; template class SPDLOG_API spdlog::sinks::wincolor_stdout_sink<spdlog::details::null_mutex>;
template class SPDLOG_API spdlog::sinks::wincolor_stderr_sink<std::mutex>; template class SPDLOG_API spdlog::sinks::wincolor_stderr_sink<std::mutex>;
template class SPDLOG_API spdlog::sinks::wincolor_stderr_sink<spdlog::details::null_mutex>; template class SPDLOG_API spdlog::sinks::wincolor_stderr_sink<spdlog::details::null_mutex>;

View File

@ -13,27 +13,20 @@
namespace spdlog { namespace spdlog {
static std::shared_ptr s_context =
#ifndef SPDLOG_DISABLE_GLOBAL_LOGGER #ifndef SPDLOG_DISABLE_GLOBAL_LOGGER
std::make_unique<details::context>(std::make_unique<logger>(std::string(), std::make_unique<sinks::stdout_color_sink_mt>())); static std::shared_ptr<logger> s_logger = std::make_shared<logger>("global", std::make_shared<sinks::stdout_color_sink_mt>());
#else #else
std::make_unique<details::context>(); // empty context static std::short_ptr<logger> s_logger = nullptr;
#endif #endif
void set_context(std::shared_ptr<details::context> context) { s_context = std::move(context); }
std::shared_ptr<details::context> context() { return s_context; } std::shared_ptr<logger> global_logger() { return s_logger; }
const std::shared_ptr<details::context> &context_ref() { return s_context; } void set_global_logger(std::shared_ptr<logger> global_logger) { s_logger = std::move(global_logger); }
std::shared_ptr<logger> global_logger() { return context_ref()->global_logger(); }
void set_global_logger(std::shared_ptr<logger> global_logger) { context()->set_logger(std::move(global_logger)); }
logger *global_logger_raw() noexcept { logger *global_logger_raw() noexcept {
auto *rv = context_ref()->global_logger_raw(); return s_logger.get();
assert(rv != nullptr);
return rv;
} }
void set_formatter(std::unique_ptr<formatter> formatter) { global_logger()->set_formatter(std::move(formatter)); } void set_formatter(std::unique_ptr<formatter> formatter) { global_logger()->set_formatter(std::move(formatter)); }
@ -52,6 +45,6 @@ void flush_on(level level) { global_logger()->flush_on(level); }
void set_error_handler(void (*handler)(const std::string &msg)) { global_logger()->set_error_handler(handler); } void set_error_handler(void (*handler)(const std::string &msg)) { global_logger()->set_error_handler(handler); }
void shutdown() { s_context.reset(); } void shutdown() { s_logger.reset(); }
} // namespace spdlog } // namespace spdlog

View File

@ -25,7 +25,6 @@
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG
#include "spdlog/async.h"
#include "spdlog/details/fmt_helper.h" #include "spdlog/details/fmt_helper.h"
#include "spdlog/pattern_formatter.h" #include "spdlog/pattern_formatter.h"
#include "spdlog/sinks/null_sink.h" #include "spdlog/sinks/null_sink.h"

View File

@ -1,86 +1,98 @@
#include <tuple>
#include "includes.h" #include "includes.h"
#include "spdlog/async.h" #include "spdlog/sinks/async_sink.h"
#include "spdlog/sinks/basic_file_sink.h" #include "spdlog/sinks/basic_file_sink.h"
#include "test_sink.h" #include "test_sink.h"
#define TEST_FILENAME "test_logs/async_test.log" #define TEST_FILENAME "test_logs/async_test.log"
using spdlog::sinks::async_sink;
using spdlog::sinks::sink;
using spdlog::sinks::test_sink_mt;
auto creat_async_logger(size_t queue_size, std::shared_ptr<sink> backend_sink) {
async_sink::config cfg;
cfg.queue_size = queue_size;
cfg.sinks.push_back(std::move(backend_sink));
auto s = std::make_shared<async_sink>(cfg);
auto logger = std::make_shared<spdlog::logger>("async_logger", s);
return std::make_tuple(logger, s);
}
TEST_CASE("basic async test ", "[async]") { TEST_CASE("basic async test ", "[async]") {
auto test_sink = std::make_shared<spdlog::sinks::test_sink_mt>(); const auto test_sink = std::make_shared<test_sink_mt>();
size_t overrun_counter = 0; size_t overrun_counter = 0;
size_t queue_size = 128;
size_t messages = 256; size_t messages = 256;
{ {
auto tp = std::make_shared<spdlog::details::thread_pool>(queue_size, 1); constexpr size_t queue_size = 16;
auto logger = std::make_shared<spdlog::async_logger>("as", test_sink, tp, spdlog::async_overflow_policy::block); auto [logger, async_sink] = creat_async_logger(queue_size, test_sink);
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);
} }
logger->flush(); logger->flush();
overrun_counter = tp->overrun_counter(); overrun_counter = async_sink->get_overrun_counter();
} }
// logger and async_sink are destroyed here so the queue should be emptied
REQUIRE(test_sink->msg_counter() == messages); REQUIRE(test_sink->msg_counter() == messages);
REQUIRE(test_sink->flush_counter() == 1); REQUIRE(test_sink->flush_counter() == 1);
REQUIRE(overrun_counter == 0); REQUIRE(overrun_counter == 0);
} }
TEST_CASE("discard policy ", "[async]") { TEST_CASE("discard policy ", "[async]") {
auto test_sink = std::make_shared<spdlog::sinks::test_sink_mt>(); auto test_sink = std::make_shared<test_sink_mt>();
test_sink->set_delay(std::chrono::milliseconds(1)); test_sink->set_delay(std::chrono::milliseconds(1));
size_t queue_size = 4; async_sink::config config;
config.queue_size = 4;
config.policy = async_sink::overflow_policy::overrun_oldest;
config.sinks.push_back(test_sink);
size_t messages = 1024; size_t messages = 1024;
auto as = std::make_shared<async_sink>(config);
auto tp = std::make_shared<spdlog::details::thread_pool>(queue_size, 1); auto logger = std::make_shared<spdlog::logger>("async_logger", as);
auto logger = std::make_shared<spdlog::async_logger>("as", test_sink, tp, spdlog::async_overflow_policy::overrun_oldest); REQUIRE(as->get_discard_counter() == 0);
REQUIRE(as->get_overrun_counter() == 0);
for (size_t i = 0; i < messages; i++) { for (size_t i = 0; i < messages; i++) {
logger->info("Hello message"); logger->info("Hello message");
} }
REQUIRE(test_sink->msg_counter() < messages); REQUIRE(test_sink->msg_counter() < messages);
REQUIRE(tp->overrun_counter() > 0); REQUIRE(as->get_overrun_counter() > 0);
as->reset_overrun_counter();
REQUIRE(as->get_overrun_counter() == 0);
} }
TEST_CASE("discard policy discard_new ", "[async]") { TEST_CASE("discard policy discard_new ", "[async]") {
auto test_sink = std::make_shared<spdlog::sinks::test_sink_mt>(); auto test_sink = std::make_shared<test_sink_mt>();
test_sink->set_delay(std::chrono::milliseconds(1)); test_sink->set_delay(std::chrono::milliseconds(1));
size_t queue_size = 4; async_sink::config config;
config.queue_size = 4;
config.policy = async_sink::overflow_policy::discard_new;
config.sinks.push_back(test_sink);
size_t messages = 1024; size_t messages = 1024;
auto as = std::make_shared<async_sink>(config);
auto logger = std::make_shared<spdlog::logger>("async_logger", as);
auto tp = std::make_shared<spdlog::details::thread_pool>(queue_size, 1);
auto logger = std::make_shared<spdlog::async_logger>("as", test_sink, tp, spdlog::async_overflow_policy::discard_new); REQUIRE(as->get_config().policy == async_sink::overflow_policy::discard_new);
REQUIRE(as->get_discard_counter() == 0);
REQUIRE(as->get_overrun_counter() == 0);
for (size_t i = 0; i < messages; i++) { for (size_t i = 0; i < messages; i++) {
logger->info("Hello message"); logger->info("Hello message");
} }
REQUIRE(test_sink->msg_counter() < messages); REQUIRE(test_sink->msg_counter() < messages);
REQUIRE(tp->discard_counter() > 0); REQUIRE(as->get_discard_counter() > 0);
} as->reset_discard_counter();
REQUIRE(as->get_discard_counter() == 0);
TEST_CASE("discard policy using factory ", "[async]") {
size_t queue_size = 4;
size_t messages = 1024;
spdlog::init_thread_pool(queue_size, 1);
auto logger = spdlog::create_async_nb<spdlog::sinks::test_sink_mt>("as2");
auto test_sink = std::static_pointer_cast<spdlog::sinks::test_sink_mt>(logger->sinks()[0]);
test_sink->set_delay(std::chrono::milliseconds(3));
for (size_t i = 0; i < messages; i++) {
logger->info("Hello message");
}
REQUIRE(test_sink->msg_counter() < messages);
} }
TEST_CASE("flush", "[async]") { TEST_CASE("flush", "[async]") {
auto test_sink = std::make_shared<spdlog::sinks::test_sink_mt>(); auto test_sink = std::make_shared<test_sink_mt>();
size_t queue_size = 256;
size_t messages = 256; size_t messages = 256;
{ {
auto tp = std::make_shared<spdlog::details::thread_pool>(queue_size, 1); constexpr size_t queue_size = 256;
auto logger = std::make_shared<spdlog::async_logger>("as", test_sink, tp, spdlog::async_overflow_policy::block); auto [logger, async_sink] = creat_async_logger(queue_size, test_sink);
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);
} }
logger->flush(); logger->flush();
} }
// std::this_thread::sleep_for(std::chrono::milliseconds(250)); // std::this_thread::sleep_for(std::chrono::milliseconds(250));
@ -88,18 +100,24 @@ TEST_CASE("flush", "[async]") {
REQUIRE(test_sink->flush_counter() == 1); REQUIRE(test_sink->flush_counter() == 1);
} }
TEST_CASE("tp->wait_empty() ", "[async]") { TEST_CASE("wait_dtor ", "[async]") {
auto test_sink = std::make_shared<spdlog::sinks::test_sink_mt>(); auto test_sink = std::make_shared<test_sink_mt>();
test_sink->set_delay(std::chrono::milliseconds(5)); test_sink->set_delay(std::chrono::milliseconds(5));
async_sink::config config;
config.sinks.push_back(test_sink);
config.queue_size = 4;
config.policy = async_sink::overflow_policy::block;
size_t messages = 100; size_t messages = 100;
{
auto tp = std::make_shared<spdlog::details::thread_pool>(messages, 2); auto as = std::make_shared<async_sink>(config);
auto logger = std::make_shared<spdlog::async_logger>("as", test_sink, tp, spdlog::async_overflow_policy::block); auto logger = std::make_shared<spdlog::logger>("async_logger", as);
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);
} }
logger->flush(); logger->flush();
tp.reset(); REQUIRE(as->get_overrun_counter() == 0);
REQUIRE(as->get_discard_counter() == 0);
}
REQUIRE(test_sink->msg_counter() == messages); REQUIRE(test_sink->msg_counter() == messages);
REQUIRE(test_sink->flush_counter() == 1); REQUIRE(test_sink->flush_counter() == 1);
@ -107,18 +125,17 @@ TEST_CASE("tp->wait_empty() ", "[async]") {
TEST_CASE("multi threads", "[async]") { TEST_CASE("multi threads", "[async]") {
auto test_sink = std::make_shared<spdlog::sinks::test_sink_mt>(); auto test_sink = std::make_shared<spdlog::sinks::test_sink_mt>();
size_t queue_size = 128;
size_t messages = 256; size_t messages = 256;
size_t n_threads = 10; size_t n_threads = 10;
{ {
auto tp = std::make_shared<spdlog::details::thread_pool>(queue_size, 1); constexpr size_t queue_size = 128;
auto logger = std::make_shared<spdlog::async_logger>("as", test_sink, tp, spdlog::async_overflow_policy::block); auto [logger, async_sink] = creat_async_logger(queue_size, test_sink);
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++) {
threads.emplace_back([logger, messages] { threads.emplace_back([l = logger, msgs = messages] {
for (size_t j = 0; j < messages; j++) { for (size_t j = 0; j < msgs; j++) {
logger->info("Hello message #{}", j); l->info("Hello message #{}", j);
} }
}); });
logger->flush(); logger->flush();
@ -128,7 +145,6 @@ TEST_CASE("multi threads", "[async]") {
t.join(); t.join();
} }
} }
REQUIRE(test_sink->msg_counter() == messages * n_threads); REQUIRE(test_sink->msg_counter() == messages * n_threads);
REQUIRE(test_sink->flush_counter() == n_threads); REQUIRE(test_sink->flush_counter() == n_threads);
} }
@ -136,45 +152,146 @@ TEST_CASE("multi threads", "[async]") {
TEST_CASE("to_file", "[async]") { TEST_CASE("to_file", "[async]") {
prepare_logdir(); prepare_logdir();
size_t messages = 1024; size_t messages = 1024;
size_t tp_threads = 1;
spdlog::filename_t filename = SPDLOG_FILENAME_T(TEST_FILENAME);
{ {
spdlog::filename_t filename = SPDLOG_FILENAME_T(TEST_FILENAME);
auto file_sink = std::make_shared<spdlog::sinks::basic_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 [logger, async_sink] = creat_async_logger(messages, file_sink);
auto logger = std::make_shared<spdlog::async_logger>("as", std::move(file_sink), std::move(tp));
for (size_t j = 0; j < messages; j++) { for (size_t j = 0; j < messages; j++) {
logger->info("Hello message #{}", j); logger->info("Hello message #{}", j);
} }
} }
require_message_count(TEST_FILENAME, messages); require_message_count(TEST_FILENAME, messages);
auto contents = file_contents(TEST_FILENAME); auto contents = file_contents(TEST_FILENAME);
using spdlog::details::os::default_eol; using spdlog::details::os::default_eol;
REQUIRE(ends_with(contents, spdlog::fmt_lib::format("Hello message #1023{}", default_eol))); REQUIRE(ends_with(contents, spdlog::fmt_lib::format("Hello message #1023{}", default_eol)));
} }
TEST_CASE("to_file multi-workers", "[async]") {
prepare_logdir(); TEST_CASE("bad_ctor", "[async]") {
size_t messages = 1024 * 10; async_sink::config cfg;
size_t tp_threads = 10; cfg.queue_size = 0;
spdlog::filename_t filename = SPDLOG_FILENAME_T(TEST_FILENAME); REQUIRE_THROWS_AS(std::make_shared<async_sink>(cfg), spdlog::spdlog_ex);
}
TEST_CASE("bad_ctor2", "[async]") {
async_sink::config cfg;
cfg.queue_size = async_sink::max_queue_size + 1;
REQUIRE_THROWS_AS(std::make_shared<async_sink>(cfg), spdlog::spdlog_ex);
}
TEST_CASE("start_stop_clbks", "[async]") {
bool start_called = false;
bool stop_called = false;
{ {
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true); async_sink::config cfg;
auto tp = std::make_shared<spdlog::details::thread_pool>(messages, tp_threads); cfg.on_thread_start = [&] { start_called = true; };
auto logger = std::make_shared<spdlog::async_logger>("as", std::move(file_sink), std::move(tp)); cfg.on_thread_stop = [&] { stop_called = true; };
auto sink = std::make_shared<async_sink>(cfg);
}
REQUIRE(start_called);
REQUIRE(stop_called);
}
TEST_CASE("start_stop_clbks2", "[async]") {
bool start_called = false;
bool stop_called = false;
{
async_sink::config cfg;
cfg.on_thread_start = [&] { start_called = true; };
auto sink = std::make_shared<async_sink>(cfg);
}
REQUIRE(start_called);
REQUIRE_FALSE(stop_called);
}
TEST_CASE("start_stop_clbks3", "[async]") {
bool start_called = false;
bool stop_called = false;
{
async_sink::config cfg;
cfg.on_thread_start = nullptr;
cfg.on_thread_stop = [&] { stop_called = true; };
auto sink = std::make_shared<async_sink>(cfg);
}
REQUIRE_FALSE(start_called);
REQUIRE(stop_called);
}
TEST_CASE("start_stop_clbks4", "[async]") {
bool start_called = false;
bool stop_called = false;
{
async_sink::config cfg;
cfg.on_thread_start = [&] { start_called = true; };
cfg.on_thread_stop = [&] { stop_called = true; };
cfg.queue_size = 128;
auto sink = std::make_shared<async_sink>(cfg);
}
REQUIRE(start_called);
REQUIRE(stop_called);
}
// should not start threads if queue size is invalid
TEST_CASE("start_stop_clbks5", "[async]") {
bool start_called = false;
bool stop_called = false;
{
async_sink::config cfg;
cfg.on_thread_start = [&] { start_called = true; };
cfg.on_thread_stop = [&] { stop_called = true; };
cfg.queue_size = 0;
REQUIRE_THROWS_AS(std::make_shared<async_sink>(cfg), spdlog::spdlog_ex);
}
REQUIRE_FALSE(start_called);
REQUIRE_FALSE(stop_called);
}
TEST_CASE("multi-sinks", "[async]") {
prepare_logdir();
auto test_sink1 = std::make_shared<test_sink_mt>();
auto test_sink2 = std::make_shared<test_sink_mt>();
auto test_sink3 = std::make_shared<test_sink_mt>();
size_t messages = 1024;
{
async_sink::config cfg;
cfg.sinks.push_back(test_sink1);
cfg.sinks.push_back(test_sink2);
cfg.sinks.push_back(test_sink3);
auto as = std::make_shared<async_sink>(cfg);
spdlog::logger l("async_logger", as);
for (size_t j = 0; j < messages; j++) { for (size_t j = 0; j < messages; j++) {
logger->info("Hello message #{}", j); l.info("Hello message #{}", j);
} }
} }
require_message_count(TEST_FILENAME, messages); REQUIRE(test_sink1->msg_counter() == messages);
REQUIRE(test_sink2->msg_counter() == messages);
REQUIRE(test_sink3->msg_counter() == messages);
} }
TEST_CASE("bad_tp", "[async]") { TEST_CASE("level-off", "[async]") {
auto test_sink = std::make_shared<spdlog::sinks::test_sink_mt>(); const auto test_sink = std::make_shared<test_sink_mt>();
std::shared_ptr<spdlog::details::thread_pool> const empty_tp; test_sink->set_level(spdlog::level::critical);
auto logger = std::make_shared<spdlog::async_logger>("as", test_sink, empty_tp); {
logger->info("Please throw an exception"); constexpr size_t messages = 256;
REQUIRE(test_sink->msg_counter() == 0); constexpr size_t queue_size = 16;
auto [logger, async_sink] = creat_async_logger(queue_size, test_sink);
logger->flush_on(spdlog::level::critical);
for (size_t i = 0; i < messages; i++) {
logger->info("Hello message #{}", i);
}
}
// logger and async_sink are destroyed here so the queue should be emptied
REQUIRE(test_sink->msg_counter() == 0);
REQUIRE(test_sink->flush_counter() == 0);
}
TEST_CASE("backend_ex", "[async]") {
const auto test_sink = std::make_shared<test_sink_mt>();
test_sink->set_exception(std::runtime_error("test backend exception"));
constexpr size_t queue_size = 16;
auto [logger, async_sink] = creat_async_logger(queue_size, test_sink);
REQUIRE_NOTHROW(logger->info("Hello message"));
REQUIRE_NOTHROW(logger->flush());
} }

View File

@ -1,5 +1,6 @@
#include "includes.h" #include "includes.h"
#include "spdlog/fmt/bin_to_hex.h" #include "spdlog/bin_to_hex.h"
#include "spdlog/sinks/ostream_sink.h" #include "spdlog/sinks/ostream_sink.h"
#include "test_sink.h" #include "test_sink.h"

View File

@ -3,7 +3,6 @@
* https://raw.githubusercontent.com/gabime/spdlog/v2.x/LICENSE * https://raw.githubusercontent.com/gabime/spdlog/v2.x/LICENSE
*/ */
#include "includes.h" #include "includes.h"
#include "spdlog/async.h"
#include "spdlog/common.h" #include "spdlog/common.h"
#include "spdlog/sinks/callback_sink.h" #include "spdlog/sinks/callback_sink.h"
#include "test_sink.h" #include "test_sink.h"

View File

@ -7,94 +7,59 @@
#include "includes.h" #include "includes.h"
#include "spdlog/sinks/basic_file_sink.h" #include "spdlog/sinks/basic_file_sink.h"
#define SIMPLE_LOG "test_logs/simple_log.txt" static spdlog::filename_t log_filename = SPDLOG_FILENAME_T("test_logs/simple_log.txt");
#define SIMPLE_ASYNC_LOG "test_logs/simple_async_log.txt" static std::string log_err_msg = "Error during log";
static std::string flush_err_msg = "Error during flush";
class failing_sink final : public spdlog::sinks::base_sink<std::mutex> { class failing_sink final : public spdlog::sinks::base_sink<std::mutex> {
protected: protected:
void sink_it_(const spdlog::details::log_msg &) final { throw std::runtime_error("some error happened during log"); } void sink_it_(const spdlog::details::log_msg &) override { throw std::runtime_error(log_err_msg.c_str()); }
void flush_() override { throw std::runtime_error(flush_err_msg.c_str()); }
void flush_() final { throw std::runtime_error("some error happened during flush"); }
}; };
struct custom_ex {}; struct custom_ex {};
using namespace spdlog::sinks;
TEST_CASE("default_error_handler", "[errors]") { TEST_CASE("default_error_handler", "[errors]") {
prepare_logdir(); prepare_logdir();
spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG); auto logger = spdlog::create<basic_file_sink_mt>("test-error", log_filename);
auto logger = spdlog::basic_logger_mt("test-error", filename);
logger->set_pattern("%v"); logger->set_pattern("%v");
logger->info(SPDLOG_FMT_RUNTIME("Test message {} {}"), 1); logger->info(SPDLOG_FMT_RUNTIME("Test message {} {}"), 1);
logger->info("Test message {}", 2); logger->info("Test message {}", 2);
logger->flush(); logger->flush();
using spdlog::details::os::default_eol; using spdlog::details::os::default_eol;
REQUIRE(file_contents(SIMPLE_LOG) == spdlog::fmt_lib::format("Test message 2{}", default_eol)); REQUIRE(file_contents(log_filename) == spdlog::fmt_lib::format("Test message 2{}", default_eol));
REQUIRE(count_lines(SIMPLE_LOG) == 1); REQUIRE(count_lines(log_filename) == 1);
} }
TEST_CASE("custom_error_handler", "[errors]") { TEST_CASE("custom_error_handler", "[errors]") {
prepare_logdir(); prepare_logdir();
spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG); auto logger = spdlog::create<basic_file_sink_mt>("test-error", log_filename);
auto logger = spdlog::basic_logger_mt("test-error", filename);
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 & msg) {
REQUIRE(msg == "argument not found");
throw custom_ex();
});
logger->info("Good message #1"); logger->info("Good message #1");
REQUIRE_THROWS_AS(logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx"), custom_ex); REQUIRE_THROWS_AS(logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx"), custom_ex);
logger->info("Good message #2"); logger->info("Good message #2");
require_message_count(SIMPLE_LOG, 2); require_message_count(log_filename, 2);
} }
TEST_CASE("default_error_handler2", "[errors]") { TEST_CASE("default_error_handler2", "[errors]") {
auto logger = std::make_shared<spdlog::logger>("failed_logger", std::make_shared<failing_sink>()); auto logger = std::make_shared<spdlog::logger>("failed_logger", std::make_shared<failing_sink>());
logger->set_error_handler([=](const std::string &) { throw custom_ex(); }); logger->set_error_handler([=](const std::string &msg) {
REQUIRE(msg == log_err_msg);
throw custom_ex();
});
REQUIRE_THROWS_AS(logger->info("Some message"), custom_ex); REQUIRE_THROWS_AS(logger->info("Some message"), custom_ex);
} }
TEST_CASE("flush_error_handler", "[errors]") { TEST_CASE("flush_error_handler", "[errors]") {
auto logger = spdlog::create<failing_sink>("failed_logger"); auto logger = spdlog::create<failing_sink>("failed_logger");
logger->set_error_handler([=](const std::string &) { throw custom_ex(); }); logger->set_error_handler([=](const std::string &msg) {
REQUIRE(msg == flush_err_msg);
throw custom_ex();
});
REQUIRE_THROWS_AS(logger->flush(), custom_ex); REQUIRE_THROWS_AS(logger->flush(), custom_ex);
} }
TEST_CASE("async_error_handler", "[errors]") {
prepare_logdir();
std::string err_msg("log failed with some msg");
spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_ASYNC_LOG);
{
spdlog::init_thread_pool(128, 1);
auto logger = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("logger", filename, true);
logger->set_error_handler([=](const std::string &) {
std::ofstream ofs("test_logs/custom_err.txt");
if (!ofs) {
throw std::runtime_error("Failed open test_logs/custom_err.txt");
}
ofs << err_msg;
});
logger->info("Good message #1");
logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx");
logger->info("Good message #2");
}
spdlog::init_thread_pool(128, 1);
require_message_count(SIMPLE_ASYNC_LOG, 2);
REQUIRE(file_contents("test_logs/custom_err.txt") == err_msg);
}
// Make sure async error handler is executed
TEST_CASE("async_error_handler2", "[errors]") {
prepare_logdir();
std::string err_msg("This is async handler error message");
{
spdlog::details::os::create_dir(SPDLOG_FILENAME_T("test_logs"));
spdlog::init_thread_pool(128, 1);
auto logger = spdlog::create_async<failing_sink>("failed_logger");
logger->set_error_handler([=](const std::string &) {
std::ofstream ofs("test_logs/custom_err2.txt");
if (!ofs) throw std::runtime_error("Failed open test_logs/custom_err2.txt");
ofs << err_msg;
});
logger->info("Hello failure");
}
spdlog::init_thread_pool(128, 1);
REQUIRE(file_contents("test_logs/custom_err2.txt") == err_msg);
}

View File

@ -136,7 +136,7 @@ TEST_CASE("file_event_handlers", "[file_helper]") {
events.clear(); events.clear();
helper.close(); helper.close();
REQUIRE(events == std::vector<flags>{flags::before_close, flags::after_close}); REQUIRE(events == std::vector<flags>{flags::before_close, flags::after_close});
REQUIRE(file_contents(TEST_FILENAME) == "after_open\nbefore_close\n"); REQUIRE(file_contents(SPDLOG_FILENAME_T(TEST_FILENAME)) == "after_open\nbefore_close\n");
helper.reopen(true); helper.reopen(true);
events.clear(); events.clear();

View File

@ -9,10 +9,12 @@
#define SIMPLE_LOG "test_logs/simple_log" #define SIMPLE_LOG "test_logs/simple_log"
#define ROTATING_LOG "test_logs/rotating_log" #define ROTATING_LOG "test_logs/rotating_log"
using namespace spdlog::sinks;
TEST_CASE("simple_file_logger", "[simple_logger]") { TEST_CASE("simple_file_logger", "[simple_logger]") {
prepare_logdir(); prepare_logdir();
spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG); spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG);
auto logger = spdlog::basic_logger_mt("logger", filename); auto logger = spdlog::create<basic_file_sink_mt>("test-error", filename);
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);
@ -25,7 +27,7 @@ TEST_CASE("simple_file_logger", "[simple_logger]") {
TEST_CASE("flush_on", "[flush_on]") { TEST_CASE("flush_on", "[flush_on]") {
prepare_logdir(); prepare_logdir();
spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG); spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG);
auto logger = spdlog::basic_logger_mt("test-error", filename); auto logger = spdlog::create<basic_file_sink_mt>("test-error", 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);
@ -43,8 +45,7 @@ TEST_CASE("rotating_file_logger1", "[rotating_logger]") {
prepare_logdir(); prepare_logdir();
size_t max_size = 1024 * 10; size_t max_size = 1024 * 10;
spdlog::filename_t basename = SPDLOG_FILENAME_T(ROTATING_LOG); spdlog::filename_t basename = SPDLOG_FILENAME_T(ROTATING_LOG);
auto logger = spdlog::rotating_logger_mt("logger", basename, max_size, 0); auto logger = spdlog::create<rotating_file_sink_mt>("logger", basename, max_size, 0);
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
logger->info("Test message {}", i); logger->info("Test message {}", i);
} }
@ -57,16 +58,14 @@ TEST_CASE("rotating_file_logger2", "[rotating_logger]") {
prepare_logdir(); prepare_logdir();
size_t max_size = 1024 * 10; size_t max_size = 1024 * 10;
spdlog::filename_t basename = SPDLOG_FILENAME_T(ROTATING_LOG); spdlog::filename_t basename = SPDLOG_FILENAME_T(ROTATING_LOG);
{ {
// make an initial logger to create the first output file // make an initial logger to create the first output file
auto logger = spdlog::rotating_logger_mt("logger", basename, max_size, 2, true); auto logger = spdlog::create<rotating_file_sink_mt>("logger", basename, max_size, 2, true);
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
logger->info("Test message {}", i); logger->info("Test message {}", i);
} }
} }
auto logger = spdlog::create<rotating_file_sink_mt>("logger", basename, max_size, 2, true);
auto logger = spdlog::rotating_logger_mt("logger", basename, max_size, 2, true);
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
logger->info("Test message {}", i); logger->info("Test message {}", i);
} }
@ -89,7 +88,7 @@ TEST_CASE("rotating_file_logger3", "[rotating_logger]") {
prepare_logdir(); prepare_logdir();
size_t max_size = 0; size_t max_size = 0;
spdlog::filename_t basename = SPDLOG_FILENAME_T(ROTATING_LOG); spdlog::filename_t basename = SPDLOG_FILENAME_T(ROTATING_LOG);
REQUIRE_THROWS_AS(spdlog::rotating_logger_mt("logger", basename, max_size, 0), spdlog::spdlog_ex); REQUIRE_THROWS_AS(spdlog::create<rotating_file_sink_mt>("logger", basename, max_size, 0), spdlog::spdlog_ex);
} }
// test on-demand rotation of logs // test on-demand rotation of logs
@ -99,15 +98,11 @@ TEST_CASE("rotating_file_logger4", "[rotating_logger]") {
spdlog::filename_t basename = SPDLOG_FILENAME_T(ROTATING_LOG); spdlog::filename_t basename = SPDLOG_FILENAME_T(ROTATING_LOG);
auto sink = std::make_shared<spdlog::sinks::rotating_file_sink_st>(basename, max_size, 2); auto sink = std::make_shared<spdlog::sinks::rotating_file_sink_st>(basename, max_size, 2);
auto logger = std::make_shared<spdlog::logger>("rotating_sink_logger", sink); auto logger = std::make_shared<spdlog::logger>("rotating_sink_logger", sink);
logger->info("Test message - pre-rotation"); logger->info("Test message - pre-rotation");
logger->flush(); logger->flush();
sink->rotate_now(); sink->rotate_now();
logger->info("Test message - post-rotation"); logger->info("Test message - post-rotation");
logger->flush(); logger->flush();
REQUIRE(get_filesize(ROTATING_LOG) > 0); REQUIRE(get_filesize(ROTATING_LOG) > 0);
REQUIRE(get_filesize(ROTATING_LOG ".1") > 0); REQUIRE(get_filesize(ROTATING_LOG ".1") > 0);
} }

View File

@ -15,7 +15,7 @@
TEST_CASE("debug and trace w/o format string", "[macros]") { TEST_CASE("debug and trace w/o format string", "[macros]") {
prepare_logdir(); prepare_logdir();
spdlog::filename_t filename = SPDLOG_FILENAME_T(TEST_FILENAME); spdlog::filename_t filename = SPDLOG_FILENAME_T(TEST_FILENAME);
auto logger = spdlog::basic_logger_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);
@ -44,7 +44,7 @@ TEST_CASE("disable param evaluation", "[macros]") {
} }
TEST_CASE("pass logger pointer", "[macros]") { TEST_CASE("pass logger pointer", "[macros]") {
auto logger = spdlog::null_logger_mt("refmacro"); auto logger = spdlog::create<spdlog::sinks::null_sink_mt>("refmacro");
auto &ref = *logger; auto &ref = *logger;
SPDLOG_LOGGER_TRACE(&ref, "Test message 1"); SPDLOG_LOGGER_TRACE(&ref, "Test message 1");
SPDLOG_LOGGER_DEBUG(&ref, "Test message 2"); SPDLOG_LOGGER_DEBUG(&ref, "Test message 2");

View File

@ -8,6 +8,7 @@
#include "includes.h" #include "includes.h"
#include "spdlog/details/os.h" #include "spdlog/details/os.h"
#include "spdlog/sinks/ostream_sink.h" #include "spdlog/sinks/ostream_sink.h"
#include "spdlog/sinks/async_sink.h"
#include "test_sink.h" #include "test_sink.h"
template <class T> template <class T>
@ -94,12 +95,14 @@ TEST_CASE("clone-logger", "[clone]") {
TEST_CASE("clone async", "[clone]") { TEST_CASE("clone async", "[clone]") {
using spdlog::sinks::test_sink_mt; using spdlog::sinks::test_sink_mt;
spdlog::init_thread_pool(4, 1);
auto test_sink = std::make_shared<test_sink_mt>(); auto test_sink = std::make_shared<test_sink_mt>();
auto logger = std::make_shared<spdlog::async_logger>("orig", test_sink, spdlog::thread_pool()); {
logger->set_pattern("%v"); auto cfg = spdlog::sinks::async_sink::config();
cfg.sinks.push_back(test_sink);
auto async_sink = spdlog::sinks::async_sink::with<test_sink_mt>();
auto logger = spdlog::create<spdlog::sinks::async_sink>("orig", cfg);
logger->set_pattern("*** %v ***");
auto cloned = logger->clone("clone"); auto cloned = logger->clone("clone");
REQUIRE(cloned->name() == "clone"); REQUIRE(cloned->name() == "clone");
REQUIRE(logger->sinks() == cloned->sinks()); REQUIRE(logger->sinks() == cloned->sinks());
REQUIRE(logger->log_level() == cloned->log_level()); REQUIRE(logger->log_level() == cloned->log_level());
@ -107,12 +110,10 @@ TEST_CASE("clone async", "[clone]") {
logger->info("Some message 1"); logger->info("Some message 1");
cloned->info("Some message 2"); cloned->info("Some message 2");
}
spdlog::details::os::sleep_for_millis(100);
REQUIRE(test_sink->lines().size() == 2); REQUIRE(test_sink->lines().size() == 2);
REQUIRE(test_sink->lines()[0] == "Some message 1"); REQUIRE(test_sink->lines()[0] == "*** Some message 1 ***");
REQUIRE(test_sink->lines()[1] == "Some message 2"); REQUIRE(test_sink->lines()[1] == "*** Some message 2 ***");
} }
TEST_CASE("global logger API", "[global logger]") { TEST_CASE("global logger API", "[global logger]") {

View File

@ -1,4 +1,5 @@
#include "includes.h" #include "includes.h"
#include "spdlog/details/mpmc_blocking_q.h"
using std::chrono::milliseconds; using std::chrono::milliseconds;
using test_clock = std::chrono::high_resolution_clock; using test_clock = std::chrono::high_resolution_clock;

View File

@ -37,7 +37,7 @@ TEST_CASE("test_drain_raw", "[ringbuffer_sink]") {
} }
int counter = 0; int counter = 0;
sink->drain_raw([&](const spdlog::details::log_msg_buffer &buffer) { sink->drain_raw([&](const spdlog::details::async_log_msg &buffer) {
REQUIRE(buffer.payload.data() == std::to_string(counter + 1)); REQUIRE(buffer.payload.data() == std::to_string(counter + 1));
counter++; counter++;
}); });

View File

@ -8,10 +8,10 @@
#include <chrono> #include <chrono>
#include <mutex> #include <mutex>
#include <thread> #include <thread>
#include <exception>
#include "spdlog/details/null_mutex.h" #include "spdlog/details/null_mutex.h"
#include "spdlog/details/os.h" #include "spdlog/details/os.h"
#include "spdlog/fmt/fmt.h"
#include "spdlog/sinks/base_sink.h" #include "spdlog/sinks/base_sink.h"
namespace spdlog { namespace spdlog {
@ -37,6 +37,14 @@ public:
delay_ = delay; delay_ = delay;
} }
void set_exception(const std::runtime_error& ex) {
exception_ptr_ = std::make_exception_ptr(ex);
}
void clear_exception() {
exception_ptr_ = nullptr;
}
// return last output without the eol // return last output without the eol
std::vector<std::string> lines() { std::vector<std::string> lines() {
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_); std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
@ -45,6 +53,9 @@ public:
protected: protected:
void sink_it_(const details::log_msg &msg) override { void sink_it_(const details::log_msg &msg) override {
if (exception_ptr_) {
std::rethrow_exception(exception_ptr_);
}
memory_buf_t formatted; memory_buf_t formatted;
base_sink<Mutex>::formatter_->format(msg, formatted); base_sink<Mutex>::formatter_->format(msg, formatted);
// save the line without the eol // save the line without the eol
@ -56,12 +67,18 @@ protected:
std::this_thread::sleep_for(delay_); std::this_thread::sleep_for(delay_);
} }
void flush_() override { flush_counter_++; } void flush_() override {
if (exception_ptr_) {
std::rethrow_exception(exception_ptr_);
}
flush_counter_++;
}
size_t msg_counter_{0}; size_t msg_counter_{0};
size_t flush_counter_{0}; size_t flush_counter_{0};
std::chrono::milliseconds delay_{std::chrono::milliseconds::zero()}; std::chrono::milliseconds delay_{std::chrono::milliseconds::zero()};
std::vector<std::string> lines_; std::vector<std::string> lines_;
std::exception_ptr exception_ptr_; // will be thrown on next log or flush if not null
}; };
using test_sink_mt = test_sink<std::mutex>; using test_sink_mt = test_sink<std::mutex>;

View File

@ -8,7 +8,7 @@
TEST_CASE("stdout_st", "[stdout]") { TEST_CASE("stdout_st", "[stdout]") {
spdlog::set_pattern("%+"); spdlog::set_pattern("%+");
auto l = spdlog::stdout_logger_st("test"); auto l = spdlog::create<spdlog::sinks::stdout_color_sink_st>("test");
l->set_level(spdlog::level::trace); l->set_level(spdlog::level::trace);
l->trace("Test stdout_st"); l->trace("Test stdout_st");
l->debug("Test stdout_st"); l->debug("Test stdout_st");
@ -19,7 +19,7 @@ TEST_CASE("stdout_st", "[stdout]") {
} }
TEST_CASE("stderr_st", "[stderr]") { TEST_CASE("stderr_st", "[stderr]") {
auto l = spdlog::stderr_logger_st("test"); auto l = spdlog::create<spdlog::sinks::stderr_color_sink_st>("test");
l->set_level(spdlog::level::trace); l->set_level(spdlog::level::trace);
l->trace("Test stderr_st"); l->trace("Test stderr_st");
l->debug("Test stderr_st"); l->debug("Test stderr_st");
@ -43,7 +43,7 @@ TEST_CASE("stderr_mt", "[stderr]") {
// color loggers // color loggers
TEST_CASE("stdout_color_st", "[stdout]") { TEST_CASE("stdout_color_st", "[stdout]") {
auto l = spdlog::stdout_color_st("test"); auto l = spdlog::create<spdlog::sinks::stdout_color_sink_st>("test");
l->set_pattern("%+"); l->set_pattern("%+");
l->set_level(spdlog::level::trace); l->set_level(spdlog::level::trace);
l->trace("Test stdout_color_st"); l->trace("Test stdout_color_st");
@ -55,7 +55,7 @@ TEST_CASE("stdout_color_st", "[stdout]") {
} }
TEST_CASE("stdout_color_mt", "[stdout]") { TEST_CASE("stdout_color_mt", "[stdout]") {
auto l = spdlog::stdout_color_mt("test"); auto l = spdlog::create<spdlog::sinks::stdout_color_sink_mt>("test");
l->set_pattern("%+"); l->set_pattern("%+");
l->set_level(spdlog::level::trace); l->set_level(spdlog::level::trace);
l->trace("Test stdout_color_mt"); l->trace("Test stdout_color_mt");
@ -67,14 +67,14 @@ TEST_CASE("stdout_color_mt", "[stdout]") {
} }
TEST_CASE("stderr_color_st", "[stderr]") { TEST_CASE("stderr_color_st", "[stderr]") {
auto l = spdlog::stderr_color_st("test"); auto l = spdlog::create<spdlog::sinks::stderr_color_sink_st>("test");
l->set_pattern("%+"); l->set_pattern("%+");
l->set_level(spdlog::level::debug); l->set_level(spdlog::level::debug);
l->debug("Test stderr_color_st"); l->debug("Test stderr_color_st");
} }
TEST_CASE("stderr_color_mt", "[stderr]") { TEST_CASE("stderr_color_mt", "[stderr]") {
auto l = spdlog::stderr_color_mt("test"); auto l = spdlog::create<spdlog::sinks::stderr_color_sink_mt>("test");
l->set_pattern("%+"); l->set_pattern("%+");
l->info("Test stderr_color_mt"); l->info("Test stderr_color_mt");
l->warn("Test stderr_color_mt"); l->warn("Test stderr_color_mt");

View File

@ -1,5 +1,4 @@
#include "includes.h" #include "includes.h"
#include "spdlog/async.h"
#include "test_sink.h" #include "test_sink.h"
TEST_CASE("time_point1", "[time_point log_msg]") { TEST_CASE("time_point1", "[time_point log_msg]") {

View File

@ -4,7 +4,6 @@
#include <windows.h> #include <windows.h>
#else #else
#include <dirent.h> #include <dirent.h>
#include <sys/types.h>
#endif #endif
void prepare_logdir() { void prepare_logdir() {
@ -18,7 +17,7 @@ void prepare_logdir() {
#endif #endif
} }
std::string file_contents(const std::string &filename) { std::string file_contents(const std::filesystem::path &filename) {
std::ifstream ifs(filename, std::ios_base::binary); std::ifstream ifs(filename, std::ios_base::binary);
if (!ifs) { if (!ifs) {
throw std::runtime_error("Failed open file "); throw std::runtime_error("Failed open file ");
@ -26,7 +25,7 @@ std::string file_contents(const std::string &filename) {
return std::string((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>())); return std::string((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
} }
std::size_t count_lines(const spdlog::filename_t &filename) { std::size_t count_lines(const std::filesystem::path &filename) {
std::ifstream ifs(filename); std::ifstream ifs(filename);
if (!ifs) { if (!ifs) {
throw std::runtime_error("Failed open file "); throw std::runtime_error("Failed open file ");
@ -52,7 +51,7 @@ std::size_t get_filesize(const std::string &filename) {
throw std::runtime_error("Failed open file "); throw std::runtime_error("Failed open file ");
} }
return static_cast<std::size_t>(ifs.tellg()); return static_cast<size_t>(ifs.tellg());
} }
// source: https://stackoverflow.com/a/2072890/192001 // source: https://stackoverflow.com/a/2072890/192001
@ -72,7 +71,7 @@ std::size_t count_files(const std::string &folder) {
// Start iterating over the files in the folder directory. // Start iterating over the files in the folder directory.
HANDLE hFind = ::FindFirstFileA((folder + "\\*").c_str(), &ffd); HANDLE hFind = ::FindFirstFileA((folder + "\\*").c_str(), &ffd);
if (hFind != INVALID_HANDLE_VALUE) { if (hFind != INVALID_HANDLE_VALUE) {
do // Managed to locate and create an handle to that folder. do // Managed to locate and create a handle to that folder.
{ {
if (ffd.cFileName[0] != '.') counter++; if (ffd.cFileName[0] != '.') counter++;
} while (::FindNextFileA(hFind, &ffd) != 0); } while (::FindNextFileA(hFind, &ffd) != 0);

View File

@ -8,7 +8,7 @@ std::size_t count_files(const std::string &folder);
void prepare_logdir(); void prepare_logdir();
std::string file_contents(const std::string &filename); std::string file_contents(const std::filesystem::path &filename);
// std::size_t count_lines(const std::string &filename); // std::size_t count_lines(const std::string &filename);
std::size_t count_lines(const std::filesystem::path &filename); std::size_t count_lines(const std::filesystem::path &filename);