Skip to content

Commit 345cdf5

Browse files
committed
feat: Use spdlog logger
1 parent c83be63 commit 345cdf5

26 files changed

+647
-544
lines changed

.github/workflows/nightly.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ jobs:
6464
disable_cache: true
6565

6666
analyze_build_time:
67-
name: Analyze Build Time
67+
name: Analyze Build Time using Clang Build Analyzer
6868

6969
strategy:
7070
fail-fast: false

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ include(deps/Threads)
5858
include(deps/libfmt)
5959
include(deps/cassandra)
6060
include(deps/libbacktrace)
61+
include(deps/spdlog)
6162

6263
add_subdirectory(src)
6364
add_subdirectory(tests)

benchmarks/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ target_sources(
1414
include(deps/gbench)
1515

1616
target_include_directories(clio_benchmark PRIVATE .)
17-
target_link_libraries(clio_benchmark PUBLIC clio_util benchmark::benchmark_main)
17+
target_link_libraries(clio_benchmark PUBLIC clio_util benchmark::benchmark_main spdlog::spdlog)
1818
set_target_properties(clio_benchmark PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})

benchmarks/util/log/LoggerBenchmark.cpp

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,28 +22,36 @@
2222
#include "util/prometheus/Prometheus.hpp"
2323

2424
#include <benchmark/benchmark.h>
25-
#include <boost/log/core/core.hpp>
26-
#include <boost/log/utility/setup/common_attributes.hpp>
25+
#include <spdlog/async.h>
26+
#include <spdlog/async_logger.h>
27+
#include <spdlog/spdlog.h>
2728

2829
#include <barrier>
2930
#include <chrono>
3031
#include <cstddef>
3132
#include <filesystem>
33+
#include <memory>
3234
#include <string>
3335
#include <thread>
36+
#include <utility>
3437
#include <vector>
3538

3639
using namespace util;
3740

