📝 refine library logger wrapper methods

This commit is contained in:
Nanaloveyuki
2026-06-14 01:16:36 +08:00
parent 3a68be920e
commit 15a9175cf4
4 changed files with 39 additions and 11 deletions
+12 -3
View File
@@ -3,7 +3,7 @@ name: library-logger-bind
group: api group: api
category: facade category: facade
update-time: 20260613 update-time: 20260613
description: Attach reusable structured fields to a LibraryLogger facade through the bind alias. description: Attach reusable structured fields to a LibraryLogger facade through the bind alias while extending the visible sink type to ContextSink.
key-word: key-word:
- library - library
- facade - facade
@@ -38,8 +38,11 @@ pub fn[S] LibraryLogger::bind(
Detailed rules explaining key parameters and behaviors Detailed rules explaining key parameters and behaviors
- `bind(...)` delegates directly to `with_context_fields(...)`. - `bind(...)` delegates directly to `with_context_fields(...)`.
- The original facade value is not mutated; a wrapped facade is returned.
- Shared fields are applied to every later log call emitted through the returned facade. - Shared fields are applied to every later log call emitted through the returned facade.
- The returned facade changes visible type from `LibraryLogger[S]` to `LibraryLogger[ContextSink[S]]` because the sink pipeline is extended with context-field merging behavior.
- Minimum level, target, and timestamp behavior are preserved while the sink pipeline changes.
- Broader composition helpers remain hidden behind the narrower facade after rewrapping; use `to_logger()` if later code needs them.
- The original facade value is not mutated; a wrapped facade is returned.
- This alias is useful when you prefer shorter chaining syntax in library code. - This alias is useful when you prefer shorter chaining syntax in library code.
### How to Use ### How to Use
@@ -68,15 +71,21 @@ let worker = LibraryLogger::new(console_sink(), target="app")
In this example, `bind(...)` communicates intent without changing underlying behavior. In this example, `bind(...)` communicates intent without changing underlying behavior.
And because it is only an alias, the resulting facade behaves the same as calling `with_context_fields(...)` directly.
### Error Case ### Error Case
e.g.: e.g.:
- If `fields` is empty, the returned facade remains valid and simply adds no extra metadata. - If `fields` is empty, the returned facade remains valid and simply stores an empty shared field set in `ContextSink[S]`.
- If duplicate field keys are bound, all copies are preserved for downstream formatting or inspection. - If duplicate field keys are bound, all copies are preserved for downstream formatting or inspection.
- If callers want event-specific fields without changing the shared bound set, they should pass those through `log(..., fields=...)` on the returned facade.
### Notes ### Notes
1. Use `bind(...)` and `with_context_fields(...)` interchangeably; choose the one that reads better in context. 1. Use `bind(...)` and `with_context_fields(...)` interchangeably; choose the one that reads better in context.
2. This alias exists for ergonomics, not for different semantics. 2. This alias exists for ergonomics, not for different semantics.
3. Use `with_context_fields(...)` when the longer name makes the shared-field sink-type change clearer at the call site.
+7 -1
View File
@@ -3,7 +3,7 @@ name: library-logger-child
group: api group: api
category: facade category: facade
update-time: 20260613 update-time: 20260613
description: Derive a child LibraryLogger facade by composing the current target with a child segment. description: Derive a child LibraryLogger facade by composing the current target with a child segment while rewrapping the same underlying logger state.
key-word: key-word:
- library - library
- facade - facade
@@ -38,6 +38,8 @@ Detailed rules explaining key parameters and behaviors
- If the parent target is empty, the child target becomes the full target. - If the parent target is empty, the child target becomes the full target.
- If the child target is empty, the parent target is preserved. - If the child target is empty, the parent target is preserved.
- If both are non-empty, they are joined with `.`. - If both are non-empty, they are joined with `.`.
- Sink type, minimum level, timestamp behavior, and any existing sink wrappers remain the same because only the derived target changes.
- Broader composition helpers remain hidden behind the narrower facade after rewrapping; use `to_logger()` if later code needs them.
### How to Use ### How to Use
@@ -65,6 +67,8 @@ let client = LibraryLogger::new(console_sink(), target="sdk")
In this example, the final facade emits under `sdk.http.client`. In this example, the final facade emits under `sdk.http.client`.
And the target derivation does not rebuild or reset the wrapped logger pipeline.
### Error Case ### Error Case
e.g.: e.g.:
@@ -77,3 +81,5 @@ e.g.:
1. This is the preferred library-facing API for hierarchical target naming. 1. This is the preferred library-facing API for hierarchical target naming.
2. Composition uses `.` as the separator between parent and child segments. 2. Composition uses `.` as the separator between parent and child segments.
3. Use `with_target(...)` instead when the new target should replace the current target rather than extend it.
+13 -5
View File
@@ -3,7 +3,7 @@ name: library-logger-with-context-fields
group: api group: api
category: facade category: facade
update-time: 20260613 update-time: 20260613
description: Attach reusable structured fields to a LibraryLogger facade. description: Attach reusable structured fields to a LibraryLogger facade while extending the visible sink type to ContextSink.
key-word: key-word:
- library - library
- facade - facade
@@ -27,7 +27,7 @@ pub fn[S] LibraryLogger::with_context_fields(
#### input #### input
- `self : LibraryLogger[S]` - Base facade that should gain shared fields. - `self : LibraryLogger[S]` - Base facade that should gain shared fields.
- `fields : Array[Field]` - Structured fields that will be prepended to each emitted record. - `fields : Array[Field]` - Structured fields stored in the added `ContextSink` and prepended to each emitted record.
#### output #### output
@@ -39,7 +39,9 @@ Detailed rules explaining key parameters and behaviors
- This API delegates to the wrapped logger's `with_context_fields(...)` behavior and then narrows the result back to `LibraryLogger`. - This API delegates to the wrapped logger's `with_context_fields(...)` behavior and then narrows the result back to `LibraryLogger`.
- Context fields are merged at write time rather than by mutating previously created records. - Context fields are merged at write time rather than by mutating previously created records.
- The returned facade carries `ContextSink[S]` because the sink pipeline has been extended. - The returned facade carries `ContextSink[S]` because the sink pipeline is extended around the previous sink instead of keeping the original visible sink type `S`.
- Minimum level, target, and timestamp behavior are preserved while the sink pipeline changes from `S` to `ContextSink[S]`.
- Broader composition helpers remain hidden behind the narrower facade after rewrapping; use `to_logger()` if later code needs them.
- `bind(...)` is an ergonomic alias for this same behavior. - `bind(...)` is an ergonomic alias for this same behavior.
### How to Use ### How to Use
@@ -68,15 +70,21 @@ let worker = LibraryLogger::new(console_sink(), target="sdk")
In this example, target composition and field binding stay separate but compose cleanly. In this example, target composition and field binding stay separate but compose cleanly.
And the returned facade keeps the same logger configuration while exposing the widened sink type `ContextSink[S]`.
### Error Case ### Error Case
e.g.: e.g.:
- If `fields` is empty, the returned facade remains valid and simply adds no extra metadata. - If `fields` is empty, the returned facade remains valid and simply stores an empty shared field set inside `ContextSink[S]`.
- If duplicate field keys are provided, all fields are still emitted for downstream formatting or inspection. - If duplicate field keys are provided, all fields are still emitted for downstream formatting or inspection.
- If callers want event-specific fields without changing the shared bound set, they should pass those through `log(..., fields=...)` on the returned facade.
### Notes ### Notes
1. Use this for stable shared metadata, not highly dynamic event-specific values. 1. Use this for stable shared metadata, not highly dynamic event-specific values.
2. The narrower `LibraryLogger` surface is preserved after context binding. 2. The narrower `LibraryLogger` surface is preserved after context binding, even though the visible sink type changes to `ContextSink[S]`.
3. Use `bind(...)` when the shorter alias reads better in chained library code.
+7 -2
View File
@@ -3,7 +3,7 @@ name: library-logger-with-target
group: api group: api
category: facade category: facade
update-time: 20260613 update-time: 20260613
description: Replace the default target carried by a LibraryLogger facade. description: Replace the default target carried by a LibraryLogger facade while rewrapping the same underlying logger state.
key-word: key-word:
- library - library
- facade - facade
@@ -35,8 +35,9 @@ pub fn[S] LibraryLogger::with_target(self : LibraryLogger[S], target : String) -
Detailed rules explaining key parameters and behaviors Detailed rules explaining key parameters and behaviors
- This API delegates to the wrapped logger's `with_target(...)` behavior and then re-wraps the result. - This API delegates to the wrapped logger's `with_target(...)` behavior and then re-wraps the result.
- The returned value keeps the same sink type and minimum level settings. - The returned value keeps the same sink type, minimum level, timestamp behavior, and any existing sink wrappers because only the default target field changes.
- This replaces the default target instead of composing it. - This replaces the default target instead of composing it.
- Broader composition helpers remain hidden behind the narrower facade after rewrapping; use `to_logger()` if later code needs them.
- The original facade value is not mutated. - The original facade value is not mutated.
### How to Use ### How to Use
@@ -64,6 +65,8 @@ let io = base.with_target("io")
In this example, one base facade becomes several target-specific facades. In this example, one base facade becomes several target-specific facades.
And each derived facade still wraps the same logger pipeline, differing only in the default target it carries.
### Error Case ### Error Case
e.g.: e.g.:
@@ -76,3 +79,5 @@ e.g.:
1. Use this API for replacement, not target-path composition. 1. Use this API for replacement, not target-path composition.
2. It keeps the narrower `LibraryLogger` boundary intact. 2. It keeps the narrower `LibraryLogger` boundary intact.
3. Use `child(...)` when the new target should be combined with the current one instead of replacing it.