📝 refine library async wrapper methods

This commit is contained in:
Nanaloveyuki
2026-06-14 01:08:21 +08:00
parent 3d88ac87a1
commit be8b4f8626
4 changed files with 39 additions and 10 deletions
+12 -3
View File
@@ -3,7 +3,7 @@ name: library-async-logger-bind
group: api group: api
category: facade category: facade
update-time: 20260613 update-time: 20260613
description: Attach reusable structured fields to a LibraryAsyncLogger facade through the bind alias. description: Attach reusable structured fields to a LibraryAsyncLogger facade through the bind alias while preserving the same underlying async logger state.
key-word: key-word:
- async - async
- library - library
@@ -38,8 +38,11 @@ pub fn[S] LibraryAsyncLogger::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(...)`.
- That means the provided `fields` array replaces the previously stored shared field set on the wrapped async logger.
- Shared fields are then prepended to every later log call emitted through the returned facade.
- Sink type, queue state, async config, and failure/lifecycle state remain the same because the method only rewraps the updated async logger value.
- Async state helpers remain hidden behind the narrower facade after rewrapping; use `to_async_logger()` if later code needs them.
- The original facade value is not mutated; a wrapped facade is returned. - 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.
- This alias is useful when you prefer shorter chaining syntax in library async code. - This alias is useful when you prefer shorter chaining syntax in library async code.
### How to Use ### How to Use
@@ -68,15 +71,21 @@ let worker = LibraryAsyncLogger::new(@bitlogger.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.
- 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 replacing 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 replacement behavior clearer at the call site.
+7 -1
View File
@@ -3,7 +3,7 @@ name: library-async-logger-child
group: api group: api
category: facade category: facade
update-time: 20260613 update-time: 20260613
description: Derive a child LibraryAsyncLogger facade by composing the current target with a child segment. description: Derive a child LibraryAsyncLogger facade by composing the current target with a child segment while rewrapping the same underlying async logger state.
key-word: key-word:
- async - async
- library - library
@@ -41,6 +41,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, queue state, async config, and failure/lifecycle state remain the same because only the derived default target changes.
- Async state helpers remain hidden behind the narrower facade after rewrapping; use `to_async_logger()` if later code needs them.
### How to Use ### How to Use
@@ -68,6 +70,8 @@ let client = LibraryAsyncLogger::new(@bitlogger.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 async logger state.
### Error Case ### Error Case
e.g.: e.g.:
@@ -80,3 +84,5 @@ e.g.:
1. This is the preferred library-facing API for hierarchical async target naming. 1. This is the preferred library-facing API for hierarchical async target naming.
2. Composition changes the target only and does not rebuild the queue or sink. 2. Composition changes the target only and does not rebuild the queue or sink.
3. Use `with_target(...)` instead when the new target should replace the current target rather than extend it.
@@ -3,7 +3,7 @@ name: library-async-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 LibraryAsyncLogger facade. description: Attach reusable structured fields to a LibraryAsyncLogger facade while rewrapping the same underlying async logger state.
key-word: key-word:
- async - async
- library - library
@@ -27,7 +27,7 @@ pub fn[S] LibraryAsyncLogger::with_context_fields(
#### input #### input
- `self : LibraryAsyncLogger[S]` - Base facade that should gain shared fields. - `self : LibraryAsyncLogger[S]` - Base facade that should gain shared fields.
- `fields : Array[@bitlogger.Field]` - Structured fields that will be prepended to each emitted record. - `fields : Array[@bitlogger.Field]` - Structured fields stored on the facade and prepended to each emitted record.
#### output #### output
@@ -38,8 +38,11 @@ pub fn[S] LibraryAsyncLogger::with_context_fields(
Detailed rules explaining key parameters and behaviors Detailed rules explaining key parameters and behaviors
- This API delegates to the wrapped async logger's `with_context_fields(...)` behavior and then narrows the result back to `LibraryAsyncLogger`. - This API delegates to the wrapped async logger's `with_context_fields(...)` behavior and then narrows the result back to `LibraryAsyncLogger`.
- Context fields are merged during `log(...)` before enqueue. - The provided `fields` array replaces the previously stored shared context field set on the wrapped async logger.
- During later `log(...)` calls, those stored shared fields are prepended ahead of per-call fields before enqueue.
- Sink type, queue state, async config, and failure/lifecycle state remain the same because only the stored shared field set changes.
- Unlike synchronous `LibraryLogger::with_context_fields(...)`, this async variant preserves the visible `LibraryAsyncLogger[S]` type instead of changing the visible sink type. - Unlike synchronous `LibraryLogger::with_context_fields(...)`, this async variant preserves the visible `LibraryAsyncLogger[S]` type instead of changing the visible sink type.
- Async state helpers remain hidden behind the narrower facade after rewrapping; use `to_async_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
@@ -71,15 +74,21 @@ let worker = LibraryAsyncLogger::new(@bitlogger.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 underlying async runtime state while carrying a different shared field set.
### 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.
- 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 to add event-specific fields without replacing the shared 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 `LibraryAsyncLogger` surface is preserved after field binding. 2. The narrower `LibraryAsyncLogger` surface is preserved after field binding.
3. Use `bind(...)` when the shorter alias reads better in chained library code.
+7 -2
View File
@@ -3,7 +3,7 @@ name: library-async-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 LibraryAsyncLogger facade. description: Replace the default target carried by a LibraryAsyncLogger facade while rewrapping the same underlying async logger state.
key-word: key-word:
- async - async
- library - library
@@ -38,8 +38,9 @@ pub fn[S] LibraryAsyncLogger::with_target(
Detailed rules explaining key parameters and behaviors Detailed rules explaining key parameters and behaviors
- This API delegates to the wrapped async logger's `with_target(...)` behavior and then re-wraps the result. - This API delegates to the wrapped async logger's `with_target(...)` behavior and then re-wraps the result.
- The returned value keeps the same queue state, sink type, and async config. - The returned value keeps the same sink type, queue state, async config, and failure/lifecycle state 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.
- Async state helpers remain hidden behind the narrower facade after rewrapping; use `to_async_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
@@ -70,6 +71,8 @@ let io = base.with_target("io")
In this example, one base facade becomes several target-specific async facades. In this example, one base facade becomes several target-specific async facades.
And each derived facade still wraps the same kind of queue-backed async logger state, differing only in the default target it carries.
### Error Case ### Error Case
e.g.: e.g.:
@@ -82,3 +85,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 `LibraryAsyncLogger` boundary intact. 2. It keeps the narrower `LibraryAsyncLogger` boundary intact.
3. Use `child(...)` when the new target should be combined with the current one instead of replacing it.