mirror of
https://github.com/Nanaloveyuki/BitLogger.git
synced 2026-07-25 17:32:20 +00:00
📝 add example-first documentation paths
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
# Sink Composition
|
||||
|
||||
Presets cover common console and file configurations. Build a `Logger::new(...)` directly when records need routing or multiple outputs.
|
||||
|
||||
## Send A Record To Two Destinations
|
||||
|
||||
```moonbit
|
||||
let logger = @log.Logger::new(
|
||||
@log.fanout_sink(@log.console_sink(), @log.json_console_sink()),
|
||||
min_level=@log.Level::Info,
|
||||
target="service",
|
||||
)
|
||||
|
||||
logger.info("request complete", fields=[@log.field("status", "200")])
|
||||
```
|
||||
|
||||
`fanout_sink(...)` writes the same record to every child sink. This keeps human-oriented terminal output and machine-oriented JSON output in one application path.
|
||||
|
||||
## Route Warnings Separately
|
||||
|
||||
```moonbit
|
||||
let logger = @log.Logger::new(
|
||||
@log.split_by_level(
|
||||
@log.callback_sink(fn(rec) {
|
||||
println("alert: \{rec.message}")
|
||||
}),
|
||||
@log.console_sink(),
|
||||
min_level=@log.Level::Warn,
|
||||
),
|
||||
min_level=@log.Level::Trace,
|
||||
target="service",
|
||||
)
|
||||
```
|
||||
|
||||
Use direct sink composition only when the routing behavior is part of the application design. A preset remains easier to audit when one sink is sufficient.
|
||||
|
||||
## API Reference
|
||||
|
||||
- [`Logger::new(...)`](../api/logger-new.md)
|
||||
- [`fanout_sink(...)`](../api/fanout-sink.md)
|
||||
- [`split_by_level(...)`](../api/split-by-level.md)
|
||||
- [`callback_sink(...)`](../api/callback-sink.md)
|
||||
@@ -0,0 +1,44 @@
|
||||
# Text Formatting And Style Tags
|
||||
|
||||
Formatting changes presentation while keeping the record's level, target, message, and fields intact. Use text output for people; use JSON output when another system parses the record.
|
||||
|
||||
## Customize The Text Shape
|
||||
|
||||
```moonbit
|
||||
let logger = @log.build_logger(
|
||||
@log.text_console(
|
||||
min_level=@log.Level::Info,
|
||||
target="service",
|
||||
text_formatter=@log.TextFormatterConfig::new(
|
||||
show_timestamp=false,
|
||||
field_separator=",",
|
||||
template="[{level}] {target} {message} :: {fields}",
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
logger.info("ready", fields=[@log.field("port", "8080")])
|
||||
```
|
||||
|
||||
The template controls the visible order. Keep fields separate from the message so they can still be rendered consistently across sinks.
|
||||
|
||||
## Add Named Styles
|
||||
|
||||
```moonbit
|
||||
let formatter = @log.text_formatter(
|
||||
show_timestamp=false,
|
||||
color_mode=@log.ColorMode::Always,
|
||||
).with_style_tags(
|
||||
@log.default_style_tag_registry()
|
||||
.set_tag("accent", fg=Some("#4cc9f0"), bold=true),
|
||||
)
|
||||
```
|
||||
|
||||
Style tags are terminal presentation metadata. Do not use them as the only way to encode operational meaning; preserve that meaning in level, target, and fields.
|
||||
|
||||
## API Reference
|
||||
|
||||
- [`text_console(...)`](../api/text-console.md)
|
||||
- [`TextFormatterConfig`](../api/text-formatter-config.md)
|
||||
- [`text_formatter(...)`](../api/text-formatter.md)
|
||||
- [`ColorMode`](../api/color-mode.md)
|
||||
@@ -0,0 +1,14 @@
|
||||
# Extend A Logger
|
||||
|
||||
Start from an [Example flow](../examples/index.md), then add one extension at a time. These pages explain when an abstraction is useful and which operational boundary it introduces.
|
||||
|
||||
## Extension Map
|
||||
|
||||
| Need | Extension | Main trade-off |
|
||||
| --- | --- | --- |
|
||||
| Absorb short output bursts | [Queueing](./queue.md) | You must choose overflow and flush behavior. |
|
||||
| Send records to multiple destinations or route by level | [Sink composition](./composition.md) | More explicit construction than presets. |
|
||||
| Control terminal appearance | [Text formatting](./formatting.md) | Formatting affects presentation, not record structure. |
|
||||
| Share code across native and web targets | [Target boundaries](./targets.md) | File and async runtime behavior differ by backend. |
|
||||
|
||||
For exact function signatures, follow each page's links into the [API reference](../api/index.md).
|
||||
@@ -0,0 +1,30 @@
|
||||
# Queueing And Overflow
|
||||
|
||||
Use a queue when a short burst of log writes should not immediately reach the output sink. Queueing is explicit because loss behavior is an application decision.
|
||||
|
||||
## Add A Synchronous Queue
|
||||
|
||||
```moonbit
|
||||
let config = @log.with_queue(
|
||||
@log.text_console(target="service"),
|
||||
max_pending=128,
|
||||
overflow=@log.QueueOverflowPolicy::DropOldest,
|
||||
)
|
||||
let logger = @log.build_logger(config)
|
||||
|
||||
logger.info("queued record")
|
||||
ignore(logger.flush())
|
||||
```
|
||||
|
||||
`DropOldest` preserves the newest operational information when the queue is full. Use `DropNewest` when preserving earlier records matters more. Calling `flush()` at a shutdown boundary makes the pending-record policy visible in application code.
|
||||
|
||||
## When To Use Async Instead
|
||||
|
||||
The synchronous queue is configuration around a normal runtime logger. When a native async application needs a worker lifecycle and batching, follow [Async logger lifecycle](../examples/async.md) instead.
|
||||
|
||||
## API Reference
|
||||
|
||||
- [`with_queue(...)`](../api/with-queue.md)
|
||||
- [`QueueConfig`](../api/queue-config.md)
|
||||
- [`QueueOverflowPolicy`](../api/queue-overflow-policy.md)
|
||||
- [`flush()`](../api/configured-logger-flush.md)
|
||||
@@ -0,0 +1,33 @@
|
||||
# Target Boundaries
|
||||
|
||||
BitLogger keeps a portable structured logging surface, but native file output and async worker behavior are target-sensitive. Keep those boundaries in application code instead of assuming every sink behaves identically everywhere.
|
||||
|
||||
## Portable Default
|
||||
|
||||
`console(...)`, `json_console(...)`, structured fields, filters, patches, and the ordinary logger surface are the appropriate starting point for code shared across targets.
|
||||
|
||||
## Native-Only File Output
|
||||
|
||||
```moonbit
|
||||
if @log.native_files_supported() {
|
||||
let logger = @log.build_logger(@log.file("service.log") catch {
|
||||
err => {
|
||||
ignore(err)
|
||||
return
|
||||
}
|
||||
})
|
||||
logger.info("file output enabled")
|
||||
}
|
||||
```
|
||||
|
||||
File sinks need native filesystem support. Do not construct a file-only configuration unconditionally in code intended for web targets.
|
||||
|
||||
## Async Library Versus Async Entry Point
|
||||
|
||||
The async library exposes a compatibility surface across declared targets, while an executable `async fn main` still has stricter entry-point support. Keep a native-only executable example separate from portable library code.
|
||||
|
||||
## API Reference
|
||||
|
||||
- [`native_files_supported()`](../api/native-files-supported.md)
|
||||
- [Target verification](../api/target-verification.md)
|
||||
- [Async logger lifecycle](../examples/async.md)
|
||||
Reference in New Issue
Block a user