mirror of
https://github.com/Nanaloveyuki/BitLogger.git
synced 2026-05-30 15:42:25 +00:00
84 lines
2.5 KiB
Markdown
84 lines
2.5 KiB
Markdown
---
|
|
name: logger-with-context-fields
|
|
group: api
|
|
category: logging
|
|
update-time: 20260512
|
|
description: Attach reusable structured fields to a logger so every emitted record inherits them.
|
|
key-word:
|
|
- logger
|
|
- fields
|
|
- context
|
|
- public
|
|
---
|
|
|
|
## Logger-with-context-fields
|
|
|
|
Bind shared structured fields to a logger. This is the standard way to attach stable metadata such as service name, component, region, request scope, or subsystem identity without repeating them for every log call.
|
|
|
|
### Interface
|
|
|
|
```moonbit
|
|
pub fn[S] Logger::with_context_fields(self : Logger[S], fields : Array[Field]) -> Logger[ContextSink[S]] {}
|
|
```
|
|
|
|
#### input
|
|
|
|
- `self : Logger[S]` - The base logger that should gain shared fields.
|
|
- `fields : Array[Field]` - Structured fields that will be prepended to each emitted record.
|
|
|
|
#### output
|
|
|
|
- `Logger[ContextSink[S]]` - A new logger wrapping the original sink with context-field merging behavior.
|
|
|
|
### Explanation
|
|
|
|
Detailed rules explaining key parameters and behaviors
|
|
|
|
- Context fields are merged at write time, not by mutating previously created records.
|
|
- When a log call also passes per-record fields, the context fields are placed before those per-call fields.
|
|
- This API returns a new typed logger wrapper; it does not mutate the original logger variable.
|
|
- `bind(...)` is an ergonomic alias for this same behavior.
|
|
|
|
### How to Use
|
|
|
|
Here are some specific examples provided.
|
|
|
|
#### When Need Stable Service Metadata
|
|
|
|
When every record from a logger should carry service-level metadata:
|
|
```moonbit
|
|
let logger = Logger::new(console_sink(), target="billing")
|
|
.with_context_fields([field("service", "billing"), field("region", "cn")])
|
|
|
|
logger.info("started")
|
|
```
|
|
|
|
In this example, both `service` and `region` are automatically included on every record.
|
|
|
|
And callers only need to provide fields that actually vary per event.
|
|
|
|
#### When Build Child Loggers For Subsystems
|
|
|
|
When a subsystem has both a target and fixed fields:
|
|
```moonbit
|
|
let worker = Logger::new(console_sink(), target="app")
|
|
.child("worker")
|
|
.with_context_fields([field("component", "worker")])
|
|
```
|
|
|
|
In this example, target composition and field binding stay separate but work together cleanly.
|
|
|
|
### Error Case
|
|
|
|
e.g.:
|
|
- If `fields` is empty, the logger remains valid and just adds no extra metadata.
|
|
|
|
- If duplicate field keys are provided, all fields are still emitted; conflict handling is left to the consumer/formatter side.
|
|
|
|
### Notes
|
|
|
|
1. Use this for stable metadata, not highly dynamic event-specific values.
|
|
|
|
2. Prefer `fields([("k", "v")])` when you want a more ergonomic call site.
|
|
|