You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(logging): add telemetry registry and context examples
* feat(prometheus): expose scrape counters and collect duration
Add four built-in metrics to PrometheusHttpServerLogger so operators
can observe scrape health and collection latency:
- logit_prometheus_scrapes_total (counter)
- logit_prometheus_scrape_errors_total (counter)
- logit_prometheus_last_scrape_timestamp_ms (gauge)
- logit_prometheus_collect_duration_seconds (gauge)
Scrapes are counted in the HTTP handler before collect_payload().
Collection duration is measured inside collect_payload() using
steady_clock. Failed scrapes (exceptions from collect_payload())
increment scrape_errors_total.
All scrape metrics carry the logger="prometheus_http_server" label
for consistency with existing built-in families.
Not-tested: scrape_errors_total > 0 (requires an exception during
collect_payload, which is hard to trigger deterministically in the
current test setup).
Co-Authored-By: Claude Opus 4.7 <[email protected]>
* feat(logging): add telemetry registry and context examples
Add PrometheusRegistry for declarative custom application metrics and wire it into Prometheus examples and docs.
Add MDC/NDC context support based on the existing local LogContext design, including formatter tokens and coverage.
Fix OTLP graceful-shutdown worker wakeups and add zstd compression integration coverage.
* fix(context): make MDC and NDC opt-in
Add LOGIT_WITH_CONTEXT so diagnostic context support does not affect the default logging hot path.
Store context as an optional shared snapshot only when the thread context is non-empty, and keep ASan builds away from intentionally leaked thread-local storage.
* fix(prometheus): honor scrape metric label config
Apply PrometheusTextFormatConfig logger and instance label settings to PrometheusHttpServerLogger scrape diagnostics.
Add coverage for custom logger label names, instance labels, and disabled logger labels on scrape metrics.
* fix(prometheus): keep collecting healthy registry metrics
Continue collecting PrometheusRegistry entries after a value callback throws, append successfully collected samples, and then rethrow the first exception so Prometheus loggers still count the collection failure.
Update registry coverage and docs for the partial-success behavior.
---------
Co-authored-by: Claude Opus 4.7 <[email protected]>
Copy file name to clipboardExpand all lines: README.md
+53-1Lines changed: 53 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -46,6 +46,13 @@ Internal headers under `logit/detail/` are private implementation details and sh
46
46
47
47
See the macro examples below or browse the `examples/` folder for focused demonstrations, including queue tuning and crash handling.
48
48
49
+
Recent focused examples include:
50
+
51
+
-`examples/example_logit_otlp_http.cpp` - OTLP/HTTP export with batching, retries, optional compression, and contextual trace/span fields.
52
+
-`examples/example_logit_prometheus_payload.cpp` - callback-based Prometheus payload emission with custom registry metrics.
53
+
-`examples/example_logit_prometheus_server.cpp` - embedded `/metrics` endpoint with built-in and application metrics.
54
+
-`examples/example_logit_mdc_ndc.cpp` - mapped and nested diagnostic context across scopes and threads.
55
+
49
56
## Macro Examples
50
57
51
58
### Long-form macros
@@ -100,6 +107,41 @@ void short_names_demo() {
100
107
101
108
For a standalone program that brings everything together and intentionally aborts after logging a fatal message, check `examples/example_logit_minimal_crash.cpp`.
102
109
110
+
### Diagnostic context
111
+
112
+
Mapped diagnostic context (MDC) stores thread-local key-value pairs, while nested
113
+
diagnostic context (NDC) stores a thread-local stack of scope names. The context
114
+
is available when the library is configured with `-DLOGIT_WITH_CONTEXT=ON`.
115
+
When this option is off, `LogRecord` keeps the original hot-path shape and the
116
+
context macros become no-ops.
117
+
118
+
With context enabled, a `LogRecord` captures a shared snapshot only when the
119
+
current thread has non-empty MDC or NDC values.
120
+
121
+
```cpp
122
+
#include<logit.hpp>
123
+
124
+
intmain() {
125
+
LOGIT_ADD_LOGGER(
126
+
logit::ConsoleLogger, (),
127
+
logit::SimpleLogFormatter,
128
+
("[%T] request=%K{request_id} ndc=[%J] %v")
129
+
);
130
+
131
+
LOGIT_MDC_PUT("request_id", "req-42");
132
+
LOGIT_NDC_PUSH("checkout");
133
+
134
+
{
135
+
LOGIT_NDC_GUARD("payment");
136
+
LOGIT_INFO("charge started");
137
+
}
138
+
139
+
LOGIT_MDC_CLEAR();
140
+
LOGIT_NDC_CLEAR();
141
+
LOGIT_WAIT();
142
+
}
143
+
```
144
+
103
145
### System error helpers
104
146
105
147
`LOGIT_SYSERR_<LEVEL>` captures the current `errno` (or `GetLastError()` on Windows) and appends the decoded information to the message, so failure details stay attached to the original context. The lower-level `LOGIT_PERROR_<LEVEL>` and `LOGIT_WINERR_<LEVEL>` families are also available if you want to explicitly choose the platform macro.
@@ -521,6 +563,12 @@ Below is a list of supported formatting flags:
521
563
-*Thread Flags*:
522
564
523
565
-`%t`: Thread identifier
566
+
567
+
-*Diagnostic Context Flags*:
568
+
569
+
-`%K`: All mapped diagnostic context values as `key=value` pairs
570
+
-`%K{key}`: One mapped diagnostic context value by key
571
+
-`%J`: Nested diagnostic context stack
524
572
525
573
-*Color Flags*:
526
574
@@ -775,6 +823,8 @@ public:
775
823
|`LOGIT_<LEVEL>_EVERY_N(n, ...)`| Log on every `n`th invocation. |
776
824
|`LOGIT_<LEVEL>_THROTTLE(period_ms, ...)`| Log at most once per `period_ms` milliseconds. |
777
825
|`LOGIT_<LEVEL>_TAG(({{"k", "v"}}), msg)`| Attach key-value tags to a message. |
826
+
|`LOGIT_MDC_PUT(key, value)`, `LOGIT_MDC_REMOVE(key)`, `LOGIT_MDC_CLEAR()`| Manage thread-local mapped diagnostic context when `LOGIT_WITH_CONTEXT` is enabled. |
827
+
|`LOGIT_NDC_PUSH(value)`, `LOGIT_NDC_POP()`, `LOGIT_NDC_CLEAR()`, `LOGIT_NDC_GUARD(value)`| Manage thread-local nested diagnostic context when `LOGIT_WITH_CONTEXT` is enabled. |
778
828
|`LOGIT_RAW(msg)`, `LOGIT_RAW_TO(index, msg)`, `LOGIT_RAW_IF(condition, msg)`| Write already formatted text without applying level filters or formatter patterns. |
779
829
|`LOGIT_SECTION(name)`, `LOGIT_SECTION_TO(index, name)`, `LOGIT_SECTION_IF(condition, name)`| Write raw section headers such as `[Proxy]`. |
780
830
|`LOGIT_<LEVEL>_TO(index, ...)`| Target a specific logger index, including single-mode backends. |
@@ -879,7 +929,9 @@ The following toggles cover all build-time features:
879
929
-`LOGIT_CPP_BUILD_EXAMPLES` (default: OFF) — build the example programs.
880
930
-`LOGIT_BENCH_ENABLE` (default: OFF) — build benchmarks; `LOGIT_BENCH_WITH_SPDLOG` (default: OFF) also builds the spdlog comparisons.
881
931
-`LOGIT_WITH_GZIP` / `LOGIT_WITH_ZSTD` (defaults: OFF) — enable gzip or zstd support for rotated files.
882
-
-`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.
932
+
-`LOGIT_WITH_FMT` (default: OFF) — include the `{}`-style formatting macros.
0 commit comments