mirror of
https://github.com/Nanaloveyuki/BitLogger.git
synced 2026-07-24 00:42:18 +00:00
📝 clarify root context shape contrast
This commit is contained in:
@@ -47,6 +47,7 @@ Detailed rules explaining key parameters and behaviors
|
||||
- `async_logger(...)` returns the full `AsyncLogger[S]` surface directly. It is therefore the underlying constructor used by both application-facing async aliases and the narrower `LibraryAsyncLogger[S]` wrapper line.
|
||||
- The constructed logger starts with `is_closed=false`, `is_running=false`, `has_failed=false`, `last_error=""`, and zeroed pending/dropped counters.
|
||||
- The constructed logger also keeps the core async target contract unchanged: `log(..., target=...)` can override the target for one call, while fixed-level helpers such as `info(...)`, `warn(...)`, and `error(...)` continue using the stored logger target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
- Unlike synchronous `Logger`, async `with_context_fields(...)` and `bind(...)` preserve the visible `AsyncLogger[S]` type because shared fields are stored directly on the async logger value instead of being modeled as a separate sink wrapper.
|
||||
- `ApplicationAsyncLogger` and `ApplicationTextAsyncLogger` are only alias names over concrete `AsyncLogger[...]` shapes, so they keep the same lifecycle, queue, failure, and state helpers without adding a wrapper layer.
|
||||
- `LibraryAsyncLogger[S]` wraps an `AsyncLogger[S]` value instead of aliasing it. That library facade preserves queue-backed logging behavior, but it narrows the directly exposed helper surface until callers recover the full logger with `to_async_logger()`.
|
||||
- In non-native targets, the implementation uses compatibility behavior while keeping the same public surface.
|
||||
@@ -88,6 +89,17 @@ In this example, the emitted record uses `app.async.audit` only for that one cal
|
||||
|
||||
And later `info(...)`, `warn(...)`, or `error(...)` calls still use the logger's stored target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
|
||||
#### When Need Shared Context On A Root Async Logger
|
||||
|
||||
When async code should attach stable metadata to later queued records:
|
||||
```moonbit
|
||||
let contextual = logger.with_context_fields([@bitlogger.field("service", "billing")])
|
||||
```
|
||||
|
||||
In this example, the returned value still has the visible type `AsyncLogger[S]`.
|
||||
|
||||
And that shape preservation is intentional because async context binding updates stored logger metadata instead of changing the exposed sink type.
|
||||
|
||||
#### When Need Configurable Overflow And Flush Behavior
|
||||
|
||||
When queue semantics matter for service durability and load:
|
||||
|
||||
@@ -38,6 +38,7 @@ Detailed rules explaining key parameters and behaviors
|
||||
- The current fields are `min_level : Level`, `sink : S`, `target : String`, and `timestamp : Bool`.
|
||||
- The sink type parameter is preserved across composition, which is why helpers such as `with_context_fields(...)`, `with_filter(...)`, `with_patch(...)`, and `with_queue(...)` can return more specific logger shapes.
|
||||
- The root logger also preserves the core target contract used across the sync API surface: `log(..., target=...)` can override the target for one call, while fixed-level helpers such as `trace(...)`, `debug(...)`, `info(...)`, `warn(...)`, and `error(...)` continue using the stored logger target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
- In particular, synchronous `with_context_fields(...)` and `bind(...)` change the visible logger type to `Logger[ContextSink[S]]` because shared fields are implemented by extending the sink pipeline rather than by storing extra root-level context metadata on `Logger[S]` itself.
|
||||
- `Logger::new(...)` constructs this type as the main synchronous entry point.
|
||||
- This root type is also what sits underneath both facade families: `ApplicationLogger` is a direct alias over the configured `Logger[RuntimeSink]` line, while `LibraryLogger[S]` is a narrowing wrapper around a `Logger[S]` value.
|
||||
|
||||
@@ -65,6 +66,17 @@ In this example, the emitted record uses `app.audit` only for that one call.
|
||||
|
||||
And later `trace(...)`, `debug(...)`, `info(...)`, `warn(...)`, or `error(...)` calls still use the logger's stored target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
|
||||
#### When Need Shared Context On A Sync Root Logger
|
||||
|
||||
When sync code should attach stable metadata to later records:
|
||||
```moonbit
|
||||
let contextual = logger.with_context_fields([field("service", "billing")])
|
||||
```
|
||||
|
||||
In this example, the returned value has the visible type `Logger[ContextSink[S]]`.
|
||||
|
||||
And that type change is expected because sync context binding extends the sink pipeline instead of only updating root-level metadata.
|
||||
|
||||
#### When Need To Build A Composed Logging Pipeline
|
||||
|
||||
When code should start from one root logger and then derive more specific wrapped forms:
|
||||
|
||||
Reference in New Issue
Block a user