📝 clarify sync alias target behavior

This commit is contained in:
Nanaloveyuki
2026-06-14 08:35:46 +08:00
parent 44903d113d
commit d777496d51
3 changed files with 38 additions and 2 deletions
+13 -1
View File
@@ -32,6 +32,7 @@ Detailed rules explaining key parameters and behaviors
- This alias does not introduce a new runtime type or wrapper layer. - This alias does not introduce a new runtime type or wrapper layer.
- It preserves the same logging, queue, and file helper APIs exposed by `ConfiguredLogger`. - It preserves the same logging, queue, and file helper APIs exposed by `ConfiguredLogger`.
- Because `ConfiguredLogger` is itself `Logger[RuntimeSink]`, the alias also keeps ordinary logger composition and write behavior such as `with_target(...)`, `child(...)`, and `log(..., target=...)`. - Because `ConfiguredLogger` is itself `Logger[RuntimeSink]`, the alias also keeps ordinary logger composition and write behavior such as `with_target(...)`, `child(...)`, and `log(..., target=...)`.
- In particular, `log(..., target=...)` can override the target for one call, while severity helpers such as `info(...)`, `warn(...)`, and `error(...)` continue using the stored logger target unless code derives another logger first with `with_target(...)` or `child(...)`.
- Because this is only an alias, the application-facing type does not hide any configured-runtime helpers or broader logger surface. - Because this is only an alias, the application-facing type does not hide any configured-runtime helpers or broader logger surface.
- The alias exists to give application boot code a clearer public entry name. - The alias exists to give application boot code a clearer public entry name.
- Builders such as `build_application_logger(...)` and `parse_and_build_application_logger(...)` return this alias. - Builders such as `build_application_logger(...)` and `parse_and_build_application_logger(...)` return this alias.
@@ -62,7 +63,18 @@ In this example, callers see the app-facing alias instead of the lower-level `Co
And the same queue/file/runtime helpers remain directly callable because no narrowing wrapper is added. And the same queue/file/runtime helpers remain directly callable because no narrowing wrapper is added.
And the inherited logger target rules stay the same: `log(..., target=...)` can override the target per call, while `with_target(...)` and `child(...)` derive new logger values with changed default targets. And the inherited logger target rules stay the same: `log(..., target=...)` can override the target per call, while `info(...)`, `warn(...)`, and `error(...)` continue using the stored target unless code derives another logger first with `with_target(...)` or `child(...)`.
#### When Need A One-call Target Override Without Rebuilding The Alias
When app-level sync code should keep the same alias value but emit one record under a different target:
```moonbit
logger.log(Level::Error, "boom", target="app.audit")
```
In this example, the emitted record uses `app.audit` only for that one call.
And later `info(...)`, `warn(...)`, or `error(...)` calls still use the alias value's stored target unless code derives another logger first with `with_target(...)` or `child(...)`.
### Error Case ### Error Case
+13 -1
View File
@@ -32,6 +32,7 @@ Detailed rules explaining key parameters and behaviors
- This is a type alias, not a separate wrapper implementation. - This is a type alias, not a separate wrapper implementation.
- It preserves normal logger methods such as `info(...)`, `warn(...)`, `error(...)`, and the other `Logger` APIs. - It preserves normal logger methods such as `info(...)`, `warn(...)`, `error(...)`, and the other `Logger` APIs.
- Because it is `Logger[RuntimeSink]`, it also keeps ordinary logger composition and target behavior such as `with_target(...)`, `child(...)`, and per-call `log(..., target=...)` overrides. - Because it is `Logger[RuntimeSink]`, it also keeps ordinary logger composition and target behavior such as `with_target(...)`, `child(...)`, and per-call `log(..., target=...)` overrides.
- In particular, `log(..., target=...)` can override the target for one call, while severity helpers such as `info(...)`, `warn(...)`, and `error(...)` continue using the stored logger target unless code derives another logger first with `with_target(...)` or `child(...)`.
- It also exposes configured runtime helpers such as `flush()`, `drain()`, `pending_count()`, `dropped_count()`, and file-specific controls when the runtime sink supports them. - It also exposes configured runtime helpers such as `flush()`, `drain()`, `pending_count()`, `dropped_count()`, and file-specific controls when the runtime sink supports them.
- Builders such as `build_logger(...)` and `parse_and_build_logger(...)` return this alias as the main sync config-to-runtime result. - Builders such as `build_logger(...)` and `parse_and_build_logger(...)` return this alias as the main sync config-to-runtime result.
- `ApplicationLogger` is another direct alias-oriented name for this same configured runtime surface, while `LibraryLogger[RuntimeSink]` is the narrowing facade variant that intentionally hides these runtime helpers until `to_logger()` is used. - `ApplicationLogger` is another direct alias-oriented name for this same configured runtime surface, while `LibraryLogger[RuntimeSink]` is the narrowing facade variant that intentionally hides these runtime helpers until `to_logger()` is used.
@@ -59,7 +60,18 @@ ignore(logger.pending_count())
In this example, the alias keeps ordinary logging calls while still exposing runtime diagnostics. In this example, the alias keeps ordinary logging calls while still exposing runtime diagnostics.
And the inherited logger target rules stay unchanged: `log(..., target=...)` can override the target per call, while `with_target(...)` and `child(...)` derive new logger values with changed default targets. And the inherited logger target rules stay unchanged: `log(..., target=...)` can override the target per call, while `info(...)`, `warn(...)`, and `error(...)` continue using the stored target unless code derives another logger first with `with_target(...)` or `child(...)`.
#### When Need A One-call Target Override On The Configured Runtime Logger
When config-built sync code should keep the same logger value but emit one record under a different target:
```moonbit
logger.log(Level::Error, "boom", target="svc.audit")
```
In this example, the emitted record uses `svc.audit` only for that one call.
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(...)`.
### Error Case ### Error Case
+12
View File
@@ -34,6 +34,7 @@ Detailed rules explaining key parameters and behaviors
- This is a public facade struct, not a type alias. - This is a public facade struct, not a type alias.
- The wrapped sink type `S` is preserved, so sink-specific typing remains available through the facade type parameter. - The wrapped sink type `S` is preserved, so sink-specific typing remains available through the facade type parameter.
- The facade keeps common library-safe operations such as `new(...)`, `with_target(...)`, `child(...)`, `bind(...)`, `is_enabled(...)`, and the main write methods `log(...)`, `info(...)`, `warn(...)`, and `error(...)`. - The facade keeps common library-safe operations such as `new(...)`, `with_target(...)`, `child(...)`, `bind(...)`, `is_enabled(...)`, and the main write methods `log(...)`, `info(...)`, `warn(...)`, and `error(...)`.
- The facade also preserves the wrapped logger's target rules on its exposed write methods: `log(..., target=...)` can override the target for one call, while `info(...)`, `warn(...)`, and `error(...)` continue using the stored logger target unless the facade first derives another logger with `with_target(...)` or `child(...)`.
- The facade wraps the same underlying `Logger[S]` value rather than copying or rebuilding it. - The facade wraps the same underlying `Logger[S]` value rather than copying or rebuilding it.
- It does not expose the wider `Logger[S]` composition surface or `ConfiguredLogger` runtime helper methods directly. - It does not expose the wider `Logger[S]` composition surface or `ConfiguredLogger` runtime helper methods directly.
- Most facade reshaping helpers keep the same visible sink type, but `with_context_fields(...)` and `bind(...)` intentionally return `LibraryLogger[ContextSink[S]]` because they extend the sink pipeline. - Most facade reshaping helpers keep the same visible sink type, but `with_context_fields(...)` and `bind(...)` intentionally return `LibraryLogger[ContextSink[S]]` because they extend the sink pipeline.
@@ -52,6 +53,17 @@ let logger : LibraryLogger[ConsoleSink] = LibraryLogger::new(console_sink(), tar
In this example, the package boundary exposes the library facade instead of the full logger type. In this example, the package boundary exposes the library facade instead of the full logger type.
#### When Need A One-call Target Override Through The Library Facade
When package code should keep the same library-facing sync value but emit one record under a different target:
```moonbit
logger.log(Level::Error, "boom", target="lib.audit")
```
In this example, the emitted record uses `lib.audit` only for that one call.
And later `info(...)`, `warn(...)`, or `error(...)` calls still use the facade's stored target unless code derives another facade first with `with_target(...)` or `child(...)`.
#### When Need To Recover The Full Logger Later #### When Need To Recover The Full Logger Later
When a library-facing facade should later be adapted back into the ordinary sync logger surface: When a library-facing facade should later be adapted back into the ordinary sync logger surface: