A thread-safe, feature-rich C++ logging library that provides flexible logging with multiple sinks, customizable formatters, and structured logging capabilities.
- Thread-Safe Logging: Full thread-safety with minimal lock contention
- Multiple Log Levels: TRACE, DEBUG, INFO, WARNING, ERROR, and FATAL severity levels
- Flexible Log Sinks:
- Stream sinks for stdout/stderr and custom streams
- File sinks with automatic rotation (size-based or time-based)
- Asynchronous sinks for non-blocking logging with configurable drop policies
- Custom Formatters:
- Default formatter with customizable timestamp formats
- JSON formatter for structured log analysis
- Structured Logging: Key-value pairs in log messages for rich context
- Log Context Storage: Thread-local context that automatically includes context in all logs
- Platform Support: Cross-platform compatibility (Windows, macOS, Linux)
- Compile-Time Filtering: Optional compile-time log level filtering to reduce binary size
- Category Loggers: Per-module loggers with individual configurations
This is a header-only library. Include ledger.h in your project and compile with C++17 or later.
- Requires: C++17 or later
- Platform-specific: Uses
localtime_son Windows,localtime_ron Unix-like systems
- Copy
ledger.hto your project's include directory - Include the header in your source files:
#include "ledger.h"
using namespace ledger;
// Simple logging
Ledger::info("Application started");
Ledger::warning("This is a warning");
Ledger::error("An error occurred");Ledger::set_level(LOG_DEBUG); // Enable all logs at DEBUG level and above
Ledger::set_level(LOG_WARNING); // Only WARNING, ERROR, and FATAL// Size-based rotation (10MB files, keep 5 files)
Ledger::set_file_logging("app.log", 10485760, 5);
// Time-based rotation (daily rotation, keep 7 files)
Ledger::set_file_logging("app.log", std::chrono::hours(24), 7);Ledger::info("User action performed",
"user_id", 12345,
"action", "login",
"ip_address", "192.168.1.1");
// Output: [2025-02-13 10:30:45] [INFO] User action performed | user_id=12345 action=login ip_address=192.168.1.1{
LogContext ctx;
ctx.add("request_id", "abc-123");
ctx.add("user_id", 42);
Ledger::info("Processing request"); // Automatically includes context
Ledger::debug("Detailed processing"); // Context included here too
} // Context automatically cleared on scope exit// Use JSON formatter
Ledger::set_formatter(std::make_unique<JSONLogFormatter>());
// Use custom timestamp format
Ledger::set_formatter(
std::make_unique<DefaultLogFormatter>(
TimestampFormat::ISO8601,
"MyApp"
)
);auto async_sink = std::make_unique<AsyncLogSink>(
std::make_unique<RotatingFileLogger>("app.log", 10485760, 5),
1024, // queue size
AsyncLogSink::DropPolicy::DROP_NEWEST
);
Ledger::add_sink(std::move(async_sink));
// Flush remaining messages
Ledger::async_flush();
// Shutdown cleanly
Ledger::async_shutdown();Ledger::configure(
Ledger::LoggerConfigBuilder()
.set_level(LOG_DEBUG)
.add_stream_sink(std::cout)
.add_async_file_sink("app.log", 1024, AsyncLogSink::DropPolicy::DROP_NEWEST)
.set_formatter(std::make_unique<JSONLogFormatter>())
.build()
);auto db_logger = Ledger::get("database");
db_logger.info("Connected to database");
auto api_logger = Ledger::get("api");
api_logger.warning("High latency detected");
// Configure category-specific settings
Ledger::LoggerRegistry::set_config(
"database",
Ledger::LoggerConfigBuilder()
.set_level(LOG_DEBUG)
.add_file_sink("database.log")
.build()
);| Level | Value | Use Case |
|---|---|---|
| TRACE | 0 | Very detailed diagnostic information (compile-time disabled by default) |
| DEBUG | 1 | Detailed information for development and debugging |
| INFO | 2 | General operational information (default level) |
| WARNING | 3 | Warning messages about potential issues |
| ERROR | 4 | Error conditions |
| FATAL | 5 | Critical errors requiring immediate attention |
- LogLevel: Enumeration for severity levels with macro-based compile-time filtering
- LogSink: Abstract interface for pluggable log destinations
StreamSink: Writes to std::ostreamRotatingFileLogger: File output with automatic rotationAsyncLogSink: Async wrapper around any sink
- LogFormatter: Abstract interface for message formatting
DefaultLogFormatter: Standard text formatJSONLogFormatter: Machine-parseable JSON format
- Logger: Main logging class with static methods
- LogContext: RAII helper for thread-local context management
- CategoryLogger: Named logger for per-module configuration
- All operations use mutex-protected critical sections
- Log formatting happens outside the critical section to minimize lock time
- Thread-local storage for log context avoids synchronization overhead
- Early exit for messages below current log level (minimal overhead when disabled)
- Non-blocking async logging option for high-throughput scenarios
- Configurable queue size and drop policies for async sinks
- Header-only implementation allows compiler optimizations
Reduce binary size by filtering out low-severity logs at compile time:
#define LEDGER_COMPILED_LOG_LEVEL LEDGER_LOG_LEVEL_INFO
#include "ledger.h"This removes TRACE and DEBUG logging calls entirely from the compiled binary.
Implement the LogSink interface to create custom destinations:
class CustomSink : public LogSink {
public:
void write(const std::string& message) override {
// Your custom logic here
}
};
Ledger::add_sink(std::make_unique<CustomSink>());Ledger is designed to be robust:
- IO errors fall back to stderr
- Exceptions in sinks are caught and logged to stderr
- Stream state errors are recovered via
clear()
Copyright (c) 2025 Interlaced Pixel
Licensed under the PolyForm Noncommercial License 1.0.0. See LICENSE file for details.
Summary: This software is free for noncommercial use. Personal projects, research, education, and noncommercial organizations can use this software. Commercial use requires a license from Interlaced Pixel.
For more information, visit: https://polyformproject.org/licenses/noncommercial/1.0.0
Ledger includes comprehensive unit tests using the doctest framework. Tests cover:
- Core logging components (sinks, formatters, context)
- Thread safety and concurrent logging
- File operations and log rotation
- Structured logging and context management
- Edge cases and special characters
- Macro functionality
See TESTING.md for detailed instructions on building and running the test suite.
mkdir build && cd build
cmake ..
cmake --build .
ctestContributions are welcome! Please ensure:
- Code follows the existing style
- All changes are thread-safe
- New features include appropriate error handling
- Changes work across supported platforms
- New features include corresponding unit tests
For issues, questions, or suggestions, please open an issue on the GitHub repository.