Skip to content

Repository files navigation

LogIt++ Library

LogIt++ Logo

MIT License Platform C++ Standard CI Windows CI Linux CI macOS

Читать на русском

Overview

LogIt++ is a macro-first C++ logging library. The core and most built-in backends support C++11; OTLP, Prometheus HTTP server, and MDBX integrations require C++17. It pairs lightweight instrumentation macros with configurable backends (console, rotating files, memory, system/crash loggers, OTLP, Prometheus, MDBX, or custom sinks). Most general-purpose native backends are asynchronous by default, while specialized backends may be synchronous or own their own worker and queue.

Key characteristics:

  • Macro-oriented API. Consistent macro families (LOGIT_<LEVEL>, LOGIT_PRINTF_<LEVEL>, LOGIT_STREAM_<LEVEL>, etc.) cover immediate messages, printf-style formatting, streaming, throttling, and tagging. Defining LOGIT_SHORT_NAME when including <logit.hpp> enables compact aliases like LOG_I, LOG_WPF, and LOG_S_INFO.
  • Flexible formatting and routing. Customize output patterns, mix console, file, system, telemetry, and storage backends, or supply custom logger implementations.
  • Configurable delivery. General-purpose native backends use asynchronous queues by default; queue limits, overflow policies, dedicated executors, and synchronous modes are configurable per backend where supported.

Normal usage goes through the public LOGIT_* / LOG_* macro families. Pick the family that matches your logging style: plain, printf, stream, conditional, targeted, or scope-based.

Header layout

The library ships with self-contained umbrella headers that provide a predictable include order:

Entry point Purpose
<logit.hpp> Brings in configuration macros, enums, utilities, formatters, loggers, the singleton Logger and public macros.
<logit/utils.hpp> Aggregates everything in logit/utils/, including LogRecord, formatting helpers and argument utilities.
<logit/formatter.hpp> Provides formatter interfaces and the default pattern compiler implementation.
<logit/loggers.hpp> Exposes the logger backends and prepares their internal dependencies.

Most application code should include <logit.hpp>. If you work directly with a module class and need a leaf header, follow the Nearest Header Requirement (NHR): include the matching umbrella first and then the specific header, e.g. for direct use of MemoryLogger:

#include <logit/loggers.hpp>
#include <logit/loggers/MemoryLogger.hpp>

Internal headers under logit/detail/ are private implementation details and should not be included directly by consumers.

See the macro examples below or browse the examples/ folder for focused demonstrations, including queue tuning and crash handling.

Recent focused examples include:

  • examples/example_logit_memory_logger.cpp - in-memory snapshots plus shared ILogReader and ILogSubscriber macros.
  • examples/example_logit_mdbx_logger.cpp - persistent MDBX storage plus the same shared read/callback macros and MDBX-specific session/payload APIs.
  • examples/example_logit_otlp_http.cpp - OTLP/HTTP export with batching, retries, optional compression, and contextual trace/span fields.
  • examples/example_logit_prometheus_payload.cpp - callback-based Prometheus payload emission with custom registry metrics.
  • examples/example_logit_prometheus_server.cpp - embedded /metrics endpoint with built-in and application metrics.
  • examples/example_logit_mdc_ndc.cpp - mapped and nested diagnostic context across scopes and threads.

Detailed guides and documentation map:

Macro Examples

Long-form macros

#include <logit.hpp>

int main() {
    LOGIT_ADD_CONSOLE_DEFAULT();
    LOGIT_SET_MAX_QUEUE(32);
    LOGIT_SET_QUEUE_POLICY(LOGIT_QUEUE_DROP);

    const bool verbose = true;
    int attempt = 1;
    double latency_ms = 12.5;

    LOGIT_TRACE0();
    LOGIT_DEBUG_IF(verbose, "Verbose diagnostics enabled");
    LOGIT_INFO("Starting service", attempt);
    LOGIT_WARN_ONCE("initializing subsystem");
    LOGIT_ERROR_EVERY_N(3, "retrying connection", attempt);
    LOGIT_ERROR_THROTTLE(250, "still failing");
    LOGIT_PRINTF_WARN("Latency %.2f ms", latency_ms);
    LOGIT_FORMAT_INFO("%.2f", 1.23f, 4.56f);
    LOGIT_INFO_TAG(({{"order_id", 123}, {"side", "BUY"}}), "sent order");
    LOGIT_STREAM_INFO() << "Streaming value: " << attempt;

    LOGIT_WAIT();
}

Short aliases

Define LOGIT_SHORT_NAME before including <logit.hpp> to enable single-letter level prefixes:

#define LOGIT_SHORT_NAME
#include <logit.hpp>

void short_names_demo() {
    LOGIT_ADD_CONSOLE_DEFAULT(); // call once during initialization

    int attempt = 2;

    LOG_I("Short alias for info");
    LOG_IPF("Attempt %d finished", attempt);
    LOG_W("Warning alias");
    LOG_WPF("Retry %d/3", attempt);
    LOG_S_INFO() << "Streaming alias " << attempt;
}

For a standalone program that brings everything together and intentionally aborts after logging a fatal message, check examples/example_logit_minimal_crash.cpp.

Diagnostic context

Mapped diagnostic context (MDC) stores thread-local key-value pairs, while nested diagnostic context (NDC) stores a thread-local stack of scope names. The context is available when the library is configured with -DLOGIT_WITH_CONTEXT=ON. When this option is off, LogRecord keeps the original hot-path shape and the context macros become no-ops.

With context enabled, a LogRecord captures a shared snapshot only when the current thread has non-empty MDC or NDC values.

#include <logit.hpp>

int main() {
    LOGIT_ADD_LOGGER(
        logit::ConsoleLogger, (),
        logit::SimpleLogFormatter,
        ("[%T] request=%K{request_id} ndc=[%J] %v")
    );

    LOGIT_MDC_PUT("request_id", "req-42");
    LOGIT_NDC_PUSH("checkout");

    {
        LOGIT_NDC_GUARD("payment");
        LOGIT_INFO("charge started");
    }

    LOGIT_MDC_CLEAR();
    LOGIT_NDC_CLEAR();
    LOGIT_WAIT();
}

System error helpers

LOGIT_SYSERR_<LEVEL> captures the current errno (or GetLastError() on Windows) and appends the decoded information to the message, so failure details stay attached to the original context. The lower-level LOGIT_PERROR_<LEVEL> and LOGIT_WINERR_<LEVEL> families are also available if you want to explicitly choose the platform macro.

