mirror of
https://github.com/gabime/spdlog.git
synced 2025-02-26 02:05:50 +08:00
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
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:
parent
166843ff3a
commit
83c9ede9e6
@ -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"
|
||||||
|
24
README.md
24
README.md
@ -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++
|
||||||
|
@ -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();
|
||||||
|
@ -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("");
|
||||||
|
@ -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);
|
||||||
|
@ -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!");
|
||||||
|
@ -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
|
|
@ -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
|
|
@ -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>)
|
@ -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>;
|
||||||
|
37
include/spdlog/details/async_log_msg.h
Normal file
37
include/spdlog/details/async_log_msg.h
Normal 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
|
@ -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>
|
||||||
|
@ -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
|
|
23
include/spdlog/details/err_helper.h
Normal file
23
include/spdlog/details/err_helper.h
Normal 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
|
@ -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 {
|
||||||
|
@ -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
|
|
@ -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_);
|
||||||
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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"
|
|
@ -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
|
||||||
|
@ -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__
|
||||||
|
@ -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>;
|
||||||
|
|
||||||
|
86
include/spdlog/sinks/async_sink.h
Normal file
86
include/spdlog/sinks/async_sink.h
Normal 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
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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>;
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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;
|
|
||||||
}
|
|
61
src/details/async_log_msg.cpp
Normal file
61
src/details/async_log_msg.cpp
Normal 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
|
@ -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
|
|
40
src/details/err_helper.cpp
Normal file
40
src/details/err_helper.cpp
Normal 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
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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
130
src/sinks/async_sink.cpp
Normal 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
|
@ -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>;
|
||||||
|
@ -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>;
|
@ -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>;
|
@ -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); }
|
|
@ -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);
|
|
@ -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);
|
|
||||||
|
@ -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>;
|
||||||
|
@ -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
|
||||||
|
@ -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"
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
|
@ -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]") {
|
||||||
|
@ -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;
|
||||||
|
@ -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++;
|
||||||
});
|
});
|
||||||
|
@ -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>;
|
||||||
|
@ -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");
|
||||||
|
@ -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]") {
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user