38-
struct BenchmarkLoggingInitializer {
39-
static constexpr auto kLOG_FORMAT = "%TimeStamp% (%SourceLocation%) [%ThreadID%] %Channel%:%Severity% %Message%";
41+
static constexpr auto kLOG_FORMAT = "%Y-%m-%d %H:%M:%S.%f %^(%@) [%t] %n:%L%$ %v";
4042

41-
static void
42-
initFileLogging(LogService::FileLoggingParams const& params)
43+
struct BenchmarkLoggingInitializer {
44+
static std::shared_ptr<spdlog::sinks::sink>
45+
createFileSink(LogService::FileLoggingParams const& params)
4346
{
44-
boost::log::add_common_attributes();
4547
std::filesystem::create_directories(params.logDir);
46-
LogService::initFileLogging(params, kLOG_FORMAT);
48+
return LogService::createFileSink(params);
49+
}
50+
51+
static Logger
52+
getLogger(std::shared_ptr<spdlog::logger> logger)
53+
{
54+
return Logger(std::move(logger));
4755
}
4856
};
4957

@@ -68,31 +76,40 @@ benchmarkConcurrentFileLogging(benchmark::State& state)
6876
auto const messagesPerThread = static_cast<size_t>(state.range(1));
6977

7078
PrometheusService::init(config::getClioConfig());
79+
spdlog::drop_all();
7180

7281
auto const logDir = uniqueLogDir();
7382
for (auto _ : state) {
7483
state.PauseTiming();
75-
std::filesystem::remove_all(logDir);
84+
spdlog::init_thread_pool(8192, 1);
7685

77-
BenchmarkLoggingInitializer::initFileLogging({
86+
auto fileSink = BenchmarkLoggingInitializer::createFileSink({
7887
.logDir = logDir,
79-
.rotationSizeMB = 1,
80-
.dirMaxSizeMB = 10,
88+
.rotationSizeMB = 128,
89+
.dirMaxSizeMB = 3200,
8190
.rotationHours = 24,
8291
});
83-
state.ResumeTiming();
8492

8593
std::vector<std::thread> threads;
8694
threads.reserve(numThreads);
8795

8896
std::chrono::high_resolution_clock::time_point start;
89-
std::barrier barrier(numThreads, [&start]() { start = std::chrono::high_resolution_clock::now(); });
97+
std::barrier barrier(numThreads, [&state, &start]() {
98+
state.ResumeTiming();
99+
start = std::chrono::high_resolution_clock::now();
100+
});
90101

91102
for (size_t threadNum = 0; threadNum < numThreads; ++threadNum) {
92-
threads.emplace_back([threadNum, messagesPerThread, &barrier]() {
93-
barrier.arrive_and_wait();
103+
threads.emplace_back([threadNum, messagesPerThread, fileSink, &barrier]() {
104+
std::string const channel = "Thread_" + std::to_string(threadNum);
105+
auto logger = std::make_shared<spdlog::async_logger>(
106+
channel, fileSink, spdlog::thread_pool(), spdlog::async_overflow_policy::block
107+
);
108+
logger->set_pattern(kLOG_FORMAT);
109+
spdlog::register_logger(logger);
110+
Logger const threadLogger = BenchmarkLoggingInitializer::getLogger(std::move(logger));
94111

95-
Logger const threadLogger("Thread_" + std::to_string(threadNum));
112+
barrier.arrive_and_wait();
96113

97114
for (size_t messageNum = 0; messageNum < messagesPerThread; ++messageNum) {
98115
LOG(threadLogger.info()) << "Test log message #" << messageNum;
@@ -103,14 +120,14 @@ benchmarkConcurrentFileLogging(benchmark::State& state)
103120
for (auto& thread : threads) {
104121
thread.join();
105122
}
106-
boost::log::core::get()->flush();
107123

108-
auto const end = std::chrono::high_resolution_clock::now();
124+
spdlog::shutdown();
109125

126+
auto const end = std::chrono::high_resolution_clock::now();
110127
state.SetIterationTime(std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count());
111-
}
112128

113-
std::filesystem::remove_all(logDir);
129+
std::filesystem::remove_all(logDir);
130+
}
114131

115132
auto const totalMessages = numThreads * messagesPerThread;
116133
state.counters["TotalMessagesRate"] = benchmark::Counter(totalMessages, benchmark::Counter::kIsRate);
@@ -120,8 +137,10 @@ benchmarkConcurrentFileLogging(benchmark::State& state)
120137

121138
BENCHMARK(benchmarkConcurrentFileLogging)
122139
->ArgsProduct({
123-
{1, 2, 4, 8}, // Number of threads
124-
{500, 1000, 2000, 100000}, // Messages per thread
140+
// Number of threads
141+
{1, 2, 4, 8},
142+
// Messages per thread
143+
{10'000, 100'000, 500'000, 1'000'000},
125144
})
126145
->UseManualTime()
127146
->Unit(benchmark::kMillisecond);

cmake/deps/spdlog.cmake

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
find_package(spdlog REQUIRED)
2+
3+
if (NOT TARGET spdlog::spdlog)
4+
message(FATAL_ERROR "spdlog::spdlog target not found")
5+
endif ()

conan.lock

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"xxhash/0.8.2#7856c968c985b2981b707ee8f2413b2b%1754325010.01",
66
"xrpl/2.5.0@clio/boost-odr#f68e48da1490c0a583052e4f068ada55%1754325014.392",
77
"sqlite3/3.47.0#7a0904fd061f5f8a2366c294f9387830%1754325009.708",
8+
"spdlog/1.15.3#3ca0e9e6b83af4d0151e26541d140c86%1748617970.519",
89
"soci/4.0.3#a9f8d773cd33e356b5879a4b0564f287%1754412158.144",
910
"re2/20230301#dfd6e2bf050eb90ddd8729cfb4c844a4%1754412148.014",
1011
"rapidjson/cci.20220822#1b9d8c2256876a154172dc5cfbe447c6%1754325007.656",
@@ -54,4 +55,4 @@
5455
]
5556
},
5657
"config_requires": []
57-
}
58+
}

conanfile.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ class ClioConan(ConanFile):
3333
'openssl/1.1.1v',
3434
'xrpl/2.5.0@clio/boost-odr',
3535
'zlib/1.3.1',
36-
'libbacktrace/cci.20210118'
36+
'libbacktrace/cci.20210118',
37+
'spdlog/1.15.3',
3738
]
3839

3940
default_options = {

docs/config-description.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -439,13 +439,21 @@ This document provides a list of all available Clio configuration properties in
439439
- **Constraints**: The value must be one of the following: `trace`, `debug`, `info`, `warning`, `error`, `fatal`, `count`.
440440
- **Description**: The general logging level of Clio. This level is applied to all log channels that do not have an explicitly defined logging level.
441441

442-
### log_format
442+
### spdlog_format
443443

444444
- **Required**: True
445445
- **Type**: string
446-
- **Default value**: `%TimeStamp% (%SourceLocation%) [%ThreadID%] %Channel%:%Severity% %Message%`
446+
- **Default value**: `%Y-%m-%d %H:%M:%S.%f %^(%@) [%t] %n:%L%$ %v`
447447
- **Constraints**: None
448-
- **Description**: The format string for log messages. The format is described here: <https://www.boost.org/doc/libs/1_83_0/libs/log/doc/html/log/tutorial/formatters.html>.
448+
- **Description**: The format string for log messages using spdlog format patterns. Documentation can be found at: <https://github.com/gabime/spdlog/wiki/Custom-formatting>.
449+
450+
### spdlog_async
451+
452+
- **Required**: True
453+
- **Type**: boolean
454+
- **Default value**: `True`
455+
- **Constraints**: None
456+
- **Description**: Whether spdlog is asynchronous or not.
449457

450458
### log_to_console
451459

@@ -479,14 +487,6 @@ This document provides a list of all available Clio configuration properties in
479487
- **Constraints**: The minimum value is `1`. The maximum value is `4294967295`.
480488
- **Description**: The maximum size of the log directory in megabytes.
481489

482-
### log_rotation_hour_interval
483-
484-
- **Required**: True
485-
- **Type**: int
486-
- **Default value**: `12`
487-
- **Constraints**: The minimum value is `1`. The maximum value is `4294967295`.
488-
- **Description**: Represents the interval (in hours) for log rotation. If the current log file reaches this value in logging, a new log file starts.
489-
490490
### log_tag_style
491491

492492
- **Required**: True

docs/examples/config/example-config.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,15 @@
122122
"compress_reply": true
123123
},
124124
"log_level": "info",
125-
// Log format (this is the default format)
126-
"log_format": "%TimeStamp% (%SourceLocation%) [%ThreadID%] %Channel%:%Severity% %Message%",
125+
// Log format using spdlog format patterns (this is the default format)
126+
"spdlog_format": "%Y-%m-%d %H:%M:%S.%f %^(%@) [%t] %n:%L%$ %v",
127+
// Whether spdlog is asynchronous or not.
128+
"spdlog_async": true,
127129
"log_to_console": true,
128130
// Clio logs to file in the specified directory only if "log_directory" is set
129131
// "log_directory": "./clio_log",
130132
"log_rotation_size": 2048,
131133
"log_directory_max_size": 51200,
132-
"log_rotation_hour_interval": 12,
133134
"log_tag_style": "uint",
134135
"extractor_threads": 8,
135136
"read_only": false,

docs/logging.md

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,26 @@ Clio provides several logging options, which all are configurable via the config
66

77
The minimum level of severity at which the log message will be outputted by default. Severity options are `trace`, `debug`, `info`, `warning`, `error`, `fatal`. Defaults to `info`.
88

9-
## `log_format`
9+
## `spdlog_format`
1010

11-
The format of log lines produced by Clio. Defaults to `"%TimeStamp% (%SourceLocation%) [%ThreadID%] %Channel%:%Severity% %Message%"`.
11+
The format of log lines produced by Clio using spdlog format patterns. Defaults to `"%Y-%m-%d %H:%M:%S.%f %^(%@) [%t] %n:%L%$ %v"`.
1212

1313
Each of the variables expands like so:
1414

15-
- `TimeStamp`: The full date and time of the log entry
16-
- `SourceLocation`: A partial path to the c++ file and the line number in said file (`source/file/path:linenumber`)
17-
- `ThreadID`: The ID of the thread the log entry is written from
18-
- `Channel`: The channel that this log entry was sent to
19-
- `Severity`: The severity (aka log level) the entry was sent at
20-
- `Message`: The actual log message
15+
- `%^`: Start color range
16+
- `%Y-%m-%d %H:%M:%S.%f`: The full date and time of the log entry with microsecond precision
17+
- `%@`: A partial path to the c++ file and the line number in said file (`source/file/path:linenumber`)
18+
- `%t`: The ID of the thread the log entry is written from
19+
- `%n`: The logger name (channel) that this log entry was sent to
20+
- `%l`: The severity (aka log level) the entry was sent at
21+
- `%$`: End color range
22+
- `%v`: The actual log message
23+
24+
For more information about spdlog format patterns, see: <https://github.com/gabime/spdlog/wiki/Custom-formatting>
25+
26+
## `spdlog_async`
27+
28+
Whether spdlog is asynchronous or not.
2129

2230
## `log_channels`
2331

@@ -60,13 +68,6 @@ The max size of the log file in **megabytes** before it will rotate into a small
6068

6169
The max size of the log directory in **megabytes** before old log files will be deleted to free up space. Defaults to 50GB.
6270

63-
## `log_rotation_hour_interval`
64-
65-
The time interval in **hours** after the last log rotation to automatically rotate the current log file. Defaults to 12 hours.
66-
67-
> [!NOTE]
68-
> Log rotation based on time occurs in conjunction with size-based log rotation. For example, if a size-based log rotation occurs, the timer for the time-based rotation will reset.
69-
7071
## `log_tag_style`
7172

7273
Tag implementation to use. Must be one of:

0 commit comments

Comments
 (0)