#include <logit.hpp>
#include <fcntl.h>

int main() {
    LOGIT_ADD_CONSOLE_DEFAULT();

    if (::open("missing.cfg", O_RDONLY) == -1) {
        LOGIT_SYSERR_ERROR("Failed to open configuration");
    }

    LOGIT_WAIT();
}

The error suffix can be customised at compile time via config.hpp macros:

#define LOGIT_OS_ERROR_JOIN " <- "
#define LOGIT_POSIX_ERROR_PATTERN "[%s] errno=%d (%s)"
#define LOGIT_WINDOWS_ERROR_PATTERN "[%s] GetLastError=%lu (%s)"
#include <logit.hpp>

// ... later in the code ...
LOGIT_SYSERR_ERROR("Deleting temp directory failed");

Targeted, conditional, and scope helpers

The public macro surface also includes targeted logger variants, conditional variants, and RAII scope timers:

#include <logit.hpp>

int main() {
    LOGIT_ADD_CONSOLE_DEFAULT();                         // index 0
    LOGIT_ADD_UNIQUE_FILE_LOGGER_DEFAULT_SINGLE_MODE(); // index 1

    const bool verbose = true;
    int retry = 3;

    LOGIT_INFO_TO(1, "write directly to the single-mode logger");
    LOGIT_PRINTF_INFO_IF(verbose, "retry=%d", retry);
    LOGIT_SCOPE_INFO("load_config");
    LOGIT_SCOPE_PRINTF_WARN_T(10, "slow step %d", retry);

    LOGIT_WAIT();
}

In-memory snapshot logger

For remote control panels, diagnostics endpoints, or operator tooling, you can register a dedicated in-memory backend and fetch the latest buffered logs by logger index.

#include <logit.hpp>

int main() {
    LOGIT_ADD_MEMORY_LOGGER_SINGLE_MODE(1000, 1024 * 1024, 24LL * 60 * 60 * 1000); // index 0

    LOGIT_INFO_TO(0, "remote-ready info");
    LOGIT_WARN_TO(0, "latest warning");

    const auto lines = LOGIT_GET_BUFFERED_STRINGS(0);
    const auto entries = LOGIT_GET_BUFFERED_ENTRIES(0);
    const auto level = LOGIT_GET_LOG_LEVEL(0);

    (void)lines;
    (void)entries;
    (void)level;
}

MemoryLogger snapshots are returned in chronological order. The retention budget uses max_bytes as buffered formatted-message payload bytes, not the full object footprint of each BufferedLogEntry. Snapshot reads are lightweight at the Logger layer and do not take the per-backend execution mutex, but they still synchronize on the memory backend's own mutex while copying the current buffer.

Common stored-log API

Use ILogReader and ILogSubscriber when application code should work with either MemoryLogger or MdbxLogger. The shared macro helpers return LogRecordSnapshot records and avoid depending on backend-specific storage:

#include <logit.hpp>

int main() {
    // This can be a MemoryLogger index or an MdbxLogger index.
    const int backend_index = 0;

    const int64_t now_ms = LOGIT_CURRENT_TIMESTAMP_MS();
    const auto recent = LOGIT_READ_RECENT_ASC(backend_index, 100, 0);
    const auto window = LOGIT_READ_RANGE(
        backend_index,
        now_ms - 60LL * 60 * 1000,
        now_ms + 1,
        0);

    std::vector<logit::LogRecordSnapshot> live_updates;
    const uint64_t callback_id = LOGIT_ADD_LOG_CALLBACK(
        backend_index,
        ([&live_updates](const logit::LogRecordSnapshot& record) {
            live_updates.push_back(record);
        }));

    LOGIT_INFO_TO(backend_index, "visible through read and callback APIs");
    LOGIT_WAIT();
    LOGIT_REMOVE_LOG_CALLBACK(backend_index, callback_id);

    (void)recent;
    (void)window;
    (void)live_updates;
}

LOGIT_READ_RANGE, LOGIT_READ_RECENT_ASC, and LOGIT_READ_RECENT_DESC use ILogReader. LOGIT_ADD_LOG_CALLBACK and LOGIT_REMOVE_LOG_CALLBACK use ILogSubscriber; callbacks receive a LogRecordSnapshot after the backend has written the record. Snapshots own their string fields, so they can be copied or stored by value. Callback dispatch follows registration order. This is the preferred fallback-friendly API between MemoryLogger and MdbxLogger.

LOGIT_GET_BUFFERED_STRINGS and LOGIT_GET_BUFFERED_ENTRIES are convenience helpers for the MemoryLogger snapshot buffer. They are useful for local diagnostics panes, but code that should switch between in-memory and MDBX storage should prefer the shared LOGIT_READ_* and callback macros above.

File-based backends also expose persisted-file access through LOGIT_LIST_LOG_FILES(index), LOGIT_READ_LOG_FILE(index, path), and LOGIT_READ_LOG_FILES(index, paths). These helpers read only what has already reached disk, do not drain async queues, and currently treat compressed rotated files as metadata-only entries. Use MemoryLogger for near-real-time snapshots and the file APIs for operational reads of today's or previous days' persisted logs.


Backpressure and hot resize

The asynchronous TaskExecutor supports both a mutex-protected deque and an optional lock-free MPSC ring (enable via LOGIT_USE_MPSC_RING). The same queue policy names (Block, DropNewest, DropOldest) are available in both implementations, but DropOldest has intentionally different semantics: the deque removes the oldest accepted task, while MPSC drops the incoming task to keep accepted work ordered. The ring build also allows "hot" queue resizes where producers briefly wait while the worker rebuilds the ring buffer without losing in-flight tasks. The default MPSC buffer holds LOGIT_TASK_EXECUTOR_DEFAULT_RING_CAPACITY tasks (1024 by default) and can be retuned by combining LOGIT_SET_MAX_QUEUE(...) with the compile-time macro if your workload needs a different baseline. See docs/TaskExecutor.md for a full breakdown and tuning tips.

Logger backend Config structs can opt into use_dedicated_executor=true when one slow sink must not delay other async loggers. On native builds this creates one worker thread per configured logger, so use it deliberately for expensive or isolated backends. Single-threaded Emscripten builds keep the same per-instance queue semantics but drain cooperatively on the browser event loop.

You can always pass a configured backend through the generic macro:

logit::ConsoleLogger::Config cfg;
cfg.async = true;
cfg.use_dedicated_executor = true;
cfg.queue_capacity = 1024;
cfg.queue_policy = logit::QueuePolicy::Block;

