slick-logger is a header-only C++20 logging library for Windows, Linux, and macOS. LOG_*
calls enqueue entries in the calling thread's own ring buffer, and a background writer formats them
and sends them to console, file, or custom sinks. It also supports log rotation, binary payloads,
and shared-memory logging across processes.
Installation | Quick start | Guide | Build from source
- High Performance: Asynchronous logging through a lock-free ring per logging thread, so the calling thread does as little as possible and threads never contend
- Modern Formatting: Message formatting with C++20
std::format, including width, precision and alignment - Multi-Sink Architecture: Log to multiple destinations simultaneously, each with its own level, or address a single sink directly
- Log Rotation: Size-based and time-based rotation with configurable retention, for text and encoded files alike
- Customizable Pattern: An spdlog-style
set_pattern()that controls the whole line (field order, widths, alignment and which span is colored), globally or per sink - Source Locations:
LOG_*macros record the call-site file and line by default, and a runtime switch turns that off - Custom Clocks: Stamp entries from any clock, including the built-in
TscTimestamper, which reads the CPU cycle counter for under half the cost ofsystem_clock - Binary Payloads: Raw byte payloads through the same queue, written verbatim by
BinarySink - Encoded Log Files:
EncodedFileSinkwrites entries in binary and skips formatting, so the writer thread drains them several times faster;slick_log_decoderenders the file later - Shared-Library Redirection: Plugin or strategy libraries can route their logs into the host application's logger
- Multi-Process Logging: Several processes log through shared memory, each thread into a ring of its own, and one collector drains them all
- Runtime Statistics: An optional background thread samples throughput, queue fullness and drop counts, and writes them to a CSV
- Header-Only, Cross-Platform: Nothing to link, no dependency beyond the standard library and slick-queue
Recorded on an AMD Ryzen 9 5900HX, Windows 11, MSVC 19.44 /O2, with log output on a local NVMe SSD (2026-10-22):
| Producer-side measurement | Result |
|---|---|
| Literal message, 1 producer | 14.35 million calls/sec |
| Literal message, 8 producers | 18.91 million calls/sec |
| Three-argument message, 8 producers | 7.48 million calls/sec |
| Mean call latency, literal message | 153 ns |
Call timings exclude the writer's drain and flush time. With 4 producer processes of 2 threads each, a call took about 185-200 ns with thread rings in shared memory, against 800-950 ns through the shared queue. Methodology and the full results are in the benchmark README, and Performance explains what is being measured.
By default, a full thread ring spills into the shared rings, which can overwrite their oldest entries under overload. See Known limitations.
- A C++20 compiler with
std::formatsupport (GCC 11+, Clang 14+, MSVC 19.29+) - CMake 3.20 or higher (for building examples/tests)
- slick-queue 2.3.0 or newer. The string ring uses its
items_per_slotconstructor, and multi-process logging relies on its shared-memory support, including the 2.3.0 guarantee that a queue never unlinks its segment when destroyed. The installed CMake package requires this version throughfind_dependency, so an older slick-queue fails at configure time - An internet connection to download the slick-queue header when it is not already installed
vcpkg installs slick-logger and its dependencies for you. In classic mode:
vcpkg install slick-loggerFor manifest-mode projects, add a vcpkg.json beside your CMakeLists.txt:
{
"dependencies": [
"slick-logger"
]
}Use the installed package in your C++20 CMake project:
cmake_minimum_required(VERSION 3.20)
project(your_project LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(slick-logger CONFIG REQUIRED)
add_executable(your_app main.cpp)
target_link_libraries(your_app PRIVATE slick::logger)Configure with the vcpkg CMake toolchain, replacing <path-to-vcpkg> with your vcpkg installation directory. In manifest mode this also installs the declared dependencies:
cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=<path-to-vcpkg>/scripts/buildsystems/vcpkg.cmake"
cmake --build build --config ReleaseCI builds and runs this package-consumer example in both classic and manifest modes; see tests/package_consumer.
CMake handles the slick-queue dependency for you.
cmake_minimum_required(VERSION 3.20)
project(your_project)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(FetchContent)
# Disable examples, tests, and benchmarks for slick-logger
set(BUILD_SLICK_LOGGER_EXAMPLES OFF CACHE BOOL "" FORCE)
set(BUILD_SLICK_LOGGER_TESTING OFF CACHE BOOL "" FORCE)
set(BUILD_SLICK_LOGGER_BENCHMARKS OFF CACHE BOOL "" FORCE)
# Optional: disable LOG_* macro source-location capture at compile time
set(SLICK_LOGGER_ENABLE_SOURCE_LOCATION OFF CACHE BOOL "" FORCE)
# Optional: build the standalone multi-process collector executable (OFF by default).
# The shared-memory feature itself is header-only and always available.
set(BUILD_SLICK_LOGGER_COLLECTOR ON CACHE BOOL "" FORCE)
# Optional: build slick_log_decode, which renders EncodedFileSink files as text (OFF by default).
set(BUILD_SLICK_LOGGER_DECODER ON CACHE BOOL "" FORCE)
FetchContent_Declare(
slick-logger
GIT_REPOSITORY https://github.com/SlickQuant/slick-logger.git
GIT_TAG main
)
FetchContent_MakeAvailable(slick-logger)
add_executable(your_app main.cpp)
target_link_libraries(your_app slick::logger)If you've installed slick-logger system-wide:
cmake_minimum_required(VERSION 3.20)
project(your_project)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Optional: also accepts -DSLICK_LOGGER_ENABLE_SOURCE_LOCATION=OFF on the CMake command line
set(SLICK_LOGGER_ENABLE_SOURCE_LOCATION OFF CACHE BOOL "" FORCE)
find_package(slick-logger CONFIG REQUIRED)
add_executable(your_app main.cpp)
target_link_libraries(your_app PRIVATE slick::logger)cmake_minimum_required(VERSION 3.20)
project(your_project)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Add slick-logger include directory
include_directories(path/to/slick-logger/include, path/to/slick-queue/include)
add_executable(your_app main.cpp)The simplest route is the archive attached to a release. It already bundles slick/queue.h and the slick/shm/ headers alongside slick/logger.hpp, so you only have to unpack it and add include/ to your include path.
To assemble the headers by hand instead, you need both slick-logger and its dependency:
- Copy the
include/slick/directory to your project - Download
queue.hfrom https://raw.githubusercontent.com/SlickQuant/slick-queue/main/include/slick/queue.h - Place
queue.hin your include path or alongside the slick-logger headers - Copy the
slick/shm/headers from slick-shm as well, since slick-queue includes them for its shared-memory support
Your project structure should look like:
your_project/
├── include/
│ ├── slick/
│ └── logger.hpp
│ └── queue.h
│ └── shm/
└── src/
└── main.cpp
The CMake options above also handle dependencies automatically.
Use this as the main.cpp referenced by your CMake target:
#include <slick/logger.hpp>
int main() {
// Initialize the logger
slick::logger::Logger::instance().init("app.log", 1024); // queue size
// Log messages - formatting happens in the background thread
LOG_INFO("Application started");
LOG_DEBUG("Debug value: {}", 42); // std::format style placeholders
LOG_WARN("Processed {} items", 150);
LOG_ERROR("Error in {} at line {}", "function_name", 123);
LOG_INFO("User {} balance: ${:.2f}", "Alice", 1234.56); // Format specifiers supported
// Shutdown (optional, called automatically on destruction)
slick::logger::Logger::instance().shutdown();
return 0;
}By default each entry carries the call-site file and line:
2026-07-01 12:34:56.123456 [INFO] [main.cpp:8] Application started
Log levels, source-location switches and the bundled examples are covered in Getting started.
The full guide is published at https://slickquant.github.io/slick-logger/. Its sources live in
docs/ and render on GitHub as well.
| Guide | Use it for |
|---|---|
| Getting started | Installation, log levels, source locations, examples and tests |
| Configuration | Sinks, queue sizing, per-thread rings and runtime controls |
| Formatting | Message fields, line patterns, alignment and color |
| Sinks and rotation | Console and file output, rotation and custom sinks |
| Binary and encoded logs | Raw payload capture, encoded entries and offline decoding |
| Timestamps | Timestamp text, custom clocks and the TSC timestamper |
| Runtime statistics | Throughput, queue pressure, loss counters and CSV output |
| Shared libraries | Route plugin logs into the host logger and unload safely |
| Multi-process logging | Shared-memory producers, collectors, sizing and cleanup |
| Architecture | Thread rings, shared rings, ordering and deferred formatting |
| Performance | Recorded producer timings, methodology and reproduction |
| Known limitations | Loss behavior, payload limits, lifetimes and build compatibility |
| API reference | Doxygen-generated C++ reference for src/logger.hpp |
cmake -S . -B build
cmake --build build --config Debug
# Optional extras
cmake -S . -B build -DBUILD_SLICK_LOGGER_COLLECTOR=ON -DBUILD_SLICK_LOGGER_DECODER=ONThat builds the examples and the test suite. To run them, see Building examples/tests; for benchmarks, see BENCHMARK_SETUP.md.
The published site is MkDocs Material for the narrative docs plus Doxygen for the API reference.
# narrative docs, with live preview on http://127.0.0.1:8000
pip install -r requirements-docs.txt
mkdocs serve
# API reference (needs doxygen + graphviz on PATH)
cmake -S . -B build
cmake --build build --target slick-logger-docs # output in doxygen-out/htmlThe slick-logger-docs target only appears in a top-level configure, and only when
find_package(Doxygen) succeeds; a normal build is unaffected if Doxygen is absent. Pulling
slick-logger in with FetchContent or add_subdirectory() leaves the docs targets out, so they
cannot collide with a docs target of your own and Doxygen is not searched for during your
configure. A top-level configure also answers to the shorter docs alias.
ci.ymlbuilds and tests Debug and Release on Windows, Ubuntu and macOS, adds a Clang job and an AddressSanitizer/UBSan job, and builds the vcpkg package consumer in both classic and manifest mode.documentation.ymlbuilds this guide withmkdocs build --strictand the API reference with Doxygen, then publishes both to GitHub Pages; it also runs a Markdown link check and markdownlint.release.ymlpackages the headers together with slick-queue and slick-shm, and builds the standalone collector for each platform.
src/logger.hpp the library: single header, installed as include/slick/logger.hpp
include/ generated headers (configured from src/ by CMake)
examples/ runnable examples, including binary, statistics and multi-process
tests/ test suite, plus the shared-library and package-consumer fixtures
tools/ slick_log_collector and slick_log_decode
benchmarks/ benchmark sources and the recorded results
docs/ this documentation's sources (MkDocs)
Doxyfile.in API reference configuration (configured by CMake)
mkdocs.yml documentation site configuration
MIT. See LICENSE.