| .clang-format | ||
| .clangd | ||
| asynclog.hh | ||
| readme.md | ||
Asynclog - header only asynchronous logging library for C++(20)
Example
#define ASYNCLOG_ENABLED
#include "asynclog.hh"
int main() {
// The default logger ships with a console_sink already attached.
LOG_INFO("started, pid={}", ::getpid());
// Attach a file sink.
LOG_ADD_FILE("logs/app.log");
// Or a rotating file: 5 MB per file, keep 3 backups.
LOG_ADD_ROTATING("logs/app.log", 5 * 1024 * 1024, 3);
LOG_WARN("disk usage {}%", 87);
LOG_ERROR("timeout after {}ms", 3000);
LOG_FLUSH(); // block until all pending records are written
}
Levels
| Enum | Macro | Use case |
|---|---|---|
level::tracez |
LOG_TRACE |
fine-grained control flow |
level::debug |
LOG_DEBUG |
diagnostic detail |
level::info |
LOG_INFO |
normal operational events |
level::warn |
LOG_WARN |
unexpected but recoverable |
level::error |
LOG_ERROR |
failures |
level::fatal |
LOG_FATAL |
unrecoverable errors |
level::off |
- |
disables all output |
Levels are ordered; setting level::warn suppresses trace, debug, and info.
Filtering happens both on the logger (global gate) and per-sink.
Sinks
console_sink
Writes to std::cerr. Automatically detects whether stderr is a TTY and
enables ANSI colors accordingly.
auto cs = std::make_shared<asynclog::console_sink>();
cs->set_colors(false); // force colors off
cs->set_level(asynclog::level::warn); // only warn+ to console
logger.add_sink(cs);
file_sink
Appends to a single file. Parent directories are created automatically.
auto fs = std::make_shared<asynclog::file_sink>("/var/log/app.log");
// or truncate on open:
auto fs2 = std::make_shared<asynclog::file_sink>("debug.log", /*truncate=*/true);
rotating_file_sink
Rotates files when the current file exceeds max_bytes. Old files are renamed
with a numeric suffix (.1, .2, …). When the number of backups exceeds
max_files, the oldest is deleted.
auto rs = std::make_shared<asynclog::rotating_file_sink>(
"logs/app.log",
10 * 1024 * 1024, // 10 MB per file
5 // keep 5 backups
);
Custom sinks
Derive from asynclog::sink and implement write() and flush():
class syslog_sink : public asynclog::sink {
public:
void write(const asynclog::record& rec) override {
if (!should_log(rec.lvl)) return;
auto text = format(rec, /*colors=*/false);
::syslog(to_syslog_priority(rec.lvl), "%s", text.c_str());
}
void flush() override { /* no-op for syslog */ }
};
Overflow policies
When the internal queue is full:
| Policy | Behaviour |
|---|---|
overflow_policy::block |
caller blocks until space is available (default) |
overflow_policy::drop_newest |
incoming record is discarded; dropped_count() incremented |
overflow_policy::drop_oldest |
oldest queued record is evicted to make room |
auto& log = asynclog::default_logger();
log.set_queue_capacity(4096);
log.set_overflow_policy(asynclog::overflow_policy::drop_newest);
Formatters
A formatter is any callable matching std::string(const record&, boolcolors). Two are provided:
default_format— timestamp, padded level, source location, payload.compact_format— time-only, three-letter level tag, payload.
Set globally:
asynclog::default_logger().set_formatter(asynclog::compact_format);
Or per-sink:
file_sink->set_formatter([](const asynclog::record& r, bool) {
return std::format("[{}] {}\n",
asynclog::to_short_string(r.lvl), r.payload);
});
Compile-time filtering
Define ASYNCLOG_ACTIVE_LEVEL before including the header to strip lower-severity macros at compile time:
#define ASYNCLOG_ACTIVE_LEVEL ::asynclog::level::info
#define ASYNCLOG_ENABLED
#include "asynclog.hh"
// LOG_TRACE and LOG_DEBUG are now zero-cost no-ops.
Macro
| Macro | Description |
|---|---|
LOG_TRACE(fmt, ...) |
trace message |
LOG_DEBUG(fmt, ...) |
debug message |
LOG_INFO(fmt, ...) |
info message |
LOG_WARN(fmt, ...) |
warning |
LOG_ERROR(fmt, ...) |
error |
LOG_FATAL(fmt, ...) |
fatal error |
LOG_SET_LEVEL(lvl) |
set runtime minimum level |
LOG_SET_CONSOLE(bool) |
remove / keep the default console sink |
LOG_SET_COLORS(bool) |
toggle ANSI colors on console sink |
LOG_ADD_FILE(path) |
attach a file_sink |
LOG_ADD_ROTATING(path, bytes, n) |
attach a rotating_file_sink |
LOG_FLUSH() |
block until queue is drained and sinks flushed |
LOG_SHUTDOWN() |
flush + join worker thread |
Architecture
Logger
Central object that owns the background worker thread and a set of
sinks. A global default instance is provided via default_logger().
Additional named loggers may be created for subsystem isolation.
sink (interface)
Receives pre-formatted records. The library ships three concrete sinks; users may implement the interface for custom destinations.
console_sink— writes to stderr with optional ANSI colorsfile_sink— appends to a single filerotating_file_sink— rotates files by size, keeps N backups
record
Immutable value type carrying the formatted payload, metadata (level, timestamp, source location), and a monotonic sequence id.
formatter
Callable with signature std::string(const record&, bool colors).
The default formatter produces lines such as
2025-06-01 14:30:05.123] [INFO ] main.cc:42 — hello world
A custom formatter can be set per-sink or globally on the logger.