LOGIT_ADD_LOGGER(
    logit::ConsoleLogger,
    (cfg),
    logit::SimpleLogFormatter,
    (LOGIT_CONSOLE_PATTERN)
);

Built-in helpers also expose config-first and short dedicated forms:

LOGIT_ADD_CONSOLE_CONFIG(cfg, LOGIT_CONSOLE_PATTERN);
LOGIT_ADD_CONSOLE_DEDICATED(
    LOGIT_CONSOLE_PATTERN,
    1024,
    logit::QueuePolicy::DropNewest
);

Features

  • Flexible Log Formatting:

Customize log message formats using patterns. You can redefine patterns via macros or specify them directly when adding a logger backend. Both standard format flags (%H, %M, %S, %v, etc.) and special ones like %N([...]) for fallback logs without arguments are supported.

#define LOGIT_CONSOLE_PATTERN "%H:%M:%S.%e | %^%N([%!g:%#])%v%$"

try {
    throw std::runtime_error("An example runtime error");
} catch (const std::exception& ex) {
    LOGIT_FATAL(ex);
}

// Output:
> 23:59:59.128 | An example runtime error
  • Macro-Based Logging:

Easily log variables and messages using macros. Choose the macro that matches the desired formatting style:

  • LOGIT_PRINTF_<LEVEL> mimics printf, where the format string controls each argument.
  • LOGIT_FORMAT_<LEVEL> applies the same format to every argument in the list.
float someFloat = 123.456f;
int someInt = 789;
LOGIT_INFO(someFloat, someInt);

auto now = std::chrono::system_clock::now();
LOGIT_PRINT_INFO("TimePoint example: ", now);
LOGIT_PRINTF_INFO("%.2f %d", someFloat, someInt); // printf-style
LOGIT_FORMAT_INFO("%.2f", someFloat, 654.321f);   // same format for all args
  • Log Filters and Throttling:

Reduce noise from repetitive messages with macros like LOGIT_WARN_ONCE, LOGIT_INFO_EVERY_N, and LOGIT_ERROR_THROTTLE. Use the _THROTTLE variants (e.g., LOGIT_INFO_THROTTLE) to limit output to one message per time period.

