Define cached threshold behavior for isEnabled

Document and test explicit refresh boundaries for isEnabled guards, and
only read the shared root threshold when no namespace threshold applies.
Include the portable Nimble configuration loader.
This commit is contained in:
jdb committed 2026-09-29 08:43:31 -05:00
1 parent 14e71c72ca
commit 011780e6ab
5 files changed
+88 -10

No files matched your search

+31 -4
View File
@@ -76,6 +76,33 @@ proc configureLogging(localLogSvc: ThreadLocalLogService, verbose: bool) =
# Changes automatically propagate to all threads
```
### Avoiding Expensive Log Preparation
Use `isEnabled` to guard expensive work performed before a logging call:
```nim
if logger.isEnabled(lvlDebug):
let details = buildExpensiveDetails()
logger.debug(details)
```
`isEnabled` checks the logger's effective threshold without refreshing its
configuration. It uses cached namespace thresholds and the shared root fallback
level. Namespace changes can remain unseen until the local service refreshes.
Normal logging calls and `getLogger` refresh the cache; callers can also use
`ensureFreshness(localLogSvc)` explicitly.
If all logging is guarded by `isEnabled`, a cached disabled level can keep
skipping those logging calls indefinitely. To pick up runtime namespace changes
in that situation, refresh the local service at suitable application boundaries,
such as the start of a request or work batch.
A true result does not guarantee delivery: the logging call refreshes
configuration and appenders apply their own filters. For a single expression,
`logger.debug(buildExpensiveDetails())` already delays evaluation until the
logger's threshold permits the message. A separate guard is useful when
preparation requires multiple statements.
## Loggers and Appenders
The logging system is composed of two main components: loggers and appenders.
@@ -310,13 +337,13 @@ No explicit flush or delay is needed after joining the threads that log.
You can change logging configuration through a service copy or a local service
in any thread. Those changes are intended to take effect automatically on
subsequent logging calls in every thread using that service, without recreating
loggers or configuring each worker separately.
loggers or configuring each worker separately. `isEnabled` intentionally does
not refresh configuration; see [Avoiding Expensive Log Preparation](#avoiding-expensive-log-preparation).
> [!NOTE]
> Thread-safety work is still in progress. Custom state and captured
> formatters must follow the ownership rules above. Standalone `isEnabled()`
> checks do not yet notice changed namespace thresholds, and concurrent
> local-time timestamp construction still has a known failure.
> formatters must follow the ownership rules above. Concurrent local-time
> timestamp construction still has a known failure.
> Nim 2.2.10 also produces sanitizer reports in its default allocator
> during some cross-thread allocation patterns. See
> [the regression tests](tests/README.md) for the remaining work.