diff --git a/Doxyfile b/Doxyfile index 4715b0d..2c871b0 100644 --- a/Doxyfile +++ b/Doxyfile @@ -962,7 +962,9 @@ INPUT = ./include \ ./docs/OtlpHttpLogger.md \ ./docs/PrometheusLogger.md \ ./docs/TaskExecutor.md \ - ./docs/backpressure.md + ./docs/backpressure.md \ + ./docs/future-plans.md \ + ./docs/adr # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/README-RU.md b/README-RU.md index 8a4ff05..a94128c 100644 --- a/README-RU.md +++ b/README-RU.md @@ -61,6 +61,8 @@ scope-замер. - [`docs/PrometheusLogger.md`](docs/PrometheusLogger.md) — payload/server-бэкенды, registry, scrape и ограничения. - [`docs/TaskExecutor.md`](docs/TaskExecutor.md) — варианты очереди, политики переполнения, hot resize и lifecycle. - [`docs/backpressure.md`](docs/backpressure.md) — настройка очереди и счётчики отброшенных задач. +- [`docs/future-plans.md`](docs/future-plans.md) — чеклист roadmap с разделением готовых, планируемых и отложенных задач. +- [`docs/adr/README.md`](docs/adr/README.md) — архитектурные решения, границы публичного API и записи о совместимости. ## Примеры макросов diff --git a/README.md b/README.md index f41aaa5..9553ac4 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,8 @@ Detailed guides and documentation map: - [`docs/PrometheusLogger.md`](docs/PrometheusLogger.md) — payload/server backends, registry metrics, scrape configuration, and limitations. - [`docs/TaskExecutor.md`](docs/TaskExecutor.md) — queue variants, overflow policies, hot resize, and lifecycle guarantees. - [`docs/backpressure.md`](docs/backpressure.md) — application-facing queue tuning and drop counters. +- [`docs/future-plans.md`](docs/future-plans.md) — checked roadmap separating delivered, planned, and deferred work. +- [`docs/adr/README.md`](docs/adr/README.md) — architecture decisions, public-boundary rationale, and compatibility records. ## Macro Examples diff --git a/docs/adr/0000-template.md b/docs/adr/0000-template.md new file mode 100644 index 0000000..42c08e0 --- /dev/null +++ b/docs/adr/0000-template.md @@ -0,0 +1,24 @@ +# ADR NNNN: Short decision title + +- Status: Proposed +- Date: YYYY-MM-DD + +## Context + +What problem, constraint, or repeated failure mode requires a decision? + +## Decision + +State the chosen approach and its public contract precisely. + +## Consequences + +Describe benefits, costs, compatibility impact, and operational trade-offs. + +## Alternatives considered + +List the credible alternatives and why they were not selected. + +## References + +Link the implementation, tests, documentation, issues, or superseding ADRs. diff --git a/docs/adr/0001-aggregate-first-public-headers.md b/docs/adr/0001-aggregate-first-public-headers.md new file mode 100644 index 0000000..2666675 --- /dev/null +++ b/docs/adr/0001-aggregate-first-public-headers.md @@ -0,0 +1,31 @@ +# ADR 0001: Aggregate-first public headers and API boundary + +- Status: Accepted +- Date: 2026-09-14 + +## Context + +The library has many historical leaf headers, including +`logit/log_macros.hpp`. Treating every header as independently includable made +include order accidental and made internal implementation details look public. + +## Decision + +`` is the supported application entry point. The module umbrellas +``, ``, and `` are +supported focused entry points. Leaf headers are standalone only when their +documentation and include-contract test explicitly say so. `logit/log_macros.hpp` +is an aggregate-owned implementation header and has no standalone-inclusion +guarantee. Public aliases, including `logit::QueuePolicy`, are consumed through +the umbrella or the relevant module umbrella. + +## Consequences + +The include contract is predictable and can evolve without promising every +historical file as an API boundary. Documentation and tests must use the +nearest supported umbrella, while implementation headers remain free to change. + +## Alternatives considered + +Making every leaf header self-contained would increase compile cost and freeze +implementation structure without adding value for normal application code. diff --git a/docs/adr/0002-async-executor-model.md b/docs/adr/0002-async-executor-model.md new file mode 100644 index 0000000..2884e75 --- /dev/null +++ b/docs/adr/0002-async-executor-model.md @@ -0,0 +1,25 @@ +# ADR 0002: Shared and dedicated asynchronous executors + +- Status: Accepted +- Date: 2026-09-14 + +## Context + +Using one shared asynchronous executor is efficient for the default case, but +a slow backend can delay unrelated backends. A separate worker per backend +improves isolation at the cost of a thread and queue per opted-in backend. + +## Decision + +The shared `TaskExecutor` remains the default. Backends that support it expose +`Config::use_dedicated_executor`; when enabled for an asynchronous backend, it +owns a `SingleThreadExecutor` with its own queue, policy, wait, and shutdown +lifecycle. Platform-specific backends that cannot provide this behavior keep +their documented limitations. + +## Consequences + +Applications can choose throughput/resource sharing or isolation per backend. +The feature is already tested for lifecycle, mixed shared/dedicated operation, +and macro configuration. Changing the default is a separate compatibility and +resource-usage decision. diff --git a/docs/adr/0003-immutable-registry-snapshots.md b/docs/adr/0003-immutable-registry-snapshots.md new file mode 100644 index 0000000..89d11a9 --- /dev/null +++ b/docs/adr/0003-immutable-registry-snapshots.md @@ -0,0 +1,25 @@ +# ADR 0003: Immutable logger registry snapshots + +- Status: Accepted +- Date: 2026-09-14 + +## Context + +Copying the mutable logger registry under a read lock on every log call made +the normal dispatch path pay synchronization and allocation costs. Logger +registry mutations and reconfiguration are infrequent compared with logging. + +## Decision + +Publish an immutable copy-on-write strategy-list snapshot on registry changes. +The hot path reads it with an atomic `shared_ptr` load. Mutable `enabled` and +`single_mode` state is atomic. The per-strategy execution mutex remains around +formatter/backend invocation because custom formatters and backends do not +have a universal concurrent-invocation contract. + +## Consequences + +Normal dispatch avoids the registry mutex and temporary vector copy while +preserving safe lifetime and mutation semantics. A future lock-elision path +requires an explicit capability contract and separate regression coverage; a +benchmark sink alone is not evidence that arbitrary backends are thread-safe. diff --git a/docs/adr/0004-timeshield-compatibility.md b/docs/adr/0004-timeshield-compatibility.md new file mode 100644 index 0000000..776f277 --- /dev/null +++ b/docs/adr/0004-timeshield-compatibility.md @@ -0,0 +1,25 @@ +# ADR 0004: TimeShield compatibility and dependency reuse + +- Status: Accepted +- Date: 2026-09-14 + +## Context + +The current TimeShield release is `v2.0.0`, whose CMake package uses +`SameMinorVersion` compatibility. Consumers may provide dependency targets +from a parent project or sibling build instead of installing another package +configuration. + +## Decision + +Pin the bundled submodule to the `v2.0.0` release and request +`TimeShield 2.0.0`, which expresses the supported `2.0.x` line. Before package +discovery, reuse an existing `time_shield::time_shield` target; installed +dependency discovery follows the same target-reuse rule for optional packages. + +## Consequences + +Build-tree and installed-package consumers remain composable, while the +minimum supported TimeShield API is explicit. Moving to another minor line or +changing the compatibility policy requires a new compatibility review and +release note. diff --git a/docs/adr/0005-benchmark-methodology.md b/docs/adr/0005-benchmark-methodology.md new file mode 100644 index 0000000..7205164 --- /dev/null +++ b/docs/adr/0005-benchmark-methodology.md @@ -0,0 +1,27 @@ +# ADR 0005: Benchmark evidence and comparison methodology + +- Status: Accepted +- Date: 2026-09-14 + +## Context + +Prepared records, the public macro path, formatted output, and external +library adapters measure different work. Mixing them into one number produces +misleading claims, and short CI runners are not a substitute for a fixed +publication machine. + +## Decision + +Keep separate scenarios for prepared-record dispatch, the real public +`LOGIT_INFO(...)` path, formatting, and external-library comparisons. The +public macro smoke benchmark may use a passthrough formatter when it is +explicitly documented as record-construction/dispatch coverage. Report +absolute timings only with compiler, platform, commit, queue, producer, and +flush settings; treat CI runs as regression smoke unless the environment is +fixed. + +## Consequences + +Benchmark documentation remains comparable and honest across changes. New +scenarios require their own workload contract and should not silently replace +historical measurements. diff --git a/docs/adr/README.md b/docs/adr/README.md new file mode 100644 index 0000000..71cb586 --- /dev/null +++ b/docs/adr/README.md @@ -0,0 +1,30 @@ +# Architecture Decision Records + +Architecture Decision Records (ADRs) capture decisions that should remain +discoverable after the implementation or the original discussion changes. +They complement the roadmap: the roadmap says **what is next**, while an ADR +explains **why the current boundary or trade-off exists**. + +## Statuses + +- **Proposed** — under discussion; do not treat it as a public contract. +- **Accepted** — the current implementation and documentation should follow it. +- **Superseded** — replaced by a newer ADR; retain it for historical context. +- **Rejected** — considered and intentionally not adopted. + +## Creating an ADR + +1. Copy [`0000-template.md`](0000-template.md) to the next zero-padded number. +2. Use a short, stable title and set the status/date. +3. Describe the context, decision, consequences, and rejected alternatives. +4. Update the implementation and user-facing documentation in the same change + when the decision changes a public contract. +5. Link a superseding ADR instead of rewriting an accepted historical record. + +## Accepted decisions + +- [0001 — Aggregate-first public headers and API boundary](0001-aggregate-first-public-headers.md) +- [0002 — Shared and dedicated asynchronous executors](0002-async-executor-model.md) +- [0003 — Immutable logger registry snapshots](0003-immutable-registry-snapshots.md) +- [0004 — TimeShield compatibility and dependency reuse](0004-timeshield-compatibility.md) +- [0005 — Benchmark evidence and comparison methodology](0005-benchmark-methodology.md) diff --git a/docs/future-plans.md b/docs/future-plans.md new file mode 100644 index 0000000..b1b895e --- /dev/null +++ b/docs/future-plans.md @@ -0,0 +1,81 @@ +# Roadmap and delivery checklist — LogIt++ + +This file is the maintained roadmap, not a changelog. It deliberately separates +delivered capabilities from planned work and from ideas that are intentionally +delegated to user-defined `ILogger` implementations. + +Legend: + +- `[x]` delivered and covered by code/docs/tests; +- `[~]` available, but opt-in or platform-limited; +- `[ ]` planned work; +- `[-]` intentionally deferred, with no current commitment to implement it in + the core library. + +## Delivered + +- [x] Public aggregate-first header policy: `` is the supported + application entry point; module umbrellas and leaf-header contracts are + documented. +- [x] Public `logit::QueuePolicy` API and queue policy macros. +- [x] Immutable copy-on-write logger registry snapshots on the production hot + path, with atomic logger state and the existing execution mutex retained for + formatter/backend safety. +- [~] Dedicated per-backend worker threads via + `Config::use_dedicated_executor=true`. The default remains the shared + `TaskExecutor`; unsupported platform backends keep their documented + limitations. +- [x] Queue capacity, overflow policies, drop counters, resize behavior, and + flush/shutdown coverage. +- [x] MDC/NDC context, structured records, stored-log readers/subscribers, and + runtime log-level controls. +- [x] TimeShield `2.0.x` compatibility (minimum `2.0.0`) and dependency-target + reuse for build-tree and installed-package consumers. +- [x] Benchmark methodology and regression infrastructure: prepared-record hot + path A/B, public `LOGIT_INFO(...)` smoke benchmark, queue/CSV validation, + delayed-sink flush regression, and CI coverage. +- [x] Doxygen generation, GitHub Pages publication, header/layout smoke tests, + and the comparison guide for spdlog, Quill, Boost.Log, glog, and IceCream-Cpp. + +## Next planned work + +- [ ] **Release 1.0.2** — prepare changelog/release notes, verify package + overlays, generate the non-`-dev` documentation, tag the release, and verify + the published Pages site. +- [ ] **Binary logging research** — choose a versioned binary record format, + define compatibility/versioning rules, and prototype a reader before adding + a production backend. +- [ ] **Transparent compressed-file reads** — make `read_log_file()` and + `read_log_files()` read `.gz`/`.zst` entries when the corresponding feature is + enabled, with platform-specific tests. +- [ ] **Configuration loading** — design a versioned JSON/properties mapping to + the existing backend configuration. Treat file watching/hot reload as a + follow-up, not part of the first configuration API. +- [ ] **Extended filtering** — evaluate source/file, message, tag/MDC, and + range filters; define their cost and ordering before adding public API. +- [ ] **Benchmark follow-up** — add a genuinely formatted public-macro scenario, + a versioned fixture containing compiler/toolchain/commit/queue/flush metadata, + and a broader 1/4/16/32-producer matrix. Keep publication numbers tied to a + fixed machine and toolchain. +- [ ] **Concurrency fast-path research** — only after documenting a formal + thread-safety capability for formatters/backends. Do not remove `exec_mx` + based on benchmark results alone. + +## Intentionally deferred + +- [-] **Database/SQLite appender** — currently better implemented as a custom + `ILogger`; revisit if a common portable schema and maintenance owner emerge. +- [-] **Telnet/TCP appender** — application-specific transport and access + policy; implement as a custom backend unless a supported protocol is agreed. +- [-] **Main-thread GUI appender** — event-loop integration is framework and + platform specific; revisit when LogIt++ ships a GUI viewer. + +## How to update this document + +Move an item to `[x]` only when the implementation, tests, and user-facing +documentation agree. Use an ADR in [`docs/adr`](https://github.com/LimiNode/log-it-cpp/tree/main/docs/adr) for architectural +decisions or compatibility changes; keep this file focused on status and next +steps. Record measurements with their environment instead of turning one local +run into a universal performance claim. + +Last reviewed: 2026-09-14. diff --git a/docs/mainpage.dox b/docs/mainpage.dox index 21366c5..cf6d5ad 100644 --- a/docs/mainpage.dox +++ b/docs/mainpage.dox @@ -31,6 +31,7 @@ int main() { - \ref benchmarks — benchmark methodology and historical snapshot. - \ref api_reference — detailed macro, formatting, configuration, and extension reference. - \ref comparison — comparison with other C++ logging libraries and trade-offs. +- Architecture decisions — the source repository's [`docs/adr/`](https://github.com/LimiNode/log-it-cpp/tree/main/docs/adr) records the rationale for public boundaries, executors, snapshots, and compatibility. \section feature_summary Feature summary diff --git a/docs/quickstart.md b/docs/quickstart.md index d238f35..2075768 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -40,6 +40,11 @@ dependency requirements are described in the [`Backend matrix`](backends.html). the historical snapshot disclaimer. - **Choosing a logging library** — [`Comparison with other C++ logging libraries`](comparison.html), including trade-offs and the scope of the comparison. +- **Architecture decisions** — [`Architecture Decision Records`](https://github.com/LimiNode/log-it-cpp/tree/main/docs/adr), + including public API boundaries, executor ownership, snapshots, and + dependency compatibility. +- **Roadmap** — [`delivery checklist`](https://github.com/LimiNode/log-it-cpp/blob/main/docs/future-plans.md), + separating delivered, planned, and intentionally deferred work. - **Examples** — browse the `examples/` directory in the source repository; each optional example states the feature macro it requires.