for (int i = 0; i < 10; ++i) {
    LOGIT_WARN_ONCE("initializing");                     // prints once
    LOGIT_INFO_EVERY_N(3, "heartbeat", i);               // every 3rd call
    LOGIT_ERROR_THROTTLE(200, "repeated error");         // max once/200ms
    std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
  • Tagged Logging:

Attach simple key-value attributes for easier filtering in log aggregators.

LOGIT_INFO_TAG(({{"order_id", 123}, {"side", "BUY"}}), "sent order");
// Output: [info] sent order order_id=123 side=BUY
  • Raw and Section Logging:

Write human-readable diagnostic snapshots without level or formatter prefixes. Raw records bypass log-level filters, but still use the configured backends, queues, file rotation, and targeted logger routing.

LOGIT_SECTION("App");
LOGIT_RAW("Name: sample.desktop.app");
LOGIT_RAW("Version: 3.3.106.wzr");

LOGIT_SECTION("Proxy");
LOGIT_RAW("Proxy enabled: False");
  • Diagnostic Context (MDC/NDC):

Enable LOGIT_WITH_CONTEXT to attach mapped and nested diagnostic context to records and format it with %K, %K{key}, and %J.

LOGIT_MDC_PUT("request_id", "req-42");
LOGIT_NDC_GUARD("checkout");
LOGIT_INFO("processing order");
  • Structured and telemetry backends:

Optional LOGIT_WITH_MDBX persists structured records and payloads through mdbx-containers. LOGIT_WITH_OTLP enables OTLP exporters: OtlpHttpLogger sends HTTP requests through kurlyk, while OtlpPayloadLogger delivers serialized payloads through a callback. LOGIT_WITH_PROMETHEUS / LOGIT_WITH_PROMETHEUS_SERVER provide callback and embedded /metrics backends. See the dedicated guides above for setup and platform/package limitations.

  • Console stream routing and cleanup:

ConsoleLogger::Config::routes can route level ranges to std::cout, std::cerr, or a caller-owned stream. LOGIT_CLEAR_LOGGER and LOGIT_CLEAR_ALL_LOGGERS clear supported in-memory or persisted records and return a LogClearResult describing the outcome.

  • Rotating File Logs:

    Automatic file rotation based on size with optional asynchronous compression using gzip or zstd.

  • Support for Multiple Backends:

Easily configure loggers for console and file output. If necessary, add support for sending messages to servers or databases by creating custom backends.

// Adding three backends: console, file, and unique file loggers
LOGIT_ADD_CONSOLE_DEFAULT();
LOGIT_ADD_FILE_LOGGER_DEFAULT();
LOGIT_ADD_UNIQUE_FILE_LOGGER_DEFAULT_SINGLE_MODE();
  • System Backends:

Use the host OS logging facility. SyslogLogger works with POSIX syslog, while EventLogLogger writes to the Windows Event Log.

  • Asynchronous Logging:

Most general-purpose native backends are asynchronous by default. Crash backends and PrometheusPayloadLogger are synchronous. OTLP HTTP and payload exporters own their queues and workers and can be configured for synchronous or asynchronous delivery. Dedicated executors create one worker per selected backend, and Emscripten without pthreads drains cooperatively without OS worker threads.

  • Stream-Based Logging:

Use stream operators for complex messages.

LOGIT_STREAM_INFO() << "Stream-based info logging with short macro. Integer value: " << 123;
  • Extensibility:

Create custom loggers and formatters to meet your specific requirements. See Custom Logger Backend and Formatter below for a complete implementation that matches the current interfaces.


Usage

Here’s a simple example demonstrating how to use LogIt++ in your application. The task queue size and overflow behavior are configurable via LOGIT_SET_MAX_QUEUE and LOGIT_SET_QUEUE_POLICY (use LOGIT_QUEUE_DROP or LOGIT_QUEUE_BLOCK):

#define LOGIT_SHORT_NAME
#include <logit.hpp>

int main() {
    // Initialize the logger with default console output
    LOGIT_ADD_CONSOLE_DEFAULT();
    LOGIT_SET_MAX_QUEUE(64);
    LOGIT_SET_QUEUE_POLICY(LOGIT_QUEUE_DROP);

    float a = 123.456f;
    int b = 789;
    int c = 899;
    const char* someStr = "Hello, World!";

    // Basic logging using macros
    LOG_INFO("Starting the application");
    LOG_DEBUG("Variable values", a, b);
    LOG_WARN("This is a warning message");

    // Formatted logging
    LOG_PRINTF_INFO("Formatted log: value of a = %.2f", a);
    LOG_FORMAT_WARN("%.4d", b, c);

    // Error and fatal logs
    LOG_ERROR("An error occurred", b);
    LOG_FATAL("Fatal error. Terminating application.");

    // Conditional logging
    LOG_ERROR_IF(b < 0, "Value of b is negative");
    LOG_WARN_IF(a > 100, "Value of a exceeds 100");

    // Stream-based logging with short and long names
    LOG_S_INFO() << "Logging a float: " << a << ", and an int: " << b;
    LOG_S_ERROR() << "Error occurred in the system";
    LOGIT_STREAM_WARN() << "Warning: potential issue detected with value: " << someStr;

    // Using LOGIT_TRACE for tracing function execution
    LOGIT_TRACE0();   // Trace without arguments
    LOG_PRINT_TRACE("Entering main function with variable a =", a);

    // Wait for all asynchronous logs to be processed
    LOGIT_WAIT();

    return 0;
}

For more usage examples, please refer to the examples folder in the repository, where you can find detailed demonstrations of various logging scenarios and configurations.


Compile-Time Log Level

You can exclude lower-severity logs from the binary by specifying the minimum severity compiled into the program. Define the LOGIT_COMPILED_LEVEL macro during compilation:

g++ -DLOGIT_COMPILED_LEVEL=LOGIT_LEVEL_WARN ...

With the example above, TRACE, DEBUG, and INFO macros are turned into no-ops at compile time.

Runtime level changes via LOGIT_SET_LOG_LEVEL(...) and LOGIT_SET_LOG_LEVEL_TO(...) still work for compiled-in severities, but they cannot re-enable log statements that were removed by LOGIT_COMPILED_LEVEL.


Log Format Customization

LogIt++ supports customizable log message formatting using patterns that define how each message should appear. You can specify patterns through macros or provide them when adding logger backends.

Format Example

Example of setting a custom format for the console logger:

LOGIT_ADD_LOGGER(
    logit::ConsoleLogger, (), 
    logit::SimpleLogFormatter, 
    ("%Y-%m-%d %H:%M:%S.%e [%l] %^%N(%g:%#)%v%$")
);

Or specify the pattern using macros:

#define LOGIT_CONSOLE_PATTERN "%H:%M:%S.%e | %^%N([%!g:%#])%v%$"
LOGIT_ADD_CONSOLE_DEFAULT();

The logger will automatically substitute the specified data into the template, for example:

23:59:59.128 | path/to/file.cpp:123 A sample log message

Log Message Formatting Flags

LogIt++ supports customizable log message formatting using flags. You can define how each log message should appear by including placeholders for various data, such as timestamps, log levels, file names, function names, and messages.

Below is a list of supported formatting flags:

  • Date and Time Flags:

    • %Y: Year (e.g., 2024)
    • %m: Month (01-12)
    • %d: Day of the month (01-31)
    • %H: Hour (00-23)
    • %M: Minute (00-59)
    • %S: Second (00-59)
    • %e: Millisecond (000-999)
    • %C: Two-digit year (e.g., 24 for 2024)
    • %c: Full date and time (e.g., Mon Oct 4 12:45:30 2024)
    • %D: Short date (e.g., 10/04/24)
    • %T, %X: Time in ISO 8601 format (e.g., 12:45:30)
    • %F: Date in ISO 8601 format (e.g., 2024-10-04)
    • %s, %E: Unix timestamp in seconds
    • %ms: Unix timestamp in milliseconds
    • %b: Abbreviated month name (e.g., Jan)
    • %B: Full month name (e.g., January)
    • %a: Abbreviated weekday name (e.g., Mon)
    • %A: Full weekday name (e.g., Monday)
  • Log Level Flags:

    • %l: Full log level (e.g., INFO, ERROR)
    • %L: Short log level (e.g., I for INFO, E for ERROR)
  • File and Function Flags:

    • %f, %fn, %bs: Base name of the source file
    • %g, %ffn: Full file path
    • %#: Line number
    • %!: Function name
  • Thread Flags:

    • %t: Thread identifier
  • Diagnostic Context Flags:

    • %K: All mapped diagnostic context values as key=value pairs
    • %K{key}: One mapped diagnostic context value by key
    • %J: Nested diagnostic context stack
  • Color Flags:

    • %^: Start color formatting
    • %$: End color formatting
    • %SC: Start removing color codes (Strip Color)
    • %EC: End removing color codes (End Color)
  • Message Flags:

    • %v: The log message content
    • %N(...): Used as a fallback when no arguments are provided (e.g., in LOG_TRACE0() calls). The pattern specified in parentheses will be used. Example: %N(%g:%#) will add the file name and line number if no message is provided.

Alignment and Truncation Support

LogIt++ allows message text formatting with width, alignment, and truncation:

  • Alignment:

    • Left: Use the - sign before the width number, e.g., %-10v.
    • Center: Use the = sign before the width number, e.g., %=10v.
    • Right (default): %10v.
  • Truncation:

    • The ! symbol after the width number specifies that text should be truncated if it exceeds the specified length. Example: %10!v.

Examples:

  • %10v – Right-align the message to 10 characters.
  • %-10v – Left-align the message to 10 characters.
  • %10!v – Truncate the message to 10 characters with right alignment.
  • %-10!v – Truncate the message to 10 characters with left alignment.

Advanced Path Handling

For file-related flags (%f, %g, %@), truncation ensures that the filename and the beginning of the path are preserved, replacing the middle portion with ... if the width is smaller than the path length.

Example:

  • Input: /very/long/path/to/file.cpp
  • Truncated to width=15: /very...file.cpp

Shortened Logging Macros

LogIt++ provides shortened versions of logging macros when LOGIT_SHORT_NAME is defined. These macros allow for concise logging across different log levels, including both standard and stream-based logging.

Available TRACE-level macros:

  • Basic logging:

    • LOG_T(...): Logs a TRACE-level message.
    • LOG_T0(): Logs a TRACE-level message without arguments.
    • LOG_0T(): Alias for LOG_T0().
    • LOG_0_T(): Alias for LOG_T0().
    • LOG_T_NOARGS(): Alias for LOG_T0().
    • LOG_NOARGS_T(): Alias for LOG_T0().
  • Formatted logging:

    • LOG_TF(fmt, ...): Logs a formatted TRACE-level message using format strings.
    • LOG_FT(fmt, ...): Alias for LOG_TF(fmt, ...).
    • LOG_T_PRINT(...): Logs a TRACE-level message by printing each argument.
    • LOG_PRINT_T(...): Alias for LOG_T_PRINT(...).
    • LOG_T_PRINTF(fmt, ...): Logs a formatted TRACE-level message using printf-style formatting.
    • LOG_PRINTF_T(fmt, ...): Alias for LOG_T_PRINTF(fmt, ...).
    • LOG_TP(...): Alias for LOG_T_PRINT(...).
    • LOG_PT(...): Alias for LOG_T_PRINT(...).
    • LOG_TPF(fmt, ...): Alias for LOG_T_PRINTF(fmt, ...).
    • LOG_PFT(fmt, ...): Alias for LOG_T_PRINTF(fmt, ...).
  • Alternative TRACE-level macros:

    • LOG_TRACE(...): Logs a TRACE-level message (same as LOG_T(...)).
    • LOG_TRACE0(): Logs a TRACE-level message without arguments (same as LOG_T0()).
    • LOG_0TRACE(): Alias for LOG_TRACE0().
    • LOG_0_TRACE(): Alias for LOG_TRACE0().
    • LOG_TRACE_NOARGS(): Logs a TRACE-level message with no arguments (same as LOG_T_NOARGS()).
    • LOG_NOARGS_TRACE(): Alias for LOG_TRACE_NOARGS().
    • LOG_TRACEF(fmt, ...): Logs a formatted TRACE-level message (same as LOG_TF(fmt, ...)).
    • LOG_FTRACE(fmt, ...): Alias for LOG_TRACEF(fmt, ...).
    • LOG_TRACE_PRINT(...): Logs a TRACE-level message by printing each argument (same as LOG_T_PRINT(...)).
    • LOG_PRINT_TRACE(...): Alias for LOG_TRACE_PRINT(...).
    • LOG_TRACE_PRINTF(fmt, ...): Logs a formatted TRACE-level message using printf-style formatting (same as LOG_T_PRINTF(fmt, ...)).
    • LOG_PRINTF_TRACE(fmt, ...): Alias for LOG_TRACE_PRINTF(fmt, ...).

These macros provide flexibility and convenience when logging messages at the TRACE level. They allow you to choose between different logging styles, such as standard logging, formatted logging, and printing each argument separately.

Note: Similar macros are available for other log levels — INFO (LOG_I, LOG_INFO), DEBUG (LOG_D, LOG_DEBUG), WARN (LOG_W, LOG_WARN), ERROR (LOG_E, LOG_ERROR), and FATAL (LOG_F, LOG_FATAL). The naming conventions are consistent across levels, you only need to replace the level letter or word in the macro name.

  • Example:
LOG_T("Trace message using short macro");
LOG_TF("%.4d", 999);
LOG_T_PRINT("Printing trace message with multiple variables: ", var1, var2);
LOG_TRACE("Trace message (alias for LOG_T)");
LOG_TRACE_PRINTF("Formatted trace: value = %d", value);

Configuration Macros

LogIt++ provides several macros that allow for customization and configuration. Below are the available configuration macros:

  • LOGIT_BASE_PATH: Defines the base path used for log file paths. If LOGIT_BASE_PATH is not defined or is empty ({}), the full path from __FILE__ will be used for log file paths. You can override this to specify a custom base path for your log files.
#define LOGIT_BASE_PATH "/path/to/your/project"
  • LOGIT_DEFAULT_COLOR: Defines the default color for console output. If LOGIT_DEFAULT_COLOR is not defined, it defaults to TextColor::LightGray. You can set a custom console text color by overriding this macro.
#define LOGIT_DEFAULT_COLOR TextColor::Green
  • LOGIT_CURRENT_TIMESTAMP_MS: Macro to get the current timestamp in milliseconds. By default, it uses std::chrono to get the timestamp. You can override this to provide a custom timestamp function if needed.
#define LOGIT_CURRENT_TIMESTAMP_MS() my_custom_timestamp_function()
  • LOGIT_CONSOLE_PATTERN: Defines the default log pattern for the console logger. This pattern controls the formatting of log messages sent to the console, including timestamp, message, and color. If LOGIT_CONSOLE_PATTERN is not defined, it defaults to %H:%M:%S.%e | %^%v%$.
#define LOGIT_CONSOLE_PATTERN "%H:%M:%S.%e | %^%v%$"
  • LOGIT_FILE_LOGGER_PATH: Defines the default directory path for log files. If LOGIT_FILE_LOGGER_PATH is not defined, it defaults to "data/logs". You can set this to a custom path to control where the log files are stored.
#define LOGIT_FILE_LOGGER_PATH "/custom/log/directory"
  • LOGIT_FILE_LOGGER_AUTO_DELETE_DAYS: Defines the number of days after which old log files are deleted. If LOGIT_FILE_LOGGER_AUTO_DELETE_DAYS is not defined, it defaults to 30 days. You can set this to a custom value to control the log file retention policy.
#define LOGIT_FILE_LOGGER_AUTO_DELETE_DAYS 60  // Keep logs for 60 days
  • LOGIT_FILE_LOGGER_PATTERN: Defines the default log pattern for file-based loggers. This pattern controls the formatting of log messages written to log files, including timestamp, filename, line number, function, and thread information. If LOGIT_FILE_LOGGER_PATTERN is not defined, it defaults to [%Y-%m-%d %H:%M:%S.%e] [%ffn:%#] [%!] [thread:%t] [%l] %SC%v.
#define LOGIT_FILE_LOGGER_PATTERN "[%Y-%m-%d %H:%M:%S.%e] [%l] %SC%v"
  • LOGIT_UNIQUE_FILE_LOGGER_PATH: Defines the default directory path for unique log files. If LOGIT_UNIQUE_FILE_LOGGER_PATH is not defined, it defaults to "data/logs/unique_logs". You can specify a custom path for unique log files.
#define LOGIT_UNIQUE_FILE_LOGGER_PATH "/custom/unique/log/directory"
  • LOGIT_UNIQUE_FILE_LOGGER_PATTERN: Defines the default log pattern for unique file-based loggers. If LOGIT_UNIQUE_FILE_LOGGER_PATTERN is not defined, it defaults to "%v". You can customize this pattern to control the format of log messages in unique files.
#define LOGIT_UNIQUE_FILE_LOGGER_PATTERN "%v"
  • LOGIT_UNIQUE_FILE_LOGGER_HASH_LENGTH: Defines the length of the hash used in unique log file names. If LOGIT_UNIQUE_FILE_LOGGER_HASH_LENGTH is not defined, it defaults to 8 characters. This ensures that unique filenames are generated for each log entry.
#define LOGIT_UNIQUE_FILE_LOGGER_HASH_LENGTH 12	 // Set hash length to 12 characters
  • LOGIT_SHORT_NAME: Enables short names for logging macros, such as LOG_T, LOG_D, LOG_E, etc., for more concise logging statements.

Custom Logger Backend and Formatter

Normal application code should keep using the public LOGIT_* / LOG_* macros. The low-level API shown below is for extension points: custom ILogger / ILogFormatter implementations, backend registration, tests, and other infrastructure code that intentionally works below the macro layer.

You can extend LogIt++ by implementing your own loggers and formatters. Here’s how:

Custom Logger Example

#include <fstream>
#include <mutex>
#include <logit.hpp>

class FileLogger : public logit::ILogger {
public:
	FileLogger(const std::string& file_name) : m_file_name(file_name) {
		m_log_file.open(file_name, std::ios::out | std::ios::app);
	}

	~FileLogger() {
		if (m_log_file.is_open()) {
			m_log_file.close();
		}
	}

	void log(const logit::LogRecord& record, const std::string& message) override {
		std::lock_guard<std::mutex> lock(m_mutex);
		if (m_log_file.is_open()) {
			m_log_file << message << std::endl;
		}
	}

	void wait() override {}

	std::string get_string_param(const logit::LoggerParam& param) const override {
		(void)param;
		return std::string();
	}

	int64_t get_int_param(const logit::LoggerParam& param) const override {
		(void)param;
		return 0;
	}

	double get_float_param(const logit::LoggerParam& param) const override {
		(void)param;
		return 0.0;
	}

	void set_log_level(logit::LogLevel level) override { m_log_level = level; }
	logit::LogLevel get_log_level() const override { return m_log_level; }

private:
	std::string m_file_name;
	std::ofstream m_log_file;
	std::mutex m_mutex;
	logit::LogLevel m_log_level = logit::LogLevel::LOG_LVL_TRACE;
};

Custom Formatter Example

#include <logit.hpp>
#include <json/json.h>

class JsonLogFormatter : public logit::ILogFormatter {
public:
	void set_timestamp_offset(int64_t offset_ms) override {
		(void)offset_ms;
	}

	std::string format(const logit::LogRecord& record) const override {
		Json::Value log_entry;
		log_entry["level"] = static_cast<int>(record.log_level);
		log_entry["timestamp_ms"] = record.timestamp_ms;
		log_entry["file"] = record.file;
		log_entry["line"] = record.line;
		log_entry["function"] = record.function;
		log_entry["format"] = record.format;

		Json::StreamWriterBuilder writer;
		return Json::writeString(writer, log_entry);
	}
};

Macro Reference

Macro pattern Description
LOGIT_<LEVEL>(...) Log a message with the given level (TRACE, DEBUG, INFO, WARN, ERROR, FATAL).
LOGIT_PRINT_<LEVEL>(...) Log a pre-formatted string or stream-built message.
LOGIT_PRINTF_<LEVEL>(fmt, ...) printf-style formatting with placeholders for each argument.
LOGIT_FORMAT_<LEVEL>(fmt, ...) Apply the same format string to every argument.
LOGIT_FMT_<LEVEL>(fmt, ...) fmt-style formatting when LOGIT_WITH_FMT is enabled.
LOGIT_STREAM_<LEVEL>() Stream-style logging with << operators; short aliases LOG_S_<LEVEL>() when LOGIT_SHORT_NAME is defined.
LOGIT_<LEVEL>_IF(condition, ...) Log only when condition is true.
LOGIT_PRINT_<LEVEL>_IF(...), LOGIT_PRINTF_<LEVEL>_IF(...), LOGIT_FORMAT_<LEVEL>_IF(...), LOGIT_FMT_<LEVEL>_IF(...) Conditional variants for the formatting families.
LOGIT_<LEVEL>_ONCE(...) Log only the first time the macro is executed.
LOGIT_<LEVEL>_EVERY_N(n, ...) Log on every nth invocation.
LOGIT_<LEVEL>_THROTTLE(period_ms, ...) Log at most once per period_ms milliseconds.
LOGIT_<LEVEL>_TAG(({{"k", "v"}}), msg) Attach key-value tags to a message.
LOGIT_MDC_PUT(key, value), LOGIT_MDC_REMOVE(key), LOGIT_MDC_CLEAR() Manage thread-local mapped diagnostic context when LOGIT_WITH_CONTEXT is enabled.
LOGIT_NDC_PUSH(value), LOGIT_NDC_POP(), LOGIT_NDC_CLEAR(), LOGIT_NDC_GUARD(value) Manage thread-local nested diagnostic context when LOGIT_WITH_CONTEXT is enabled.
LOGIT_RAW(msg), LOGIT_RAW_TO(index, msg), LOGIT_RAW_IF(condition, msg) Write already formatted text without applying level filters or formatter patterns.
LOGIT_SECTION(name), LOGIT_SECTION_TO(index, name), LOGIT_SECTION_IF(condition, name) Write raw section headers such as [Proxy].
LOGIT_<LEVEL>_TO(index, ...) Target a specific logger index, including single-mode backends.
LOGIT_PRINT_<LEVEL>_TO(...), LOGIT_PRINTF_<LEVEL>_TO(...), LOGIT_FORMAT_<LEVEL>_TO(...), LOGIT_FMT_<LEVEL>_TO(...), LOGIT_STREAM_<LEVEL>_TO(...) Targeted variants for the print/printf/format/fmt/stream families.
LOGIT_SCOPE_<LEVEL>(phase) / LOGIT_SCOPE_<LEVEL>_T(threshold_ms, phase) RAII scope-duration logging, optionally only when a threshold is exceeded.
LOGIT_SCOPE_PRINTF_<LEVEL>(...) / LOGIT_SCOPE_PRINTF_<LEVEL>_T(...) Scope timers with printf-style formatting.
LOGIT_SCOPE_FMT_<LEVEL>(...) / LOGIT_SCOPE_FMT_<LEVEL>_T(...) Scope timers with fmt-style formatting.
LOGIT_CLEAR_LOGGER(index) / LOGIT_CLEAR_ALL_LOGGERS() Clear supported logger-owned records and return a LogClearResult; _EX variants accept LogClearOptions.
LOGIT_PERROR_<LEVEL>(msg), LOGIT_WINERR_<LEVEL>(msg), LOGIT_SYSERR_<LEVEL>(msg) Append decoded platform error information to a message.
LOGIT_ADD_LOGGER(...) and LOGIT_ADD_* backend macros Register console, memory, file, unique-file, crash, syslog, event-log, or custom backends.
LOGIT_GET_*, LOGIT_SET_*, LOGIT_IS_*, LOGIT_WAIT(), LOGIT_SHUTDOWN() Query and manage logger/task-executor state.
LOGIT_QUEUE_*, LOGIT_GET_DROPPED_TASKS(), LOGIT_RESET_DROPPED_TASKS() Queue policy constants and dropped-task counters.

Pattern-consistent aliases also exist for short-name and compatibility paths; the rows above document the canonical public families.

Configuration Macros

Macro Description
LOGIT_BASE_PATH Trim this prefix from __FILE__ paths shown in logs.
LOGIT_DEFAULT_COLOR Default console color for messages.
LOGIT_COLOR_TRACE, LOGIT_COLOR_DEBUG, LOGIT_COLOR_INFO, LOGIT_COLOR_WARN, LOGIT_COLOR_ERROR, LOGIT_COLOR_FATAL, LOGIT_COLOR_DEFAULT Override per-level and default console colors.
LOGIT_WALLCLOCK_MS() / LOGIT_MONOTONIC_MS() Override the wall-clock or monotonic time source helpers used by the library.
LOGIT_CURRENT_TIMESTAMP_MS() Override the main timestamp hook used in log records.
LOGIT_CONSOLE_PATTERN Default format pattern for console output.
LOGIT_FILE_LOGGER_PATH Directory for rotating file logs.
LOGIT_FILE_LOGGER_AUTO_DELETE_DAYS Retention window for file logger cleanup.
LOGIT_FILE_LOGGER_PATTERN Default message pattern for file loggers.
LOGIT_FILE_LOGGER_MAX_FILE_SIZE_BYTES Rotation threshold for size-based file rotation.
LOGIT_FILE_LOGGER_MAX_ROTATED_FILES Maximum number of rotated files to retain.
LOGIT_UNIQUE_FILE_LOGGER_PATH Directory for one-message-per-file logs.
LOGIT_UNIQUE_FILE_LOGGER_PATTERN Default message pattern for unique-file loggers.
LOGIT_UNIQUE_FILE_LOGGER_HASH_LENGTH Hash length used in unique-file logger names.
LOGIT_OS_ERROR_JOIN, LOGIT_POSIX_ERROR_PATTERN, LOGIT_WINDOWS_ERROR_PATTERN, LOGIT_SYSTEM_ERROR_PATTERN Control how decoded system errors are appended to messages.
LOGIT_TAGS_JOIN, LOGIT_TAG_PAIR_SEP, LOGIT_TAG_KV_SEP, LOGIT_TAG_QUOTE_VALUES Control how key-value tags are rendered after the message.
LOGIT_TASK_EXECUTOR_BLOCK_WAIT_USEC Polling cadence used by blocking producers when the queue is full.
LOGIT_TASK_EXECUTOR_DRAIN_BUDGET Maximum number of queued tasks drained per worker iteration in ring mode.
LOGIT_TASK_EXECUTOR_DEFAULT_RING_CAPACITY Default MPSC ring capacity used when unlimited queue mode needs a backing size.
LOGIT_SHORT_NAME Enable compact aliases such as LOG_I, LOG_WPF, and LOG_S_INFO.

Management Macros

Macro Description
LOGIT_SET_MAX_QUEUE(size) Limit the asynchronous task queue (0 for unlimited).
LOGIT_SET_QUEUE_POLICY(mode) Set overflow behavior: LOGIT_QUEUE_DROP_NEWEST, LOGIT_QUEUE_DROP_OLDEST, or LOGIT_QUEUE_BLOCK.
LOGIT_SET_LOG_LEVEL_TO(index, level) Set minimum log level for a specific logger.
LOGIT_SET_LOG_LEVEL(level) Set minimum log level for all loggers.
LOGIT_GET_LOG_LEVEL(index) Read the current minimum log level of a specific logger.
LOGIT_SET_LOGGER_ENABLED(index, enabled) Enable or disable a logger.
LOGIT_IS_LOGGER_ENABLED(index) Check whether a logger is enabled.
LOGIT_SET_SINGLE_MODE(index, single_mode) Toggle single-message-per-file mode for a logger.
LOGIT_IS_SINGLE_MODE(index) Determine if a logger is in single mode.
LOGIT_SET_TIME_OFFSET(index, offset_ms) Adjust timestamp offset for a logger.
LOGIT_GET_STRING_PARAM(index, param) Retrieve a string parameter from a logger.
LOGIT_GET_INT_PARAM(index, param) Retrieve an integer parameter from a logger.
LOGIT_GET_FLOAT_PARAM(index, param) Retrieve a floating-point parameter from a logger.
LOGIT_GET_LAST_FILE_NAME(index) Get the last file name written by a logger.
LOGIT_GET_LAST_FILE_PATH(index) Get the last file path written by a logger.
LOGIT_GET_LAST_LOG_TIMESTAMP(index) Get the timestamp of the last log entry.
LOGIT_GET_TIME_SINCE_LAST_LOG(index) Seconds elapsed since the last log entry.
LOGIT_GET_BUFFERED_STRINGS(index) Return buffered formatted messages from a logger that supports snapshots.
LOGIT_GET_BUFFERED_ENTRIES(index) Return buffered structured entries from a logger that supports snapshots.
LOGIT_LIST_LOG_FILES(index) List persisted log files exposed by a file-based logger.
LOGIT_READ_LOG_FILE(index, path) Read one persisted plain-text log file owned by a file-based logger.
LOGIT_READ_LOG_FILES(index, paths) Read several persisted plain-text log files and preserve request order.
LOGIT_WAIT() Wait for all asynchronous loggers to finish.
LOGIT_SHUTDOWN() Shut down the logging system.

Installation

LogIt++ itself is header-only. When consumed through the CMake target, enabled optional features may add transitive compile and link dependencies. Choose one of the following integration paths.

  1. Clone the repository with its submodules:
git clone --recurse-submodules https://github.com/LimiNode/log-it-cpp.git
  1. Include the LogIt++ headers in your project:
#include <logit.hpp>
  1. Configure dependencies.

CMake builds first look for the required TimeShield package and then fall back to this repository's bundled external/time-shield-cpp submodule when it is present. If you vendor dependencies inside your own project, use your own install or vendor paths; the directory does not need to be named external.

Optional dependencies are needed only for the features you enable: fmt for LOGIT_WITH_FMT, zlib for LOGIT_WITH_GZIP, zstd for LOGIT_WITH_ZSTD, kurlyk for LOGIT_WITH_OTLP, and mdbx-containers for LOGIT_WITH_MDBX. Install them as packages, provide them from your own dependency layout, or set LOGIT_USE_SUBMODULES=ON to let CMake use bundled copies for development. Installed package exports require optional dependencies to be provided as installed/imported targets.

CMake subdirectory or vendored checkout

add_subdirectory(external/log-it-cpp)
target_link_libraries(my_app PRIVATE log-it-cpp::log-it-cpp)

Installed CMake package

find_package(log-it-cpp CONFIG REQUIRED)
target_link_libraries(my_app PRIVATE log-it-cpp::log-it-cpp)

Build and install the package with:

cmake -S . -B build -DLOGIT_CPP_BUILD_TESTS=OFF
cmake --build build
cmake --install build --prefix ./install

Pass -DCMAKE_PREFIX_PATH=/path/to/install when configuring the consumer. LOGIT_WITH_PROMETHEUS_SERVER=ON and bundled optional dependency targets are currently supported for source/build-tree development only; the install step rejects them rather than exporting a broken package.

  1. (Optional) Enable fmt-style macros:

LogIt++ includes the fmt library for {}-based formatting. To use the LOGIT_FMT_* and LOGIT_SCOPE_FMT_* macros, build the library with the CMake option -DLOGIT_WITH_FMT=ON.

CMake options

The following toggles cover all build-time features:

  • LOGIT_CPP_BUILD_TESTS (default: ON when the project is the root build) — build the test suite.
  • LOGIT_CPP_BUILD_EXAMPLES (default: OFF) — build the example programs.
  • LOGIT_BENCH_ENABLE (default: OFF) — build benchmarks; LOGIT_BENCH_WITH_SPDLOG (default: OFF) also builds the spdlog comparisons.
  • LOGIT_WITH_GZIP / LOGIT_WITH_ZSTD (defaults: OFF) — enable gzip or zstd support for rotated files.
  • LOGIT_WITH_FMT (default: OFF) — include the {}-style formatting macros.
  • LOGIT_WITH_CONTEXT (default: OFF) — enable MDC/NDC helpers and %K, %K{key}, %J formatter tokens.
  • LOGIT_WITH_OTLP (default: OFF, C++17) — enable OTLP/HTTP export through kurlyk; not supported on Emscripten.
  • LOGIT_WITH_PROMETHEUS (default: OFF) — enable Prometheus text payload support; not supported on Emscripten.
  • LOGIT_WITH_PROMETHEUS_SERVER (default: OFF, C++17) — enable the embedded Prometheus HTTP server; not supported on Emscripten and currently rejected by cmake --install.
  • LOGIT_WITH_MDBX (default: OFF, C++17) — enable structured MDBX storage through mdbx-containers; not supported on Emscripten or MSVC.
  • LOGIT_USE_SUBMODULES (default: OFF) allows bundled optional dependency fallbacks such as fmt, zlib, and zstd when system packages are missing.
  • LOGIT_WITH_SYSLOG (default: ON on Unix-like targets) — build the syslog backend.
  • LOGIT_WITH_WIN_EVENT_LOG (default: ON on Windows) — build the Windows Event Log backend.
  • LOGIT_FORCE_ASYNC_OFF (default: OFF) — force synchronous logging even in multi-threaded builds.
  • LOGIT_USE_MPSC_RING (default: ON) — use the lock-free task queue instead of the mutex-backed deque.
  • LOGIT_EMSCRIPTEN (default: ON under Emscripten toolchains) — adjust the build for single-threaded WebAssembly environments.

Backend matrix

Supported backends include console, file, memory, system logging, OTLP, Prometheus, and MDBX. See the canonical backend matrix for standards, feature-specific dependencies, and platform/package restrictions.

System Backends

LogIt++ can forward messages to system logging facilities.

Syslog (Unix)

Available when LOGIT_WITH_SYSLOG=ON on Unix-like systems. Log levels are mapped as follows: TRACE/DEBUG → LOG_DEBUG, INFO → LOG_INFO, WARN → LOG_WARNING, ERROR/FATAL → LOG_ERR/LOG_CRIT.

LOGIT_ADD_SYSLOG_DEFAULT();
LOGIT_INFO("Syslog is alive");

Windows Event Log

Enabled with LOGIT_WITH_WIN_EVENT_LOG=ON on Windows. Levels map TRACE/DEBUG/INFO → INFORMATION, WARN → WARNING, ERROR/FATAL → ERROR.

LOGIT_ADD_EVENT_LOG_DEFAULT();
LOGIT_ERROR("Something went wrong");

Both loggers compile to no-ops on unsupported platforms.

Emscripten

When building with Emscripten the library runs without threads. Console logging works as usual while file-based loggers are replaced by stubs that warn when used.

Benchmarks

The canonical benchmark guide is docs/benchmarks.md. It contains the methodology, interpretation rules, historical snapshot, and LatencyRecorder notes referenced by the detailed material below.

Latency and throughput benchmarks live under bench/. Enable them during configuration and optionally pull in the spdlog adapters:

cmake -S . -B build -DLOGIT_BENCH_ENABLE=ON -DLOGIT_BENCH_WITH_SPDLOG=ON
cmake --build build --target logit_bench

Run ./build/bench/logit_bench to record the full matrix (sync/async × null/file × producer counts × message sizes). Results are appended to bench/results/latency.csv with one row per library/combination. Override the workload via LOGIT_BENCH_TOTAL and LOGIT_BENCH_WARMUP environment variables if you need a lighter run.

What this benchmark measures

See the canonical benchmark guide for the measurement model, comparison caveats, and interpretation rules.

Latest snapshot

The historical snapshot and full comparison table are maintained in the benchmark guide.

Benchmark harness notes

See the benchmark guide for LatencyRecorder details.


Documentation

Detailed documentation for LogIt++, including API reference and usage examples, can be found here.


License

This library is licensed under the MIT License. See the LICENSE file in the repository for more details.

About

Header-only C++ logging library with a macro-first API, asynchronous logging, structured records, flexible formatting and multiple backends.

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages