From 8d1005c0471db74dc6db7ae4e1daa1f8bd363c07 Mon Sep 17 00:00:00 2001 From: Aster Seker Date: Mon, 7 Sep 2026 16:14:44 +0300 Subject: [PATCH 1/6] docs: reorganize guide and benchmark documentation Split the Doxygen landing page from the detailed API reference and add focused quick-start, backend, and benchmark guides. Extend publication checks to cover the new pages and validate generated local links. --- .github/workflows/publish.yaml | 30 + Doxyfile | 4 + README-RU.md | 44 +- README.md | 65 +- docs/backends.md | 43 ++ docs/benchmarks.md | 54 ++ docs/mainpage.dox | 1097 +------------------------------- docs/quickstart.md | 50 ++ docs/reference.dox | 1063 +++++++++++++++++++++++++++++++ 9 files changed, 1306 insertions(+), 1144 deletions(-) create mode 100644 docs/backends.md create mode 100644 docs/benchmarks.md create mode 100644 docs/quickstart.md create mode 100644 docs/reference.dox diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index a0791c1..5dd3470 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -36,13 +36,43 @@ jobs: test -s docs/html/index.html test -s docs/html/pages.html test -s docs/html/classes.html + test -s docs/html/quickstart.html + test -s docs/html/backends.html + test -s docs/html/benchmarks.html + test -s docs/html/api_reference.html grep -q "1.0.2-dev" docs/html/index.html + grep -q "Quick start" docs/html/index.html + grep -q "Backend matrix" docs/html/index.html + grep -q "Performance and benchmarks" docs/html/index.html + grep -q "API reference and concepts" docs/html/index.html grep -R -q "MemoryLogger" docs/html grep -R -q "MdbxLogger" docs/html grep -R -q "PrometheusHttpServerLogger" docs/html grep -R -q "OtlpHttpLogger" docs/html ! grep -R -q "AGENTS.md" docs/html ! grep -R -q "NewYaroslav" docs/html + python3 - <<'PY' + from pathlib import Path + from urllib.parse import urlsplit + import re + + root = Path("docs/html") + missing = [] + for page in root.glob("*.html"): + text = page.read_text(encoding="utf-8", errors="ignore") + for href in re.findall(r'href="([^"]+)"', text): + parsed = urlsplit(href) + target = parsed.path + if not target or parsed.scheme or href.startswith("#"): + continue + target = target.split("#", 1)[0] + if target and not (page.parent / target).exists(): + missing.append(f"{page}: {href}") + if missing: + print("Broken local documentation links:") + print("\n".join(missing)) + raise SystemExit(1) + PY - name: Publish generated content to GitHub Pages uses: peaceiris/actions-gh-pages@v3 with: diff --git a/Doxyfile b/Doxyfile index 993e019..e122b67 100644 --- a/Doxyfile +++ b/Doxyfile @@ -952,6 +952,10 @@ WARN_LOGFILE = INPUT = ./include \ ./examples \ ./docs/mainpage.dox \ + ./docs/quickstart.md \ + ./docs/backends.md \ + ./docs/reference.dox \ + ./docs/benchmarks.md \ ./docs/groups.dox \ ./docs/OtlpHttpLogger.md \ ./docs/PrometheusLogger.md \ diff --git a/README-RU.md b/README-RU.md index 6488eb6..7e99958 100644 --- a/README-RU.md +++ b/README-RU.md @@ -49,7 +49,11 @@ scope-замер. Ниже приведены примеры макросов; также загляните в каталог `examples/` с отдельными сценариями, включая настройку очереди и обработку аварийного завершения. -Дополнительные руководства: +Дополнительные руководства и карта документации: + +- [`docs/quickstart.md`](docs/quickstart.md) — краткий старт и карта документации. +- [`docs/backends.md`](docs/backends.md) — матрица бэкендов, платформ, зависимостей и packaging. +- [`docs/benchmarks.md`](docs/benchmarks.md) — методика benchmark и исторический snapshot. - [`docs/OtlpHttpLogger.md`](docs/OtlpHttpLogger.md) — OTLP/HTTP, callback-экспорт, атрибуты, retries, разбиение payload и сжатие. - [`docs/PrometheusLogger.md`](docs/PrometheusLogger.md) — payload/server-бэкенды, registry, scrape и ограничения. @@ -910,41 +914,25 @@ LogIt++ включает библиотеку *fmt* для форматиров ## Бенчмарки +Каноническое руководство по бенчмаркам находится в +[`docs/benchmarks.md`](docs/benchmarks.md); там собраны методика, +интерпретация результатов, исторический снимок и заметки о `LatencyRecorder`. + Запустите `./build/bench/logit_bench`, чтобы получить полный набор измерений (sync/async × null/file × количество продюсеров × размер сообщений). Результаты дописываются в `bench/results/latency.csv` по одной строке на каждую библиотеку/комбинацию. При необходимости сократите нагрузку с помощью переменных окружения `LOGIT_BENCH_TOTAL` и `LOGIT_BENCH_WARMUP`. ### Что на самом деле измеряет бенчмарк -Харнесс меряет end-to-end латентность (*вызов лога → доставка в sink*) и суммарную пропускную. Он полезен для поиска регрессий и сравнения дизайна пайплайнов, но это **не** идеальное соревнование «кто быстрее». LogIt++ осознанно тратит больше работы в духе Python `icecream`: один `LOGIT_*` может парсить имена аргументов, собирать `args_array` из `VariableValue` и опционально форматировать структуру. Классические printf-логгеры вроде spdlog оптимизируются под быстрое форматирование строк и очереди, без этой «леденцовой» ветки. Для корректного сравнения держите оба лагеря в одном режиме: - -В этой методике LogIt++ проходит путь «record → formatter → sink/queue» с IceCream-подобными метаданными (имена/значения аргументов), а spdlog в адаптере получает уже готовую строку и измеряет «string → queue → sink». - -- *Только текст / passthrough* показывает стоимость dispatch/очереди/sink и ближе всего к поведению spdlog по умолчанию. -- *IceCream-стиль метаданных* (`LOGIT_*` с захватом аргументов) включает парсинг имён и упаковку значений; тут LogIt++ делает больше работы на вызов намеренно. - -Асинхронные цифры включают enqueue + пробуждение воркера/планирование ОС + работу sink; для file sink добавляется разброс из-за буферов/flush. Латентности в async сильно зависят от размера thread_pool/overflow policy и поведения sink; числа ниже отражают именно адаптер из этого репозитория, а не «spdlog в целом». - -### Последний снимок (05.12.2025) - -- Сборка: `Release`, `LOGIT_BENCH_ENABLE=ON`, `LOGIT_BENCH_WITH_SPDLOG=ON`, `LOGIT_USE_MPSC_RING=ON` (по умолчанию). -- Нагрузка: `LOGIT_BENCH_TOTAL=10000`, 4 продюсера, размер сообщений 200 байт для таблицы сравнения (остальные комбинации см. в `bench/results/latency-2025-12-05-10k.csv`). -- Метрики: медианная задержка (`p50`) в наносекундах и достигнутая пропускная способность (сообщений/с). -- Железо: 3 vCPU (Intel Xeon E5-2673 v4 @ 2.30GHz) в виртуальной машине, одна NUMA-нода. -- Данные: обновлено по `bench/results/latency-2025-12-05-10k.csv` (05.12.2025, 03:18 UTC). -- Таблица отражает только этот сценарий; полный набор — в CSV. +Полная методика, ограничения сравнения и правила интерпретации находятся в +[`docs/benchmarks.md`](docs/benchmarks.md). -| Режим | Приёмник | LogIt++ p50 | Пропускная (LogIt++) | spdlog p50 | Пропускная (spdlog) | -|-------|----------|-------------|----------------------|------------|---------------------| -| Sync | Null | 119 нс | 2 127 704 сооб./с | 86 нс | 5 803 783 сооб./с | -| Sync | File | 130 нс | 1 035 690 сооб./с | 87 нс | 1 593 987 сооб./с | -| Async | Null | 20 916 нс | 1 846 272 сооб./с | 1 248 779 нс | 1 303 573 сооб./с | -| Async | File | 255 323 нс | 651 384 сооб./с | 5 001 140 нс | 1 153 976 сооб./с | +### Последний снимок -**Выводы:** В синхронных режимах LogIt++ показывает p50 ~120–130 нс при IceCream-подобном пути метаданных; адаптер spdlog работает с готовой строкой, поэтому на Null/File быстрее в этой методике. В async обе стороны меряют enqueue + пробуждения + sink и чувствительны к конфигурации thread_pool/overflow/sink: здесь LogIt++ остаётся в десятках–сотнях микросекунд, а spdlog-адаптер уходит в миллисекунды и требует отдельной настройки/профиля для других конфигураций. При необходимости можно включить passthrough/fmt_only и отключить лишние метаданные. +Исторический снимок и полная таблица сравнения находятся в +[`docs/benchmarks.md`](docs/benchmarks.md). -### Как устроен бенч-харнесс (LatencyRecorder) +### Как устроен бенч-харнесс -- `bench/LatencyRecorder.hpp` заранее резервирует слоты и ведёт `Token {slot, t0_ns, active}` → `Summary {p50, p99, p999}` с защитой от повторных `complete()` на один слот. Доступны методы `recorded()`, `wait_for_all()` и `finalize()` для end-to-end измерений между продюсерами и консюмером. -- Адаптер LogIt кладёт номер слота в `LogRecord::line` (см. `bench/adapters/LogItAdapter.cpp`). Приёмник вызывает `LatencyRecorder::complete_slot()`, когда видит неотрицательный номер строки; никаких дополнительных полей в записи не требуется. +Детали `LatencyRecorder` собраны в [`docs/benchmarks.md`](docs/benchmarks.md). ## Матрица бэкендов diff --git a/README.md b/README.md index 99bdb82..3b9d47f 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,11 @@ Recent focused examples include: - `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 backend and executor guides: +Detailed guides and documentation map: + +- [`docs/quickstart.md`](docs/quickstart.md) — quick start and documentation map. +- [`docs/backends.md`](docs/backends.md) — backend, platform, dependency, and packaging matrix. +- [`docs/benchmarks.md`](docs/benchmarks.md) — benchmark methodology and historical snapshot. - [`docs/OtlpHttpLogger.md`](docs/OtlpHttpLogger.md) — OTLP/HTTP and callback exporters, structured attributes, retries, splitting, and compression. - [`docs/PrometheusLogger.md`](docs/PrometheusLogger.md) — payload/server backends, registry metrics, scrape configuration, and limitations. @@ -1135,6 +1139,10 @@ used. ## Benchmarks +The canonical benchmark guide is [docs/benchmarks.md](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: @@ -1149,50 +1157,17 @@ and `LOGIT_BENCH_WARMUP` environment variables if you need a lighter run. ### What this benchmark measures -The harness times end-to-end latency (*log call → delivery into the sink*) and aggregate throughput. It is great for spotting -regressions and comparing pipeline designs, but it is **not** a perfect “fastest logger wins” contest. LogIt++ intentionally does -extra work inspired by Python’s `icecream`: a single `LOGIT_*` call can extract argument names, build `args_array` with -`VariableValue`, and optionally format those structured values. Classic printf-style loggers such as spdlog focus on fast string -formatting and queueing instead of this metadata path. In this harness LogIt++ travels the “record → formatter → sink/queue” path -with IceCream-inspired metadata (argument names/values), while the spdlog adapter receives an already formatted string and measures “string → queue → sink.” -If you want an apples-to-apples view, keep the comparison within the same -mode: - -- *Text-only/passthrough* shows dispatch/queue/sink cost and is the closest to spdlog’s default path. -- *Metadata-heavy* (`LOGIT_*` with argument capture) includes parsing and packing the structured arguments; LogIt++ will do more - work per call here by design. - -Async numbers also include enqueue + worker wakeup/scheduling + sink time; file sinks add I/O variance from buffering and flush -policies. Async latencies depend heavily on thread pool size/overflow policy and sink behavior; the values below reflect the -adapter in this repository rather than spdlog at large. - -### Latest snapshot (Dec 05, 2025) - -- Build: `Release`, `LOGIT_BENCH_ENABLE=ON`, `LOGIT_BENCH_WITH_SPDLOG=ON`, `LOGIT_USE_MPSC_RING=ON` (default). -- Workload: `LOGIT_BENCH_TOTAL=10000`, 4 producers, message size 200 bytes for the comparison table (all other sizes/counts - are in `bench/results/latency-2025-12-05-10k.csv`). -- Metrics: median (`p50`) latency in nanoseconds and achieved throughput (messages/sec). -- Hardware: 3 vCPU VM (Intel Xeon E5-2673 v4 @ 2.30GHz), single NUMA node. -- Data: refreshed from `bench/results/latency-2025-12-05-10k.csv` (Dec 05, 2025 @ 03:18 UTC). -- The table captures that single scenario; see the CSV for the full matrix. - -| Mode | Sink | LogIt++ p50 | LogIt++ throughput | spdlog p50 | spdlog throughput | -|------|------|-------------|--------------------|------------|-------------------| -| Sync | Null | 119 ns | 2,127,704 msg/s | 86 ns | 5,803,783 msg/s | -| Sync | File | 130 ns | 1,035,690 msg/s | 87 ns | 1,593,987 msg/s | -| Async | Null | 20,916 ns | 1,846,272 msg/s | 1,248,779 ns | 1,303,573 msg/s | -| Async | File | 255,323 ns | 651,384 msg/s | 5,001,140 ns | 1,153,976 msg/s | - -**Takeaways:** In synchronous modes LogIt++ shows p50 ~120–130 ns while carrying the IceCream-inspired metadata path; the spdlog adapter receives preformatted strings, so it remains faster on the null/file sinks in this scenario. Asynchronously, both sides measure enqueue + worker wakeups + sink work and are sensitive to thread-pool/overflow/sink configuration; here LogIt++ stays in the tens-to-hundreds of microseconds, while the spdlog adapter lands in low-to-mid milliseconds and would need tuning/profiling for other setups. Passthrough/fmt-only modes remain available if you want to trim the metadata cost. - -### Benchmark harness notes (LatencyRecorder) - -- `bench/LatencyRecorder.hpp` preallocates slots and tracks `Token {slot, t0_ns, active}` → `Summary {p50, p99, p999}` with per- -slot deduplication (duplicate `complete()` calls are ignored). It exposes `recorded()`, `wait_for_all()`, and `finalize()` for -end-to-end timing across producers/consumers. -- The LogIt adapter stores the benchmark slot in `LogRecord::line` (see `bench/adapters/LogItAdapter.cpp`). Sinks call - `LatencyRecorder::complete_slot()` when they observe a non-negative line number, so no extra payload is needed inside the log - record. +See the canonical [benchmark guide](docs/benchmarks.md) for the measurement +model, comparison caveats, and interpretation rules. + +### Latest snapshot + +The historical snapshot and full comparison table are maintained in the +[benchmark guide](docs/benchmarks.md). + +### Benchmark harness notes + +See the [benchmark guide](docs/benchmarks.md) for `LatencyRecorder` details. --- diff --git a/docs/backends.md b/docs/backends.md new file mode 100644 index 0000000..5cfadf6 --- /dev/null +++ b/docs/backends.md @@ -0,0 +1,43 @@ +\page backends Backend matrix + +# Backend matrix + +Choose a backend by delivery model, platform, and dependency requirements. +Every backend implements `ILogger`; stored-log backends may additionally +implement `ILogReader` and `ILogSubscriber`. + +| Backend | Enablement | Standard | Extra dependency | Platform and packaging notes | +|---|---|---:|---|---| +| Console, file, unique file, memory, crash | built in | C++11 | TimeShield | Native and documented Emscripten stubs | +| `WindowsDebugLogger` | built in | C++11 | Windows API | `OutputDebugStringW` on Windows; stderr fallback elsewhere | +| `SyslogLogger` | `LOGIT_WITH_SYSLOG=ON` | C++11 | POSIX syslog | Unix-like platforms | +| `EventLogLogger` | `LOGIT_WITH_WIN_EVENT_LOG=ON` | C++11 | Windows SDK | Windows only | +| `OtlpHttpLogger` | `LOGIT_WITH_OTLP=ON` | C++17 | kurlyk | Outbound OTLP/HTTP; installed exports need external kurlyk | +| `OtlpPayloadLogger` | `LOGIT_WITH_OTLP=ON` | C++17 | None for callback | JSON payload callback; application owns transport | +| `PrometheusPayloadLogger` | `LOGIT_WITH_PROMETHEUS=ON` | C++11 | None | Text payload callback; no HTTP client | +| `PrometheusHttpServerLogger` | `LOGIT_WITH_PROMETHEUS_SERVER=ON` | C++17 | Simple-Web-Server/Asio | Build-tree only; install currently rejected | +| `MdbxLogger` | `LOGIT_WITH_MDBX=ON` | C++17 | mdbx-containers | Not supported on Emscripten or MSVC | + +## Delivery models + +General-purpose native backends use the shared asynchronous `TaskExecutor` by +default. A backend configured with `use_dedicated_executor=true` owns a +per-backend `SingleThreadExecutor`. Crash and callback payload backends are +synchronous unless their own configuration says otherwise; OTLP HTTP and +payload exporters own their queues and workers. Emscripten builds without +pthreads use cooperative queues instead of OS worker threads. + +## Packaging + +The source/build-tree configuration supports all feature combinations subject +to their platform restrictions. Installed CMake exports require optional +dependencies to be provided as installed/imported targets. Bundled optional +dependencies and `LOGIT_WITH_PROMETHEUS_SERVER=ON` are intentionally rejected +by `cmake --install` until their dependency trees can be exported reliably. + +See the feature-specific guides for details: + +- [`OTLP exporters`](otlp_http_logger.html) +- [`Prometheus`](prometheus_logger.html) +- [`TaskExecutor`](task_executor.html) +- [`Queue back-pressure`](backpressure.html) diff --git a/docs/benchmarks.md b/docs/benchmarks.md new file mode 100644 index 0000000..8c44151 --- /dev/null +++ b/docs/benchmarks.md @@ -0,0 +1,54 @@ +\page benchmarks Performance and benchmarks + +# Performance and benchmarks + +The benchmark harness lives under `bench/` and is disabled by default. Enable +it with `LOGIT_BENCH_ENABLE=ON`; add `LOGIT_BENCH_WITH_SPDLOG=ON` for the +optional spdlog comparison binaries. + +```bash +cmake -S . -B build -DLOGIT_BENCH_ENABLE=ON +cmake --build build --target logit_bench +./build/bench/logit_bench +``` + +The harness records end-to-end latency from the logging call until delivery to +the sink, together with aggregate throughput. It compares synchronous and +asynchronous modes, null and file sinks, producer counts, and message sizes. +Results are appended to `bench/results/latency.csv`; workload size can be +reduced with `LOGIT_BENCH_TOTAL` and `LOGIT_BENCH_WARMUP`. + +## Interpreting results + +The benchmark measures the complete path, not just formatter throughput. A +LogIt++ call may parse argument names, build `args_array`, and optionally +format values, while another logger may receive an already formatted string. +Compare implementations within the same mode and configuration; these numbers +are not a universal speed ranking. + +The asynchronous measurement includes enqueue, worker wake-up/scheduling, and +sink time. Results are sensitive to queue capacity, overflow policy, worker +count, filesystem cache state, compiler, operating system, and hardware. + +## Historical snapshot + +The repository includes a comparison snapshot from 2025-12-05 in +`bench/results/latency-2025-12-05-10k.csv`: + +- workload: `LOGIT_BENCH_TOTAL=10000`, four producers, 200-byte messages; +- metrics: median (`p50`) latency in nanoseconds and throughput in messages per + second; +- timestamp: 2025-12-05 03:18 UTC. + +This is a historical, reproducible fixture rather than a current performance +claim. Re-run the harness on the target hardware before making deployment or +library-selection decisions. + +## Harness details + +`bench/LatencyRecorder.hpp` preallocates slots and tracks +`Token {slot, t0_ns, active}` and `Summary {p50, p99, p999}`. It exposes +`recorded()`, `wait_for_all()`, and `finalize()` for end-to-end timing across +producers and consumers. The LogIt adapter stores the benchmark slot in +`LogRecord::line`; sinks call `LatencyRecorder::complete_slot()` when they +observe a non-negative line number. diff --git a/docs/mainpage.dox b/docs/mainpage.dox index cbfeff2..5543a98 100644 --- a/docs/mainpage.dox +++ b/docs/mainpage.dox @@ -5,1090 +5,45 @@ Version: VERSION_PLACEHOLDER \section overview_sec 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_`, `LOGIT_PRINTF_`, `LOGIT_STREAM_`, etc.) cover immediate messages, `printf`-style formatting, streaming, throttling, and tagging. Defining `LOGIT_SHORT_NAME` when including `` 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. - -See the macro examples below or browse the `examples/` directory for focused demonstrations, including queue tuning and crash handling. `examples/example_logit_memory_logger.cpp` and `examples/example_logit_mdbx_logger.cpp` show the shared read/callback API for in-memory and MDBX-backed stored logs. - -The `logit::detail` namespace is implementation-only and carries no source or -API compatibility guarantee. It is shown in the reference for maintainers; -application code should use the public umbrella headers and macros. - -\section macro_first_usage_sec Macro-first usage - -For normal application logging, prefer the public macros from `` or -``. Choose the matching family -(`LOGIT_`, `LOGIT_PRINTF_`, `LOGIT_STREAM_`, -`LOGIT__IF`, `LOGIT__TO`, `LOGIT_SCOPE_`, and related -helpers) and pass the data directly to that macro. - -Avoid manually constructing `logit::LogRecord`, filling `args_array`, or -calling `logit::Logger::get_instance()` just to emit an ordinary log message. -Those low-level entry points are intended for extension work such as custom -`ILogger` / `ILogFormatter` implementations, backend registration, tests, -benchmarks, adapters, or internal maintenance. - -\section backpressure_sec Backpressure and queue variants - -The asynchronous `TaskExecutor` supports both a mutex-protected deque and an optional lock-free MPSC ring (enable via `LOGIT_USE_MPSC_RING`). Overflow policies (`Block`, `DropNewest`, `DropOldest`) behave the same in both variants, with the MPSC build intentionally dropping the **incoming** task for `DropOldest` to preserve the ordering of accepted work. The ring uses `LOGIT_TASK_EXECUTOR_DEFAULT_RING_CAPACITY` entries (1024 by default); adjust the baseline with that macro alongside `LOGIT_SET_MAX_QUEUE(...)` if your workload needs a different buffer size. MPSC builds also allow "hot" resizes where producers briefly wait while the worker rebuilds the ring without losing in-flight tasks. - -\section macro_examples_sec Macro Examples - -\subsection macro_examples_long Long-form macros +LogIt++ is a header-only, macro-first C++ logging library. The core and most +native backends support C++11; OTLP, the Prometheus HTTP server, and MDBX use +C++17 through their CMake feature options. \code{.cpp} #include 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(); -} -\endcode - -\subsection macro_examples_short Short aliases - -Define `LOGIT_SHORT_NAME` before including `` to enable single-letter level prefixes: - -\code{.cpp} -#define LOGIT_SHORT_NAME -#include - -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; -} -\endcode - -For a standalone program that brings everything together and intentionally aborts after logging a fatal message, check `examples/example_logit_minimal_crash.cpp`. - -\subsection macro_examples_context Diagnostic context (MDC/NDC) - -Enable `LOGIT_WITH_CONTEXT` to keep mapped key/value context and a nested -diagnostic context stack in thread-local storage. Use `%K`, `%K{key}`, and `%J` -pattern tokens to render the values. - -\code{.cpp} -#include - -void handle_request() { - LOGIT_MDC_PUT("request_id", "req-42"); - { - LOGIT_NDC_GUARD("checkout"); - LOGIT_INFO("processing order"); - } - LOGIT_MDC_CLEAR(); -} -\endcode - -\subsection macro_examples_optional Optional backends - -The `MemoryLogger`, `MdbxLogger`, OTLP, and Prometheus backends are demonstrated -in the corresponding files under `examples/`. OTLP requires -`LOGIT_WITH_OTLP=ON`, Prometheus payload/server requires -`LOGIT_WITH_PROMETHEUS=ON` or `LOGIT_WITH_PROMETHEUS_SERVER=ON`, and MDBX -requires `LOGIT_WITH_MDBX=ON`. See `\ref otlp_http_logger` and -`\ref prometheus_logger` for backend-specific configuration and limitations. - -\subsection macro_examples_targeted Targeted, conditional, and scope helpers - -Beyond the base logging calls, LogIt++ exposes canonical helper families for -addressing a specific backend, applying conditions, and measuring scope -duration. - -\code{.cpp} -#include - -void process_request(bool verbose, double latency_ms) { - LOGIT_ADD_CONSOLE_DEFAULT(); - LOGIT_ADD_UNIQUE_FILE_LOGGER_DEFAULT_SINGLE_MODE(); - - LOGIT_INFO_TO(1, "Only logger index 1 receives this message"); - LOGIT_PRINTF_INFO_IF(verbose, "Latency %.2f ms", latency_ms); - - LOGIT_SCOPE_INFO("process_request"); - LOGIT_SCOPE_PRINTF_WARN_T(50, "slow path latency=%.2f ms", latency_ms); - + LOGIT_INFO("service started", 42); LOGIT_WAIT(); } \endcode -\subsection macro_examples_memory In-memory snapshot logger - -For remote control surfaces, diagnostics endpoints, or embedded operator tools, -LogIt++ can register a dedicated in-memory backend and expose the latest logs as -either formatted strings or structured entries. - -\code{.cpp} -#include - -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; -} -\endcode - -`MemoryLogger` snapshots are returned oldest-to-newest. The `max_bytes` -retention budget counts buffered formatted-message payload bytes rather than the -full object footprint of each `BufferedLogEntry`. Snapshot reads avoid the -`Logger` execution mutex, but they still synchronize on the memory backend's -own mutex while copying the current buffer. - -\subsection macro_examples_shared_reader 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: - -\code{.cpp} -#include - -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 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; -} -\endcode - -`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 return only what has -already reached disk; they do not drain async queues, and compressed rotated -files are listed as metadata-only artifacts in v1. Use `MemoryLogger` for -near-real-time snapshots and the file APIs for operational reads of persisted -daily logs. - -\section features_sec Features - -LogIt++ provides a robust and flexible set of features to accommodate various logging needs. - -\subsection flexible_formatting Flexible Log Formatting - -Customize log message formats using patterns. You can redefine patterns via macros or provide them directly when adding a logger backend. Both standard format flags (e.g., `%H`, `%M`, `%S`, `%v`) and special ones, like `%N([...])` for fallback logs without arguments, are supported. - -\code{.cpp} -#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 -\endcode - -\subsection macro_logging Logging with Macros - -Log variables and messages easily using macros. Simply select the appropriate macro and pass variables or arguments. Use `LOGIT_PRINTF_` for `printf`-style formatting and `LOGIT_FORMAT_` to apply the same format to every argument. - -\code{.cpp} -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 -\endcode - -Canonical public macro families also include: - -- Targeted families such as `LOGIT__TO`, `LOGIT_PRINTF__TO`, `LOGIT_FMT__TO`, and `LOGIT_STREAM__TO`. -- Conditional families such as `LOGIT__IF`, `LOGIT_PRINTF__IF`, `LOGIT_FORMAT__IF`, and `LOGIT_FMT__IF`. -- Scope-duration families such as `LOGIT_SCOPE_`, `LOGIT_SCOPE_PRINTF_`, and `LOGIT_SCOPE_FMT_`, including their `_T` threshold variants. -- System-error helpers `LOGIT_PERROR_`, `LOGIT_WINERR_`, and `LOGIT_SYSERR_`. -- Backend registration helpers such as `LOGIT_ADD_LOGGER(...)` and the built-in `LOGIT_ADD_*` backend macros. -- Management and query helpers such as `LOGIT_GET_*`, `LOGIT_SET_*`, `LOGIT_IS_*`, `LOGIT_GET_LOG_LEVEL(index)`, `LOGIT_LIST_LOG_FILES(index)`, `LOGIT_READ_LOG_FILE(index, path)`, `LOGIT_READ_LOG_FILES(index, paths)`, `LOGIT_WAIT()`, `LOGIT_SHUTDOWN()`, `LOGIT_GET_DROPPED_TASKS()`, and `LOGIT_RESET_DROPPED_TASKS()`. -- Snapshot helpers such as `LOGIT_GET_BUFFERED_STRINGS(index)` and `LOGIT_GET_BUFFERED_ENTRIES(index)` for backends that keep recent history. - -Pattern-consistent aliases exist for short-name and compatibility paths, but the -families above are the canonical public surface to document and prefer in -examples. - -\subsection multiple_backends Support for Multiple Backends - -Easily configure loggers for output to the console, files, or system logging facilities. Optionally, add support for sending messages to servers or databases by creating custom backends. - -\code{.cpp} -// Adding several backends: console, file, unique file and system loggers -LOGIT_ADD_CONSOLE_DEFAULT(); -LOGIT_ADD_FILE_LOGGER_DEFAULT(); -LOGIT_ADD_UNIQUE_FILE_LOGGER_DEFAULT_SINGLE_MODE(); -LOGIT_ADD_SYSLOG_DEFAULT(); -LOGIT_ADD_EVENT_LOG_DEFAULT(); -\endcode - -\subsection async_logging Asynchronous Logging - -Most general-purpose native backends handle messages asynchronously by -default. Crash and payload callback backends are synchronous, OTLP maintains -its own exporter queue, and dedicated executors create one worker per selected -backend. Emscripten builds without pthreads drain cooperatively without OS -worker threads. - -\subsection buffer_modes Queue Buffer Modes - -Control how the asynchronous queue behaves when full by setting a queue policy. -\code{.cpp} -LOGIT_SET_MAX_QUEUE(64); -LOGIT_SET_QUEUE_POLICY(LOGIT_QUEUE_BLOCK); // Block when full -\endcode -Available policies: `LOGIT_QUEUE_DROP_NEWEST`, `LOGIT_QUEUE_DROP_OLDEST`, `LOGIT_QUEUE_BLOCK`. - -Backend `Config` structs can set `use_dedicated_executor=true` to isolate a slow -async sink from the global task executor. Native builds create one worker thread -per configured logger; single-threaded Emscripten builds use a cooperative -per-instance queue instead. - -\code{.cpp} -logit::ConsoleLogger::Config cfg; -cfg.async = true; -cfg.use_dedicated_executor = true; -cfg.queue_capacity = 1024; -cfg.queue_policy = logit::detail::QueuePolicy::Block; - -LOGIT_ADD_LOGGER( - logit::ConsoleLogger, - (cfg), - logit::SimpleLogFormatter, - (LOGIT_CONSOLE_PATTERN) -); - -LOGIT_ADD_CONSOLE_CONFIG(cfg, LOGIT_CONSOLE_PATTERN); -LOGIT_ADD_CONSOLE_DEDICATED( - LOGIT_CONSOLE_PATTERN, - 1024, - logit::detail::QueuePolicy::DropNewest -); -\endcode - -\subsection stream_logging Stream-Based Logging - -Use stream operators for complex messages. - -\code{.cpp} -LOGIT_STREAM_INFO() << "Stream-based info logging with short macro. Integer value: " << 123; -\endcode - -\subsection compile_level Compile-Time Log Level - -Exclude lower-severity logs from the final binary by defining the minimum -severity compiled into the program. Set the `LOGIT_COMPILED_LEVEL` macro during -compilation: - -\code{.bash} -g++ -DLOGIT_COMPILED_LEVEL=LOGIT_LEVEL_WARN ... -\endcode - -With this configuration, `TRACE`, `DEBUG`, and `INFO` macros are disabled at compile time. - -Runtime filtering via `LOGIT_SET_LOG_LEVEL(...)` and -`LOGIT_SET_LOG_LEVEL_TO(...)` still works for compiled-in severities, but it -cannot re-enable macros removed earlier by `LOGIT_COMPILED_LEVEL`. - -\subsection extensibility Extensibility - -Create custom loggers and formatters to meet your specific requirements. -See the complete implementation in `\ref custom_backend_sec` below; it matches -the current `ILogger` and `ILogFormatter` interfaces. - -\section usage_sec Usage - -Here's a simple example demonstrating how to use LogIt++ in your application: - -\code{.cpp} -#define LOGIT_SHORT_NAME -#include - -int main() { - // Initialize the logger with default console output - LOGIT_ADD_CONSOLE_DEFAULT(); - - float a = 123.456f; - int b = 789; - const char* someStr = "Hello, World!"; - - // Basic logging using short macros - LOG_I("Starting the application"); - LOG_D(a, b); - LOG_W("This is a warning message"); - - // Formatted logging using short macros - LOG_IPF("Formatted log: value of a = %.2f", a); - LOG_WPF("Warning! Values: a = %.2f, b = %d", a, b); - - // Error and fatal logs using short macros - LOG_EP("An error occurred with value b =", b); - LOG_F("Fatal error. Terminating application."); - - // Conditional logging - LOGIT_INFO_IF(b < 0, "Value of b is negative"); - LOGIT_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 - LOG_TRACE0(); // Trace without arguments - LOG_T("Entering main function with variable", a); - - // Wait for all asynchronous logs to be processed - LOGIT_WAIT(); - - return 0; -} -\endcode - -\section log_formatting_sec Customizing Log Formats - -LogIt++ supports customizable log message formatting using patterns that define the appearance of each log message. -You can specify patterns either through macros or by providing them directly when adding logger backends. - -\subsection pattern_example Examples of Formatting Patterns - -### Example for Setting a Custom Console Logger Format - -You can define a custom format for the console logger as follows: - -\code{.cpp} -LOGIT_ADD_LOGGER( - logit::ConsoleLogger, (), - logit::SimpleLogFormatter, - ("%Y-%m-%d %H:%M:%S.%e [%l] %^%N(%g:%#)%v%$") -); -\endcode - -### Example Using Macros for Simplicity - -Alternatively, use macros to specify a pattern: - -\code{.cpp} -#define LOGIT_CONSOLE_PATTERN "%H:%M:%S.%e | %^%N([%!g:%#])%v%$" -LOGIT_ADD_CONSOLE_DEFAULT(); -\endcode - -In both cases, the logger will automatically replace placeholders in the pattern with corresponding data, such as: - -\code{.txt} -23:59:59.128 | path/to/file.cpp:123 A sample log message -\endcode - -\section format_flags_sec Log Message Formatting Flags - -`LogIt++` supports customizable log message formatting using format flags. You can define how each log message should appear by including placeholders for different pieces of information such as the timestamp, log level, file name, function name, and message. - -Below is a list of all supported format flags and their meanings: - -\subsection datetime_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 - -\subsection weekday_month_flags Weekday and Month Names -- `%%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) - -\subsection log_level_flags Log Level -- `%%l`: Full log level (e.g., INFO, ERROR) -- `%%L`: Short log level (e.g., I for INFO, E for ERROR) - -\subsection file_function_flags File and Function Information -- `%%f`, `%%fn`, `%%bs`: Base name of the source file (e.g., main.cpp) -- `%%g`, `%%ffn`: Full file path (e.g., /home/user/project/src/main.cpp) -- `%@`: Source file and line number (e.g., main.cpp:45) -- `%#`: Line number (e.g., 45) -- `%!`: Function name (e.g., main) - -\subsection thread_flags Thread Information -- `%%t`: Thread identifier - -\subsection color_flags Color Formatting -- `%^`: Start color formatting -- `%$`: End color formatting -- `%%SC`: Start removing color codes (Strip Color) -- `%%EC`: End removing color codes (End Color) - -\subsection message_flags Message Content -- `%%v`: The log message content -- `%%N(...)`: Fallback format for cases with no arguments. - - When used in a pattern (e.g., `%%N(%g:%#)`), the specified sub-pattern will be applied - if no arguments are provided in the log macro (e.g., `LOG_TRACE0()`). - -\subsection alignment_truncation_flags Alignment and Truncation - -- **Alignment**: - - Left: Use `-` before the width, e.g., `%-10v` (aligns text to the left). - - Center: Use `=` before the width, e.g., `%=10v` (centers text). - - Right (default): `%10v` (aligns text to the right). - -- **Truncation**: - - Use `!` after the width to truncate text if it exceeds the specified length, e.g., `%10!v`. - -**Examples**: -- `%10v`: Right-aligned message with a width of 10 characters. -- `%-10v`: Left-aligned message with a width of 10 characters. -- `%10!v`: Right-aligned, truncated to 10 characters. -- `%-10!v`: Left-aligned, truncated to 10 characters. - -\subsection advanced_path_handling 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` - -\section short_macros 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; replace the level letter or word in the macro name. - -\code{.cpp} -LOG_T("Trace message using short macro"); -LOG_FT("%.4d", 999); -LOG_PRINT_T("Printing trace message with multiple variables: ", var1, var2); -LOG_TRACE("Trace message (alias for LOG_T)"); -LOG_PRINTF_TRACE("Formatted trace: value = %d", value); -\endcode - -\section config_macros 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. - -\code{.cpp} -// Defines the base path for project folder. -#define LOGIT_BASE_PATH "/path/to/your/project" -\endcode - -- **LOGIT_DEFAULT_COLOR**: - -Sets the default color for console output. If `LOGIT_DEFAULT_COLOR` is not defined, it defaults to `TextColor::LightGray`. - -\code{.cpp} -// Sets the default log message color to green. -#define LOGIT_DEFAULT_COLOR TextColor::Green -\endcode - -- **LOGIT_COLOR_**: - -Defines the console text color for each log level. By default, each log level is associated with a specific color, but these can be customized. - -Available log levels: - - **TRACE**: Defaults to `TextColor::DarkGray` - - **DEBUG**: Defaults to `TextColor::Blue` - - **INFO**: Defaults to `TextColor::Green` - - **WARN**: Defaults to `TextColor::Yellow` - - **ERROR**: Defaults to `TextColor::Red` - - **FATAL**: Defaults to `TextColor::Magenta` - -\code{.cpp} -// Customize the color for different log levels -#define LOGIT_COLOR_TRACE TextColor::Blue -#define LOGIT_COLOR_ERROR TextColor::Cyan -\endcode - -- **LOGIT_COLOR_DEFAULT**: - -Defines the fallback console color used when a message does not map to a -severity-specific override. - -\code{.cpp} -#define LOGIT_COLOR_DEFAULT TextColor::White -\endcode - -- **LOGIT_WALLCLOCK_MS** / **LOGIT_MONOTONIC_MS**: - -Override the wall-clock or monotonic timestamp helpers used internally by the -library. This is useful when integrating platform-specific clock sources. - -\code{.cpp} -#define LOGIT_WALLCLOCK_MS() my_wallclock_ms() -#define LOGIT_MONOTONIC_MS() my_monotonic_ms() -\endcode - -- **LOGIT_CURRENT_TIMESTAMP_MS**: - -Macro to get the current timestamp in milliseconds. By default, it uses `std::chrono` for time calculation. You can override this to customize the timestamp generation. - -\code{.cpp} -// Customize timestamp calculation if needed. -#define LOGIT_CURRENT_TIMESTAMP_MS() my_custom_timestamp_function() -\endcode - -- **LOGIT_CONSOLE_PATTERN**: -Defines the default log pattern for the console logger. If `LOGIT_CONSOLE_PATTERN` is not defined, it defaults to `%%H:%%M:%%S.%%e | %^%N([%50!g:%#])%%v%$`. - -\code{.cpp} -// Customize the console log message pattern. -#define LOGIT_CONSOLE_PATTERN "%H:%M:%S.%e | %v" -\endcode - -- **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". - -\code{.cpp} -// Specify a custom path for log files. -#define LOGIT_FILE_LOGGER_PATH "/custom/log/directory" -\endcode - -- **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. - -\code{.cpp} -// Set the number of days to keep log files. -#define LOGIT_FILE_LOGGER_AUTO_DELETE_DAYS 60 -\endcode - -- **LOGIT_FILE_LOGGER_PATTERN**: - -Defines the default log pattern for file-based loggers. If `LOGIT_FILE_LOGGER_PATTERN` is not defined, it defaults to `[%%Y-%%m-%%d %%H:%%M:%%S.%%e] [%-5l] [%60!@] [thread:%%t] %%SC%%v`. - -\code{.cpp} -// Customize the log file message pattern. -#define LOGIT_FILE_LOGGER_PATTERN "[%Y-%m-%d %H:%M:%S.%e] [%l] %v" -\endcode - -- **LOGIT_FILE_LOGGER_MAX_FILE_SIZE_BYTES**: - -Defines the optional size threshold for rotating file loggers. Set it to a -non-zero value to enable size-based rotation. - -\code{.cpp} -#define LOGIT_FILE_LOGGER_MAX_FILE_SIZE_BYTES (10 * 1024 * 1024) -\endcode - -- **LOGIT_FILE_LOGGER_MAX_ROTATED_FILES**: - -Defines how many rotated files are retained when size-based rotation is active. - -\code{.cpp} -#define LOGIT_FILE_LOGGER_MAX_ROTATED_FILES 5 -\endcode - -- **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". - -\code{.cpp} -// Specify a custom path for unique log files. -#define LOGIT_UNIQUE_FILE_LOGGER_PATH "/custom/unique/log/directory" -\endcode - -- **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`. - -\code{.cpp} -// Customize the unique file log message pattern. -#define LOGIT_UNIQUE_FILE_LOGGER_PATTERN "[%Y-%m-%d %H:%M:%S.%e] [%l] %v" -\endcode - -- **LOGIT_UNIQUE_FILE_LOGGER_HASH_LENGTH**: - -Defines the length of the hash used in the unique log file names. If `LOGIT_UNIQUE_FILE_LOGGER_HASH_LENGTH` is not defined, it defaults to `8` characters. - -This macro controls the length of the hash part in the filenames for unique log files, ensuring unique names for each log. - -\code{.cpp} -// Set the hash length to 12 characters for unique file names. -#define LOGIT_UNIQUE_FILE_LOGGER_HASH_LENGTH 12 -\endcode - -- **LOGIT_OS_ERROR_JOIN**, **LOGIT_POSIX_ERROR_PATTERN**, - **LOGIT_WINDOWS_ERROR_PATTERN**, **LOGIT_SYSTEM_ERROR_PATTERN**: - -Control how decoded `errno` / `GetLastError()` information is appended by the -system-error macro families (`LOGIT_PERROR_*`, `LOGIT_WINERR_*`, -`LOGIT_SYSERR_*`). - -\code{.cpp} -#define LOGIT_OS_ERROR_JOIN " <- " -#define LOGIT_SYSTEM_ERROR_PATTERN "%s <- code=%d (%s)" -\endcode - -- **LOGIT_TAGS_JOIN**, **LOGIT_TAG_PAIR_SEP**, **LOGIT_TAG_KV_SEP**, - **LOGIT_TAG_QUOTE_VALUES**: - -Customize how key-value tags are rendered after the main message. - -\code{.cpp} -#define LOGIT_TAGS_JOIN " || " -#define LOGIT_TAG_PAIR_SEP "; " -#define LOGIT_TAG_KV_SEP ":" -#define LOGIT_TAG_QUOTE_VALUES 0 -\endcode - -- **LOGIT_TASK_EXECUTOR_BLOCK_WAIT_USEC**: - -Controls how frequently blocking producers poll for capacity while -`LOGIT_QUEUE_BLOCK` is active. - -\code{.cpp} -#define LOGIT_TASK_EXECUTOR_BLOCK_WAIT_USEC 200 -\endcode - -- **LOGIT_TASK_EXECUTOR_DRAIN_BUDGET**: - -Defines how many queued tasks a worker drains per iteration in ring-buffer -builds before yielding. - -\code{.cpp} -#define LOGIT_TASK_EXECUTOR_DRAIN_BUDGET 2048 -\endcode - -- **LOGIT_TASK_EXECUTOR_DEFAULT_RING_CAPACITY**: - -Defines the default MPSC ring capacity used when unlimited queue mode still -needs a backing ring size. - -\code{.cpp} -#define LOGIT_TASK_EXECUTOR_DEFAULT_RING_CAPACITY 1024 -\endcode - -- **LOGIT_SHORT_NAME**: - -Enables short names for logging macros, such as `LOG_T`, `LOG_D`, `LOG_E`, etc., for concise logging. - -\code{.cpp} -// Enable short macro names for logging. -#define LOGIT_SHORT_NAME -\endcode - -\section custom_backend_sec Custom Logger Backend and Formatter - -LogIt++ allows you to extend the logging system by creating your own loggers and formatters. This section explains how to implement a custom backend for logging and a custom log formatter. - -Normal application code should continue to use the public `LOGIT_*` / `LOG_*` -macros for emitting messages. The low-level APIs in this section are for -extension points only: custom backends, custom formatters, tests, adapters, and -other infrastructure code that intentionally works below the macro layer. - -\subsection custom_logger Custom Logger Example - -To create a custom logger backend, implement all pure virtual methods of the -`ILogger` interface (`log()`, parameter accessors, log-level accessors, and -`wait()`). The complete example below logs messages to a text file and matches -the current interface: - -\code{.cpp} -#include -#include -#include - -class FileLogger : public logit::ILogger { -public: - // Constructor to initialize the file logger with a file name - 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(); - } - } - - // Logs the message to the file - void log(const logit::LogRecord& record, const std::string& message) override { - std::lock_guard lock(m_mutex); - if (m_log_file.is_open()) { - m_log_file << message << std::endl; - } - } - - // Waits for any asynchronous log operations (none in this case) - void wait() override { - // No async processing, so no need to implement - } - - 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; ///< The name of the log file - std::ofstream m_log_file; ///< The file stream for logging - std::mutex m_mutex; ///< Mutex to ensure thread-safe logging - logit::LogLevel m_log_level = logit::LogLevel::LOG_LVL_TRACE; -}; -\endcode - -This `FileLogger` class writes log messages to a specified file. You can add this logger to your logging system like this: - -\code{.cpp} -LOGIT_ADD_LOGGER( - FileLogger, ("logfile.txt"), - logit::SimpleLogFormatter, ()); - -// or, if you intentionally need the lower-level equivalent... - -logit::Logger::get_instance().add_logger( - std::unique_ptr(new FileLogger("logfile.txt")), - std::unique_ptr(new logit::SimpleLogFormatter())); -\endcode - -Prefer `LOGIT_ADD_LOGGER(...)` when it fits your use case; calling -`logit::Logger::get_instance().add_logger(...)` directly is mainly useful when -an extension scenario cannot be expressed through the registration macro. - -\subsection custom_formatter Custom Formatter Example - -In addition to creating custom loggers, you can also create custom formatters by implementing the `ILogFormatter` interface. Here's an example of a simple formatter that outputs log messages in JSON format: - -\code{.cpp} -#include -#include // Or your preferred JSON library - -class JsonLogFormatter : public logit::ILogFormatter { -public: - void set_timestamp_offset(int64_t offset_ms) override { - (void)offset_ms; - } - - // Formats the log record into a JSON string - std::string format(const logit::LogRecord& record) const override { - Json::Value log_entry; - log_entry["level"] = static_cast(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["message"] = record.format; - - Json::StreamWriterBuilder writer; - return Json::writeString(writer, log_entry); - } -}; -\endcode - -This `JsonLogFormatter` formats log messages as JSON objects. You can combine it with any logger, including the `FileLogger`, as shown below: - -\code{.cpp} -LOGIT_ADD_LOGGER( - FileLogger, ("logfile.json"), - JsonLogFormatter, ()); - -// or, if you intentionally need the lower-level equivalent... - -logit::Logger::get_instance().add_logger( - std::unique_ptr(new FileLogger("logfile.json")), - std::unique_ptr(new JsonLogFormatter())); -\endcode - -\subsection summary_custom_backend Summary - -By implementing your own `ILogger` and `ILogFormatter`, you can extend the functionality of LogIt++ to log messages to various destinations or in different formats. You can combine custom loggers and formatters to create powerful logging solutions tailored to your application's needs. - -Here's a quick summary: - -- **ILogger**: Defines where the logs should be sent (e.g., file, console, database, network). -- **ILogFormatter**: Defines how the logs should be formatted (e.g., plain text, JSON, XML). -- **Registering custom backends**: Prefer `LOGIT_ADD_LOGGER(...)` for the common extension path; `logit::Logger::get_instance().add_logger()` is the lower-level equivalent when you need direct control. - -\section install_sec Installation - -LogIt++ itself is header-only. When consumed through the CMake target, -enabled optional features may add transitive compile and link dependencies. -Below are the steps to integrate it into your project. - -\subsection step1 Step 1: Clone the Repository - -First, clone the LogIt++ repository from GitHub along with its submodules. The -required dependency is **time-shield-cpp** (for time utilities); optional -features may also use **fmt**, **zlib**, **zstd**, **kurlyk**, or -**mdbx-containers**. - -To clone the repository with submodules, use the following command: - -\code{bash} -git clone --recurse-submodules https://github.com/LimiNode/log-it-cpp.git -\endcode - -If you have already cloned the repository without submodules, you can initialize and update the submodules by running the following commands: - -\code{bash} -git submodule init -git submodule update -\endcode - -\subsection step2 Step 2: Include the LogIt++ Headers in Your Project - -Since LogIt++ is a header-only library, you can simply include the main header in your project: - -\code{cpp} -#include -\endcode - -This will give you access to the entire logging system. - -\subsection step3 Step 3: 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 -those dependencies to be provided as installed/imported targets. - -\subsection step4 Step 4: Using fmt (Optional) - -LogIt++ ships with the **fmt** library for `{}`-style formatting. To use the `LOGIT_FMT_*` and `LOGIT_SCOPE_FMT_*` macros, build the library with the CMake option `-DLOGIT_WITH_FMT=ON`. - -\subsection cmake_options_sec CMake options - -All build-time toggles: - -- `LOGIT_CPP_BUILD_TESTS` (default: ON when this repository is the top-level project) — build the test suite. -- `LOGIT_CPP_BUILD_EXAMPLES` (default: OFF) — build the example programs. -- `LOGIT_BENCH_ENABLE` (default: OFF) — build the benchmarks; `LOGIT_BENCH_WITH_SPDLOG` (default: OFF) adds the spdlog comparison binaries. -- `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_USE_SUBMODULES` (default: OFF) allows bundled optional dependency fallbacks such as fmt, zlib, and zstd when system packages are missing. -- `LOGIT_WITH_CONTEXT` (default: OFF) — enable MDC/NDC helpers and context 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_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 on multi-threaded builds. -- `LOGIT_USE_MPSC_RING` (default: ON) — enable the lock-free task queue instead of the mutex-backed deque. -- `LOGIT_ENABLE_DROP_OLDEST_SLOWPATH` (default: ON) — include the drop-oldest slow-path used when the ring is full. -- `LOGIT_EMSCRIPTEN` (default: ON when building under Emscripten) — adjust the build for single-threaded WebAssembly targets. - -Detailed guides for the optional backends and queue internals are available as -separate pages: `\ref otlp_http_logger`, `\ref prometheus_logger`, -`\ref task_executor`, and `\ref backpressure`. - -\section bench_sec Benchmarks - -Run `./build/bench/logit_bench` to capture 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. Adjust the workload with `LOGIT_BENCH_TOTAL` and `LOGIT_BENCH_WARMUP` if you need a lighter pass. - -The harness tracks end-to-end latency (*log call → sink delivery*) and throughput. It is great for regression hunting and pipeline design comparisons, but it is **not** a perfect “which logger is fastest” race. LogIt++ intentionally mirrors Python `icecream`: a single `LOGIT_*` call may parse argument names, build `args_array` with `VariableValue`, and optionally format those values. Many printf-style loggers (e.g., spdlog) optimize for lightweight formatting and queueing instead of this metadata path. Compare implementations inside the same mode: - -In this harness LogIt++ travels the “record → formatter → sink/queue” path with IceCream-inspired metadata (argument names/values), while the spdlog adapter receives an already formatted string and measures “string → queue → sink.” - -- *Text-only/passthrough* emphasizes dispatch/queue/sink cost and is closest to the spdlog default path. -- *Metadata-heavy* (`LOGIT_*` with argument capture) measures parsing and packing of structured arguments; LogIt++ does more per-call work here by design. - -Async results include enqueue + worker wakeup/scheduling + sink time. File sinks add variability from buffering and flush policy. Async latencies depend heavily on thread pool sizing/overflow policy and sink behavior; the numbers below reflect the adapter in this repository rather than spdlog at large. - -\subsection bench_latest Latest snapshot (Dec 05, 2025) - -- Build: `Release`, `LOGIT_BENCH_ENABLE=ON`, `LOGIT_BENCH_WITH_SPDLOG=ON`, `LOGIT_USE_MPSC_RING=ON` (default). -- Workload: `LOGIT_BENCH_TOTAL=10000`, 4 producers, 200-byte messages for the comparison table (see `bench/results/latency-2025-12-05-10k.csv` for other sizes/counts). -- Metrics: median (`p50`) latency in nanoseconds and achieved throughput (messages/sec). -- Hardware: 3 vCPU VM (Intel Xeon E5-2673 v4 @ 2.30GHz), single NUMA node. -- Data: refreshed from `bench/results/latency-2025-12-05-10k.csv` (Dec 05, 2025 @ 03:18 UTC). -- The table reflects that single scenario; see the CSV for the full matrix. - -| Mode | Sink | LogIt++ p50 | LogIt++ throughput | spdlog p50 | spdlog throughput | -|------|------|-------------|--------------------|------------|-------------------| -| Sync | Null | 119 ns | 2,127,704 msg/s | 86 ns | 5,803,783 msg/s | -| Sync | File | 130 ns | 1,035,690 msg/s | 87 ns | 1,593,987 msg/s | -| Async | Null | 20,916 ns | 1,846,272 msg/s | 1,248,779 ns | 1,303,573 msg/s | -| Async | File | 255,323 ns | 651,384 msg/s | 5,001,140 ns | 1,153,976 msg/s | - -**Takeaways:** In synchronous modes LogIt++ shows p50 ~120–130 ns while carrying the IceCream-inspired metadata path; the spdlog adapter receives preformatted strings, so it remains faster on the null/file sinks in this scenario. Asynchronously, both sides measure enqueue + worker wakeups + sink work and are sensitive to thread-pool/overflow/sink configuration; here LogIt++ stays in the tens-to-hundreds of microseconds, while the spdlog adapter lands in low-to-mid milliseconds and would need tuning/profiling for other setups. Passthrough/fmt-only modes remain available if you want to trim the metadata cost. - -\subsection bench_harness Benchmark context (LatencyRecorder) - -- `bench/LatencyRecorder.hpp` preallocates slots and tracks `Token {slot, t0_ns, active}` → `Summary {p50, p99, p999}` with per-slot deduplication (duplicate `complete()` calls are ignored). It exposes `recorded()`, `wait_for_all()`, and `finalize()` for end-to-end timing across producers/consumers. -- The LogIt adapter stores the benchmark slot in `LogRecord::line` (see `bench/adapters/LogItAdapter.cpp`). Sinks call `LatencyRecorder::complete_slot()` when they observe a non-negative line number, so no extra payload is needed inside the log record. - -\subsection step5 Step 5: Build and Run Your Project - -After adding the necessary include paths, you can proceed to build and run your -project. For a vendored or installed CMake package, link the exported target: - -\code{.cmake} -find_package(log-it-cpp CONFIG REQUIRED) -target_link_libraries(my_app PRIVATE log-it-cpp::log-it-cpp) -\endcode +\section docs_map Documentation map -The repository can be installed with `cmake --install`; use separately -installed dependency targets for optional features. `LOGIT_WITH_PROMETHEUS_SERVER` -and bundled optional dependencies are intentionally rejected by the install -step until their exported dependency targets are available. +- \ref quickstart — quick start, installation paths, and public API boundary. +- \ref backends — backend, platform, dependency, and packaging matrix. +- \ref otlp_http_logger — OTLP HTTP and callback exporters. +- \ref prometheus_logger — Prometheus payload and HTTP server backends. +- \ref task_executor — shared executor, dedicated workers, and lifecycle. +- \ref backpressure — queue policies and drop counters. +- \ref benchmarks — benchmark methodology and historical snapshot. +- \ref api_reference — detailed macro, formatting, configuration, and extension reference. -\section repo_sec Repository +\section feature_summary Feature summary -The LogIt++ library is open-source and hosted on GitHub: -[LogIt++ GitHub Repository](https://github.com/LimiNode/log-it-cpp). +- Macro families cover direct, printf-style, stream, conditional, throttled, + tagged, and scope-timer logging. +- Console, file, unique-file, memory, crash, system, OTLP, Prometheus, and MDBX + backends are available behind their documented feature options. +- MDC/NDC context, structured records, stored-log readers/subscribers, queue + backpressure, and runtime log-level controls are supported. -\section license_sec License +Application code should include the public umbrella headers and use the +`LOGIT_*` macros. The `logit::detail` namespace and implementation headers are +internal and carry no source or API compatibility guarantee. -This library is licensed under the **MIT License**. See the [LICENSE](https://github.com/LimiNode/log-it-cpp/blob/main/LICENSE) file in the repository for more details. +See the source `examples/` directory for complete, buildable examples. The +full reference page is intentionally separate so this landing page remains a +concise entry point. */ diff --git a/docs/quickstart.md b/docs/quickstart.md new file mode 100644 index 0000000..1b0ae76 --- /dev/null +++ b/docs/quickstart.md @@ -0,0 +1,50 @@ +\page quickstart Quick start and documentation map + +# Quick start + +LogIt++ is a header-only, macro-first C++ logging library. The core and most +native backends support C++11. OTLP, the Prometheus HTTP server, and MDBX use +C++17 through their CMake feature options. + +## Minimal application + +```cpp +#include + +int main() { + LOGIT_ADD_CONSOLE_DEFAULT(); + LOGIT_INFO("service started", 42); + LOGIT_WAIT(); +} +``` + +For a vendored checkout, add the repository with `add_subdirectory()` and link +`log-it-cpp::log-it-cpp`. For an installed package, use +`find_package(log-it-cpp CONFIG REQUIRED)` and link the same target. Optional +features and their dependency requirements are described in the +[`Backend matrix`](backends.html). + +## Documentation map + +- **Installation and CMake** — see the installation section in the project + README and the generated CMake target reference. +- **Macros and formatting** — use the public `` entry point; the + macro and pattern references are available from the API index. +- **Backends** — [`Backend matrix`](backends.html), + [`OTLP exporters`](otlp_http_logger.html), and + [`Prometheus`](prometheus_logger.html). +- **Stored logs and context** — `MemoryLogger`, `MdbxLogger`, `ILogReader`, + `ILogSubscriber`, and MDC/NDC are documented in the generated class reference + and examples. +- **Asynchronous delivery** — [`TaskExecutor`](task_executor.html) and + [`Queue back-pressure`](backpressure.html). +- **Performance** — [`Benchmarks`](benchmarks.html), including methodology and + the historical snapshot disclaimer. +- **Examples** — browse the `examples/` directory in the source repository; + each optional example states the feature macro it requires. + +## Public API boundary + +Application code should include the public umbrella headers and use the +`LOGIT_*` macros. The `logit::detail` namespace and implementation headers are +internal and carry no source or API compatibility guarantee. diff --git a/docs/reference.dox b/docs/reference.dox new file mode 100644 index 0000000..a182064 --- /dev/null +++ b/docs/reference.dox @@ -0,0 +1,1063 @@ +/*! +\page api_reference API reference and concepts + +\section reference_overview_sec 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_`, `LOGIT_PRINTF_`, `LOGIT_STREAM_`, etc.) cover immediate messages, `printf`-style formatting, streaming, throttling, and tagging. Defining `LOGIT_SHORT_NAME` when including `` 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. + +See the macro examples below or browse the `examples/` directory for focused demonstrations, including queue tuning and crash handling. `examples/example_logit_memory_logger.cpp` and `examples/example_logit_mdbx_logger.cpp` show the shared read/callback API for in-memory and MDBX-backed stored logs. + +The `logit::detail` namespace is implementation-only and carries no source or +API compatibility guarantee. It is shown in the reference for maintainers; +application code should use the public umbrella headers and macros. + +\section macro_first_usage_sec Macro-first usage + +For normal application logging, prefer the public macros from `` or +``. Choose the matching family +(`LOGIT_`, `LOGIT_PRINTF_`, `LOGIT_STREAM_`, +`LOGIT__IF`, `LOGIT__TO`, `LOGIT_SCOPE_`, and related +helpers) and pass the data directly to that macro. + +Avoid manually constructing `logit::LogRecord`, filling `args_array`, or +calling `logit::Logger::get_instance()` just to emit an ordinary log message. +Those low-level entry points are intended for extension work such as custom +`ILogger` / `ILogFormatter` implementations, backend registration, tests, +benchmarks, adapters, or internal maintenance. + +\section backpressure_sec Backpressure and queue variants + +The asynchronous `TaskExecutor` supports both a mutex-protected deque and an optional lock-free MPSC ring (enable via `LOGIT_USE_MPSC_RING`). Overflow policies (`Block`, `DropNewest`, `DropOldest`) behave the same in both variants, with the MPSC build intentionally dropping the **incoming** task for `DropOldest` to preserve the ordering of accepted work. The ring uses `LOGIT_TASK_EXECUTOR_DEFAULT_RING_CAPACITY` entries (1024 by default); adjust the baseline with that macro alongside `LOGIT_SET_MAX_QUEUE(...)` if your workload needs a different buffer size. MPSC builds also allow "hot" resizes where producers briefly wait while the worker rebuilds the ring without losing in-flight tasks. + +\section macro_examples_sec Macro Examples + +\subsection macro_examples_long Long-form macros + +\code{.cpp} +#include + +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(); +} +\endcode + +\subsection macro_examples_short Short aliases + +Define `LOGIT_SHORT_NAME` before including `` to enable single-letter level prefixes: + +\code{.cpp} +#define LOGIT_SHORT_NAME +#include + +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; +} +\endcode + +For a standalone program that brings everything together and intentionally aborts after logging a fatal message, check `examples/example_logit_minimal_crash.cpp`. + +\subsection macro_examples_context Diagnostic context (MDC/NDC) + +Enable `LOGIT_WITH_CONTEXT` to keep mapped key/value context and a nested +diagnostic context stack in thread-local storage. Use `%K`, `%K{key}`, and `%J` +pattern tokens to render the values. + +\code{.cpp} +#include + +void handle_request() { + LOGIT_MDC_PUT("request_id", "req-42"); + { + LOGIT_NDC_GUARD("checkout"); + LOGIT_INFO("processing order"); + } + LOGIT_MDC_CLEAR(); +} +\endcode + +\subsection macro_examples_optional Optional backends + +The `MemoryLogger`, `MdbxLogger`, OTLP, and Prometheus backends are demonstrated +in the corresponding files under `examples/`. OTLP requires +`LOGIT_WITH_OTLP=ON`, Prometheus payload/server requires +`LOGIT_WITH_PROMETHEUS=ON` or `LOGIT_WITH_PROMETHEUS_SERVER=ON`, and MDBX +requires `LOGIT_WITH_MDBX=ON`. See `\ref otlp_http_logger` and +`\ref prometheus_logger` for backend-specific configuration and limitations. + +\subsection macro_examples_targeted Targeted, conditional, and scope helpers + +Beyond the base logging calls, LogIt++ exposes canonical helper families for +addressing a specific backend, applying conditions, and measuring scope +duration. + +\code{.cpp} +#include + +void process_request(bool verbose, double latency_ms) { + LOGIT_ADD_CONSOLE_DEFAULT(); + LOGIT_ADD_UNIQUE_FILE_LOGGER_DEFAULT_SINGLE_MODE(); + + LOGIT_INFO_TO(1, "Only logger index 1 receives this message"); + LOGIT_PRINTF_INFO_IF(verbose, "Latency %.2f ms", latency_ms); + + LOGIT_SCOPE_INFO("process_request"); + LOGIT_SCOPE_PRINTF_WARN_T(50, "slow path latency=%.2f ms", latency_ms); + + LOGIT_WAIT(); +} +\endcode + +\subsection macro_examples_memory In-memory snapshot logger + +For remote control surfaces, diagnostics endpoints, or embedded operator tools, +LogIt++ can register a dedicated in-memory backend and expose the latest logs as +either formatted strings or structured entries. + +\code{.cpp} +#include + +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; +} +\endcode + +`MemoryLogger` snapshots are returned oldest-to-newest. The `max_bytes` +retention budget counts buffered formatted-message payload bytes rather than the +full object footprint of each `BufferedLogEntry`. Snapshot reads avoid the +`Logger` execution mutex, but they still synchronize on the memory backend's +own mutex while copying the current buffer. + +\subsection macro_examples_shared_reader 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: + +\code{.cpp} +#include + +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 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; +} +\endcode + +`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 return only what has +already reached disk; they do not drain async queues, and compressed rotated +files are listed as metadata-only artifacts in v1. Use `MemoryLogger` for +near-real-time snapshots and the file APIs for operational reads of persisted +daily logs. + +\section features_sec Features + +LogIt++ provides a robust and flexible set of features to accommodate various logging needs. + +\subsection flexible_formatting Flexible Log Formatting + +Customize log message formats using patterns. You can redefine patterns via macros or provide them directly when adding a logger backend. Both standard format flags (e.g., `%H`, `%M`, `%S`, `%v`) and special ones, like `%N([...])` for fallback logs without arguments, are supported. + +\code{.cpp} +#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 +\endcode + +\subsection macro_logging Logging with Macros + +Log variables and messages easily using macros. Simply select the appropriate macro and pass variables or arguments. Use `LOGIT_PRINTF_` for `printf`-style formatting and `LOGIT_FORMAT_` to apply the same format to every argument. + +\code{.cpp} +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 +\endcode + +Canonical public macro families also include: + +- Targeted families such as `LOGIT__TO`, `LOGIT_PRINTF__TO`, `LOGIT_FMT__TO`, and `LOGIT_STREAM__TO`. +- Conditional families such as `LOGIT__IF`, `LOGIT_PRINTF__IF`, `LOGIT_FORMAT__IF`, and `LOGIT_FMT__IF`. +- Scope-duration families such as `LOGIT_SCOPE_`, `LOGIT_SCOPE_PRINTF_`, and `LOGIT_SCOPE_FMT_`, including their `_T` threshold variants. +- System-error helpers `LOGIT_PERROR_`, `LOGIT_WINERR_`, and `LOGIT_SYSERR_`. +- Backend registration helpers such as `LOGIT_ADD_LOGGER(...)` and the built-in `LOGIT_ADD_*` backend macros. +- Management and query helpers such as `LOGIT_GET_*`, `LOGIT_SET_*`, `LOGIT_IS_*`, `LOGIT_GET_LOG_LEVEL(index)`, `LOGIT_LIST_LOG_FILES(index)`, `LOGIT_READ_LOG_FILE(index, path)`, `LOGIT_READ_LOG_FILES(index, paths)`, `LOGIT_WAIT()`, `LOGIT_SHUTDOWN()`, `LOGIT_GET_DROPPED_TASKS()`, and `LOGIT_RESET_DROPPED_TASKS()`. +- Snapshot helpers such as `LOGIT_GET_BUFFERED_STRINGS(index)` and `LOGIT_GET_BUFFERED_ENTRIES(index)` for backends that keep recent history. + +Pattern-consistent aliases exist for short-name and compatibility paths, but the +families above are the canonical public surface to document and prefer in +examples. + +\subsection multiple_backends Support for Multiple Backends + +Easily configure loggers for output to the console, files, or system logging facilities. Optionally, add support for sending messages to servers or databases by creating custom backends. + +\code{.cpp} +// Adding several backends: console, file, unique file and system loggers +LOGIT_ADD_CONSOLE_DEFAULT(); +LOGIT_ADD_FILE_LOGGER_DEFAULT(); +LOGIT_ADD_UNIQUE_FILE_LOGGER_DEFAULT_SINGLE_MODE(); +LOGIT_ADD_SYSLOG_DEFAULT(); +LOGIT_ADD_EVENT_LOG_DEFAULT(); +\endcode + +\subsection async_logging Asynchronous Logging + +Most general-purpose native backends handle messages asynchronously by +default. Crash and payload callback backends are synchronous, OTLP maintains +its own exporter queue, and dedicated executors create one worker per selected +backend. Emscripten builds without pthreads drain cooperatively without OS +worker threads. + +\subsection buffer_modes Queue Buffer Modes + +Control how the asynchronous queue behaves when full by setting a queue policy. +\code{.cpp} +LOGIT_SET_MAX_QUEUE(64); +LOGIT_SET_QUEUE_POLICY(LOGIT_QUEUE_BLOCK); // Block when full +\endcode +Available policies: `LOGIT_QUEUE_DROP_NEWEST`, `LOGIT_QUEUE_DROP_OLDEST`, `LOGIT_QUEUE_BLOCK`. + +Backend `Config` structs can set `use_dedicated_executor=true` to isolate a slow +async sink from the global task executor. Native builds create one worker thread +per configured logger; single-threaded Emscripten builds use a cooperative +per-instance queue instead. + +\code{.cpp} +logit::ConsoleLogger::Config cfg; +cfg.async = true; +cfg.use_dedicated_executor = true; +cfg.queue_capacity = 1024; +cfg.queue_policy = logit::detail::QueuePolicy::Block; + +LOGIT_ADD_LOGGER( + logit::ConsoleLogger, + (cfg), + logit::SimpleLogFormatter, + (LOGIT_CONSOLE_PATTERN) +); + +LOGIT_ADD_CONSOLE_CONFIG(cfg, LOGIT_CONSOLE_PATTERN); +LOGIT_ADD_CONSOLE_DEDICATED( + LOGIT_CONSOLE_PATTERN, + 1024, + logit::detail::QueuePolicy::DropNewest +); +\endcode + +\subsection stream_logging Stream-Based Logging + +Use stream operators for complex messages. + +\code{.cpp} +LOGIT_STREAM_INFO() << "Stream-based info logging with short macro. Integer value: " << 123; +\endcode + +\subsection compile_level Compile-Time Log Level + +Exclude lower-severity logs from the final binary by defining the minimum +severity compiled into the program. Set the `LOGIT_COMPILED_LEVEL` macro during +compilation: + +\code{.bash} +g++ -DLOGIT_COMPILED_LEVEL=LOGIT_LEVEL_WARN ... +\endcode + +With this configuration, `TRACE`, `DEBUG`, and `INFO` macros are disabled at compile time. + +Runtime filtering via `LOGIT_SET_LOG_LEVEL(...)` and +`LOGIT_SET_LOG_LEVEL_TO(...)` still works for compiled-in severities, but it +cannot re-enable macros removed earlier by `LOGIT_COMPILED_LEVEL`. + +\subsection extensibility Extensibility + +Create custom loggers and formatters to meet your specific requirements. +See the complete implementation in `\ref custom_backend_sec` below; it matches +the current `ILogger` and `ILogFormatter` interfaces. + +\section usage_sec Usage + +Here's a simple example demonstrating how to use LogIt++ in your application: + +\code{.cpp} +#define LOGIT_SHORT_NAME +#include + +int main() { + // Initialize the logger with default console output + LOGIT_ADD_CONSOLE_DEFAULT(); + + float a = 123.456f; + int b = 789; + const char* someStr = "Hello, World!"; + + // Basic logging using short macros + LOG_I("Starting the application"); + LOG_D(a, b); + LOG_W("This is a warning message"); + + // Formatted logging using short macros + LOG_IPF("Formatted log: value of a = %.2f", a); + LOG_WPF("Warning! Values: a = %.2f, b = %d", a, b); + + // Error and fatal logs using short macros + LOG_EP("An error occurred with value b =", b); + LOG_F("Fatal error. Terminating application."); + + // Conditional logging + LOGIT_INFO_IF(b < 0, "Value of b is negative"); + LOGIT_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 + LOG_TRACE0(); // Trace without arguments + LOG_T("Entering main function with variable", a); + + // Wait for all asynchronous logs to be processed + LOGIT_WAIT(); + + return 0; +} +\endcode + +\section log_formatting_sec Customizing Log Formats + +LogIt++ supports customizable log message formatting using patterns that define the appearance of each log message. +You can specify patterns either through macros or by providing them directly when adding logger backends. + +\subsection pattern_example Examples of Formatting Patterns + +### Example for Setting a Custom Console Logger Format + +You can define a custom format for the console logger as follows: + +\code{.cpp} +LOGIT_ADD_LOGGER( + logit::ConsoleLogger, (), + logit::SimpleLogFormatter, + ("%Y-%m-%d %H:%M:%S.%e [%l] %^%N(%g:%#)%v%$") +); +\endcode + +### Example Using Macros for Simplicity + +Alternatively, use macros to specify a pattern: + +\code{.cpp} +#define LOGIT_CONSOLE_PATTERN "%H:%M:%S.%e | %^%N([%!g:%#])%v%$" +LOGIT_ADD_CONSOLE_DEFAULT(); +\endcode + +In both cases, the logger will automatically replace placeholders in the pattern with corresponding data, such as: + +\code{.txt} +23:59:59.128 | path/to/file.cpp:123 A sample log message +\endcode + +\section format_flags_sec Log Message Formatting Flags + +`LogIt++` supports customizable log message formatting using format flags. You can define how each log message should appear by including placeholders for different pieces of information such as the timestamp, log level, file name, function name, and message. + +Below is a list of all supported format flags and their meanings: + +\subsection datetime_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 + +\subsection weekday_month_flags Weekday and Month Names +- `%%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) + +\subsection log_level_flags Log Level +- `%%l`: Full log level (e.g., INFO, ERROR) +- `%%L`: Short log level (e.g., I for INFO, E for ERROR) + +\subsection file_function_flags File and Function Information +- `%%f`, `%%fn`, `%%bs`: Base name of the source file (e.g., main.cpp) +- `%%g`, `%%ffn`: Full file path (e.g., /home/user/project/src/main.cpp) +- `%@`: Source file and line number (e.g., main.cpp:45) +- `%#`: Line number (e.g., 45) +- `%!`: Function name (e.g., main) + +\subsection thread_flags Thread Information +- `%%t`: Thread identifier + +\subsection color_flags Color Formatting +- `%^`: Start color formatting +- `%$`: End color formatting +- `%%SC`: Start removing color codes (Strip Color) +- `%%EC`: End removing color codes (End Color) + +\subsection message_flags Message Content +- `%%v`: The log message content +- `%%N(...)`: Fallback format for cases with no arguments. + - When used in a pattern (e.g., `%%N(%g:%#)`), the specified sub-pattern will be applied + if no arguments are provided in the log macro (e.g., `LOG_TRACE0()`). + +\subsection alignment_truncation_flags Alignment and Truncation + +- **Alignment**: + - Left: Use `-` before the width, e.g., `%-10v` (aligns text to the left). + - Center: Use `=` before the width, e.g., `%=10v` (centers text). + - Right (default): `%10v` (aligns text to the right). + +- **Truncation**: + - Use `!` after the width to truncate text if it exceeds the specified length, e.g., `%10!v`. + +**Examples**: +- `%10v`: Right-aligned message with a width of 10 characters. +- `%-10v`: Left-aligned message with a width of 10 characters. +- `%10!v`: Right-aligned, truncated to 10 characters. +- `%-10!v`: Left-aligned, truncated to 10 characters. + +\subsection advanced_path_handling 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` + +\section short_macros 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; replace the level letter or word in the macro name. + +\code{.cpp} +LOG_T("Trace message using short macro"); +LOG_FT("%.4d", 999); +LOG_PRINT_T("Printing trace message with multiple variables: ", var1, var2); +LOG_TRACE("Trace message (alias for LOG_T)"); +LOG_PRINTF_TRACE("Formatted trace: value = %d", value); +\endcode + +\section config_macros 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. + +\code{.cpp} +// Defines the base path for project folder. +#define LOGIT_BASE_PATH "/path/to/your/project" +\endcode + +- **LOGIT_DEFAULT_COLOR**: + +Sets the default color for console output. If `LOGIT_DEFAULT_COLOR` is not defined, it defaults to `TextColor::LightGray`. + +\code{.cpp} +// Sets the default log message color to green. +#define LOGIT_DEFAULT_COLOR TextColor::Green +\endcode + +- **LOGIT_COLOR_**: + +Defines the console text color for each log level. By default, each log level is associated with a specific color, but these can be customized. + +Available log levels: + - **TRACE**: Defaults to `TextColor::DarkGray` + - **DEBUG**: Defaults to `TextColor::Blue` + - **INFO**: Defaults to `TextColor::Green` + - **WARN**: Defaults to `TextColor::Yellow` + - **ERROR**: Defaults to `TextColor::Red` + - **FATAL**: Defaults to `TextColor::Magenta` + +\code{.cpp} +// Customize the color for different log levels +#define LOGIT_COLOR_TRACE TextColor::Blue +#define LOGIT_COLOR_ERROR TextColor::Cyan +\endcode + +- **LOGIT_COLOR_DEFAULT**: + +Defines the fallback console color used when a message does not map to a +severity-specific override. + +\code{.cpp} +#define LOGIT_COLOR_DEFAULT TextColor::White +\endcode + +- **LOGIT_WALLCLOCK_MS** / **LOGIT_MONOTONIC_MS**: + +Override the wall-clock or monotonic timestamp helpers used internally by the +library. This is useful when integrating platform-specific clock sources. + +\code{.cpp} +#define LOGIT_WALLCLOCK_MS() my_wallclock_ms() +#define LOGIT_MONOTONIC_MS() my_monotonic_ms() +\endcode + +- **LOGIT_CURRENT_TIMESTAMP_MS**: + +Macro to get the current timestamp in milliseconds. By default, it uses `std::chrono` for time calculation. You can override this to customize the timestamp generation. + +\code{.cpp} +// Customize timestamp calculation if needed. +#define LOGIT_CURRENT_TIMESTAMP_MS() my_custom_timestamp_function() +\endcode + +- **LOGIT_CONSOLE_PATTERN**: +Defines the default log pattern for the console logger. If `LOGIT_CONSOLE_PATTERN` is not defined, it defaults to `%%H:%%M:%%S.%%e | %^%N([%50!g:%#])%%v%$`. + +\code{.cpp} +// Customize the console log message pattern. +#define LOGIT_CONSOLE_PATTERN "%H:%M:%S.%e | %v" +\endcode + +- **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". + +\code{.cpp} +// Specify a custom path for log files. +#define LOGIT_FILE_LOGGER_PATH "/custom/log/directory" +\endcode + +- **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. + +\code{.cpp} +// Set the number of days to keep log files. +#define LOGIT_FILE_LOGGER_AUTO_DELETE_DAYS 60 +\endcode + +- **LOGIT_FILE_LOGGER_PATTERN**: + +Defines the default log pattern for file-based loggers. If `LOGIT_FILE_LOGGER_PATTERN` is not defined, it defaults to `[%%Y-%%m-%%d %%H:%%M:%%S.%%e] [%-5l] [%60!@] [thread:%%t] %%SC%%v`. + +\code{.cpp} +// Customize the log file message pattern. +#define LOGIT_FILE_LOGGER_PATTERN "[%Y-%m-%d %H:%M:%S.%e] [%l] %v" +\endcode + +- **LOGIT_FILE_LOGGER_MAX_FILE_SIZE_BYTES**: + +Defines the optional size threshold for rotating file loggers. Set it to a +non-zero value to enable size-based rotation. + +\code{.cpp} +#define LOGIT_FILE_LOGGER_MAX_FILE_SIZE_BYTES (10 * 1024 * 1024) +\endcode + +- **LOGIT_FILE_LOGGER_MAX_ROTATED_FILES**: + +Defines how many rotated files are retained when size-based rotation is active. + +\code{.cpp} +#define LOGIT_FILE_LOGGER_MAX_ROTATED_FILES 5 +\endcode + +- **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". + +\code{.cpp} +// Specify a custom path for unique log files. +#define LOGIT_UNIQUE_FILE_LOGGER_PATH "/custom/unique/log/directory" +\endcode + +- **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`. + +\code{.cpp} +// Customize the unique file log message pattern. +#define LOGIT_UNIQUE_FILE_LOGGER_PATTERN "[%Y-%m-%d %H:%M:%S.%e] [%l] %v" +\endcode + +- **LOGIT_UNIQUE_FILE_LOGGER_HASH_LENGTH**: + +Defines the length of the hash used in the unique log file names. If `LOGIT_UNIQUE_FILE_LOGGER_HASH_LENGTH` is not defined, it defaults to `8` characters. + +This macro controls the length of the hash part in the filenames for unique log files, ensuring unique names for each log. + +\code{.cpp} +// Set the hash length to 12 characters for unique file names. +#define LOGIT_UNIQUE_FILE_LOGGER_HASH_LENGTH 12 +\endcode + +- **LOGIT_OS_ERROR_JOIN**, **LOGIT_POSIX_ERROR_PATTERN**, + **LOGIT_WINDOWS_ERROR_PATTERN**, **LOGIT_SYSTEM_ERROR_PATTERN**: + +Control how decoded `errno` / `GetLastError()` information is appended by the +system-error macro families (`LOGIT_PERROR_*`, `LOGIT_WINERR_*`, +`LOGIT_SYSERR_*`). + +\code{.cpp} +#define LOGIT_OS_ERROR_JOIN " <- " +#define LOGIT_SYSTEM_ERROR_PATTERN "%s <- code=%d (%s)" +\endcode + +- **LOGIT_TAGS_JOIN**, **LOGIT_TAG_PAIR_SEP**, **LOGIT_TAG_KV_SEP**, + **LOGIT_TAG_QUOTE_VALUES**: + +Customize how key-value tags are rendered after the main message. + +\code{.cpp} +#define LOGIT_TAGS_JOIN " || " +#define LOGIT_TAG_PAIR_SEP "; " +#define LOGIT_TAG_KV_SEP ":" +#define LOGIT_TAG_QUOTE_VALUES 0 +\endcode + +- **LOGIT_TASK_EXECUTOR_BLOCK_WAIT_USEC**: + +Controls how frequently blocking producers poll for capacity while +`LOGIT_QUEUE_BLOCK` is active. + +\code{.cpp} +#define LOGIT_TASK_EXECUTOR_BLOCK_WAIT_USEC 200 +\endcode + +- **LOGIT_TASK_EXECUTOR_DRAIN_BUDGET**: + +Defines how many queued tasks a worker drains per iteration in ring-buffer +builds before yielding. + +\code{.cpp} +#define LOGIT_TASK_EXECUTOR_DRAIN_BUDGET 2048 +\endcode + +- **LOGIT_TASK_EXECUTOR_DEFAULT_RING_CAPACITY**: + +Defines the default MPSC ring capacity used when unlimited queue mode still +needs a backing ring size. + +\code{.cpp} +#define LOGIT_TASK_EXECUTOR_DEFAULT_RING_CAPACITY 1024 +\endcode + +- **LOGIT_SHORT_NAME**: + +Enables short names for logging macros, such as `LOG_T`, `LOG_D`, `LOG_E`, etc., for concise logging. + +\code{.cpp} +// Enable short macro names for logging. +#define LOGIT_SHORT_NAME +\endcode + +\section custom_backend_sec Custom Logger Backend and Formatter + +LogIt++ allows you to extend the logging system by creating your own loggers and formatters. This section explains how to implement a custom backend for logging and a custom log formatter. + +Normal application code should continue to use the public `LOGIT_*` / `LOG_*` +macros for emitting messages. The low-level APIs in this section are for +extension points only: custom backends, custom formatters, tests, adapters, and +other infrastructure code that intentionally works below the macro layer. + +\subsection custom_logger Custom Logger Example + +To create a custom logger backend, implement all pure virtual methods of the +`ILogger` interface (`log()`, parameter accessors, log-level accessors, and +`wait()`). The complete example below logs messages to a text file and matches +the current interface: + +\code{.cpp} +#include +#include +#include + +class FileLogger : public logit::ILogger { +public: + // Constructor to initialize the file logger with a file name + 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(); + } + } + + // Logs the message to the file + void log(const logit::LogRecord& record, const std::string& message) override { + std::lock_guard lock(m_mutex); + if (m_log_file.is_open()) { + m_log_file << message << std::endl; + } + } + + // Waits for any asynchronous log operations (none in this case) + void wait() override { + // No async processing, so no need to implement + } + + 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; ///< The name of the log file + std::ofstream m_log_file; ///< The file stream for logging + std::mutex m_mutex; ///< Mutex to ensure thread-safe logging + logit::LogLevel m_log_level = logit::LogLevel::LOG_LVL_TRACE; +}; +\endcode + +This `FileLogger` class writes log messages to a specified file. You can add this logger to your logging system like this: + +\code{.cpp} +LOGIT_ADD_LOGGER( + FileLogger, ("logfile.txt"), + logit::SimpleLogFormatter, ()); + +// or, if you intentionally need the lower-level equivalent... + +logit::Logger::get_instance().add_logger( + std::unique_ptr(new FileLogger("logfile.txt")), + std::unique_ptr(new logit::SimpleLogFormatter())); +\endcode + +Prefer `LOGIT_ADD_LOGGER(...)` when it fits your use case; calling +`logit::Logger::get_instance().add_logger(...)` directly is mainly useful when +an extension scenario cannot be expressed through the registration macro. + +\subsection custom_formatter Custom Formatter Example + +In addition to creating custom loggers, you can also create custom formatters by implementing the `ILogFormatter` interface. Here's an example of a simple formatter that outputs log messages in JSON format: + +\code{.cpp} +#include +#include // Or your preferred JSON library + +class JsonLogFormatter : public logit::ILogFormatter { +public: + void set_timestamp_offset(int64_t offset_ms) override { + (void)offset_ms; + } + + // Formats the log record into a JSON string + std::string format(const logit::LogRecord& record) const override { + Json::Value log_entry; + log_entry["level"] = static_cast(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["message"] = record.format; + + Json::StreamWriterBuilder writer; + return Json::writeString(writer, log_entry); + } +}; +\endcode + +This `JsonLogFormatter` formats log messages as JSON objects. You can combine it with any logger, including the `FileLogger`, as shown below: + +\code{.cpp} +LOGIT_ADD_LOGGER( + FileLogger, ("logfile.json"), + JsonLogFormatter, ()); + +// or, if you intentionally need the lower-level equivalent... + +logit::Logger::get_instance().add_logger( + std::unique_ptr(new FileLogger("logfile.json")), + std::unique_ptr(new JsonLogFormatter())); +\endcode + +\subsection summary_custom_backend Summary + +By implementing your own `ILogger` and `ILogFormatter`, you can extend the functionality of LogIt++ to log messages to various destinations or in different formats. You can combine custom loggers and formatters to create powerful logging solutions tailored to your application's needs. + +Here's a quick summary: + +- **ILogger**: Defines where the logs should be sent (e.g., file, console, database, network). +- **ILogFormatter**: Defines how the logs should be formatted (e.g., plain text, JSON, XML). +- **Registering custom backends**: Prefer `LOGIT_ADD_LOGGER(...)` for the common extension path; `logit::Logger::get_instance().add_logger()` is the lower-level equivalent when you need direct control. + +\section install_sec Installation + +LogIt++ itself is header-only. When consumed through the CMake target, +enabled optional features may add transitive compile and link dependencies. +Below are the steps to integrate it into your project. + +\subsection step1 Step 1: Clone the Repository + +First, clone the LogIt++ repository from GitHub along with its submodules. The +required dependency is **time-shield-cpp** (for time utilities); optional +features may also use **fmt**, **zlib**, **zstd**, **kurlyk**, or +**mdbx-containers**. + +To clone the repository with submodules, use the following command: + +\code{bash} +git clone --recurse-submodules https://github.com/LimiNode/log-it-cpp.git +\endcode + +If you have already cloned the repository without submodules, you can initialize and update the submodules by running the following commands: + +\code{bash} +git submodule init +git submodule update +\endcode + +\subsection step2 Step 2: Include the LogIt++ Headers in Your Project + +Since LogIt++ is a header-only library, you can simply include the main header in your project: + +\code{cpp} +#include +\endcode + +This will give you access to the entire logging system. + +\subsection step3 Step 3: 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 +those dependencies to be provided as installed/imported targets. + +\subsection step4 Step 4: Using fmt (Optional) + +LogIt++ ships with the **fmt** library for `{}`-style formatting. To use the `LOGIT_FMT_*` and `LOGIT_SCOPE_FMT_*` macros, build the library with the CMake option `-DLOGIT_WITH_FMT=ON`. + +\subsection cmake_options_sec CMake options + +All build-time toggles: + +- `LOGIT_CPP_BUILD_TESTS` (default: ON when this repository is the top-level project) — build the test suite. +- `LOGIT_CPP_BUILD_EXAMPLES` (default: OFF) — build the example programs. +- `LOGIT_BENCH_ENABLE` (default: OFF) — build the benchmarks; `LOGIT_BENCH_WITH_SPDLOG` (default: OFF) adds the spdlog comparison binaries. +- `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_USE_SUBMODULES` (default: OFF) allows bundled optional dependency fallbacks such as fmt, zlib, and zstd when system packages are missing. +- `LOGIT_WITH_CONTEXT` (default: OFF) — enable MDC/NDC helpers and context 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_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 on multi-threaded builds. +- `LOGIT_USE_MPSC_RING` (default: ON) — enable the lock-free task queue instead of the mutex-backed deque. +- `LOGIT_ENABLE_DROP_OLDEST_SLOWPATH` (default: ON) — include the drop-oldest slow-path used when the ring is full. +- `LOGIT_EMSCRIPTEN` (default: ON when building under Emscripten) — adjust the build for single-threaded WebAssembly targets. + +Detailed guides for the optional backends and queue internals are available as +separate pages: `\ref otlp_http_logger`, `\ref prometheus_logger`, +`\ref task_executor`, and `\ref backpressure`. + +\section bench_sec Benchmarks + +Benchmark commands, methodology, historical measurements, and harness details +are maintained on the dedicated `\ref benchmarks` page. Keeping this material +in one place avoids conflicting snapshots between the API reference and the +benchmark guide. + +\subsection step5 Step 5: Build and Run Your Project + +After adding the necessary include paths, you can proceed to build and run your +project. For a vendored or installed CMake package, link the exported target: + +\code{.cmake} +find_package(log-it-cpp CONFIG REQUIRED) +target_link_libraries(my_app PRIVATE log-it-cpp::log-it-cpp) +\endcode + +The repository can be installed with `cmake --install`; use separately +installed dependency targets for optional features. `LOGIT_WITH_PROMETHEUS_SERVER` +and bundled optional dependencies are intentionally rejected by the install +step until their exported dependency targets are available. + +\section repo_sec Repository + +The LogIt++ library is open-source and hosted on GitHub: +[LogIt++ GitHub Repository](https://github.com/LimiNode/log-it-cpp). + +\section license_sec License + +This library is licensed under the **MIT License**. See the [LICENSE](https://github.com/LimiNode/log-it-cpp/blob/main/LICENSE) file in the repository for more details. +*/ From e15ce95263cb23e7e8333051f7e316f192932d91 Mon Sep 17 00:00:00 2001 From: Aster Seker Date: Mon, 7 Sep 2026 18:48:15 +0300 Subject: [PATCH 2/6] docs: align installation and backend guidance Document shared OTLP dependencies and asynchronous payload delivery, centralize backend and benchmark references, and add a complete installation guide. Validate documentation on pull requests with dynamic version checks. --- .github/workflows/publish.yaml | 7 ++- Doxyfile | 1 + README-RU.md | 27 +++++------- README.md | 26 +++++------ docs/backends.md | 22 +++++++--- docs/installation.md | 79 ++++++++++++++++++++++++++++++++++ docs/mainpage.dox | 1 + docs/quickstart.md | 12 +++--- docs/reference.dox | 14 +++--- guides/build.md | 6 +-- 10 files changed, 136 insertions(+), 59 deletions(-) create mode 100644 docs/installation.md diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 5dd3470..fc07d6c 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -4,6 +4,9 @@ on: push: branches: - main + pull_request: + branches: + - main workflow_dispatch: jobs: @@ -27,6 +30,7 @@ jobs: fi DOC_VERSION="${VERSION}-dev" echo "Using version: $DOC_VERSION" + echo "DOC_VERSION=$DOC_VERSION" >> "$GITHUB_ENV" test -f docs/mainpage.dox || { echo "mainpage.dox not found!"; exit 1; } sed -i "0,/VERSION_PLACEHOLDER/s//${DOC_VERSION}/" docs/mainpage.dox - name: Generate Documentation @@ -40,7 +44,7 @@ jobs: test -s docs/html/backends.html test -s docs/html/benchmarks.html test -s docs/html/api_reference.html - grep -q "1.0.2-dev" docs/html/index.html + grep -q "$DOC_VERSION" docs/html/index.html grep -q "Quick start" docs/html/index.html grep -q "Backend matrix" docs/html/index.html grep -q "Performance and benchmarks" docs/html/index.html @@ -74,6 +78,7 @@ jobs: raise SystemExit(1) PY - name: Publish generated content to GitHub Pages + if: github.event_name != 'pull_request' uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.ACCESS_TOKEN }} diff --git a/Doxyfile b/Doxyfile index e122b67..8280f78 100644 --- a/Doxyfile +++ b/Doxyfile @@ -953,6 +953,7 @@ INPUT = ./include \ ./examples \ ./docs/mainpage.dox \ ./docs/quickstart.md \ + ./docs/installation.md \ ./docs/backends.md \ ./docs/reference.dox \ ./docs/benchmarks.md \ diff --git a/README-RU.md b/README-RU.md index 7e99958..d4ed12e 100644 --- a/README-RU.md +++ b/README-RU.md @@ -52,6 +52,7 @@ scope-замер. Дополнительные руководства и карта документации: - [`docs/quickstart.md`](docs/quickstart.md) — краткий старт и карта документации. +- [`docs/installation.md`](docs/installation.md) — установка через CMake, vendored и installed package сценарии. - [`docs/backends.md`](docs/backends.md) — матрица бэкендов, платформ, зависимостей и packaging. - [`docs/benchmarks.md`](docs/benchmarks.md) — методика benchmark и исторический snapshot. @@ -242,8 +243,8 @@ Prometheus text payload, а `LOGIT_WITH_PROMETHEUS_SERVER` — встроенн ## Обратное давление и горячее изменение размера Асинхронный `TaskExecutor` поддерживает как очередь на основе `std::deque` под мьютексом, так и опциональный lock-free MPSC ring - (включается флагом `LOGIT_USE_MPSC_RING`). Политики переполнения (`Block`, `DropNewest`, `DropOldest`) ведут себя одинаково в - обеих конфигурациях; в MPSC-режиме `DropOldest` намеренно отбрасывает **входящую** задачу, чтобы не нарушать порядок уже приня + (включается флагом `LOGIT_USE_MPSC_RING`). Имена политик переполнения (`Block`, `DropNewest`, `DropOldest`) доступны в обеих + конфигурациях, но семантика `DropOldest` различается: deque удаляет старую принятую задачу, а MPSC намеренно отбрасывает **входящую**, чтобы не нарушать порядок уже приня тых. Кольцевой буфер по умолчанию вмещает `LOGIT_TASK_EXECUTOR_DEFAULT_RING_CAPACITY` задач (1024) и может быть перенастроен ком бинацией `LOGIT_SET_MAX_QUEUE(...)` с этим макросом, если приложению требуется другой базовый объём. В сборках с MPSC допускаетс я "горячее" изменение размера очереди без потери принятых задач — продюсеры кратковременно ждут, пока поток-воркер пересобирает @@ -320,9 +321,10 @@ LOGIT_ADD_UNIQUE_FILE_LOGGER_DEFAULT_SINGLE_MODE(); - **Асинхронное логирование**: Большинство обычных native-бэкендов по умолчанию работают асинхронно. -Crash- и payload callback-бэкенды синхронны, OTLP использует собственную -очередь экспортёра, dedicated executor создаёт worker для выбранного бэкенда, -а Emscripten без pthreads работает кооперативно без OS-потока. +Crash-бэкенды и `PrometheusPayloadLogger` синхронны. OTLP HTTP и payload- +экспортёры владеют собственными очередями и worker-потоками и могут работать +синхронно или асинхронно. Dedicated executor создаёт worker для выбранного +бэкенда, а Emscripten без pthreads работает кооперативно без OS-потока. - **Потоковое логирование**: @@ -909,7 +911,6 @@ LogIt++ включает библиотеку *fmt* для форматиров - `LOGIT_WITH_WIN_EVENT_LOG` (по умолчанию: ON в Windows) — сборка бэкенда Windows Event Log. - `LOGIT_FORCE_ASYNC_OFF` (по умолчанию: OFF) — принудительно отключить асинхронное выполнение даже в многопоточных сборках. - `LOGIT_USE_MPSC_RING` (по умолчанию: ON) — использовать lock-free очередь вместо варианта на `std::deque`. -- `LOGIT_ENABLE_DROP_OLDEST_SLOWPATH` (по умолчанию: ON) — скомпилировать медленный путь для `DropOldest`, когда кольцо заполнено. - `LOGIT_EMSCRIPTEN` (по умолчанию: ON при сборке Emscripten) — подстройка под однопоточные среды WebAssembly. ## Бенчмарки @@ -937,17 +938,9 @@ LogIt++ включает библиотеку *fmt* для форматиров ## Матрица бэкендов -| Бэкенд | Включение | Standard | Зависимость | Ограничения | -|---|---|---:|---|---| -| Console, file, unique file, memory, crash | встроены | C++11 | TimeShield | Native и документированные Emscripten stubs | -| Syslog | `LOGIT_WITH_SYSLOG=ON` | C++11 | POSIX syslog | Unix-подобные системы | -| Windows Event Log | `LOGIT_WITH_WIN_EVENT_LOG=ON` | C++11 | Windows SDK | Только Windows | -| `WindowsDebugLogger` | встроен | C++11 | Windows API | `OutputDebugStringW` в Windows; в остальных системах fallback в stderr | -| OTLP/HTTP | `LOGIT_WITH_OTLP=ON` | C++17 | kurlyk | Не Emscripten; для install нужен внешний kurlyk | -| OTLP payload callback | `LOGIT_WITH_OTLP=ON` | C++17 | Для callback не нужен; общая OTLP-функция | JSON-сериализация и callback вызывающей стороны | -| Prometheus payload | `LOGIT_WITH_PROMETHEUS=ON` | C++11 | нет | Не Emscripten | -| Prometheus HTTP server | `LOGIT_WITH_PROMETHEUS_SERVER=ON` | C++17 | Simple-Web-Server/Asio | Только build-tree; install запрещён | -| MDBX | `LOGIT_WITH_MDBX=ON` | C++17 | mdbx-containers | Не Emscripten и не MSVC | +Поддерживаются консольные, файловые, системные, OTLP, Prometheus и MDBX- +бэкенды. Каноническая [матрица бэкендов](docs/backends.md) содержит стандарты, +feature-specific зависимости и ограничения платформ/packaging. ## Системные бэкенды diff --git a/README.md b/README.md index 3b9d47f..0041c44 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ Recent focused examples include: Detailed guides and documentation map: - [`docs/quickstart.md`](docs/quickstart.md) — quick start and documentation map. +- [`docs/installation.md`](docs/installation.md) — CMake, vendored, installed-package, and package-manager setup. - [`docs/backends.md`](docs/backends.md) — backend, platform, dependency, and packaging matrix. - [`docs/benchmarks.md`](docs/benchmarks.md) — benchmark methodology and historical snapshot. @@ -488,10 +489,12 @@ Use the host OS logging facility. `SyslogLogger` works with POSIX `syslog`, whil - **Asynchronous Logging**: -Most general-purpose native backends are asynchronous by default. Crash and -payload callback backends are synchronous, OTLP maintains its own exporter -queue, dedicated executors create one worker per selected backend, and -Emscripten without pthreads drains cooperatively without OS worker threads. +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**: @@ -1090,22 +1093,13 @@ The following toggles cover all build-time features: - `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_ENABLE_DROP_OLDEST_SLOWPATH` (default: ON) — compile the slow-path used by `DropOldest` when the ring is full. - `LOGIT_EMSCRIPTEN` (default: ON under Emscripten toolchains) — adjust the build for single-threaded WebAssembly environments. ## Backend matrix -| Backend | Enablement | Standard | Extra dependency | Platform/package notes | -|---|---|---:|---|---| -| Console, file, unique file, memory, crash | built in | C++11 | TimeShield | Native and Emscripten stubs where documented | -| Syslog | `LOGIT_WITH_SYSLOG=ON` | C++11 | POSIX syslog | Unix-like platforms | -| Windows Event Log | `LOGIT_WITH_WIN_EVENT_LOG=ON` | C++11 | Windows SDK | Windows only | -| `WindowsDebugLogger` | built in | C++11 | Windows API | Windows `OutputDebugStringW`; stderr fallback elsewhere | -| OTLP/HTTP | `LOGIT_WITH_OTLP=ON` | C++17 | kurlyk | Not supported on Emscripten; installed exports need external kurlyk | -| OTLP payload callback | `LOGIT_WITH_OTLP=ON` | C++17 | None for callback; shared OTLP feature | Serializes JSON and invokes the caller callback | -| Prometheus payload | `LOGIT_WITH_PROMETHEUS=ON` | C++11 | None | Not supported on Emscripten | -| Prometheus HTTP server | `LOGIT_WITH_PROMETHEUS_SERVER=ON` | C++17 | Simple-Web-Server/Asio | Build-tree only; install currently rejected | -| MDBX structured storage | `LOGIT_WITH_MDBX=ON` | C++17 | mdbx-containers | Not supported on Emscripten or MSVC | +Supported backends include console, file, memory, system logging, OTLP, +Prometheus, and MDBX. See the canonical [backend matrix](docs/backends.md) for +standards, feature-specific dependencies, and platform/package restrictions. ## System Backends diff --git a/docs/backends.md b/docs/backends.md index 5cfadf6..4fd8699 100644 --- a/docs/backends.md +++ b/docs/backends.md @@ -6,14 +6,21 @@ Choose a backend by delivery model, platform, and dependency requirements. Every backend implements `ILogger`; stored-log backends may additionally implement `ILogReader` and `ILogSubscriber`. -| Backend | Enablement | Standard | Extra dependency | Platform and packaging notes | +All LogIt++ builds require **TimeShield 1.0.6 or newer**. The dependency column +below lists only feature-specific dependencies. + +| Backend | Enablement | Standard | Feature-specific dependency | Platform and packaging notes | |---|---|---:|---|---| -| Console, file, unique file, memory, crash | built in | C++11 | TimeShield | Native and documented Emscripten stubs | +| `ConsoleLogger` | built in | C++11 | None | Native and documented Emscripten behavior | +| `FileLogger` / `UniqueFileLogger` | built in | C++11 | zlib or zstd only when compression is enabled | Native and documented Emscripten stubs | +| `MemoryLogger` | built in | C++11 | None | Supports snapshots and subscriber callbacks | +| `CrashLogger` | built in | C++11 | Platform crash facilities | Synchronous crash path | | `WindowsDebugLogger` | built in | C++11 | Windows API | `OutputDebugStringW` on Windows; stderr fallback elsewhere | | `SyslogLogger` | `LOGIT_WITH_SYSLOG=ON` | C++11 | POSIX syslog | Unix-like platforms | | `EventLogLogger` | `LOGIT_WITH_WIN_EVENT_LOG=ON` | C++11 | Windows SDK | Windows only | -| `OtlpHttpLogger` | `LOGIT_WITH_OTLP=ON` | C++17 | kurlyk | Outbound OTLP/HTTP; installed exports need external kurlyk | -| `OtlpPayloadLogger` | `LOGIT_WITH_OTLP=ON` | C++17 | None for callback | JSON payload callback; application owns transport | +| `SystemLogger` | built in alias | C++11 | Platform system API | Alias for `SyslogLogger` or `EventLogLogger` | +| `OtlpHttpLogger` | `LOGIT_WITH_OTLP=ON` | C++17 | kurlyk (required by the current option) | Outbound OTLP/HTTP; installed exports need external kurlyk | +| `OtlpPayloadLogger` | `LOGIT_WITH_OTLP=ON` | C++17 | kurlyk (required by the shared option; not used for callback transport) | JSON payload callback; application owns transport; async by default | | `PrometheusPayloadLogger` | `LOGIT_WITH_PROMETHEUS=ON` | C++11 | None | Text payload callback; no HTTP client | | `PrometheusHttpServerLogger` | `LOGIT_WITH_PROMETHEUS_SERVER=ON` | C++17 | Simple-Web-Server/Asio | Build-tree only; install currently rejected | | `MdbxLogger` | `LOGIT_WITH_MDBX=ON` | C++17 | mdbx-containers | Not supported on Emscripten or MSVC | @@ -22,9 +29,10 @@ implement `ILogReader` and `ILogSubscriber`. General-purpose native backends use the shared asynchronous `TaskExecutor` by default. A backend configured with `use_dedicated_executor=true` owns a -per-backend `SingleThreadExecutor`. Crash and callback payload backends are -synchronous unless their own configuration says otherwise; OTLP HTTP and -payload exporters own their queues and workers. Emscripten builds without +per-backend `SingleThreadExecutor`. Crash backends and +`PrometheusPayloadLogger` are synchronous. OTLP HTTP and OTLP payload +exporters own their queues and workers and can be configured for synchronous or +asynchronous delivery. Emscripten builds without pthreads use cooperative queues instead of OS worker threads. ## Packaging diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..028e658 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,79 @@ +\page installation Installation guide + +# Installation guide + +## Requirements + +LogIt++ requires CMake 3.18 or newer and **TimeShield 1.0.6 or newer**. The +core library and most built-in backends use C++11. OTLP, the Prometheus HTTP +server, and MDBX integrations require C++17. + +## Vendored checkout + +Use `add_subdirectory()` when LogIt++ is part of the source tree: + +```cmake +add_subdirectory(external/log-it-cpp) +target_link_libraries(my_app PRIVATE log-it-cpp::log-it-cpp) +``` + +The directory name is arbitrary. If dependencies are supplied as sibling +targets, define them before adding LogIt++. + +## Git submodule + +```bash +git submodule add https://github.com/LimiNode/log-it-cpp.git external/log-it-cpp +git submodule update --init --recursive +``` + +Then use the vendored CMake flow above. The bundled TimeShield submodule is a +development fallback; package-manager builds may provide an installed +`time_shield::time_shield` target instead. + +## Installed package + +Build and install the package from a clean checkout: + +```bash +cmake -S . -B build -DLOGIT_CPP_BUILD_TESTS=OFF +cmake --build build +cmake --install build --prefix ./install +``` + +Consume it from another CMake project: + +```cmake +find_package(log-it-cpp CONFIG REQUIRED) +target_link_libraries(my_app PRIVATE log-it-cpp::log-it-cpp) +``` + +Pass `-DCMAKE_PREFIX_PATH=/path/to/install` when configuring the consumer. + +## Optional dependencies and features + +Enable only the features needed by the application. `fmt`, zlib, and zstd can +be provided as installed CMake packages or by bundled submodules with +`LOGIT_USE_SUBMODULES=ON`. `LOGIT_WITH_OTLP=ON` currently requires kurlyk for +both OTLP logger variants because the option controls the shared OTLP build. +MDBX requires `mdbx-containers`. Prometheus payload support has no extra +dependency; the Prometheus HTTP server uses Simple-Web-Server and Asio. + +See the [`Backend matrix`](backends.html) for standards, dependencies, and +platform restrictions. All CMake options are listed in the API reference. + +## Install limitations + +Installed exports require optional dependencies to be available as installed +or imported targets. Bundled optional dependencies are intended for source and +build-tree development. `LOGIT_WITH_PROMETHEUS_SERVER=ON` is currently +rejected by `cmake --install` because its HTTP dependency tree is not exported +as part of the package. + +## Package managers + +The exported target is suitable for package-manager recipes that provide the +required dependency targets before configuring LogIt++. For the repository's +current vcpkg integration, follow the port and consumer checks in the CI +workflow. Treat package-manager manifests as versioned integration metadata and +verify them against the exact release tag being packaged. diff --git a/docs/mainpage.dox b/docs/mainpage.dox index 5543a98..14c9b2f 100644 --- a/docs/mainpage.dox +++ b/docs/mainpage.dox @@ -22,6 +22,7 @@ int main() { \section docs_map Documentation map - \ref quickstart — quick start, installation paths, and public API boundary. +- \ref installation — complete CMake, vendored, installed-package, and package-manager setup. - \ref backends — backend, platform, dependency, and packaging matrix. - \ref otlp_http_logger — OTLP HTTP and callback exporters. - \ref prometheus_logger — Prometheus payload and HTTP server backends. diff --git a/docs/quickstart.md b/docs/quickstart.md index 1b0ae76..66b871e 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -18,16 +18,14 @@ int main() { } ``` -For a vendored checkout, add the repository with `add_subdirectory()` and link -`log-it-cpp::log-it-cpp`. For an installed package, use -`find_package(log-it-cpp CONFIG REQUIRED)` and link the same target. Optional -features and their dependency requirements are described in the -[`Backend matrix`](backends.html). +Installation choices and complete CMake examples are collected in the +[`Installation guide`](installation.html). Optional features and their +dependency requirements are described in the [`Backend matrix`](backends.html). ## Documentation map -- **Installation and CMake** — see the installation section in the project - README and the generated CMake target reference. +- **Installation and CMake** — [`Installation guide`](installation.html), + including vendored, submodule, installed-package, and package-manager flows. - **Macros and formatting** — use the public `` entry point; the macro and pattern references are available from the API index. - **Backends** — [`Backend matrix`](backends.html), diff --git a/docs/reference.dox b/docs/reference.dox index a182064..24f61bc 100644 --- a/docs/reference.dox +++ b/docs/reference.dox @@ -43,7 +43,7 @@ benchmarks, adapters, or internal maintenance. \section backpressure_sec Backpressure and queue variants -The asynchronous `TaskExecutor` supports both a mutex-protected deque and an optional lock-free MPSC ring (enable via `LOGIT_USE_MPSC_RING`). Overflow policies (`Block`, `DropNewest`, `DropOldest`) behave the same in both variants, with the MPSC build intentionally dropping the **incoming** task for `DropOldest` to preserve the ordering of accepted work. The ring uses `LOGIT_TASK_EXECUTOR_DEFAULT_RING_CAPACITY` entries (1024 by default); adjust the baseline with that macro alongside `LOGIT_SET_MAX_QUEUE(...)` if your workload needs a different buffer size. MPSC builds also allow "hot" resizes where producers briefly wait while the worker rebuilds the ring without losing in-flight tasks. +The asynchronous `TaskExecutor` supports both a mutex-protected deque and an optional lock-free MPSC ring (enable via `LOGIT_USE_MPSC_RING`). The same policy names (`Block`, `DropNewest`, `DropOldest`) are available in both implementations, but `DropOldest` has intentionally different semantics in MPSC mode: the deque removes the oldest accepted task, while MPSC drops the incoming task to preserve the ordering of accepted work. The ring uses `LOGIT_TASK_EXECUTOR_DEFAULT_RING_CAPACITY` entries (1024 by default); adjust the baseline with that macro alongside `LOGIT_SET_MAX_QUEUE(...)` if your workload needs a different buffer size. MPSC builds also allow "hot" resizes where producers briefly wait while the worker rebuilds the ring without losing in-flight tasks. \section macro_examples_sec Macro Examples @@ -306,10 +306,11 @@ LOGIT_ADD_EVENT_LOG_DEFAULT(); \subsection async_logging Asynchronous Logging Most general-purpose native backends handle messages asynchronously by -default. Crash and payload callback backends are synchronous, OTLP maintains -its own exporter queue, and dedicated executors create one worker per selected -backend. Emscripten builds without pthreads drain cooperatively without OS -worker threads. +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. Emscripten builds without pthreads drain +cooperatively without OS worker threads. \subsection buffer_modes Queue Buffer Modes @@ -921,7 +922,7 @@ public: log_entry["file"] = record.file; log_entry["line"] = record.line; log_entry["function"] = record.function; - log_entry["message"] = record.format; + log_entry["format"] = record.format; Json::StreamWriterBuilder writer; return Json::writeString(writer, log_entry); @@ -1023,7 +1024,6 @@ All build-time toggles: - `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 on multi-threaded builds. - `LOGIT_USE_MPSC_RING` (default: ON) — enable the lock-free task queue instead of the mutex-backed deque. -- `LOGIT_ENABLE_DROP_OLDEST_SLOWPATH` (default: ON) — include the drop-oldest slow-path used when the ring is full. - `LOGIT_EMSCRIPTEN` (default: ON when building under Emscripten) — adjust the build for single-threaded WebAssembly targets. Detailed guides for the optional backends and queue internals are available as diff --git a/guides/build.md b/guides/build.md index caf1bde..c1552d0 100644 --- a/guides/build.md +++ b/guides/build.md @@ -38,8 +38,6 @@ From `CMakeLists.txt` and `README.md`, the most relevant toggles are: - `LOGIT_WITH_WIN_EVENT_LOG` - enable the Windows Event Log backend on Windows. - `LOGIT_FORCE_ASYNC_OFF` - force synchronous logging. - `LOGIT_USE_MPSC_RING` - enable the lock-free task queue. -- `LOGIT_ENABLE_DROP_OLDEST_SLOWPATH` - compile the ring slow-path for - `DropOldest`. When zlib, zstd, kurlyk, or mdbx-containers are supplied from submodules, they are suitable for development and tests. Package installation must use @@ -80,8 +78,8 @@ cmake -S . -B build -DLOGIT_BENCH_ENABLE=ON -DLOGIT_BENCH_WITH_SPDLOG=ON cmake --build build --target logit_bench ``` -Benchmark output is described in `README.md`; the benchmark binary lives under -the build tree, typically `build/bench/logit_bench`. +Benchmark output is described in `docs/benchmarks.md`; the benchmark binary +lives under the build tree, typically `build/bench/logit_bench`. ## Verification notes From 73c9a57b560988acc7150b9f34ddbedb3827cd83 Mon Sep 17 00:00:00 2001 From: Aster Seker Date: Mon, 7 Sep 2026 19:09:40 +0300 Subject: [PATCH 3/6] docs: use public queue policy examples Update queue configuration examples to use the stable logit::QueuePolicy name introduced by the API cleanup. --- README.md | 4 ++-- docs/reference.dox | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0041c44..b16e643 100644 --- a/README.md +++ b/README.md @@ -342,7 +342,7 @@ logit::ConsoleLogger::Config cfg; cfg.async = true; cfg.use_dedicated_executor = true; cfg.queue_capacity = 1024; -cfg.queue_policy = logit::detail::QueuePolicy::Block; +cfg.queue_policy = logit::QueuePolicy::Block; LOGIT_ADD_LOGGER( logit::ConsoleLogger, @@ -359,7 +359,7 @@ LOGIT_ADD_CONSOLE_CONFIG(cfg, LOGIT_CONSOLE_PATTERN); LOGIT_ADD_CONSOLE_DEDICATED( LOGIT_CONSOLE_PATTERN, 1024, - logit::detail::QueuePolicy::DropNewest + logit::QueuePolicy::DropNewest ); ``` diff --git a/docs/reference.dox b/docs/reference.dox index 24f61bc..b94b45a 100644 --- a/docs/reference.dox +++ b/docs/reference.dox @@ -331,7 +331,7 @@ logit::ConsoleLogger::Config cfg; cfg.async = true; cfg.use_dedicated_executor = true; cfg.queue_capacity = 1024; -cfg.queue_policy = logit::detail::QueuePolicy::Block; + cfg.queue_policy = logit::QueuePolicy::Block; LOGIT_ADD_LOGGER( logit::ConsoleLogger, @@ -344,7 +344,7 @@ LOGIT_ADD_CONSOLE_CONFIG(cfg, LOGIT_CONSOLE_PATTERN); LOGIT_ADD_CONSOLE_DEDICATED( LOGIT_CONSOLE_PATTERN, 1024, - logit::detail::QueuePolicy::DropNewest + logit::QueuePolicy::DropNewest ); \endcode From d352b3c1d36f7053f33d52621067bd07ffa692ff Mon Sep 17 00:00:00 2001 From: Aster Seker Date: Tue, 8 Sep 2026 12:47:25 +0300 Subject: [PATCH 4/6] docs: clarify aggregate-first header contracts Make logit.hpp the supported application entry point and document that log_macros.hpp is aggregate-owned without a standalone inclusion guarantee. Keep standalone contracts explicit for public type headers. --- AGENTS.md | 6 ++++++ docs/TaskExecutor.md | 3 ++- docs/backpressure.md | 3 +-- docs/reference.dox | 4 ++-- guides/orientation.md | 9 +++++---- include/logit_cpp/AGENTS.md | 3 +++ 6 files changed, 19 insertions(+), 9 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index a528219..c6dcf24 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -33,6 +33,12 @@ Use the project umbrella headers instead of recreating include order manually: These headers prepare internal dependencies in the intended order. +`` is the supported application entry point. Module umbrellas are +supported for focused use; `logit/log_macros.hpp` is an aggregate-owned macro +implementation header and has no standalone-inclusion guarantee. A leaf type +header is standalone only when its documentation and include-contract test say +so (for example, ``). + ## Include Policy - Do not use `../` in `#include` directives. diff --git a/docs/TaskExecutor.md b/docs/TaskExecutor.md index be1dacd..7d000ce 100644 --- a/docs/TaskExecutor.md +++ b/docs/TaskExecutor.md @@ -157,7 +157,8 @@ Public methods exposed by `TaskExecutor`: * `dropped_tasks()` and `reset_dropped_tasks()` — inspect or reset the overflow counter. -Macros in `` map directly onto these calls: +Macros from the supported `` entry point map directly onto these +calls: * `LOGIT_SET_MAX_QUEUE(size)` → `set_max_queue_size(size)` * `LOGIT_SET_QUEUE_POLICY(mode)` → `set_queue_policy(mode)` diff --git a/docs/backpressure.md b/docs/backpressure.md index 6375fde..6a58c2e 100644 --- a/docs/backpressure.md +++ b/docs/backpressure.md @@ -6,8 +6,7 @@ The global asynchronous task executor backs loggers that use the default executor and can be tuned to handle high-load bursts. Some backends are synchronous, while configured dedicated executors and OTLP maintain their own queues. Use the following helpers from -`` when preparing stress tests or -long-running services: +`` when preparing stress tests or long-running services: - `LOGIT_SET_MAX_QUEUE(size)` sets the maximum number of queued tasks. Use a small `size` to emulate a constrained environment or `0` to remove the diff --git a/docs/reference.dox b/docs/reference.dox index b94b45a..8d89a37 100644 --- a/docs/reference.dox +++ b/docs/reference.dox @@ -29,8 +29,8 @@ application code should use the public umbrella headers and macros. \section macro_first_usage_sec Macro-first usage -For normal application logging, prefer the public macros from `` or -``. Choose the matching family +For normal application logging, include `` and use the public macros. +Choose the matching family (`LOGIT_`, `LOGIT_PRINTF_`, `LOGIT_STREAM_`, `LOGIT__IF`, `LOGIT__TO`, `LOGIT_SCOPE_`, and related helpers) and pass the data directly to that macro. diff --git a/guides/orientation.md b/guides/orientation.md index 6343649..c5418c6 100644 --- a/guides/orientation.md +++ b/guides/orientation.md @@ -7,7 +7,7 @@ does not replace them. ## Quick Model `log-it-cpp` is a header-only C++ logging library. Its public surface is a -macro-first facade (`include/logit_cpp/logit/log_macros.hpp`) backed by a +macro-first facade exposed by the supported `` entry point and backed by a singleton dispatcher (`include/logit_cpp/logit/Logger.hpp`), formatter strategies (`include/logit_cpp/logit/formatter/`), logger backends (`include/logit_cpp/logit/loggers/`), utility DTOs/helpers @@ -46,7 +46,7 @@ See `guides/header-impl.md` before changing include structure. | Subsystem | Main files | Responsibility | | --- | --- | --- | -| Macro facade | `log_macros.hpp` | Public logging, setup, query, queue, and short-name macros. Normal application code should stay here. | +| Macro facade | `log_macros.hpp` | Macro implementation consumed by ``; normal application code should use the umbrella entry point. Standalone inclusion is not guaranteed. | | Dispatcher | `Logger.hpp` | Owns logger/formatter strategies, filtering, single-mode routing, targeted logging, snapshots, shutdown. | | Logger interfaces | `loggers/ILogger.hpp` | Backend contract for sinks, parameters, buffered snapshots, persisted file access, and flush/wait. | | Logger backends | `ConsoleLogger.hpp`, `FileLogger.hpp`, `UniqueFileLogger.hpp`, `MemoryLogger.hpp`, `SyslogLogger.hpp`, `EventLogLogger.hpp`, `CrashLogger.hpp` | Concrete sinks. Platform-specific backends provide stubs or aliases where unsupported. | @@ -69,7 +69,8 @@ The practical dependency direction is: 4. `loggers.hpp` depends on utilities and detail helpers, then exposes backend implementations. 5. `Logger.hpp` combines `ILogger` and `ILogFormatter` strategies. -6. `log_macros.hpp` is the macro facade over `Logger` and `TaskExecutor`. +6. `log_macros.hpp` is the macro facade over `Logger` and `TaskExecutor`, + included by the supported `` entry point. Avoid these dependency shapes: @@ -343,7 +344,7 @@ changing async behavior, run the relevant backpressure tests and prefer a full | `include/logit_cpp/logit/loggers/` | Concrete sinks and `ILogger`. | Adding or changing backend behavior. | | `include/logit_cpp/logit/detail/` | Private executor, compression, stream, scope internals. | Internal library mechanics only; avoid from consumer code. | | `include/logit_cpp/logit/Logger.hpp` | Singleton dispatcher and strategy management. | Changing routing, filtering, snapshot, or shutdown behavior. | -| `include/logit_cpp/logit/log_macros.hpp` | Public macro API. | Adding macro families, setup/query macros, or C++11/17 macro branches. | +| `include/logit_cpp/logit/log_macros.hpp` | Macro implementation behind ``. | Adding macro families, setup/query macros, or C++11/17 macro branches. | | `tests/` | Unit, integration, include, ODR, optional feature tests. | Any behavior or include-contract change. | | `examples/` | User-facing examples. | Public workflow or new backend examples. | | `bench/` | Benchmark harness and adapters. | Performance scenarios or benchmark-specific adapter changes. | diff --git a/include/logit_cpp/AGENTS.md b/include/logit_cpp/AGENTS.md index c59da3d..dd45f33 100644 --- a/include/logit_cpp/AGENTS.md +++ b/include/logit_cpp/AGENTS.md @@ -17,6 +17,9 @@ For subsystem-specific work, also read the nearest guide: - Include the nearest umbrella (`logit.hpp`, `utils.hpp`, `formatter.hpp`, or `loggers.hpp`) in examples and integration tests. +- Treat `` as the supported application entry point. Do not infer a + standalone contract for `log_macros.hpp` or other aggregate-owned leaf + headers unless a focused public-header test documents it. - Preserve the existing public names, overloads, macro expansion contracts, and feature guards. Add new API only with a focused test and documentation. - Keep headers self-contained: include every standard type used directly and From e4204f30d44c93a03440e361ef44923b67514a81 Mon Sep 17 00:00:00 2001 From: Aster Seker Date: Tue, 8 Sep 2026 13:00:47 +0300 Subject: [PATCH 5/6] docs: synchronize queue and formatter examples Describe the distinct MPSC DropOldest semantics and represent LogRecord::format as a format field in both README variants. --- README-RU.md | 2 +- README.md | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/README-RU.md b/README-RU.md index d4ed12e..0fe5328 100644 --- a/README-RU.md +++ b/README-RU.md @@ -823,7 +823,7 @@ public: log_entry["file"] = record.file; log_entry["line"] = record.line; log_entry["function"] = record.function; - log_entry["message"] = record.format; + log_entry["format"] = record.format; Json::StreamWriterBuilder writer; return Json::writeString(writer, log_entry); diff --git a/README.md b/README.md index b16e643..6ee7629 100644 --- a/README.md +++ b/README.md @@ -317,10 +317,11 @@ 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`). Queue overflow -policies (`Block`, `DropNewest`, `DropOldest`) behave consistently across both -implementations, with the MPSC build intentionally dropping the *incoming* task -for `DropOldest` to keep accepted work ordered. The ring build also allows +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 @@ -916,7 +917,7 @@ public: log_entry["file"] = record.file; log_entry["line"] = record.line; log_entry["function"] = record.function; - log_entry["message"] = record.format; + log_entry["format"] = record.format; Json::StreamWriterBuilder writer; return Json::writeString(writer, log_entry); From 94199f2a701f40aaa93a326dcd77ed28d7f2d714 Mon Sep 17 00:00:00 2001 From: Aster Seker Date: Tue, 8 Sep 2026 19:52:08 +0300 Subject: [PATCH 6/6] docs: clarify aggregate-first consumer contracts Use the supported umbrella entry point in Prometheus examples and avoid implying standalone contracts for aggregate-owned headers or public aliases. --- AGENTS.md | 3 ++- docs/PrometheusLogger.md | 2 +- include/logit_cpp/AGENTS.md | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index c6dcf24..aac64e7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -37,7 +37,8 @@ These headers prepare internal dependencies in the intended order. supported for focused use; `logit/log_macros.hpp` is an aggregate-owned macro implementation header and has no standalone-inclusion guarantee. A leaf type header is standalone only when its documentation and include-contract test say -so (for example, ``). +so. Public aliases such as `logit::QueuePolicy` are normally consumed through +`` or the relevant module umbrella. ## Include Policy diff --git a/docs/PrometheusLogger.md b/docs/PrometheusLogger.md index 47cf5ec..d742ccc 100644 --- a/docs/PrometheusLogger.md +++ b/docs/PrometheusLogger.md @@ -107,7 +107,7 @@ Use `PrometheusRegistry` with the `on_collect` callback to register application-specific metrics once and collect them on each scrape: ```cpp -#include +#include logit::PrometheusRegistry registry("myapp_"); diff --git a/include/logit_cpp/AGENTS.md b/include/logit_cpp/AGENTS.md index dd45f33..f7d4d8b 100644 --- a/include/logit_cpp/AGENTS.md +++ b/include/logit_cpp/AGENTS.md @@ -19,7 +19,8 @@ For subsystem-specific work, also read the nearest guide: `loggers.hpp`) in examples and integration tests. - Treat `` as the supported application entry point. Do not infer a standalone contract for `log_macros.hpp` or other aggregate-owned leaf - headers unless a focused public-header test documents it. + headers unless a focused public-header test documents it. Public aliases are + normally consumed through `` or the relevant module umbrella. - Preserve the existing public names, overloads, macro expansion contracts, and feature guards. Add new API only with a focused test and documentation. - Keep headers self-contained: include every standard type used directly and