Files
BitLogger/docs/api/logger-with-context-fields.md
T
2026-05-12 13:32:15 +08:00

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.