47 Commits

Author SHA1 Message Date
Nanaloveyuki 91096a9e0d ⬆️ Update MoonBit Version to v0.9.2 and Fix warns 2026-05-20 07:55:14 +08:00
Nanaloveyuki 78423384ea Clarify application and library logger entries 2026-05-15 11:42:46 +08:00
Nanaloveyuki 1b56e1e20a Add library logger facades 2026-05-15 11:15:34 +08:00
Nanaloveyuki 91d778d92e ♻️ Split runtime and async shared layers 2026-05-15 11:15:20 +08:00
Nanaloveyuki 1c75c98e3c 🚚 Move bitlogger&bitlogger-async to src& src-async 2026-05-15 10:13:36 +08:00
Nanaloveyuki 02c40f26f9 ⬆️ 升级 Moonbit 版本和 Async 版本 2026-05-15 09:55:29 +08:00
Nanaloveyuki 640b717c70 📝 Add record and level API docs 2026-05-12 16:13:50 +08:00
Nanaloveyuki bd1ef99189 📝 Add global logger API docs 2026-05-12 16:10:24 +08:00
Nanaloveyuki 661c17e093 📝 Add logger write API docs 2026-05-12 16:06:00 +08:00
Nanaloveyuki 474a1931c2 📝 Add record patch API docs 2026-05-12 16:00:17 +08:00
Nanaloveyuki dd895ac211 📝 Add filter predicate API docs 2026-05-12 15:56:30 +08:00
Nanaloveyuki 9248135b9c 📝 Expand API index coverage 2026-05-12 15:51:54 +08:00
Nanaloveyuki 694414e068 📝 Add file state export API docs 2026-05-12 15:05:58 +08:00
Nanaloveyuki bab9864f1f 📝 Add configured logger file state API docs 2026-05-12 14:59:59 +08:00
Nanaloveyuki d1260c5deb 📝 Add configured logger file policy API docs 2026-05-12 14:58:22 +08:00
Nanaloveyuki cfde700526 📝 Add configured logger file control API docs 2026-05-12 14:52:23 +08:00
Nanaloveyuki 87cf651c4c 📝 Update README with remove async summary 2026-05-12 14:49:18 +08:00
Nanaloveyuki 1e487f2ffc 📝 Add API index and simplify README links 2026-05-12 14:30:49 +08:00
Nanaloveyuki f21aca670a 📝 Refocus English README on entry points 2026-05-12 14:26:38 +08:00
Nanaloveyuki 6f1d6086d6 📝 Refocus READMEs on features and entry points 2026-05-12 14:25:11 +08:00
Nanaloveyuki 0ab3b95959 📝 Add configured logger file runtime API docs 2026-05-12 14:18:54 +08:00
Nanaloveyuki bd3a1c24d0 📝 Add configured logger runtime control API docs 2026-05-12 14:17:19 +08:00
Nanaloveyuki d7f93e9f9c 📝 Add async logger write API docs 2026-05-12 14:04:44 +08:00
Nanaloveyuki dad55a241f 📝 Add async logger lifecycle API docs 2026-05-12 13:55:05 +08:00
Nanaloveyuki f172305453 📝 Add async logger composition API docs 2026-05-12 13:51:08 +08:00
Nanaloveyuki 80f15cd455 📝 Polish API doc consistency and scope 2026-05-12 13:47:04 +08:00
Nanaloveyuki c6c153cf53 📝 Refine API doc notes and guidance 2026-05-12 13:32:15 +08:00
Nanaloveyuki 4d913aa642 📝 Align API docs with updated interface template 2026-05-12 13:20:36 +08:00
Nanaloveyuki 8dbadd5938 📝 Add async state and config export API docs 2026-05-12 13:08:27 +08:00
Nanaloveyuki 3dbf848a53 📝 Document logger composition APIs 2026-05-12 13:08:21 +08:00
Nanaloveyuki 0b93af9261 📝 Add sync config export API docs 2026-05-12 13:08:15 +08:00
Nanaloveyuki 6e6c14d28c 📝 Document async logger state diagnostics 2026-05-12 10:57:38 +08:00
Nanaloveyuki f1b7d1d21c Add async logger runtime snapshots 2026-05-12 10:50:42 +08:00
Nanaloveyuki 8584fc7e01 💚 Expand cross-target CI coverage 2026-05-12 10:49:06 +08:00
Nanaloveyuki a328414087 Prepare 0.4.1 release documentation 2026-05-12 10:37:43 +08:00
Nanaloveyuki f609b02377 Add cross-target async compatibility runtime 2026-05-12 10:37:15 +08:00
Nanaloveyuki 3124d7a445 🔖 Release 0.4.0 2026-05-10 16:02:19 +08:00
Nanaloveyuki 4b54005401 Add ANSI color support fallback modes 2026-05-10 15:32:48 +08:00
Nanaloveyuki 2d2388c79f Support named style closing tags 2026-05-10 15:22:56 +08:00
Nanaloveyuki e78183d267 Add scoped target and field style markup 2026-05-10 15:17:13 +08:00
Nanaloveyuki 4be861acce Add builtin semantic style tags 2026-05-10 15:10:29 +08:00
Nanaloveyuki 20f79bbe2a Add configurable style markup modes 2026-05-10 15:06:20 +08:00
Nanaloveyuki f3e903b578 Add formatter style_tags config support 2026-05-10 15:00:37 +08:00
Nanaloveyuki f1b223f203 📝 Document styled formatter usage 2026-05-10 14:52:17 +08:00
Nanaloveyuki 3b6536f980 Add style tag registry overrides 2026-05-10 14:50:06 +08:00
Nanaloveyuki b1b2235160 Add inline style markup 2026-05-10 14:41:57 +08:00
Nanaloveyuki 90af009e93 Add ANSI color mode 2026-05-10 14:33:49 +08:00
188 changed files with 14788 additions and 1748 deletions
+24
View File
@@ -39,10 +39,34 @@ jobs:
run: |
moon check bitlogger --target native
- name: Check bitlogger wasm-gc
run: |
moon check bitlogger --target wasm-gc
- name: Check bitlogger js
run: |
moon check bitlogger --target js
- name: Check bitlogger_async native
run: |
moon check bitlogger_async --target native
- name: Check bitlogger_async wasm-gc
run: |
moon check bitlogger_async --target wasm-gc
- name: Check bitlogger_async js
run: |
moon check bitlogger_async --target js
- name: Test bitlogger_async wasm-gc
run: |
moon test bitlogger_async --target wasm-gc
- name: Test bitlogger_async js
run: |
moon test bitlogger_async --target js
- name: Run basic example
run: |
moon run examples/basic
+31 -248
View File
@@ -12,22 +12,25 @@
## 📖 介绍
BitLogger 是一个使用 MoonBit 编写的结构化日志库
BitLogger 是一个使用 MoonBit 编写的结构化日志库,目标是提供可组合、可配置、可跨端编译的日志基础设施。
## ❇️ 特点
## 🧭 后端兼容
- 🧩 基础能力: 支持 level, formatter, sink, context field 和全局 logger.
- 🏗️ 结构清晰: 按 `level / record / formatter / sinks / logger / global` 拆分文件, 便于维护.
- 🔌 可扩展: 支持 `fanout_sink(...)``callback_sink(...)`, 方便接入文件, 指标或外部系统.
- 🔀 可分流: 支持 `split_sink(...)` / `split_by_level(...)`, 可按谓词或 level 将日志路由到不同 sink.
- 🧱 可组合: 支持 `buffered_sink(...)``filter_sink(...)`, 可以组合不同输出策略.
- 🔎 可复用过滤: 提供 `target_has_prefix(...)`, `message_contains(...)`, `level_at_least(...)`, `field_equals(...)` 等过滤辅助函数.
- 🩹 可变换 Record: 支持 `with_patch(...)`, `patch_sink(...)` 以及脱敏, 补字段, message 变换 helper.
- 🧷 可绑定上下文: 支持 `bind(...)``fields(...)`, 便于复用上下文字段.
- 📮 显式队列: 支持 `queued_sink(...)` / `with_queue(...)`, 支持有界积压和溢出策略.
- 🧾 可配置文本格式: 支持 `text_formatter(...)`, `format_text(...)`, `text_console_sink(...)`, `formatted_callback_sink(...)` 和模板化 `template` 输出.
- 💾 Native 文件输出: 支持 `file_sink(...)`, 基础 size rotation / backup retention, 显式 `reopen()` / `reopen_with_current_policy()` / `reopen_append()` / `reopen_truncate()` 与失败计数, 仅在 `native/llvm` backend 可用.
- 📦 MoonBit 适配: API 和工程结构与 MoonBit 的 package / visibility / toolchain 模型保持一致.
| 模块 / 能力 | native / llvm | js / wasm / wasm-gc |
| --- | --- | --- |
| `src` 主包 | 支持 | 支持 |
| `file_sink(...)` | 支持 | 不支持, `native_files_supported()` 返回 `false` |
| `src-async` | 支持原生 worker 语义 | 支持兼容实现 |
| `examples/async_basic` | 支持 | 受 `async fn main` 入口限制, 当前不提供 |
## ❇️ 关键特性
- 结构化日志基础能力:level、record、formatter、sink、target、context field。
- 组合式设计:支持 filter、patch、fanout、split、callback、queued sink 等组合能力。
- 配置驱动:支持 JSON 配置解析、导出与 `build_logger(...)` / `build_async_logger(...)` 运行时组装。
- 文本格式化:支持 `text_formatter(...)`、template、style tag、`color_mode` / `style_markup`
- Native 文件输出:支持 file sink、基础 size rotation、reopen、failure counter 与运行时状态读取。
- 异步层:提供独立 `src-async` package,支持 queue、worker lifecycle、runtime state 和跨端兼容实现。
## 🚀 快速开始
@@ -39,248 +42,28 @@ let logger = Logger::new(console_sink(), min_level=Level::Info, target="demo")
logger.info("starting", fields=[field("port", "8080")])
```
<details><summary>层级 target 示例</summary>
异步入口示例:
```moonbit
let worker = Logger::new(console_sink(), target="app").child("worker")
worker.info("job ready")
```
</details>
<details><summary>自定义 callback sink 示例</summary>
```moonbit
let hook = Logger::new(
callback_sink(fn(rec) {
println("callback saw [\{rec.target}] \{rec.message}")
}),
target="hook",
)
hook.info("hello")
```
</details>
<details><summary>基础 buffered sink 示例</summary>
```moonbit
let sink = buffered_sink(console_sink(), flush_limit=2)
let logger = Logger::new(sink, target="buffered")
logger.info("one")
logger.info("two")
sink.flush()
```
</details>
<details><summary>基础 filter sink 示例</summary>
```moonbit
let sink = filter_sink(console_sink(), fn(rec) {
rec.target == "kept"
let logger = async_logger(console_sink(), target="async.demo")
@async.with_task_group(group => {
group.spawn_bg(() => logger.run())
logger.info("started")
logger.shutdown()
})
let kept = Logger::new(sink, target="kept")
let dropped = Logger::new(sink, target="dropped")
kept.info("visible")
dropped.info("hidden")
```
</details>
<details><summary>Logger 链式 filter 示例</summary>
```moonbit
let logger = Logger::new(console_sink(), target="service")
.with_filter(all_of([
target_has_prefix("service"),
message_contains("visible"),
]))
logger.info("hidden")
logger.child("api").info("visible")
```
</details>
<details><summary>Record patch 示例</summary>
```moonbit
let logger = Logger::new(console_sink(), target="auth")
.with_patch(compose_patches([
prefix_message("[safe] "),
redact_fields(["token"]),
append_fields([field("service", "bitlogger")]),
]))
logger.info("login", fields=[field("user", "alice"), field("token", "secret")])
```
</details>
<details><summary>bind 上下文示例</summary>
```moonbit
let logger = Logger::new(console_sink(), target="audit")
.bind(fields([("service", "bitlogger"), ("scope", "login")]))
logger.info("accepted", fields=[field("user", "alice")])
```
</details>
<details><summary>显式 queue sink 示例</summary>
```moonbit
let logger = Logger::new(console_sink(), target="queue")
.with_queue(max_pending=2, overflow=QueueOverflowPolicy::DropOldest)
logger.info("one")
logger.info("two")
logger.info("three")
ignore(logger.sink.flush())
```
</details>
<details><summary>按 level 分流 sink 示例</summary>
```moonbit
let logger = Logger::new(
split_by_level(
callback_sink(fn(rec) {
println("high priority: \{rec.level.label()} \{rec.message}")
}),
console_sink(),
min_level=Level::Warn,
),
min_level=Level::Trace,
target="split",
)
logger.info("normal output")
logger.warn("warning output")
```
</details>
<details><summary>自定义文本 formatter 示例</summary>
```moonbit
let formatter = text_formatter(
show_timestamp=false,
field_separator=",",
template="[{level}] {target} {message} :: {fields}",
)
let logger = Logger::new(text_console_sink(formatter), target="pretty")
logger.info("hello", fields=[field("mode", "pretty")])
```
</details>
<details><summary>JSON 配置加载示例</summary>
```moonbit
let config = parse_logger_config_text(
"{\"min_level\":\"debug\",\"target\":\"config.demo\",\"timestamp\":true,\"sink\":{\"kind\":\"text_console\",\"text_formatter\":{\"show_timestamp\":false,\"field_separator\":\",\",\"template\":\"[{level}] {target} {message} :: {fields}\"}},\"queue\":{\"max_pending\":2,\"overflow\":\"DropOldest\"}}",
)
let logger = build_logger(config)
logger.info("configured from json")
ignore(logger.flush())
```
</details>
<details><summary>native 文件 sink 示例</summary>
```moonbit
if native_files_supported() {
let logger = Logger::new(
file_sink("bitlogger.log", rotation=Some(file_rotation(128, max_backups=2))),
target="file",
)
logger.info("hello", fields=[field("kind", "file")])
ignore(logger.sink.flush())
ignore(logger.sink.close())
}
```
</details>
<details><summary>file runtime state dump 示例</summary>
```moonbit
let logger = build_logger(
LoggerConfig::new(
sink=SinkConfig::new(kind=SinkKind::File, path="bitlogger-runtime.log"),
queue=Some(QueueConfig::new(16)),
),
)
logger.info("queued hello")
match logger.file_runtime_state() {
Some(snapshot) => println(stringify_runtime_file_state(snapshot, pretty=true))
None => ()
}
```
</details>
## 📂 仓库结构
- `bitlogger/`: MoonBit 库 package, 包含本体实现, 测试与 Mooncake README
- `examples/basic/`: 最小可运行示例
- `examples/async_basic/`: 基于 `moonbitlang/async` 的异步 logger 示例
- `src/`: 主日志库 package。
- `src-async/`: 基于 `moonbitlang/async` 的异步日志层。
- `docs/api/`: 单接口粒度 API 文档。
- `examples/basic/`: 最小同步示例。
- `examples/async_basic/`: 异步 logger 示例。
## 🔗 相关文档
## 🔗 文档入口
- [Mooncake 文档页](https://mooncakes.io/docs/Nanaloveyuki/BitLogger)
- [English README](./docs/README-en.md)
## 📝 配置说明
- 提供 JSON 配置层: `parse_logger_config_text(...)`, `stringify_logger_config(...)`, `build_logger(...)`
- `QueueConfig`, `TextFormatterConfig`, `SinkConfig` 可分别通过 `queue_config_to_json(...)` / `stringify_queue_config(...)`, `text_formatter_config_to_json(...)` / `stringify_text_formatter_config(...)`, `sink_config_to_json(...)` / `stringify_sink_config(...)` 单独导出 JSON
- 支持字段: `min_level`, `target`, `timestamp`, `sink.kind`, `sink.path`, `sink.append`, `sink.auto_flush`, `sink.rotation`, `sink.text_formatter`, `queue`
- `sink.rotation` 支持 `max_bytes``max_backups`, 用于基础 size-based rotation 和 backup retention
- `file_sink(...)` 提供 `reopen()`, `reopen_with_current_policy()`, `reopen_append()`, `reopen_truncate()`, `open_failures()`, `write_failures()`, `flush_failures()`, `rotation_failures()`, 用于基础可观测性
- `file_sink(...)` 提供 `append_mode()`. 显式传入 `reopen(append=...)` 时, 会更新后续 reopen 使用的 append 策略. `reopen_with_current_policy()` 使用当前保存的策略重开文件, `reopen_append()` / `reopen_truncate()` 提供常见的 append 和 truncate 模式
- `file_sink(...)` 支持 `set_append_mode(...)`, 用于修改后续 reopen 使用的 append 策略
- `file_sink(...)` 可读取 `path()``auto_flush_enabled()` 等基础 file 策略状态
- `file_sink(...)` 提供 `rotation_enabled()``rotation_config()`, 可查询 rotation 是否启用及其参数
- `file_sink(...)` 提供 `state()`, 可一次性读取 path, available, append, auto_flush, rotation 与各类 failure counter 快照
- `file_sink(...)` 提供 `policy()``default_policy()`, 可分别读取当前策略与创建时默认策略
- `file_sink(...)` 提供 `policy_matches_default()`, 可判断当前运行期策略是否偏离默认策略
- `file_sink(...)` 支持 `set_policy(...)`, 可一次性写回 append / auto_flush / rotation 三项策略
- `file_sink(...)` 提供 `reset_failure_counters()`, 可清空 open / write / flush / rotation 失败计数
- `file_sink(...)` 提供 `reset_policy()`, 可将 append / auto_flush / rotation 恢复到创建 sink 时的默认策略
- `file_sink(...)` 支持 `set_auto_flush(...)`, `set_rotation(...)`, `clear_rotation()`, 可在运行期调整写出策略
- `build_logger(...)` 产出的 `ConfiguredLogger` 也提供 `file_reopen()`, `file_reopen_with_current_policy()`, `file_reopen_append()`, `file_reopen_truncate()`, `file_flush()`, `file_close()`, `file_append_mode()`, `file_path()`, `file_auto_flush()`, `file_rotation_enabled()`, `file_rotation_config()`, `file_state()`, 以及 `file_set_append_mode(...)`, `file_set_auto_flush(...)`, `file_set_rotation(...)`, `file_clear_rotation()` 和对应的 file failure 计数访问器
- `ConfiguredLogger` 提供 `file_runtime_state()`, 可在 file sink 被 queue 包装时同时读取底层 file 快照, queue 状态, pending 计数与 dropped 计数
- `ConfiguredLogger` 提供 `file_policy()``file_default_policy()`, 可分别读取当前 file 策略与初始配置策略
- `ConfiguredLogger` 提供 `file_policy_matches_default()`, 可判断当前配置式 file 策略是否偏离默认值
- `ConfiguredLogger` 支持 `file_set_policy(...)`, 可一次性改写配置式 file sink 的当前运行期策略
- `ConfiguredLogger` 支持 `file_reset_failure_counters()`, 可在配置式 file sink 上统一清空失败计数
- `ConfiguredLogger` 支持 `file_reset_policy()`, 可将配置式 file sink 的运行期策略恢复到初始配置
- `file_sink_policy_to_json(...)`, `stringify_file_sink_policy(...)` 可将独立 file policy 直接导出为 JSON, 便于策略快照, 配置对比或诊断上报
- `file_sink_state_to_json(...)`, `stringify_file_sink_state(...)`, `runtime_file_state_to_json(...)`, `stringify_runtime_file_state(...)` 可直接把 file / queued-file 快照导出为 JSON, 便于排障或上报
- `sink.text_formatter.template` 支持固定 token: `{timestamp}`, `{timestamp_ms}`, `{level}`, `{target}`, `{message}`, `{fields}`
- 可由配置直接组装的 sink 类型: `console`, `json_console`, `text_console`, `file`
- `queue` 作为显式包装层附着在最终 sink 外侧. 这仍然是同步 drain 模型, 不是 async runtime
## 🧵 异步层
- 提供独立 package: `bitlogger_async/`
- 异步层基于 `moonbitlang/async`, 提供 `AsyncLogger`, `async_logger(...)`, 后台 `run()` worker 与有界 async queue
- async API 支持 `with_context_fields(...)`, `with_filter(...)`, `with_patch(...)`, `with_target(...)`, `child(...)`
- 建议使用 `shutdown()` 停止 worker. 默认模式下, 它会先等待队列清空, 再关闭 queue, 最后等待 worker 退出
- 提供基础生命周期观测: `is_closed()`, `is_running()`, `has_failed()`, `last_error()`
- async worker 支持 `max_batch` 批量消费, 以及 `flush=Never|Batch|Shutdown` 的基础 flush 策略
- 示例见 [examples/async_basic/main.mbt](/E:/repo/MooLiteyukiBot/examples/async_basic/main.mbt:1)
- 仅支持 `native/llvm` backend, 与同步 core 分开维护
### Async Config
- 提供 `parse_async_logger_config_text(...)`, `stringify_async_logger_config(...)`, `parse_async_logger_build_config_text(...)`, `build_async_logger(...)`
- JSON 顶层结构分为两个字段: `logger``async_config`
- `logger` 复用同步 `LoggerConfig` 的 schema, `async_config` 支持 `max_pending`, `overflow`, `max_batch`, `flush`
- 用法可参考 [examples/async_basic/main.mbt](/E:/repo/MooLiteyukiBot/examples/async_basic/main.mbt:1)
- [src package README](./src/README.mbt.md)
- [API 索引](./docs/api/index.md)
-263
View File
@@ -1,263 +0,0 @@
# BitLogger
BitLogger is a minimal structured logger for MoonBit.
BitLogger 是一个使用 MoonBit 编写的结构化日志库.
## Features / 特性
- log levels: `Trace`, `Debug`, `Info`, `Warn`, `Error`
- 日志级别: `Trace`, `Debug`, `Info`, `Warn`, `Error`
- structured key-value fields
- 结构化字段: `field("key", "value")`
- sink abstraction
- sink 抽象与组合接口
- default global console logger
- 默认全局 logger 辅助函数
- context fields via `with_context_fields(...)`
- 通过 `with_context_fields(...)` 添加上下文字段
- child target composition via `child(...)`
- 通过 `child(...)` 组合层级 target
- optional timestamps via `with_timestamp()`
- 通过 `with_timestamp()` 启用时间戳
- JSON console output via `json_console_sink()`
- `json_console_sink()` 提供 JSON 控制台输出
- sink composition via `fanout_sink(...)`
- `fanout_sink(...)` 支持多 sink 组合
- sink routing via `split_sink(...)` and `split_by_level(...)`
- `split_sink(...)`, `split_by_level(...)` 支持按谓词或 level 将日志路由到不同 sink
- custom callback sink via `callback_sink(...)`
- `callback_sink(...)` 支持自定义外部集成
- buffered sink via `buffered_sink(...)`
- `buffered_sink(...)` 支持内存缓冲与 flush
- filter sink via `filter_sink(...)`
- `filter_sink(...)` 支持按 `Record` 条件筛选输出
- reusable filter helpers such as `target_has_prefix(...)`, `message_contains(...)`, and `field_equals(...)`
- 提供 `target_has_prefix(...)`, `message_contains(...)`, `field_equals(...)` 等可复用过滤辅助函数
- record patching via `with_patch(...)` and `patch_sink(...)`
- 支持 `with_patch(...)`, `patch_sink(...)` 以及常见 record patch helper
- context binding via `bind(...)` and `fields(...)`
- 支持 `bind(...)`, `fields(...)`, 更方便封装上下文字段
- explicit queued delivery via `queued_sink(...)` and `with_queue(...)`
- 支持 `queued_sink(...)`, `with_queue(...)`, 有界积压与溢出策略
- configurable text formatting via `text_formatter(...)`, `format_text(...)`, `text_console_sink(...)`, and template-driven `template` output
- 支持 `text_formatter(...)`, `format_text(...)`, `text_console_sink(...)` 以及模板化 `template` 文本输出
- JSON config parsing via `parse_logger_config_text(...)` and `stringify_logger_config(...)`
- 支持 `parse_logger_config_text(...)`, `stringify_logger_config(...)` 进行最小 JSON 配置读写
- `QueueConfig` / `TextFormatterConfig` / `SinkConfig` can also be exported independently through dedicated JSON helpers
- `QueueConfig` / `TextFormatterConfig` / `SinkConfig` 也可分别通过专用 JSON helper 单独导出
- config-driven logger assembly via `build_logger(...)`
- 支持 `build_logger(...)` 将配置组装为可直接使用的 logger
- native-only file output via `file_sink(...)`, with basic size rotation, backup retention, explicit `reopen()` / `reopen_with_current_policy()` / `reopen_append()` / `reopen_truncate()`, and failure counters
- 支持 `file_sink(...)`, 基础 size rotation / backup retention, 显式 `reopen()` / `reopen_with_current_policy()` / `reopen_append()` / `reopen_truncate()` 与失败计数, 仅在 `native/llvm` backend 可用
## Example / 示例
```mbt check
test {
let logger = Logger::new(console_sink(), min_level=Level::Debug, target="demo")
.with_timestamp()
logger.info("starting", fields=[field("port", "8080")])
}
```
```mbt check
test {
let logger = Logger::new(console_sink(), target="app").child("worker")
logger.info("ready")
}
```
```mbt check
test {
let logger = Logger::new(
fanout_sink(console_sink(), json_console_sink()),
min_level=Level::Info,
target="demo",
)
logger.info("ready", fields=[field("mode", "fanout")])
}
```
```mbt check
test {
let logger = Logger::new(
callback_sink(fn(rec) {
println("callback saw [\{rec.target}] \{rec.message}")
}),
target="hook",
)
logger.info("hello")
}
```
```mbt check
test {
let sink = buffered_sink(console_sink(), flush_limit=2)
let logger = Logger::new(sink, target="buffered")
logger.info("one")
logger.info("two")
sink.flush()
}
```
```mbt check
test {
let sink = filter_sink(console_sink(), fn(rec) {
rec.target == "kept"
})
let kept = Logger::new(sink, target="kept")
let dropped = Logger::new(sink, target="dropped")
kept.info("visible")
dropped.info("hidden")
}
```
```mbt check
test {
let logger = Logger::new(console_sink(), target="service")
.with_filter(all_of([
target_has_prefix("service"),
message_contains("visible"),
]))
logger.info("hidden")
logger.child("api").info("visible")
}
```
```mbt check
test {
let logger = Logger::new(console_sink(), target="auth")
.with_patch(compose_patches([
prefix_message("[safe] "),
redact_fields(["token"]),
append_fields([field("service", "bitlogger")]),
]))
logger.info("login", fields=[field("user", "alice"), field("token", "secret")])
}
```
```mbt check
test {
let logger = Logger::new(console_sink(), target="audit")
.bind(fields([("service", "bitlogger"), ("scope", "login")]))
logger.info("accepted", fields=[field("user", "alice")])
}
```
```mbt check
test {
let logger = Logger::new(console_sink(), target="queue")
.with_queue(max_pending=2, overflow=QueueOverflowPolicy::DropOldest)
logger.info("one")
logger.info("two")
logger.info("three")
ignore(logger.sink.flush())
}
```
```mbt check
test {
let logger = Logger::new(
split_by_level(
callback_sink(fn(rec) {
println("high priority: \{rec.level.label()} \{rec.message}")
}),
console_sink(),
min_level=Level::Warn,
),
min_level=Level::Trace,
target="split",
)
logger.info("normal output")
logger.warn("warning output")
}
```
```mbt check
test {
let formatter = text_formatter(
show_timestamp=false,
field_separator=",",
template="[{level}] {target} {message} :: {fields}",
)
let logger = Logger::new(text_console_sink(formatter), target="pretty")
logger.info("hello", fields=[field("mode", "pretty")])
}
```
```mbt check
test {
let config = parse_logger_config_text(
"{\"min_level\":\"debug\",\"target\":\"config.demo\",\"timestamp\":true,\"sink\":{\"kind\":\"text_console\",\"text_formatter\":{\"show_timestamp\":false,\"field_separator\":\",\",\"template\":\"[{level}] {target} {message} :: {fields}\"}},\"queue\":{\"max_pending\":2,\"overflow\":\"DropOldest\"}}",
)
let logger = build_logger(config)
logger.info("configured from json")
ignore(logger.flush())
}
```
## Formatter Template / 模板格式
- supported tokens / 支持的 token: `{timestamp}`, `{timestamp_ms}`, `{level}`, `{target}`, `{message}`, `{fields}`
- disabled or missing parts render as empty text / 被关闭或缺失的部分会渲染为空字符串
- `template` is intentionally a simple token replacement layer, not a full DSL / `template` 使用轻量 token 替换方式, 不是完整 DSL
```mbt check
test {
if native_files_supported() {
let logger = Logger::new(
file_sink("bitlogger.log", rotation=Some(file_rotation(128, max_backups=2))),
target="file",
)
logger.info("hello", fields=[field("kind", "file")])
ignore(logger.sink.flush())
ignore(logger.sink.close())
}
}
```
```mbt check
test {
let logger = build_logger(
LoggerConfig::new(
sink=SinkConfig::new(kind=SinkKind::File, path="bitlogger-runtime.log"),
queue=Some(QueueConfig::new(16)),
),
)
logger.info("queued hello")
match logger.file_runtime_state() {
Some(snapshot) => println(stringify_runtime_file_state(snapshot, pretty=true))
None => ()
}
}
```
## File Rotation / 文件轮转
- basic rotation is size-based / 基础轮转按文件大小触发
- `file_rotation(max_bytes, max_backups=...)` controls threshold and retained backups / `file_rotation(max_bytes, max_backups=...)` 控制触发阈值和保留备份数
- JSON config uses `sink.rotation.max_bytes` and `sink.rotation.max_backups` / JSON 配置使用 `sink.rotation.max_bytes` 与 `sink.rotation.max_backups`
- `FileSink::reopen()` can explicitly reopen the current file handle, `FileSink::reopen_with_current_policy()` makes the stored-policy reopen path explicit, and `FileSink::reopen_append()` / `FileSink::reopen_truncate()` cover the two common reopen modes directly / `FileSink::reopen()` 可显式重开当前文件句柄, `FileSink::reopen_with_current_policy()` 会按当前保存的策略重开文件, `FileSink::reopen_append()` / `FileSink::reopen_truncate()` 提供常见的 append 与 truncate 模式
- `append_mode()` exposes the current append policy, and `reopen(append=...)` updates that policy for later reopen calls / `append_mode()` 可读取当前 append 策略, `reopen(append=...)` 会更新后续 reopen 复用的 append 策略
- `set_append_mode(...)` updates the stored append policy without forcing an immediate reopen / `set_append_mode(...)` 可直接更新保存的 append 策略, 不会强制立即 reopen
- `path()` and `auto_flush_enabled()` expose core file sink policy state / `path()` 与 `auto_flush_enabled()` 可读取 file sink 的基础策略状态
- `rotation_enabled()` and `rotation_config()` expose whether rotation is active and which settings are currently applied / `rotation_enabled()` 与 `rotation_config()` 可读取 rotation 是否启用及当前配置参数
- `state()` exposes a single file-sink snapshot including path, availability, append policy, auto-flush, rotation config, and failure counters / `state()` 可一次性读取包含 path, availability, append, auto_flush, rotation 配置与失败计数的 file sink 快照
- `policy()` and `default_policy()` expose the current runtime policy and the sink's original defaults separately / `policy()` 与 `default_policy()` 可分别读取当前运行期策略与 sink 初始默认策略
- `policy_matches_default()` explicitly tells whether the current runtime policy has drifted from the defaults / `policy_matches_default()` 可显式判断当前运行期策略是否已偏离默认策略
- `set_policy(...)` applies append, auto-flush, and rotation as a bundled runtime update / `set_policy(...)` 可将 append, auto_flush, rotation 作为一组运行期策略一次性写回
- `reset_failure_counters()` clears the open/write/flush/rotation counters after diagnostics or recovery / `reset_failure_counters()` 可在排障或恢复后清空 open/write/flush/rotation 失败计数
- `reset_policy()` restores append, auto-flush, and rotation back to the sink's original defaults / `reset_policy()` 可将 append, auto_flush, rotation 恢复到 sink 初始默认策略
- `file_sink_policy_to_json(...)` / `stringify_file_sink_policy(...)` also export standalone file policy snapshots as JSON / `file_sink_policy_to_json(...)` / `stringify_file_sink_policy(...)` 也可将独立 file policy 快照直接导出为 JSON
- `file_sink_state_to_json(...)` / `stringify_file_sink_state(...)` and `runtime_file_state_to_json(...)` / `stringify_runtime_file_state(...)` export snapshots as JSON / `file_sink_state_to_json(...)` / `stringify_file_sink_state(...)` 与 `runtime_file_state_to_json(...)` / `stringify_runtime_file_state(...)` 可将快照直接导出为 JSON
- `set_auto_flush(...)`, `set_rotation(...)`, and `clear_rotation()` allow runtime tuning of core file sink policies / `set_auto_flush(...)`, `set_rotation(...)`, `clear_rotation()` 可在运行期调整 file sink 的基础策略
- `open_failures()`, `write_failures()`, `flush_failures()`, `rotation_failures()` expose basic sink health counters / `open_failures()`, `write_failures()`, `flush_failures()`, `rotation_failures()` 可用于观察基础 sink 健康状态
- `ConfiguredLogger` also forwards file reopen, flush, close, append-mode, path, auto-flush, rotation-config, state snapshot, append setter, policy setter, and failure-counter helpers for config-built file sinks / `ConfiguredLogger` 也会为配置生成的 file sink 转发 reopen, flush, close, append-mode, path, auto-flush, rotation 配置, state 快照, append setter, 策略 setter 与失败计数访问器
- `ConfiguredLogger::file_runtime_state()` also reports whether a file sink is queue-wrapped and exposes the outer queue pending/drop counters together with the inner file snapshot / `ConfiguredLogger::file_runtime_state()` 还可报告 file sink 是否被 queue 包装, 并将外层 queue 的 pending/drop 计数与内层 file 快照一起返回
- `ConfiguredLogger::file_policy()` and `ConfiguredLogger::file_default_policy()` also expose current runtime policy and initial config policy separately / `ConfiguredLogger::file_policy()` 与 `ConfiguredLogger::file_default_policy()` 也可分别读取当前运行期策略与初始配置策略
- `ConfiguredLogger::file_policy_matches_default()` also tells whether the current runtime file policy has drifted from the default config / `ConfiguredLogger::file_policy_matches_default()` 也可显式判断当前运行期 file 策略是否已偏离默认配置
- `ConfiguredLogger::file_set_policy()` also applies a bundled runtime file policy through the config-built control surface / `ConfiguredLogger::file_set_policy()` 也可通过配置式控制面一次性写回 bundled file 策略
- `ConfiguredLogger::file_reset_failure_counters()` also clears file failure counters through the config-built control surface / `ConfiguredLogger::file_reset_failure_counters()` 也可通过配置式控制面清空 file 失败计数
- `ConfiguredLogger::file_reset_policy()` also restores runtime file policy back to the initial config values / `ConfiguredLogger::file_reset_policy()` 也可将运行期 file 策略恢复到初始配置值
- current scope is observability-first, not a full self-healing sink runtime / 当前以可观测性为主, 不提供完整的自恢复 sink runtime.
-128
View File
@@ -1,128 +0,0 @@
pub type RecordFormatter = (Record) -> String
pub struct TextFormatter {
show_timestamp : Bool
show_level : Bool
show_target : Bool
show_fields : Bool
separator : String
field_separator : String
template : String
}
pub fn text_formatter(
show_timestamp~ : Bool = true,
show_level~ : Bool = true,
show_target~ : Bool = true,
show_fields~ : Bool = true,
separator~ : String = " ",
field_separator~ : String = " ",
template~ : String = "",
) -> TextFormatter {
{
show_timestamp,
show_level,
show_target,
show_fields,
separator,
field_separator,
template,
}
}
fn fields_to_json(fields : Array[Field]) -> Json {
let obj : Map[String, Json] = {}
for item in fields {
obj[item.key] = Json::string(item.value)
}
Json::object(obj)
}
fn format_fields(fields : Array[Field], separator : String) -> String {
fields.map(fn(f) { "\{f.key}=\{f.value}" }).join(separator)
}
fn timestamp_text(rec : Record, formatter : TextFormatter) -> String {
if formatter.show_timestamp && rec.timestamp_ms != 0UL {
rec.timestamp_ms.to_string()
} else {
""
}
}
fn level_text(rec : Record, formatter : TextFormatter) -> String {
if formatter.show_level {
rec.level.label()
} else {
""
}
}
fn target_text(rec : Record, formatter : TextFormatter) -> String {
if formatter.show_target && rec.target != "" {
rec.target
} else {
""
}
}
fn fields_text(rec : Record, formatter : TextFormatter) -> String {
if formatter.show_fields && rec.fields.length() != 0 {
format_fields(rec.fields, formatter.field_separator)
} else {
""
}
}
fn render_template(rec : Record, formatter : TextFormatter) -> String {
formatter.template
.replace_all(old="{timestamp}", new=timestamp_text(rec, formatter))
.replace_all(old="{timestamp_ms}", new=timestamp_text(rec, formatter))
.replace_all(old="{level}", new=level_text(rec, formatter))
.replace_all(old="{target}", new=target_text(rec, formatter))
.replace_all(old="{message}", new=rec.message)
.replace_all(old="{fields}", new=fields_text(rec, formatter))
.trim()
.to_owned()
}
pub fn format_text(rec : Record, formatter~ : TextFormatter = text_formatter()) -> String {
if formatter.template != "" {
return render_template(rec, formatter)
}
let parts : Array[String] = []
if formatter.show_timestamp && rec.timestamp_ms != 0UL {
parts.push("[\{rec.timestamp_ms.to_string()}]")
}
if formatter.show_level {
parts.push("[\{rec.level.label()}]")
}
if formatter.show_target && rec.target != "" {
parts.push("[\{rec.target}]")
}
parts.push(rec.message)
let base = parts.join(formatter.separator)
if !formatter.show_fields || rec.fields.length() == 0 {
base
} else {
let details = format_fields(rec.fields, formatter.field_separator)
"\{base}\{formatter.separator}\{details}"
}
}
pub fn format_json(rec : Record) -> String {
let obj : Map[String, Json] = {
"level": Json::string(rec.level.label()),
"message": Json::string(rec.message),
"fields": fields_to_json(rec.fields),
}
if rec.timestamp_ms != 0UL {
obj["timestamp_ms"] = rec.timestamp_ms.to_json()
}
if rec.target == "" {
Json::object(obj).stringify()
} else {
obj["target"] = Json::string(rec.target)
Json::object(obj).stringify()
}
}
-150
View File
@@ -1,150 +0,0 @@
async test "shutdown drains pending records" {
let written : Ref[Array[String]] = Ref::new([])
let flushes : Ref[Int] = Ref::new(0)
let logger = async_logger(
@bitlogger.callback_sink(fn(rec) {
written.val.push(rec.message)
}),
config=AsyncLoggerConfig::new(
max_pending=4,
overflow=AsyncOverflowPolicy::Blocking,
max_batch=4,
linger_ms=10,
flush=AsyncFlushPolicy::Batch,
),
min_level=@bitlogger.Level::Info,
target="async.test",
flush=fn(_) {
flushes.val += 1
1
},
)
@async.with_task_group(group => {
group.spawn_bg(() => logger.run())
logger.info("one")
logger.info("two")
logger.shutdown()
})
inspect(logger.is_closed(), content="true")
inspect(logger.is_running(), content="false")
inspect(logger.has_failed(), content="false")
inspect(logger.pending_count(), content="0")
inspect(match logger.flush_policy() {
AsyncFlushPolicy::Never => "Never"
AsyncFlushPolicy::Batch => "Batch"
AsyncFlushPolicy::Shutdown => "Shutdown"
}, content="Batch")
inspect(written.val.length(), content="2")
inspect(written.val[0], content="one")
inspect(written.val[1], content="two")
inspect(flushes.val, content="1")
}
async test "close clear counts abandoned records as dropped" {
let logger = async_logger(
@bitlogger.callback_sink(fn(_) {
}),
config=AsyncLoggerConfig::new(
max_pending=4,
overflow=AsyncOverflowPolicy::Blocking,
),
min_level=@bitlogger.Level::Info,
target="async.clear",
)
logger.info("one")
logger.info("two")
inspect(logger.pending_count(), content="2")
inspect(logger.dropped_count(), content="0")
logger.close(clear=true)
inspect(logger.is_closed(), content="true")
inspect(logger.pending_count(), content="0")
inspect(logger.dropped_count(), content="2")
}
async test "shutdown clear closes without worker startup" {
let logger = async_logger(
@bitlogger.callback_sink(fn(_) {
}),
config=AsyncLoggerConfig::new(
max_pending=2,
overflow=AsyncOverflowPolicy::Blocking,
),
min_level=@bitlogger.Level::Info,
target="async.noworker",
)
logger.info("one")
logger.shutdown(clear=true)
inspect(logger.is_closed(), content="true")
inspect(logger.is_running(), content="false")
inspect(logger.pending_count(), content="0")
inspect(logger.dropped_count(), content="1")
}
test "async logger config stringify roundtrips stable fields" {
let text = stringify_async_logger_config(
AsyncLoggerConfig::new(
max_pending=8,
overflow=AsyncOverflowPolicy::DropOldest,
max_batch=3,
linger_ms=25,
flush=AsyncFlushPolicy::Batch,
),
)
let config = parse_async_logger_config_text(text)
inspect(config.max_pending, content="8")
inspect(config.max_batch, content="3")
inspect(config.linger_ms, content="25")
inspect(match config.overflow {
AsyncOverflowPolicy::Blocking => "Blocking"
AsyncOverflowPolicy::DropOldest => "DropOldest"
AsyncOverflowPolicy::DropNewest => "DropNewest"
}, content="DropOldest")
inspect(match config.flush {
AsyncFlushPolicy::Never => "Never"
AsyncFlushPolicy::Batch => "Batch"
AsyncFlushPolicy::Shutdown => "Shutdown"
}, content="Batch")
}
test "async build config stringify roundtrips nested logger and async fields" {
let text = stringify_async_logger_build_config(
AsyncLoggerBuildConfig::new(
logger=@bitlogger.LoggerConfig::new(
min_level=@bitlogger.Level::Warn,
target="async.roundtrip",
timestamp=true,
sink=@bitlogger.SinkConfig::new(kind=@bitlogger.SinkKind::TextConsole),
),
async_config=AsyncLoggerConfig::new(
max_pending=2,
overflow=AsyncOverflowPolicy::DropNewest,
max_batch=5,
linger_ms=40,
flush=AsyncFlushPolicy::Shutdown,
),
),
)
let config = parse_async_logger_build_config_text(text)
inspect(config.logger.min_level.label(), content="WARN")
inspect(config.logger.target, content="async.roundtrip")
inspect(config.logger.timestamp, content="true")
inspect(config.async_config.max_pending, content="2")
inspect(config.async_config.max_batch, content="5")
inspect(config.async_config.linger_ms, content="40")
inspect(match config.async_config.overflow {
AsyncOverflowPolicy::Blocking => "Blocking"
AsyncOverflowPolicy::DropOldest => "DropOldest"
AsyncOverflowPolicy::DropNewest => "DropNewest"
}, content="DropNewest")
inspect(match config.async_config.flush {
AsyncFlushPolicy::Never => "Never"
AsyncFlushPolicy::Batch => "Batch"
AsyncFlushPolicy::Shutdown => "Shutdown"
}, content="Shutdown")
}
-234
View File
@@ -1,234 +0,0 @@
pub(all) suberror AsyncLoggerClosed {
AsyncLoggerClosed
}
pub(all) enum AsyncOverflowPolicy {
Blocking
DropOldest
DropNewest
}
pub(all) enum AsyncFlushPolicy {
Never
Batch
Shutdown
}
pub struct AsyncLoggerConfig {
max_pending : Int
overflow : AsyncOverflowPolicy
max_batch : Int
linger_ms : Int
flush : AsyncFlushPolicy
}
pub fn AsyncLoggerConfig::new(
max_pending~ : Int = 0,
overflow~ : AsyncOverflowPolicy = AsyncOverflowPolicy::Blocking,
max_batch~ : Int = 1,
linger_ms~ : Int = 0,
flush~ : AsyncFlushPolicy = AsyncFlushPolicy::Never,
) -> AsyncLoggerConfig {
{
max_pending,
overflow,
max_batch: if max_batch <= 1 { 1 } else { max_batch },
linger_ms: if linger_ms < 0 { 0 } else { linger_ms },
flush,
}
}
pub struct AsyncLogger[S] {}
pub struct AsyncLoggerBuildConfig {
logger : @bitlogger.LoggerConfig
async_config : AsyncLoggerConfig
}
pub fn AsyncLoggerBuildConfig::new(
logger~ : @bitlogger.LoggerConfig = @bitlogger.default_logger_config(),
async_config~ : AsyncLoggerConfig = AsyncLoggerConfig::new(),
) -> AsyncLoggerBuildConfig {
{ logger, async_config }
}
pub fn parse_async_logger_build_config_text(input : String) -> AsyncLoggerBuildConfig raise {
ignore(input)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn parse_async_logger_config_text(input : String) -> AsyncLoggerConfig raise {
ignore(input)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn async_logger_config_to_json(config : AsyncLoggerConfig) -> @json_parser.JsonValue {
ignore(config)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn stringify_async_logger_config(config : AsyncLoggerConfig, pretty~ : Bool = false) -> String {
ignore(config)
ignore(pretty)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn async_logger_build_config_to_json(
config : AsyncLoggerBuildConfig,
) -> @json_parser.JsonValue {
ignore(config)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn stringify_async_logger_build_config(
config : AsyncLoggerBuildConfig,
pretty~ : Bool = false,
) -> String {
ignore(config)
ignore(pretty)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn async_logger[S : @bitlogger.Sink](
sink : S,
config~ : AsyncLoggerConfig = AsyncLoggerConfig::new(),
min_level~ : @bitlogger.Level = @bitlogger.Level::Info,
target~ : String = "",
flush~ : (S) -> Int = fn(_) { 0 },
) -> AsyncLogger[S] {
ignore(sink)
ignore(config)
ignore(min_level)
ignore(target)
ignore(flush)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn[S] AsyncLogger::with_timestamp(self : AsyncLogger[S], enabled~ : Bool = true) -> AsyncLogger[S] {
ignore(self)
ignore(enabled)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn[S] AsyncLogger::with_target(self : AsyncLogger[S], target : String) -> AsyncLogger[S] {
ignore(self)
ignore(target)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn[S] AsyncLogger::with_context_fields(
self : AsyncLogger[S],
fields : Array[@bitlogger.Field],
) -> AsyncLogger[S] {
ignore(self)
ignore(fields)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn[S] AsyncLogger::with_filter(
self : AsyncLogger[S],
predicate : (@bitlogger.Record) -> Bool,
) -> AsyncLogger[S] {
ignore(self)
ignore(predicate)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn[S] AsyncLogger::with_patch(
self : AsyncLogger[S],
patch : @bitlogger.RecordPatch,
) -> AsyncLogger[S] {
ignore(self)
ignore(patch)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn[S] AsyncLogger::with_min_level(
self : AsyncLogger[S],
min_level : @bitlogger.Level,
) -> AsyncLogger[S] {
ignore(self)
ignore(min_level)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn[S] AsyncLogger::child(self : AsyncLogger[S], target : String) -> AsyncLogger[S] {
ignore(self)
ignore(target)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn[S] AsyncLogger::is_enabled(self : AsyncLogger[S], level : @bitlogger.Level) -> Bool {
ignore(self)
ignore(level)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn[S] AsyncLogger::pending_count(self : AsyncLogger[S]) -> Int {
ignore(self)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn[S] AsyncLogger::dropped_count(self : AsyncLogger[S]) -> Int {
ignore(self)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn[S] AsyncLogger::is_closed(self : AsyncLogger[S]) -> Bool {
ignore(self)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn[S] AsyncLogger::is_running(self : AsyncLogger[S]) -> Bool {
ignore(self)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn[S] AsyncLogger::has_failed(self : AsyncLogger[S]) -> Bool {
ignore(self)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn[S] AsyncLogger::last_error(self : AsyncLogger[S]) -> String {
ignore(self)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn[S] AsyncLogger::flush_policy(self : AsyncLogger[S]) -> AsyncFlushPolicy {
ignore(self)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn[S] AsyncLogger::close(self : AsyncLogger[S], clear? : Bool = false) -> Unit {
ignore(self)
ignore(clear)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub async fn[S] AsyncLogger::wait_idle(self : AsyncLogger[S]) -> Unit {
ignore(self)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub async fn[S] AsyncLogger::shutdown(self : AsyncLogger[S], clear? : Bool = false) -> Unit {
ignore(self)
ignore(clear)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub async fn[S : @bitlogger.Sink] AsyncLogger::run(self : AsyncLogger[S]) -> Unit {
ignore(self)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn build_async_logger(
config : AsyncLoggerBuildConfig,
) -> AsyncLogger[@bitlogger.RuntimeSink] {
ignore(config)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn build_async_text_logger(config : AsyncLoggerBuildConfig) -> AsyncLogger[@bitlogger.FormattedConsoleSink] {
ignore(config)
abort("bitlogger_async currently only supports native/llvm backends")
}
+42 -239
View File
@@ -2,33 +2,29 @@
BitLogger is a structured logging library written in MoonBit.
This README focuses on project positioning, core capabilities, and entry points. Detailed API coverage now lives in `docs/api/`.
## Overview
BitLogger currently provides:
BitLogger is designed to provide composable, configurable, and cross-target logging infrastructure for MoonBit projects.
- log levels: `Trace`, `Debug`, `Info`, `Warn`, `Error`
- structured key-value fields
- plain console output
- JSON console output
- child target composition via `child(...)`
- context fields via `with_context_fields(...)`
- optional timestamps via `with_timestamp()`
- sink fanout via `fanout_sink(...)`
- sink routing via `split_sink(...)` and `split_by_level(...)`
- custom integration via `callback_sink(...)`
- in-memory buffering via `buffered_sink(...)`
- record filtering via `filter_sink(...)`
- reusable filter helpers such as `target_has_prefix(...)`, `message_contains(...)`, `level_at_least(...)`, and `field_equals(...)`
- record patching via `with_patch(...)` and `patch_sink(...)`
- patch helpers such as `prefix_message(...)`, `append_fields(...)`, and `redact_fields(...)`
- context binding via `bind(...)` and `fields(...)`
- explicit queued delivery via `queued_sink(...)` and `with_queue(...)`
- bounded backlog with `QueueOverflowPolicy::DropNewest` and `QueueOverflowPolicy::DropOldest`
- configurable text formatting via `text_formatter(...)`, `format_text(...)`, `text_console_sink(...)`, and template-driven `template` output
- formatter-based callback integration via `formatted_callback_sink(...)`
- native-only file output via `file_sink(...)`, with basic size rotation, backup retention, explicit `reopen()` / `reopen_with_current_policy()` / `reopen_append()` / `reopen_truncate()`, and failure counters
- `native_files_supported()` for backend capability detection
- default global logger helpers
## Backend Compatibility
| Module / capability | native / llvm | js / wasm / wasm-gc |
| --- | --- | --- |
| `src` core package | Supported | Supported |
| `file_sink(...)` | Supported | Not available, `native_files_supported()` returns `false` |
| `src-async` | Native worker semantics | Compatibility implementation |
| `examples/async_basic` | Supported | Not shipped currently because `async fn main` entry support is still limited |
## Key Features
- Structured logging with levels, targets, and key-value fields.
- Composable sinks, filters, patches, fanout, routing, and queue wrappers.
- Config-driven runtime assembly through JSON parse/export helpers and `build_logger(...)` / `build_async_logger(...)`.
- Configurable text formatting with templates, style tags, and color control.
- Native file sink support with basic rotation, reopen helpers, and runtime observability.
- Separate async layer with bounded queueing, worker lifecycle control, runtime state, and cross-target compatibility.
## Quick Start
@@ -40,231 +36,38 @@ let logger = Logger::new(console_sink(), min_level=Level::Info, target="demo")
logger.info("starting", fields=[field("port", "8080")])
```
Child target composition:
Async entry example:
```moonbit
let worker = Logger::new(console_sink(), target="app").child("worker")
worker.info("job ready")
```
Custom callback sink:
```moonbit
let hook = Logger::new(
callback_sink(fn(rec) {
println("callback saw [\{rec.target}] \{rec.message}")
}),
target="hook",
)
hook.info("hello")
```
Basic buffered sink:
```moonbit
let sink = buffered_sink(console_sink(), flush_limit=2)
let logger = Logger::new(sink, target="buffered")
logger.info("one")
logger.info("two")
sink.flush()
```
Basic filter sink:
```moonbit
let sink = filter_sink(console_sink(), fn(rec) {
rec.target == "kept"
let logger = async_logger(console_sink(), target="async.demo")
@async.with_task_group(group => {
group.spawn_bg(() => logger.run())
logger.info("started")
logger.shutdown()
})
let kept = Logger::new(sink, target="kept")
let dropped = Logger::new(sink, target="dropped")
kept.info("visible")
dropped.info("hidden")
```
Chained logger filter:
```moonbit
let logger = Logger::new(console_sink(), target="service")
.with_filter(all_of([
target_has_prefix("service"),
message_contains("visible"),
]))
logger.info("hidden")
logger.child("api").info("visible")
```
Record patching:
```moonbit
let logger = Logger::new(console_sink(), target="auth")
.with_patch(compose_patches([
prefix_message("[safe] "),
redact_fields(["token"]),
append_fields([field("service", "bitlogger")]),
]))
logger.info("login", fields=[field("user", "alice"), field("token", "secret")])
```
Context binding:
```moonbit
let logger = Logger::new(console_sink(), target="audit")
.bind(fields([("service", "bitlogger"), ("scope", "login")]))
logger.info("accepted", fields=[field("user", "alice")])
```
Explicit queued sink:
```moonbit
let logger = Logger::new(console_sink(), target="queue")
.with_queue(max_pending=2, overflow=QueueOverflowPolicy::DropOldest)
logger.info("one")
logger.info("two")
logger.info("three")
ignore(logger.sink.flush())
```
Level-based split sink:
```moonbit
let logger = Logger::new(
split_by_level(
callback_sink(fn(rec) {
println("high priority: \{rec.level.label()} \{rec.message}")
}),
console_sink(),
min_level=Level::Warn,
),
min_level=Level::Trace,
target="split",
)
logger.info("normal output")
logger.warn("warning output")
```
Custom text formatter:
```moonbit
let formatter = text_formatter(
show_timestamp=false,
field_separator=",",
template="[{level}] {target} {message} :: {fields}",
)
let logger = Logger::new(text_console_sink(formatter), target="pretty")
logger.info("hello", fields=[field("mode", "pretty")])
```
JSON config loading:
```moonbit
let config = parse_logger_config_text(
"{\"min_level\":\"debug\",\"target\":\"config.demo\",\"timestamp\":true,\"sink\":{\"kind\":\"text_console\",\"text_formatter\":{\"show_timestamp\":false,\"field_separator\":\",\",\"template\":\"[{level}] {target} {message} :: {fields}\"}},\"queue\":{\"max_pending\":2,\"overflow\":\"DropOldest\"}}",
)
let logger = build_logger(config)
logger.info("configured from json")
ignore(logger.flush())
```
Native file sink:
```moonbit
if native_files_supported() {
let logger = Logger::new(
file_sink("bitlogger.log", rotation=Some(file_rotation(128, max_backups=2))),
target="file",
)
logger.info("hello", fields=[field("kind", "file")])
ignore(logger.sink.flush())
ignore(logger.sink.close())
}
```
File runtime state dump:
```moonbit
let logger = build_logger(
LoggerConfig::new(
sink=SinkConfig::new(kind=SinkKind::File, path="bitlogger-runtime.log"),
queue=Some(QueueConfig::new(16)),
),
)
logger.info("queued hello")
match logger.file_runtime_state() {
Some(snapshot) => println(stringify_runtime_file_state(snapshot, pretty=true))
None => ()
}
```
## Repository Layout
- `bitlogger/`: MoonBit library package, tests, and Mooncake package README
- `examples/basic/`: runnable example package
- `examples/async_basic/`: runnable async logger example built on `moonbitlang/async`
- `src/`: core logging package.
- `src-async/`: async logging layer built on `moonbitlang/async`.
- `docs/api/`: one-file-per-interface API documentation.
- `examples/basic/`: minimal synchronous example.
- `examples/async_basic/`: async logger example.
## Links
## Documentation Entry Points
- [Mooncake package page](https://mooncakes.io/docs/Nanaloveyuki/BitLogger)
- [Chinese README](../README.md)
- [src package README](../src/README.mbt.md)
- Selected API docs in `docs/api/`:
- [logger-new.md](./api/logger-new.md)
- [async-logger.md](./api/async-logger.md)
- [build-logger.md](./api/build-logger.md)
- [build-async-logger.md](./api/build-async-logger.md)
## Config Notes
## Notes
- BitLogger now includes a JSON config layer via `parse_logger_config_text(...)`, `stringify_logger_config(...)`, and `build_logger(...)`.
- `QueueConfig`, `TextFormatterConfig`, and `SinkConfig` can also be exported independently through `queue_config_to_json(...)` / `stringify_queue_config(...)`, `text_formatter_config_to_json(...)` / `stringify_text_formatter_config(...)`, and `sink_config_to_json(...)` / `stringify_sink_config(...)`.
- Supported keys include `min_level`, `target`, `timestamp`, `sink.kind`, `sink.path`, `sink.append`, `sink.auto_flush`, `sink.rotation`, `sink.text_formatter`, and `queue`.
- `sink.rotation` currently supports `max_bytes` and `max_backups` for basic size-based rotation and backup retention.
- `file_sink(...)` also exposes `reopen()`, `reopen_with_current_policy()`, `reopen_append()`, `reopen_truncate()`, `open_failures()`, `write_failures()`, `flush_failures()`, and `rotation_failures()` for basic observability.
- `file_sink(...)` also exposes `append_mode()`. Passing `append=...` to `reopen(...)` updates the current append policy used by later reopen calls, `reopen_with_current_policy()` makes that stored-policy reopen path explicit, and `reopen_append()` / `reopen_truncate()` cover the two common policy switches directly.
- `file_sink(...)` also supports `set_append_mode(...)` for explicitly changing the append policy that later reopen calls will use.
- `file_sink(...)` also exposes `path()` and `auto_flush_enabled()` for reading basic file-sink policy state.
- `file_sink(...)` also exposes `rotation_enabled()` and `rotation_config()` for reading whether rotation is active and which parameters are currently in effect.
- `file_sink(...)` also exposes `state()` for reading a single snapshot that includes path, availability, append policy, auto-flush flag, rotation config, and all current failure counters.
- `file_sink(...)` also exposes `policy()` and `default_policy()` for reading the current runtime policy and the sink's original default policy separately.
- `file_sink(...)` also exposes `policy_matches_default()` for explicitly checking whether the current runtime policy has drifted from the original defaults.
- `file_sink(...)` also exposes `set_policy(...)` for applying append, auto-flush, and rotation as a single bundled runtime policy update.
- `file_sink(...)` also exposes `reset_failure_counters()` so open/write/flush/rotation failure counters can be cleared after diagnostics or recovery handling.
- `file_sink(...)` also exposes `reset_policy()` so append, auto-flush, and rotation settings can be restored to the sink's original defaults.
- `file_sink(...)` also supports `set_auto_flush(...)`, `set_rotation(...)`, and `clear_rotation()` for runtime policy updates.
- `ConfiguredLogger` built through `build_logger(...)` also exposes `file_reopen()`, `file_reopen_with_current_policy()`, `file_reopen_append()`, `file_reopen_truncate()`, `file_flush()`, `file_close()`, `file_append_mode()`, `file_path()`, `file_auto_flush()`, `file_rotation_enabled()`, `file_rotation_config()`, `file_state()`, plus `file_set_append_mode(...)`, `file_set_auto_flush(...)`, `file_set_rotation(...)`, `file_clear_rotation()`, and the corresponding file failure counters, so config-driven file logging keeps a usable control surface.
- `ConfiguredLogger` also exposes `file_runtime_state()` so queued file loggers can report both the underlying file snapshot and the outer queue backlog/drop state in one read.
- `ConfiguredLogger` also exposes `file_policy()` and `file_default_policy()` for reading current runtime file policy and initial config policy separately.
- `ConfiguredLogger` also exposes `file_policy_matches_default()` for explicitly checking whether the current runtime file policy differs from its default config.
- `ConfiguredLogger` also exposes `file_set_policy(...)` for applying a bundled runtime file policy through the config-built control surface.
- `ConfiguredLogger` also exposes `file_reset_failure_counters()` for clearing file failure counters through the config-built control surface.
- `ConfiguredLogger` also exposes `file_reset_policy()` for restoring runtime file policy back to the initial config values.
- `file_sink_policy_to_json(...)` and `stringify_file_sink_policy(...)` can export standalone file-policy snapshots directly as JSON for policy diffing, diagnostics, or reporting.
- `file_sink_state_to_json(...)`, `stringify_file_sink_state(...)`, `runtime_file_state_to_json(...)`, and `stringify_runtime_file_state(...)` can export file and queued-file snapshots directly as JSON for diagnostics or reporting.
- `sink.text_formatter.template` currently supports fixed tokens: `{timestamp}`, `{timestamp_ms}`, `{level}`, `{target}`, `{message}`, and `{fields}`.
- Config-driven sink assembly currently supports `console`, `json_console`, `text_console`, and `file`.
- `queue` remains a synchronous bounded wrapper around the final sink, not an async runtime.
## Async Layer
- A separate `bitlogger_async/` package is now included.
- It uses `moonbitlang/async` and provides `AsyncLogger`, `async_logger(...)`, a background `run()` worker, and bounded async queue delivery.
- The current async API already supports `with_context_fields(...)`, `with_filter(...)`, `with_patch(...)`, `with_target(...)`, and `child(...)`.
- `shutdown()` is now the recommended way to stop the async worker. By default it waits for the queue to drain, closes the queue, and then waits for the worker to exit.
- Basic lifecycle observability is also available through `is_closed()`, `is_running()`, `has_failed()`, and `last_error()`.
- The async worker now supports batched queue draining via `max_batch` and basic flush policies through `flush=Never|Batch|Shutdown`.
- The recommended startup pattern is shown in [examples/async_basic/main.mbt](/E:/repo/MooLiteyukiBot/examples/async_basic/main.mbt:1).
- This layer currently targets `native/llvm` only and remains isolated from the synchronous logger core.
### Async Config
- `parse_async_logger_config_text(...)`, `stringify_async_logger_config(...)`, `parse_async_logger_build_config_text(...)`, and `build_async_logger(...)` are now available.
- The JSON root is split into `logger` and `async_config`.
- `logger` fully reuses the synchronous `LoggerConfig` schema, while `async_config` currently supports `max_pending`, `overflow`, `max_batch`, and `flush`.
- The recommended config-driven startup flow is shown in [examples/async_basic/main.mbt](/E:/repo/MooLiteyukiBot/examples/async_basic/main.mbt:1).
- `docs/README-en.md` no longer acts as an API catalog.
- Detailed API references, config fields, runtime control helpers, and lifecycle surfaces now live under `docs/api/`.
- For concrete runnable flows, prefer `examples/`.
+146
View File
@@ -0,0 +1,146 @@
---
name: example-api
group: dev
category: example-group
update-time: 20260512
description: An example API file to show how to write API doc.
key-word:
- example
- async
- sync
- public
- doc
---
**ONE API ONE FILE**
## Example-api-name
long discription.
### Interface
```moonbit
pub fn function_name(input) -> output {}
```
#### input
- `args : type` - Explain
#### output
- `output : type` - Explain
---
> `---` Just when interface has double or more write. Used to separate two different APIs.
<!--
e.g.:
```moonbit
pub fn target_is(target : String) -> RecordPredicate {}
```
#### input
- `target : String` - the expected target value
#### output
- `RecordPredicate` - a predicate used for filtering records
---
-->
> Use<! --The content packaged with -->does not actually need to be written in the official document, it is only used as an example for reference.
It is not necessary to write the complete function implementation.
### Explanation
Detailed rules explaining key parameters and behaviors
- ...
### How to Use
Here are some specific examples provided.
e.g.:
#### <What-Time-To-Use>
> title like: `#### When Need Colorful Formatter`
When sometime ...:
```moonbit
impl
```
In this example, <something> will <do-what>.
And <extra-info>.
#### <Next-Use-Method>
...
### Error Case
e.g.:
- If `target` is empty, returns a predicate that always evaluates to false.
- ...
...
### Notes
1. ...
2. ...
...
---
## API MARKDOWN YAML HEADER
> This just is an example, `---` in fact has yaml grammer error.
```yaml
---
name: example-api
group: dev
category: example-group
update-time: 20260512
description: An example API file to show how to write API doc.
key-word:
- example
- async
- sync
- public
- doc
---
```
It has 6 key:
- `name` - short and clear api name
- `group` - in static doc template site will use this key to render how to fold and group
- `category` - fastly search category in repo and will be used in template site
- `update-time` - full number use YYYYMMdd(year, month, day)
- `discription` - short discription
- `key-word` - use 2~5 key-words to help user fastly search
## Title Capitalization Standards
NO `# ...`
- `## ...` use `Abcd`
- `### ...` use `Abcd`
- `#### ...` use `abcd`
NO `##### ...`
+82
View File
@@ -0,0 +1,82 @@
---
name: all-of
group: api
category: filtering
update-time: 20260512
description: Create a reusable record predicate that requires every nested predicate to pass.
key-word:
- combine
- filter
- predicate
- public
---
## All-of
Create a `RecordPredicate` that returns `true` only when every predicate in the array returns `true`. This helper is the standard way to build strict multi-condition filters.
### Interface
```moonbit
pub fn all_of(predicates : Array[RecordPredicate]) -> RecordPredicate {}
```
#### input
- `predicates : Array[RecordPredicate]` - Predicates that must all succeed for a record to match.
#### output
- `RecordPredicate` - Predicate that returns `true` only when every nested predicate returns `true`.
### Explanation
Detailed rules explaining key parameters and behaviors
- Predicates are evaluated in array order.
- Evaluation stops early on the first predicate that returns `false`.
- If the array is empty, the combined predicate returns `true` because no condition failed.
- This helper is ideal for combining namespace, level, and field requirements into one reusable rule.
### How to Use
Here are some specific examples provided.
#### When Require Several Conditions
When routing should be both target- and level-aware:
```moonbit
let predicate = all_of([
target_has_prefix("service.api"),
level_at_least(Level::Warn),
])
```
In this example, records must satisfy both conditions before they pass.
#### When Add Field Constraints
When only contextual failures should remain:
```moonbit
let predicate = all_of([
message_contains("failed"),
has_field("request_id"),
not_(field_equals("tenant", "internal")),
])
```
In this example, the filter stays readable even though the rule has several parts.
### Error Case
e.g.:
- If `predicates` is empty, the returned predicate always evaluates to `true`.
- If one nested predicate is too strict, the whole combination may reject more records than expected.
### Notes
1. Put the cheapest or most selective predicates earlier when evaluation cost matters.
2. `all_of(...)` is usually easier to maintain than a custom inline predicate closure.
+82
View File
@@ -0,0 +1,82 @@
---
name: any-of
group: api
category: filtering
update-time: 20260512
description: Create a reusable record predicate that passes when any nested predicate matches.
key-word:
- combine
- filter
- predicate
- public
---
## Any-of
Create a `RecordPredicate` that returns `true` when at least one predicate in the array returns `true`. This helper is useful for routing several independent cases through the same path.
### Interface
```moonbit
pub fn any_of(predicates : Array[RecordPredicate]) -> RecordPredicate {}
```
#### input
- `predicates : Array[RecordPredicate]` - Predicates where any successful match should admit the record.
#### output
- `RecordPredicate` - Predicate that returns `true` when at least one nested predicate returns `true`.
### Explanation
Detailed rules explaining key parameters and behaviors
- Predicates are evaluated in array order.
- Evaluation stops early on the first predicate that returns `true`.
- If the array is empty, the combined predicate returns `false` because no predicate matched.
- This helper is useful when several targets, levels, or field signatures should share one sink.
### How to Use
Here are some specific examples provided.
#### When Accept Several Target Paths
When multiple subsystems should share one route:
```moonbit
let predicate = any_of([
target_is("audit"),
target_has_prefix("security"),
])
```
In this example, either matching branch is enough for the record to pass.
#### When Combine Different Diagnostic Conditions
When several independent signals are interesting:
```moonbit
let predicate = any_of([
level_at_least(Level::Error),
message_contains("timeout"),
field_equals("retryable", "true"),
])
```
In this example, one satisfied condition is enough to keep the record visible.
### Error Case
e.g.:
- If `predicates` is empty, the returned predicate always evaluates to `false`.
- If one nested predicate is too broad, it may shadow the intent of the other branches.
### Notes
1. Put the most common or cheapest success path earlier when evaluation cost matters.
2. Use `any_of(...)` when a single sink should accept multiple independent match patterns.
+82
View File
@@ -0,0 +1,82 @@
---
name: append-fields
group: api
category: patching
update-time: 20260512
description: Create a reusable record patch that appends extra fields to the record.
key-word:
- patch
- fields
- transform
- public
---
## Append-fields
Create a `RecordPatch` that appends extra fields to `rec.fields`. Use it when records should be enriched with stable metadata before reaching sinks.
### Interface
```moonbit
pub fn append_fields(extra_fields : Array[Field]) -> RecordPatch {}
```
#### input
- `extra_fields : Array[Field]` - Fields appended after the record's existing field list.
#### output
- `RecordPatch` - Patch that returns a record with appended fields.
### Explanation
Detailed rules explaining key parameters and behaviors
- If `extra_fields` is empty, the patch returns the original record unchanged.
- If the original record has no fields, the appended fields become the new field list.
- Otherwise, the original fields stay first and `extra_fields` are appended afterward.
- This helper is useful for environment tags, service metadata, and bridge-layer context.
### How to Use
Here are some specific examples provided.
#### When Add Service Metadata
When every record should carry shared context:
```moonbit
let logger = Logger::new(console_sink())
.with_patch(append_fields([
field("service", "billing"),
field("region", "cn"),
]))
```
In this example, the extra fields are added to every emitted record.
#### When Compose With Message Rewriting
When both visible and structured context are needed:
```moonbit
let patch = compose_patches([
prefix_message("[api] "),
append_fields([field("component", "gateway")]),
])
```
In this example, the record gains both textual and structured enrichment.
### Error Case
e.g.:
- If `extra_fields` is empty, the patch behaves like a no-op.
- If appended field keys duplicate existing keys, both copies remain in the field list.
### Notes
1. This helper appends fields; it does not deduplicate or overwrite existing entries.
2. Field order can matter for downstream formatting or inspection, so keep appended context intentional.
@@ -0,0 +1,76 @@
---
name: async-logger-build-config-to-json
group: api
category: async
update-time: 20260512
description: Convert AsyncLoggerBuildConfig into a JSON value for exporting complete async logger build settings.
key-word:
- async
- build
- config
- public
---
## Async-logger-build-config-to-json
Convert `AsyncLoggerBuildConfig` into a `JsonValue`. This helper exports both the base synchronous logger config and the async runtime config as one structured payload.
### Interface
```moonbit
pub fn async_logger_build_config_to_json(
config : AsyncLoggerBuildConfig,
) -> @json_parser.JsonValue {}
```
#### input
- `config : AsyncLoggerBuildConfig` - Complete build config used by async logger builders.
#### output
- `JsonValue` - Structured JSON representation of the full async build config.
### Explanation
Detailed rules explaining key parameters and behaviors
- The output always includes `logger` and `async_config`.
- Logger export is delegated to `@bitlogger.logger_config_to_json(...)`.
- Async export is delegated to `async_logger_config_to_json(...)`.
- This helper is useful when generated setup should preserve both sink/logger behavior and async runtime behavior together.
### How to Use
Here are some specific examples provided.
#### When Need Structured Export Of Full Async Setup
When a tool or test needs one object describing the whole async logger build:
```moonbit
let payload = async_logger_build_config_to_json(
AsyncLoggerBuildConfig::new(
logger=@bitlogger.LoggerConfig::new(target="svc"),
async_config=AsyncLoggerConfig::new(max_pending=64),
),
)
```
In this example, both layers of configuration are exported together.
#### When Need Roundtrip-friendly Build Config Data
When generated build config should later be parsed again:
```moonbit
let value = async_logger_build_config_to_json(AsyncLoggerBuildConfig::new())
```
In this example, the resulting JSON matches the supported async build config shape.
### Error Case
e.g.:
- If callers only need the async runtime section, this API is broader than necessary and `async_logger_config_to_json(...)` should be used instead.
- If callers want direct text output, they should use `stringify_async_logger_build_config(...)` instead.
+78
View File
@@ -0,0 +1,78 @@
---
name: async-logger-child
group: api
category: async
update-time: 20260512
description: Derive a child async logger by composing the current target with a child target segment.
key-word:
- async
- logger
- target
- public
---
## Async-logger-child
Create a child async logger by composing the current target with another target segment. This is the standard API for hierarchical async logger naming such as `app.worker` or `service.http.client`.
### Interface
```moonbit
pub fn[S] AsyncLogger::child(self : AsyncLogger[S], target : String) -> AsyncLogger[S] {}
```
#### input
- `self : AsyncLogger[S]` - Parent async logger whose target should be extended.
- `target : String` - Child target segment or suffix.
#### output
- `AsyncLogger[S]` - A new async logger whose default target is the composed child path.
### Explanation
Detailed rules explaining key parameters and behaviors
- 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 both are non-empty, they are joined with `.`.
- Queue settings, sink wiring, and runtime behavior are preserved in the returned logger.
### How to Use
Here are some specific examples provided.
#### When Need Hierarchical Async Targets
When subsystem logs should stay grouped under one async namespace:
```moonbit
let logger = async_logger(console_sink(), target="service")
let worker = logger.child("worker")
```
In this example, `worker` emits under `service.worker` while keeping the same async queue behavior.
#### When Build Deep Async Scopes Step By Step
When deeper target composition should remain readable:
```moonbit
let http = async_logger(console_sink(), target="app")
.child("http")
.child("client")
```
In this example, the final logger target becomes `app.http.client`.
### Error Case
e.g.:
- If `target` is empty, the returned logger keeps the original parent target.
- If callers need complete replacement rather than composition, `with_target(...)` should be used instead.
### Notes
1. This is the preferred API for hierarchical async logger naming.
2. Composition changes the target only and does not rebuild the queue or sink.
+75
View File
@@ -0,0 +1,75 @@
---
name: async-logger-close
group: api
category: async
update-time: 20260512
description: Close the async logger queue and optionally clear pending records immediately.
key-word:
- async
- logger
- lifecycle
- public
---
## Async-logger-close
Close the async logger queue and stop treating the logger as an active enqueue target. This API is the low-level lifecycle close primitive behind shutdown flows.
### Interface
```moonbit
pub fn[S] AsyncLogger::close(self : AsyncLogger[S], clear? : Bool = false) -> Unit {}
```
#### input
- `self : AsyncLogger[S]` - Async logger that should be closed.
- `clear : Bool` - Whether pending records should be abandoned immediately instead of being left for drain behavior.
#### output
- `Unit` - No return value. The logger lifecycle state is updated in place.
### Explanation
Detailed rules explaining key parameters and behaviors
- `close(...)` marks the logger as closed immediately.
- `clear=false` closes the queue without explicitly abandoning pending records in the helper itself.
- `clear=true` counts pending records as dropped and resets `pending_count` to `0` before closing the queue.
- This helper does not itself wait for the worker to finish.
### How to Use
Here are some specific examples provided.
#### When Need Immediate Queue Closure
When teardown should stop normal enqueue activity right away:
```moonbit
logger.close()
```
In this example, the logger enters closed state immediately.
#### When Need To Abandon Backlog Explicitly
When pending records should be discarded during fast shutdown:
```moonbit
logger.close(clear=true)
```
In this example, queued backlog is counted as dropped instead of waiting for further drain.
### Error Case
e.g.:
- If `clear=true`, pending records are intentionally discarded and contribute to `dropped_count()`.
- If callers need graceful waiting for drain completion, `shutdown()` is usually the better API.
### Notes
1. This is a low-level lifecycle helper; prefer `shutdown()` for normal graceful teardown.
2. Use `clear=true` only when backlog loss is an acceptable shutdown tradeoff.
+71
View File
@@ -0,0 +1,71 @@
---
name: async-logger-config-to-json
group: api
category: async
update-time: 20260512
description: Convert AsyncLoggerConfig into a JSON value for export, persistence, or generated async config output.
key-word:
- async
- config
- json
- public
---
## Async-logger-config-to-json
Convert a typed `AsyncLoggerConfig` into a `JsonValue`. This helper exports async queue capacity, overflow policy, batch sizing, linger timing, and flush behavior in a structured form.
### Interface
```moonbit
pub fn async_logger_config_to_json(config : AsyncLoggerConfig) -> @json_parser.JsonValue {}
```
#### input
- `config : AsyncLoggerConfig` - Async logger runtime config to export.
#### output
- `JsonValue` - Structured JSON representation of the async config.
### Explanation
Detailed rules explaining key parameters and behaviors
- The output includes `max_pending`, `max_batch`, `linger_ms`, `overflow`, and `flush`.
- Policy fields are serialized using the stable labels accepted by the config parser.
- This helper exports effective typed config after constructor normalization has already happened.
- The JSON shape matches the `async_config` section used by async build config parsing.
### How to Use
Here are some specific examples provided.
#### When Need Structured Async Config Export
When async runtime policy should be embedded in a larger JSON payload:
```moonbit
let async_json = async_logger_config_to_json(
AsyncLoggerConfig::new(max_pending=128, max_batch=8),
)
```
In this example, callers receive a machine-readable config value.
#### When Need Roundtrip-friendly Async Settings
When code generates async policy and later persists it:
```moonbit
let value = async_logger_config_to_json(AsyncLoggerConfig::new(flush=AsyncFlushPolicy::Batch))
```
In this example, the exported JSON stays aligned with parser expectations.
### Error Case
e.g.:
- If `max_batch` or `linger_ms` were normalized during construction, the exported JSON reflects the normalized values rather than the original invalid inputs.
- If callers want direct text output instead of a JSON value, they should use `stringify_async_logger_config(...)` instead.
+90
View File
@@ -0,0 +1,90 @@
---
name: async-logger-config
group: api
category: async
update-time: 20260512
description: Create the queue, batching, linger, and flush policy config used by async loggers.
key-word:
- async
- config
- queue
- public
---
## Async-logger-config
Create an `AsyncLoggerConfig` value describing queue capacity, overflow behavior, batching size, linger timing, and flush policy for async logger construction.
### Interface
```moonbit
pub fn AsyncLoggerConfig::new(
max_pending~ : Int = 0,
overflow~ : AsyncOverflowPolicy = AsyncOverflowPolicy::Blocking,
max_batch~ : Int = 1,
linger_ms~ : Int = 0,
flush~ : AsyncFlushPolicy = AsyncFlushPolicy::Never,
) -> AsyncLoggerConfig {}
```
#### input
- `max_pending : Int` - Maximum queued records.
- `overflow : AsyncOverflowPolicy` - Queue overflow strategy.
- `max_batch : Int` - Maximum records drained per batch.
- `linger_ms : Int` - Optional wait window for batch accumulation.
- `flush : AsyncFlushPolicy` - Flush behavior for batch/shutdown phases.
#### output
- `AsyncLoggerConfig` - Async runtime config object used by `async_logger(...)` or async build helpers.
### Explanation
Detailed rules explaining key parameters and behaviors
- `max_batch <= 1` is normalized to `1`.
- `linger_ms < 0` is normalized to `0`.
- `overflow` and `flush` define the most important queue/runtime behavior tradeoffs.
- This type is used directly by `async_logger(...)` and embedded in `AsyncLoggerBuildConfig`.
### How to Use
Here are some specific examples provided.
#### When Tune Async Queue Backlog And Batch Size
When async behavior should be explicit in code:
```moonbit
let config = AsyncLoggerConfig::new(
max_pending=128,
overflow=AsyncOverflowPolicy::DropOldest,
max_batch=8,
linger_ms=10,
flush=AsyncFlushPolicy::Batch,
)
```
In this example, queue pressure, batch size, and flush timing are configured together.
#### When Export Async Config
When async policy should be serialized or logged:
```moonbit
println(stringify_async_logger_config(AsyncLoggerConfig::new(max_pending=8)))
```
In this example, the config becomes a stable JSON payload.
### Error Case
e.g.:
- If `max_batch` is set to `0` or below, runtime config normalizes it to `1`.
- If `linger_ms` is negative, it is normalized to `0`.
### Notes
1. This type controls async runtime behavior, not synchronous queue wrapping.
2. Prefer explicit values for production services so overflow and flush semantics are visible.
+83
View File
@@ -0,0 +1,83 @@
---
name: async-logger-debug
group: api
category: async
update-time: 20260512
description: Enqueue a debug-level record through the async logger using the built-in severity shortcut.
key-word:
- async
- logger
- debug
- public
---
## Async-logger-debug
Enqueue a debug-level record through the async logger. This is the convenience wrapper for `log(Level::Debug, ...)`.
### Interface
```moonbit
pub async fn[S] AsyncLogger::debug(
self : AsyncLogger[S],
message : String,
fields~ : Array[@bitlogger.Field] = [],
) -> Unit {}
```
#### input
- `self : AsyncLogger[S]` - Async logger that should receive the debug record.
- `message : String` - Debug message text.
- `fields : Array[Field]` - Optional structured fields added to the record.
#### output
- `Unit` - No return value. The record is handled according to logger state and policy.
### Explanation
Detailed rules explaining key parameters and behaviors
- This helper delegates to `log(Level::Debug, ...)`.
- The record is still subject to min-level gating, patching, filtering, and overflow policy.
- Debug records are useful for development and targeted diagnostics.
- Use this helper when a named debug call is clearer than a raw `log(...)` call.
### How to Use
Here are some specific examples provided.
#### When Need Async Development Diagnostics
When intermediate async flow details should be visible during debugging:
```moonbit
await logger.debug("loaded worker config")
```
In this example, the call site communicates its intended diagnostic level directly.
#### When Attach Structured Debug Context
When a debug event should include extra fields:
```moonbit
await logger.debug(
"dispatch start",
fields=[@bitlogger.field("job_id", "42")],
)
```
In this example, the record carries structured context without needing the generic `log(...)` form.
### Error Case
e.g.:
- If the logger minimum level is above `Debug`, the record is skipped before enqueue.
- If the logger is closed or overflow policy prevents acceptance, the write may not become a normal queued record.
### Notes
1. Prefer this helper when the event is semantically debug-level.
2. Use `log(...)` when the level must be chosen dynamically.
+77
View File
@@ -0,0 +1,77 @@
---
name: async-logger-dropped-count
group: api
category: async
update-time: 20260512
description: Read the number of records dropped by the async logger because of overflow or queue clearing.
key-word:
- async
- logger
- queue
- public
---
## Async-logger-dropped-count
Read the cumulative number of records dropped by an async logger. This metric is useful when overflow policy or forced shutdown behavior may discard queued data.
### Interface
```moonbit
pub fn[S] AsyncLogger::dropped_count(self : AsyncLogger[S]) -> Int {}
```
#### input
- `self : AsyncLogger[S]` - Async logger whose dropped-record counter should be inspected.
#### output
- `Int` - Number of records dropped so far.
### Explanation
Detailed rules explaining key parameters and behaviors
- The counter increases when overflow policy discards records.
- The counter can also increase when `close(clear=true)` or `shutdown(clear=true)` abandons queued records.
- This is a cumulative counter for the lifetime of the logger value.
- Use this helper when you need a focused loss metric rather than a full `state()` snapshot.
### How to Use
Here are some specific examples provided.
#### When Need To Detect Loss Under Pressure
When queue overflow may discard records:
```moonbit
if logger.dropped_count() > 0 {
println("async log loss detected")
}
```
In this example, the code checks whether the async logger has already discarded records.
#### When Validate Shutdown Behavior In Tests
When a test intentionally clears the queue:
```moonbit
logger.close(clear=true)
ignore(logger.dropped_count())
```
In this example, the drop counter helps confirm that abandoned backlog was tracked.
### Error Case
e.g.:
- If no records have been dropped, the method simply returns `0`.
- If callers need to know why records were lost, they must interpret this metric together with overflow policy and shutdown behavior.
### Notes
1. This helper reports record loss only; it does not explain the full logger state.
2. Pair it with `pending_count()` or `state()` when investigating backlog pressure.
+83
View File
@@ -0,0 +1,83 @@
---
name: async-logger-error
group: api
category: async
update-time: 20260512
description: Enqueue an error-level record through the async logger using the highest built-in severity shortcut.
key-word:
- async
- logger
- error
- public
---
## Async-logger-error
Enqueue an error-level record through the async logger. This is the convenience wrapper for `log(Level::Error, ...)`.
### Interface
```moonbit
pub async fn[S] AsyncLogger::error(
self : AsyncLogger[S],
message : String,
fields~ : Array[@bitlogger.Field] = [],
) -> Unit {}
```
#### input
- `self : AsyncLogger[S]` - Async logger that should receive the error record.
- `message : String` - Error message text.
- `fields : Array[Field]` - Optional structured fields added to the record.
#### output
- `Unit` - No return value. The record is handled according to logger state and policy.
### Explanation
Detailed rules explaining key parameters and behaviors
- This helper delegates to `log(Level::Error, ...)`.
- The record is still subject to patching, filtering, and overflow policy.
- Error records represent the highest built-in severity in this logger API.
- Use this helper when a named error call is clearer than a raw `log(...)` call.
### How to Use
Here are some specific examples provided.
#### When Need Async Failure Reporting
When an operation should emit a high-severity failure event:
```moonbit
await logger.error("worker execution failed")
```
In this example, failure intent is explicit at the call site.
#### When Attach Structured Error Context
When an error event should include diagnostic fields:
```moonbit
await logger.error(
"dispatch failed",
fields=[@bitlogger.field("job_id", "42")],
)
```
In this example, the error record carries structured context without falling back to the generic `log(...)` form.
### Error Case
e.g.:
- If the logger is closed or overflow policy prevents acceptance, even an error-level record may not become a normal queued record.
- If callers need to inspect worker failure rather than emit an error record, `has_failed()` and `last_error()` are the relevant APIs.
### Notes
1. Use this helper for high-severity async application failures.
2. Emitting an error record is separate from the logger worker itself entering failure state.
+74
View File
@@ -0,0 +1,74 @@
---
name: async-logger-flush-policy
group: api
category: async
update-time: 20260512
description: Read the async logger flush policy currently governing batch and shutdown flushing behavior.
key-word:
- async
- logger
- flush
- public
---
## Async-logger-flush-policy
Read the async logger flush policy. This helper exposes which flush mode currently controls batch and shutdown behavior.
### Interface
```moonbit
pub fn[S] AsyncLogger::flush_policy(self : AsyncLogger[S]) -> AsyncFlushPolicy {}
```
#### input
- `self : AsyncLogger[S]` - Async logger whose flush policy should be inspected.
#### output
- `AsyncFlushPolicy` - Current flush policy used by the async worker logic.
### Explanation
Detailed rules explaining key parameters and behaviors
- The returned value reflects the policy captured when the async logger was created.
- `Batch` causes explicit flush calls after worker batch processing.
- `Shutdown` causes explicit flush calls at worker shutdown.
- `Never` leaves flushing entirely to sink behavior or external control.
### How to Use
Here are some specific examples provided.
#### When Need To Inspect Runtime Flush Semantics
When diagnostics should show how the worker flushes:
```moonbit
ignore(logger.flush_policy())
```
In this example, the configured flush mode is exposed directly from the logger.
#### When Export Async Runtime Metadata
When code should include flush behavior in custom state reporting:
```moonbit
let flush = logger.flush_policy()
```
In this example, flush behavior can be surfaced without reading the full snapshot.
### Error Case
e.g.:
- This helper does not expose a normal runtime error path; it returns the configured policy.
- If callers need the policy together with backlog and failure state, `state()` is usually the better API.
### Notes
1. This helper exposes configuration-driven runtime behavior, not dynamic worker health.
2. Use `state()` when you want flush policy packaged with the rest of async logger diagnostics.
+76
View File
@@ -0,0 +1,76 @@
---
name: async-logger-has-failed
group: api
category: async
update-time: 20260512
description: Read whether the async logger worker has encountered a failure during queue drain.
key-word:
- async
- logger
- failure
- public
---
## Async-logger-has-failed
Read whether the async logger worker has encountered a failure. This helper is a compact health signal for async delivery problems.
### Interface
```moonbit
pub fn[S] AsyncLogger::has_failed(self : AsyncLogger[S]) -> Bool {}
```
#### input
- `self : AsyncLogger[S]` - Async logger whose failure flag should be inspected.
#### output
- `Bool` - Whether the worker has failed.
### Explanation
Detailed rules explaining key parameters and behaviors
- `run()` clears previous failure state at startup.
- If the worker loop raises an error, the logger records that failure and exposes it through this flag.
- This helper is intentionally compact and should usually be paired with `last_error()` for details.
- Failure state is about runtime drain execution, not whether records were dropped due to overflow policy.
### How to Use
Here are some specific examples provided.
#### When Need A Fast Failure Signal
When runtime diagnostics should branch on worker health:
```moonbit
if logger.has_failed() {
println(logger.last_error())
}
```
In this example, the code checks failure state first, then reads the error detail.
#### When Inspect Async Runtime State In Tests
When a test needs to confirm that drain execution stayed healthy:
```moonbit
ignore(logger.has_failed())
```
In this example, the helper exposes a simple pass-fail runtime indicator.
### Error Case
e.g.:
- If `has_failed()` is `false`, queue pressure or dropped records may still exist for non-failure reasons.
- If `has_failed()` is `true`, callers should inspect `last_error()` or `state()` for more context.
### Notes
1. This helper reports worker failure, not general queue stress.
2. Pair it with `last_error()` when you need actionable detail.
+83
View File
@@ -0,0 +1,83 @@
---
name: async-logger-info
group: api
category: async
update-time: 20260512
description: Enqueue an info-level record through the async logger using the most common built-in severity shortcut.
key-word:
- async
- logger
- info
- public
---
## Async-logger-info
Enqueue an info-level record through the async logger. This is the convenience wrapper for `log(Level::Info, ...)`.
### Interface
```moonbit
pub async fn[S] AsyncLogger::info(
self : AsyncLogger[S],
message : String,
fields~ : Array[@bitlogger.Field] = [],
) -> Unit {}
```
#### input
- `self : AsyncLogger[S]` - Async logger that should receive the info record.
- `message : String` - Info message text.
- `fields : Array[Field]` - Optional structured fields added to the record.
#### output
- `Unit` - No return value. The record is handled according to logger state and policy.
### Explanation
Detailed rules explaining key parameters and behaviors
- This helper delegates to `log(Level::Info, ...)`.
- The record is still subject to min-level gating, patching, filtering, and overflow policy.
- Info is often the default operational logging level for async application events.
- Use this helper when explicit info intent is clearer than a raw `log(...)` call.
### How to Use
Here are some specific examples provided.
#### When Need Normal Operational Async Events
When async code should report routine progress or lifecycle events:
```moonbit
await logger.info("worker started")
```
In this example, the event is expressed at the most common operational logging level.
#### When Add Structured Operational Metadata
When an info event should include stable structured detail:
```moonbit
await logger.info(
"job queued",
fields=[@bitlogger.field("queue", "sync")],
)
```
In this example, the record remains concise while still carrying useful metadata.
### Error Case
e.g.:
- If the logger minimum level is above `Info`, the record is skipped before enqueue.
- If the logger is closed or overflow policy prevents acceptance, the write may not become a normal queued record.
### Notes
1. This is often the most common convenience method for normal async application events.
2. Use `log(...)` when the call site needs a dynamic level or target override.
+77
View File
@@ -0,0 +1,77 @@
---
name: async-logger-is-closed
group: api
category: async
update-time: 20260512
description: Read whether the async logger has been closed and should no longer accept normal new queue traffic.
key-word:
- async
- logger
- lifecycle
- public
---
## Async-logger-is-closed
Read whether the async logger has been closed. This helper is useful for lifecycle checks around shutdown and queue finalization.
### Interface
```moonbit
pub fn[S] AsyncLogger::is_closed(self : AsyncLogger[S]) -> Bool {}
```
#### input
- `self : AsyncLogger[S]` - Async logger whose closure state should be inspected.
#### output
- `Bool` - Whether the logger has already been closed.
### Explanation
Detailed rules explaining key parameters and behaviors
- `close(...)` sets the closed state immediately.
- `shutdown(...)` also results in a closed logger by the end of its lifecycle flow.
- A closed logger should no longer be treated as a normal active enqueue target.
- This helper reflects lifecycle state only and does not indicate whether the worker is still draining.
### How to Use
Here are some specific examples provided.
#### When Guard Late-stage Logging
When code should avoid treating a logger as fully active during teardown:
```moonbit
if logger.is_closed() {
println("logger already closed")
}
```
In this example, teardown logic can branch on the closure state.
#### When Verify Shutdown Progress
When tests or diagnostics want to inspect lifecycle state:
```moonbit
logger.close()
ignore(logger.is_closed())
```
In this example, the helper confirms that close state was entered.
### Error Case
e.g.:
- If `is_closed()` returns `true`, pending records may still exist until drain or clear behavior completes.
- If callers need to know whether the worker is still active, they should also inspect `is_running()`.
### Notes
1. Closed state and running state are related but not identical.
2. Use this helper when lifecycle control matters more than queue counters.
+76
View File
@@ -0,0 +1,76 @@
---
name: async-logger-is-running
group: api
category: async
update-time: 20260512
description: Read whether the async logger worker is currently running and draining the queue.
key-word:
- async
- logger
- lifecycle
- public
---
## Async-logger-is-running
Read whether the async logger worker is currently active. This helper is useful for runtime diagnostics and shutdown coordination.
### Interface
```moonbit
pub fn[S] AsyncLogger::is_running(self : AsyncLogger[S]) -> Bool {}
```
#### input
- `self : AsyncLogger[S]` - Async logger whose worker state should be inspected.
#### output
- `Bool` - Whether the async worker loop is currently running.
### Explanation
Detailed rules explaining key parameters and behaviors
- `run()` sets the running state while the worker loop is active.
- The flag is cleared when the worker exits normally or after failure handling finishes.
- A logger may be closed while still running briefly during final drain or shutdown processing.
- This helper focuses on worker activity rather than queue size or failure details.
### How to Use
Here are some specific examples provided.
#### When Need Worker Activity Diagnostics
When runtime output should show whether the worker loop is active:
```moonbit
println(logger.is_running().to_string())
```
In this example, diagnostics can distinguish an idle configured logger from one with an active worker.
#### When Coordinate Shutdown Waiting
When code should poll worker completion explicitly:
```moonbit
while logger.is_running() {
@async.pause()
}
```
In this example, callers watch the worker lifecycle directly.
### Error Case
e.g.:
- If `is_running()` is `false`, pending records may still exist if the worker was never started or has already failed.
- If callers need a one-shot lifecycle flow, `shutdown()` is usually better than manual polling.
### Notes
1. Use this helper for worker activity checks, not as a complete health signal.
2. Pair it with `has_failed()` or `state()` when diagnosing stalled pipelines.
+76
View File
@@ -0,0 +1,76 @@
---
name: async-logger-last-error
group: api
category: async
update-time: 20260512
description: Read the last error recorded by the async logger worker during runtime failure handling.
key-word:
- async
- logger
- failure
- public
---
## Async-logger-last-error
Read the last error string recorded by the async logger worker. This helper gives the textual detail behind `has_failed()`.
### Interface
```moonbit
pub fn[S] AsyncLogger::last_error(self : AsyncLogger[S]) -> String {}
```
#### input
- `self : AsyncLogger[S]` - Async logger whose last worker error should be inspected.
#### output
- `String` - Last recorded worker error message, or an empty string if no error was recorded.
### Explanation
Detailed rules explaining key parameters and behaviors
- `run()` resets the stored error string when the worker starts.
- If the worker loop fails, the error text is captured from the raised exception.
- An empty string normally means no failure has been recorded.
- This helper reports worker execution errors, not ordinary overflow or backpressure conditions.
### How to Use
Here are some specific examples provided.
#### When Need Failure Detail In Diagnostics
When a compact error message should be surfaced to operators:
```moonbit
if logger.has_failed() {
println(logger.last_error())
}
```
In this example, the error string is only read when failure is present.
#### When Export Full Async State
When custom diagnostics want to include the last error field directly:
```moonbit
let err = logger.last_error()
```
In this example, the helper provides the textual failure detail without building a full snapshot.
### Error Case
e.g.:
- If no runtime failure has occurred, the method returns an empty string.
- If callers need broader context than just the error text, they should use `state()`.
### Notes
1. Read this helper together with `has_failed()` when interpreting worker health.
2. The stored value is a diagnostic string, not a typed error object.
+89
View File
@@ -0,0 +1,89 @@
---
name: async-logger-log
group: api
category: async
update-time: 20260512
description: Enqueue a record into the async logger with an explicit level, message, optional fields, and optional target override.
key-word:
- async
- logger
- log
- public
---
## Async-logger-log
Enqueue a record into the async logger with an explicit level and message. This is the core write API behind all async level-specific convenience methods.
### Interface
```moonbit
pub async fn[S] AsyncLogger::log(
self : AsyncLogger[S],
level : @bitlogger.Level,
message : String,
fields~ : Array[@bitlogger.Field] = [],
target? : String = "",
) -> Unit {}
```
#### input
- `self : AsyncLogger[S]` - Async logger that should receive the record.
- `level : Level` - Severity level for the record.
- `message : String` - Log message text.
- `fields : Array[Field]` - Optional structured fields added to the record.
- `target : String` - Optional per-call target override.
#### output
- `Unit` - No return value. The record is either skipped, enqueued, or dropped according to logger state and policy.
### Explanation
Detailed rules explaining key parameters and behaviors
- The logger checks `is_enabled(level)` before building a record.
- Context fields, patch logic, and filter logic are applied before enqueue.
- If timestamping is enabled, `@env.now()` is captured before the record enters the queue.
- Overflow behavior depends on the configured `AsyncOverflowPolicy`.
### How to Use
Here are some specific examples provided.
#### When Need A Fully Explicit Async Log Call
When code should choose level, fields, and target per event:
```moonbit
await logger.log(
@bitlogger.Level::Info,
"worker started",
fields=[@bitlogger.field("job", "sync")],
target="service.worker",
)
```
In this example, all per-record inputs are supplied explicitly.
#### When Build Higher-level Async Logging Helpers
When application code wants a custom wrapper around the base API:
```moonbit
await logger.log(@bitlogger.Level::Warn, "slow request")
```
In this example, `log(...)` acts as the common primitive under custom wrappers or convenience methods.
### Error Case
e.g.:
- If the level is below the current minimum threshold, the record is skipped before queue insertion.
- If the logger is closed or overflow policy rejects the record, enqueue may not proceed as a normal accepted write.
### Notes
1. Use this API when the call site needs full control instead of a fixed severity helper.
2. Prefer `info()`, `warn()`, and the other shortcuts when only the level differs.
+76
View File
@@ -0,0 +1,76 @@
---
name: async-logger-pending-count
group: api
category: async
update-time: 20260512
description: Read the current number of queued records that have not yet been drained by the async logger worker.
key-word:
- async
- logger
- queue
- public
---
## Async-logger-pending-count
Read the current number of queued records that are still waiting to be processed. This API is the most direct backlog metric for an async logger instance.
### Interface
```moonbit
pub fn[S] AsyncLogger::pending_count(self : AsyncLogger[S]) -> Int {}
```
#### input
- `self : AsyncLogger[S]` - Async logger whose current backlog should be inspected.
#### output
- `Int` - Current number of pending records still in the async pipeline.
### Explanation
Detailed rules explaining key parameters and behaviors
- The count increases when records are accepted into the queue.
- The count decreases as the worker drains records.
- This is a point-in-time metric and may change immediately after it is read.
- Use this helper when a single backlog number is enough and a full `state()` snapshot is unnecessary.
### How to Use
Here are some specific examples provided.
#### When Need A Fast Backlog Check
When code should observe queue pressure directly:
```moonbit
let pending = logger.pending_count()
```
In this example, callers get the current queue backlog without building a full diagnostics snapshot.
#### When Wait For Near-idle Conditions
When operators or tests want to inspect drain progress:
```moonbit
if logger.pending_count() == 0 {
println("queue idle")
}
```
In this example, the queue backlog is checked directly.
### Error Case
e.g.:
- If the worker is not running, `pending_count()` may stay above `0` until records are drained or cleared.
- If the queue is empty, the method simply returns `0`.
### Notes
1. Use `state()` when you also need dropped counts, failure state, or runtime mode.
2. This helper is useful for lightweight health checks and tests.
+79
View File
@@ -0,0 +1,79 @@
---
name: async-logger-run
group: api
category: async
update-time: 20260512
description: Start the async logger worker loop so queued records are drained to the underlying sink.
key-word:
- async
- logger
- worker
- public
---
## Async-logger-run
Start the async logger worker loop. This is the core runtime API that drains queued records to the underlying sink and updates worker lifecycle state.
### Interface
```moonbit
pub async fn[S : @bitlogger.Sink] AsyncLogger::run(self : AsyncLogger[S]) -> Unit {}
```
#### input
- `self : AsyncLogger[S]` - Async logger whose queue should be drained by the worker loop.
#### output
- `Unit` - No return value. The method runs until the queue is closed or a worker failure occurs.
### Explanation
Detailed rules explaining key parameters and behaviors
- `run()` sets `is_running` to `true` while the worker loop is active.
- It clears previous failure state before worker execution begins.
- On failure, the logger records `has_failed=true` and stores the error text in `last_error`.
- The worker exits when the queue is closed or when a failure aborts processing.
### How to Use
Here are some specific examples provided.
#### When Need Background Queue Drain
When async logging should be processed by a worker task:
```moonbit
let logger = async_logger(console_sink())
@async.with_task_group(group => {
group.spawn_bg(() => logger.run())
logger.info("started")
logger.shutdown()
})
```
In this example, `run()` is the worker loop that makes the async logger actually deliver queued records.
#### When Need Explicit Worker Lifetime Control
When worker execution should be started under application control:
```moonbit
group.spawn_bg(() => logger.run())
```
In this example, the application decides when the worker begins instead of hiding that lifecycle step.
### Error Case
e.g.:
- If the worker loop fails, `has_failed()` becomes `true` and `last_error()` stores the error text.
- If `run()` is never started, accepted records may remain queued and not reach the sink.
### Notes
1. `async_logger(...)` only constructs the logger; `run()` is what activates queue draining.
2. Pair this API with `shutdown()` for a complete worker lifecycle.
+75
View File
@@ -0,0 +1,75 @@
---
name: async-logger-shutdown
group: api
category: async
update-time: 20260512
description: Gracefully stop an async logger by waiting for idle or clearing queued work, then waiting for the worker to finish.
key-word:
- async
- logger
- lifecycle
- public
---
## Async-logger-shutdown
Gracefully stop an async logger. This is the main high-level shutdown API for async logging because it coordinates drain behavior, closure, and worker completion.
### Interface
```moonbit
pub async fn[S] AsyncLogger::shutdown(self : AsyncLogger[S], clear? : Bool = false) -> Unit {}
```
#### input
- `self : AsyncLogger[S]` - Async logger that should be shut down.
- `clear : Bool` - Whether pending records should be abandoned immediately instead of waiting for idle first.
#### output
- `Unit` - No return value. The method completes after shutdown coordination finishes.
### Explanation
Detailed rules explaining key parameters and behaviors
- `clear=false` first waits for idle, then closes the logger.
- If backlog still remains after waiting, shutdown falls back to `close(clear=true)`.
- `clear=true` immediately closes and abandons pending records.
- The method waits until `is_running()` becomes `false` before returning.
### How to Use
Here are some specific examples provided.
#### When Need Graceful Service Shutdown
When a service should stop logging only after queued records are drained:
```moonbit
await logger.shutdown()
```
In this example, the logger waits for normal drain behavior before final closure.
#### When Need Fast Shutdown Under Pressure
When teardown should prefer speed over preserving backlog:
```moonbit
await logger.shutdown(clear=true)
```
In this example, pending work is abandoned intentionally so shutdown can complete sooner.
### Error Case
e.g.:
- If `clear=true`, pending records are intentionally dropped rather than drained.
- If callers skip `shutdown()` and only inspect flags manually, it is easier to leave the worker lifecycle in an unclear state.
### Notes
1. Prefer this API over raw `close()` in normal application shutdown paths.
2. Choose `clear=true` only when loss of queued records is acceptable.
+76
View File
@@ -0,0 +1,76 @@
---
name: async-logger-state-to-json
group: api
category: async
update-time: 20260512
description: Convert an AsyncLoggerState snapshot into a JSON value for diagnostics and transport.
key-word:
- async
- state
- json
- public
---
## Async-logger-state-to-json
Convert `AsyncLoggerState` into a `JsonValue`. This helper is the structured export path for async logger runtime snapshots when callers want machine-readable diagnostics instead of a plain string.
### Interface
```moonbit
pub fn async_logger_state_to_json(state : AsyncLoggerState) -> @json_parser.JsonValue {}
```
#### input
- `state : AsyncLoggerState` - Snapshot produced by `AsyncLogger::state()`.
#### output
- `JsonValue` - Structured JSON representation of the async logger snapshot.
### Explanation
Detailed rules explaining key parameters and behaviors
- The JSON includes runtime mode, worker support, queue counters, lifecycle flags, last error, and flush policy.
- This helper is suitable for health endpoints, diagnostics payloads, and custom serialization flows.
- It shares the same stable field names used by `stringify_async_logger_state(...)`.
- The state must already have been captured before serialization.
### How to Use
Here are some specific examples provided.
#### When Need Machine-readable Diagnostics
When the snapshot should be embedded into a JSON payload:
```moonbit
let state_json = async_logger_state_to_json(logger.state())
```
In this example, callers receive a structured value that can be composed into larger JSON objects.
#### When Need A Snapshot Before Custom Stringify
When another serializer or pipeline expects a JSON value:
```moonbit
let payload = async_logger_state_to_json(logger.state())
println(@json_parser.stringify(payload))
```
In this example, the helper stays useful even outside the built-in stringify wrapper.
### Error Case
e.g.:
- If the snapshot contains no error, `last_error` is serialized as an empty string.
- If the queue is empty, `pending_count` and `dropped_count` are still serialized normally as numeric values.
### Notes
1. Use this API when downstream code wants a JSON value rather than a ready-made string.
2. Pair it with `AsyncLogger::state()` to capture the snapshot first.
+80
View File
@@ -0,0 +1,80 @@
---
name: async-logger-state
group: api
category: async
update-time: 20260512
description: Read a full async logger runtime snapshot including queue counters, lifecycle flags, and runtime mode.
key-word:
- async
- state
- diagnostics
- public
---
## Async-logger-state
Read a complete async logger runtime snapshot for diagnostics. This API is the preferred way to inspect queue backlog, dropped counts, lifecycle status, and runtime mode before exporting them through JSON helpers when needed.
### Interface
```moonbit
pub fn[S] AsyncLogger::state(self : AsyncLogger[S]) -> AsyncLoggerState {}
```
#### input
- `self : AsyncLogger[S]` - The async logger whose runtime snapshot should be read.
#### output
- `AsyncLoggerState` - A snapshot containing runtime mode, worker support, queue counts, lifecycle flags, last error, and flush policy.
### Explanation
Detailed rules explaining key parameters and behaviors
- `AsyncLoggerState` includes `runtime`, `pending_count`, `dropped_count`, `is_closed`, `is_running`, `has_failed`, `last_error`, and `flush_policy`.
- `state()` returns a point-in-time snapshot rather than a live handle.
- `async_logger_state_to_json(...)` and `stringify_async_logger_state(...)` convert the snapshot to stable diagnostic output.
- `runtime` embeds the result of `async_runtime_state()` so callers do not need to join separate helpers manually.
### How to Use
Here are some specific examples provided.
#### When Need Startup Diagnostics
When you want to expose current async logger mode and queue state at startup:
```moonbit
let logger = build_async_logger(config)
println(stringify_async_logger_state(logger.state(), pretty=true))
```
In this example, the snapshot can be printed directly without extra manual formatting.
And downstream operators can see both runtime mode and queue-related status together.
#### When Need Failure Investigation Data
When diagnosing async delivery issues:
```moonbit
let state = logger.state()
if state.has_failed {
println(stringify_async_logger_state(state, pretty=true))
}
```
In this example, the same snapshot object works for conditional diagnostics and serialization.
### Error Case
e.g.:
- If no error has occurred, `last_error` is just an empty string.
- If the queue is empty, `pending_count` is `0`; this is normal and not a special error condition.
### Notes
1. Prefer this API over manually combining `pending_count()`, `dropped_count()`, and runtime-mode helpers.
2. Use `pretty=true` when emitting logs for humans and the compact form for machine-oriented payloads.
+83
View File
@@ -0,0 +1,83 @@
---
name: async-logger-trace
group: api
category: async
update-time: 20260512
description: Enqueue a trace-level record through the async logger using the lowest built-in severity shortcut.
key-word:
- async
- logger
- trace
- public
---
## Async-logger-trace
Enqueue a trace-level record through the async logger. This is the convenience wrapper for `log(Level::Trace, ...)`.
### Interface
```moonbit
pub async fn[S] AsyncLogger::trace(
self : AsyncLogger[S],
message : String,
fields~ : Array[@bitlogger.Field] = [],
) -> Unit {}
```
#### input
- `self : AsyncLogger[S]` - Async logger that should receive the trace record.
- `message : String` - Trace message text.
- `fields : Array[Field]` - Optional structured fields added to the record.
#### output
- `Unit` - No return value. The record is handled according to logger state and policy.
### Explanation
Detailed rules explaining key parameters and behaviors
- This helper delegates to `log(Level::Trace, ...)`.
- The record is still subject to min-level gating, patching, filtering, and overflow policy.
- Trace records are often skipped in production because they are the lowest built-in severity.
- Use this helper when explicit trace intent is clearer than a raw `log(...)` call.
### How to Use
Here are some specific examples provided.
#### When Need Fine-grained Async Diagnostics
When low-level execution flow should be observable during debugging:
```moonbit
await logger.trace("entered reconciliation step")
```
In this example, the call site makes trace intent explicit.
#### When Attach Structured Trace Data
When a trace event should carry extra fields:
```moonbit
await logger.trace(
"cache probe",
fields=[@bitlogger.field("key", "user:42")],
)
```
In this example, the record stays lightweight while still carrying structured detail.
### Error Case
e.g.:
- If the logger minimum level is above `Trace`, the record is skipped before enqueue.
- If the logger is closed or overflow policy prevents acceptance, the write may not become a normal queued record.
### Notes
1. Prefer this helper when trace intent is more readable than `log(Level::Trace, ...)`.
2. Trace-level async logging can increase queue pressure quickly under verbose workloads.
+75
View File
@@ -0,0 +1,75 @@
---
name: async-logger-wait-idle
group: api
category: async
update-time: 20260512
description: Wait until the async logger backlog drains to zero or a worker failure interrupts normal progress.
key-word:
- async
- logger
- queue
- public
---
## Async-logger-wait-idle
Wait until the async logger backlog drains to zero. This helper is useful when callers want to observe idle state without fully shutting down the logger.
### Interface
```moonbit
pub async fn[S] AsyncLogger::wait_idle(self : AsyncLogger[S]) -> Unit {}
```
#### input
- `self : AsyncLogger[S]` - Async logger whose backlog should be waited on.
#### output
- `Unit` - No return value. The method completes when the logger becomes idle or failure prevents normal progress.
### Explanation
Detailed rules explaining key parameters and behaviors
- The helper keeps yielding while `pending_count() > 0`.
- If `has_failed()` becomes `true`, waiting stops early instead of looping forever.
- This API does not close the logger or stop the worker.
- It is narrower than `shutdown()` and is useful when the logger should continue to be used later.
### How to Use
Here are some specific examples provided.
#### When Need A Drain Barrier Without Shutdown
When code should wait for queued work to flush before continuing:
```moonbit
await logger.wait_idle()
```
In this example, the caller waits for backlog drain but leaves the logger usable afterward.
#### When Need Phase Boundaries In Tests
When a test wants to ensure earlier async logs were processed:
```moonbit
await logger.wait_idle()
println("phase complete")
```
In this example, the wait acts as a barrier between test phases.
### Error Case
e.g.:
- If the worker has failed, `wait_idle()` stops waiting even if pending records remain.
- If the worker was never started, pending records may not drain and callers should not expect idle progress automatically.
### Notes
1. Use this helper when you want a drain barrier without closing the logger.
2. Prefer `shutdown()` when lifecycle completion matters more than continued reuse.
+83
View File
@@ -0,0 +1,83 @@
---
name: async-logger-warn
group: api
category: async
update-time: 20260512
description: Enqueue a warning-level record through the async logger using the built-in severity shortcut.
key-word:
- async
- logger
- warn
- public
---
## Async-logger-warn
Enqueue a warning-level record through the async logger. This is the convenience wrapper for `log(Level::Warn, ...)`.
### Interface
```moonbit
pub async fn[S] AsyncLogger::warn(
self : AsyncLogger[S],
message : String,
fields~ : Array[@bitlogger.Field] = [],
) -> Unit {}
```
#### input
- `self : AsyncLogger[S]` - Async logger that should receive the warning record.
- `message : String` - Warning message text.
- `fields : Array[Field]` - Optional structured fields added to the record.
#### output
- `Unit` - No return value. The record is handled according to logger state and policy.
### Explanation
Detailed rules explaining key parameters and behaviors
- This helper delegates to `log(Level::Warn, ...)`.
- The record is still subject to min-level gating, patching, filtering, and overflow policy.
- Warning records are useful for degraded but non-fatal runtime conditions.
- Use this helper when a named warning call is clearer than a raw `log(...)` call.
### How to Use
Here are some specific examples provided.
#### When Need Async Degradation Signals
When the system should report a non-fatal problem:
```moonbit
await logger.warn("retry budget running low")
```
In this example, the event is surfaced at warning severity without using the generic `log(...)` form.
#### When Attach Structured Warning Detail
When a warning event should include context:
```moonbit
await logger.warn(
"queue near capacity",
fields=[@bitlogger.field("pending", logger.pending_count().to_string())],
)
```
In this example, the warning carries structured operational detail.
### Error Case
e.g.:
- If the logger minimum level is above `Warn`, the record is skipped before enqueue.
- If the logger is closed or overflow policy prevents acceptance, the write may not become a normal queued record.
### Notes
1. Use this helper for notable but non-fatal async runtime conditions.
2. Pair warnings with structured fields when operators need quick context.
@@ -0,0 +1,84 @@
---
name: async-logger-with-context-fields
group: api
category: async
update-time: 20260512
description: Attach reusable structured fields to an async logger so every queued record inherits them.
key-word:
- async
- logger
- fields
- public
---
## Async-logger-with-context-fields
Bind shared structured fields to an async logger. This is the standard way to attach stable metadata such as service name, component, region, or subsystem identity without repeating them for every async log call.
### Interface
```moonbit
pub fn[S] AsyncLogger::with_context_fields(
self : AsyncLogger[S],
fields : Array[@bitlogger.Field],
) -> AsyncLogger[S] {}
```
#### input
- `self : AsyncLogger[S]` - Base async logger that should gain shared fields.
- `fields : Array[Field]` - Structured fields that will be prepended to each emitted record.
#### output
- `AsyncLogger[S]` - A new async logger carrying the shared field set.
### Explanation
Detailed rules explaining key parameters and behaviors
- Context fields are merged during `log(...)` before enqueue.
- When a log call also passes per-record fields, the context fields are placed before those per-call fields.
- This API returns a new logger value; it does not mutate the original async logger.
- Unlike synchronous `Logger::with_context_fields(...)`, this async variant stores fields directly on `AsyncLogger` instead of changing the visible sink type.
### How to Use
Here are some specific examples provided.
#### When Need Stable Async Service Metadata
When every queued record should carry service-level metadata:
```moonbit
let logger = async_logger(console_sink(), target="billing")
.with_context_fields([
@bitlogger.field("service", "billing"),
@bitlogger.field("region", "cn"),
])
```
In this example, both fields are attached before each record enters the queue.
#### When Build Child Async Loggers For Subsystems
When a subsystem has both a target and fixed fields:
```moonbit
let worker = async_logger(console_sink(), target="app")
.child("worker")
.with_context_fields([@bitlogger.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 side.
### Notes
1. Use this for stable metadata, not highly dynamic event-specific values.
2. This async variant preserves the visible `AsyncLogger[S]` type while still injecting shared fields.
+82
View File
@@ -0,0 +1,82 @@
---
name: async-logger-with-filter
group: api
category: async
update-time: 20260512
description: Attach predicate-based filtering to an async logger so only matching records reach the queue.
key-word:
- async
- logger
- filter
- public
---
## Async-logger-with-filter
Attach a record predicate to an async logger so only matching records are enqueued. This is the main API for async routing-by-predicate without rewriting sink implementations.
### Interface
```moonbit
pub fn[S] AsyncLogger::with_filter(
self : AsyncLogger[S],
predicate : (@bitlogger.Record) -> Bool,
) -> AsyncLogger[S] {}
```
#### input
- `self : AsyncLogger[S]` - Base async logger to constrain.
- `predicate : (Record) -> Bool` - Record predicate that decides whether a record should be enqueued.
#### output
- `AsyncLogger[S]` - A new async logger that only enqueues matching records.
### Explanation
Detailed rules explaining key parameters and behaviors
- Filtering happens after record construction and patch application but before enqueue.
- Existing filter logic is preserved and combined with the new predicate using logical `and`.
- The original async logger is not mutated.
- Filtering avoids unnecessary queue pressure for records that should never be delivered.
### How to Use
Here are some specific examples provided.
#### When Keep Only One Async Target Namespace
When an async logger should only enqueue records from a specific subsystem:
```moonbit
let logger = async_logger(console_sink(), target="service")
.with_filter(@bitlogger.target_has_prefix("service.api"))
```
In this example, non-matching records are dropped before they reach the async queue.
#### When Combine Several Async Filter Rules
When filtering depends on multiple conditions:
```moonbit
let logger = async_logger(console_sink(), target="api")
.with_filter(fn(rec) {
rec.level.enabled(@bitlogger.Level::Warn) && rec.message.contains("timeout")
})
```
In this example, only warning-or-higher timeout records are enqueued.
### Error Case
e.g.:
- If the predicate always returns `false`, the logger silently drops every record before enqueue.
- If the predicate always returns `true`, the wrapper behaves like a pass-through filter.
### Notes
1. Use this API for selection logic, not record mutation.
2. Async filtering is especially useful when queue capacity should be reserved for high-value records.
+80
View File
@@ -0,0 +1,80 @@
---
name: async-logger-with-min-level
group: api
category: async
update-time: 20260512
description: Replace the async logger minimum enabled level so lower-severity records are skipped before enqueue.
key-word:
- async
- logger
- level
- public
---
## Async-logger-with-min-level
Replace the async logger's minimum enabled level. This API controls the first gate checked before record creation and queue insertion.
### Interface
```moonbit
pub fn[S] AsyncLogger::with_min_level(
self : AsyncLogger[S],
min_level : @bitlogger.Level,
) -> AsyncLogger[S] {}
```
#### input
- `self : AsyncLogger[S]` - Base async logger whose level threshold should change.
- `min_level : Level` - New minimum enabled level.
#### output
- `AsyncLogger[S]` - A new async logger value carrying the updated threshold.
### Explanation
Detailed rules explaining key parameters and behaviors
- `log(...)` checks `is_enabled(level)` before creating a record or touching the queue.
- Lower-severity records below `min_level` are skipped before enqueue.
- This API replaces the logger threshold and does not alter queue configuration.
- The returned logger keeps the same sink, target, and timestamp settings.
### How to Use
Here are some specific examples provided.
#### When Raise Async Noise Floor In Production
When only warning and error records should reach the async queue:
```moonbit
let logger = async_logger(console_sink())
.with_min_level(@bitlogger.Level::Warn)
```
In this example, lower-severity records are skipped before queue pressure increases.
#### When Derive A More Verbose Async Branch
When one branch of code should keep a different threshold:
```moonbit
let base = async_logger(console_sink(), min_level=@bitlogger.Level::Info)
let debug_logger = base.with_min_level(@bitlogger.Level::Debug)
```
In this example, the async sink and queue settings are reused while the threshold changes per logger value.
### Error Case
e.g.:
- If `min_level` is set too high, expected lower-severity diagnostics may disappear before they ever enter the queue.
- If callers need richer predicate logic than a simple threshold, `with_filter(...)` should be used instead.
### Notes
1. This API reduces async queue pressure by dropping disabled levels before enqueue.
2. Use it before adding more complex async filtering rules.
+82
View File
@@ -0,0 +1,82 @@
---
name: async-logger-with-patch
group: api
category: async
update-time: 20260512
description: Attach record transformation logic to an async logger before records reach the queue.
key-word:
- async
- logger
- patch
- public
---
## Async-logger-with-patch
Attach a record patch to an async logger so each record is transformed before filtering and enqueue. This is the main API for async record rewriting without changing the sink implementation.
### Interface
```moonbit
pub fn[S] AsyncLogger::with_patch(
self : AsyncLogger[S],
patch : @bitlogger.RecordPatch,
) -> AsyncLogger[S] {}
```
#### input
- `self : AsyncLogger[S]` - Base async logger to wrap.
- `patch : RecordPatch` - Transformation applied to each record before enqueue.
#### output
- `AsyncLogger[S]` - A new async logger that rewrites each record before filtering and queue insertion.
### Explanation
Detailed rules explaining key parameters and behaviors
- Patch logic runs after record creation and field merging but before filtering and enqueue.
- Existing patch logic is preserved and composed so the new patch wraps the current one.
- The original async logger is not mutated.
- Patching can normalize, redact, or enrich records before they consume queue capacity.
### How to Use
Here are some specific examples provided.
#### When Need Async Record Enrichment
When records should gain stable extra data before enqueue:
```moonbit
let logger = async_logger(console_sink())
.with_patch(@bitlogger.append_fields([
@bitlogger.field("channel", "async"),
]))
```
In this example, the added fields are part of the record before filtering and queue insertion.
#### When Need Redaction Before Queueing
When sensitive fields should be removed early:
```moonbit
let logger = async_logger(console_sink())
.with_patch(@bitlogger.redact_fields(["token", "password"]))
```
In this example, sensitive values are rewritten before they enter the async pipeline.
### Error Case
e.g.:
- If the patch removes or rewrites important data incorrectly, later filters and sinks will only see the patched version.
- If callers need selection logic rather than transformation, `with_filter(...)` should be used instead.
### Notes
1. Use patches for transformation, not filtering decisions.
2. Redaction before enqueue helps keep sensitive data out of the queued pipeline.
+78
View File
@@ -0,0 +1,78 @@
---
name: async-logger-with-target
group: api
category: async
update-time: 20260512
description: Replace the default target carried by an async logger so later records inherit a new target namespace.
key-word:
- async
- logger
- target
- public
---
## Async-logger-with-target
Replace the async logger's default target. This API retargets later enqueue operations without changing the queue, overflow policy, or sink wiring.
### Interface
```moonbit
pub fn[S] AsyncLogger::with_target(self : AsyncLogger[S], target : String) -> AsyncLogger[S] {}
```
#### input
- `self : AsyncLogger[S]` - Base async logger whose default target should be replaced.
- `target : String` - New default target namespace.
#### output
- `AsyncLogger[S]` - A new async logger value carrying the updated target.
### Explanation
Detailed rules explaining key parameters and behaviors
- The returned logger keeps the same sink, queue state, overflow policy, flush policy, and lifecycle flags.
- This API replaces the default target instead of composing it.
- Per-call `target?` arguments on `log(...)` can still override the default target.
- The original logger value is not mutated.
### How to Use
Here are some specific examples provided.
#### When Need A Stable Async Target Namespace
When one async logger should always emit under a fixed target:
```moonbit
let logger = async_logger(console_sink())
.with_target("service.worker")
```
In this example, later async log calls inherit `service.worker` unless a call overrides the target explicitly.
#### When Reuse One Async Setup Across Namespaces
When multiple subsystem loggers should share the same async queue behavior:
```moonbit
let base = async_logger(console_sink(), config=AsyncLoggerConfig::new(max_pending=64))
let api = base.with_target("api")
let jobs = base.with_target("jobs")
```
In this example, target routing changes without rebuilding the async runtime configuration.
### Error Case
e.g.:
- If `target` is empty, the logger remains valid and later records default to an empty target.
- If callers need hierarchical target composition rather than replacement, `child(...)` is the better API.
### Notes
1. Use this API for replacement, not parent-child target composition.
2. It is useful when several subsystems should share one async queue policy.
+77
View File
@@ -0,0 +1,77 @@
---
name: async-logger-with-timestamp
group: api
category: async
update-time: 20260512
description: Enable or disable automatic timestamp capture for records emitted by an async logger.
key-word:
- async
- logger
- timestamp
- public
---
## Async-logger-with-timestamp
Enable or disable automatic timestamp capture on async log emission. This API controls whether `AsyncLogger::log(...)` records the current time before enqueue or leaves the timestamp at `0UL`.
### Interface
```moonbit
pub fn[S] AsyncLogger::with_timestamp(self : AsyncLogger[S], enabled~ : Bool = true) -> AsyncLogger[S] {}
```
#### input
- `self : AsyncLogger[S]` - Base async logger whose timestamp behavior should change.
- `enabled : Bool` - Whether emitted records should capture current time automatically.
#### output
- `AsyncLogger[S]` - A new async logger value with updated timestamp behavior.
### Explanation
Detailed rules explaining key parameters and behaviors
- When enabled, `log(...)` captures `@env.now()` before placing the record into the queue.
- When disabled, emitted records use `0UL` as the timestamp value.
- This setting affects later emitted records only.
- Queue, batching, and flush behavior are unchanged.
### How to Use
Here are some specific examples provided.
#### When Need Real Event Time Before Queueing
When downstream formatting or JSON output should include event time:
```moonbit
let logger = async_logger(console_sink())
.with_timestamp()
```
In this example, each record captures its timestamp before entering the async queue.
#### When Need Deterministic Async Records
When timestamps should be disabled for tests or reduced output:
```moonbit
let logger = async_logger(console_sink())
.with_timestamp(enabled=false)
```
In this example, queued records are emitted without runtime time capture.
### Error Case
e.g.:
- If timestamps are disabled, formatters that expect meaningful time values may show empty or zero-like timestamp output.
- If callers need timestamps only for one record, a separate logger value is usually clearer than toggling behavior repeatedly.
### Notes
1. This API controls record creation before enqueue, not formatter display policy.
2. It is useful for tests, deterministic snapshots, and production timing.
+100
View File
@@ -0,0 +1,100 @@
---
name: async-logger
group: api
category: async
update-time: 20260512
description: Create an async logger with bounded queueing, overflow policy, lifecycle helpers, and background run control.
key-word:
- async
- logger
- queue
- public
---
## Async-logger
Create an `AsyncLogger[S]` on top of a sink and async queue configuration. This API is the main entry for queue-backed async logging, including overflow policy, batching, lifecycle control, and runtime observability.
### Interface
```moonbit
pub fn[S] async_logger(
sink : S,
config~ : AsyncLoggerConfig = AsyncLoggerConfig::new(),
min_level~ : @bitlogger.Level = @bitlogger.Level::Info,
target~ : String = "",
flush~ : (S) -> Int = fn(_) { 0 },
) -> AsyncLogger[S] {}
```
#### input
- `sink : S` - Underlying sink used after queue drain.
- `config : AsyncLoggerConfig` - Queue size, overflow behavior, batching, linger, and flush policy.
- `min_level : Level` - Level gate applied before enqueue.
- `target : String` - Default target for emitted records.
- `flush : (S) -> Int` - Flush callback used by batch/shutdown flush policies.
#### output
- `AsyncLogger[S]` - A queue-backed async logger with lifecycle and state helpers.
### Explanation
Detailed rules explaining key parameters and behaviors
- `async_logger(...)` only builds the logger. Actual background draining is started by `run()`.
- In non-native targets, the implementation uses compatibility behavior while keeping the same public surface.
- `flush` is used only when batch or shutdown policy wants explicit flushing.
- Queue overflow behavior depends on `AsyncOverflowPolicy`.
### How to Use
Here are some specific examples provided.
#### When Need Background Queue Drain
When your sink should not be written directly on the caller path:
```moonbit
let logger = async_logger(callback_sink(fn(rec) { println(rec.message) }))
@async.with_task_group(group => {
group.spawn_bg(() => logger.run())
logger.info("hello")
logger.shutdown()
})
```
In this example, the worker drains queued records in the background and `shutdown()` waits for completion.
And the logging call path stays queue-oriented rather than direct-sink oriented.
#### When Need Configurable Overflow And Flush Behavior
When queue semantics matter for service durability and load:
```moonbit
let logger = async_logger(
console_sink(),
config=AsyncLoggerConfig::new(
max_pending=128,
overflow=AsyncOverflowPolicy::DropOldest,
max_batch=8,
flush=AsyncFlushPolicy::Batch,
),
)
```
In this example, queue pressure and flush timing are both explicit.
### Error Case
e.g.:
- If the logger is closed, further enqueue attempts stop being normal active logging operations.
- If queue drain fails internally, runtime state can reflect that through `has_failed()` and `last_error()`.
### Notes
1. `async_logger(...)` is the async counterpart to `Logger::new(...)`.
2. Use `state()`, `pending_count()`, and `dropped_count()` for runtime diagnostics.
+69
View File
@@ -0,0 +1,69 @@
---
name: async-runtime-mode-label
group: api
category: async
update-time: 20260512
description: Convert AsyncRuntimeMode into a stable string label for logs, JSON, and diagnostics.
key-word:
- async
- runtime
- label
- public
---
## Async-runtime-mode-label
Convert `AsyncRuntimeMode` into a stable string label. This helper is useful when runtime mode should be logged, serialized, or exposed through human-readable diagnostics.
### Interface
```moonbit
pub fn async_runtime_mode_label(mode : AsyncRuntimeMode) -> String {}
```
#### input
- `mode : AsyncRuntimeMode` - Runtime mode enum value.
#### output
- `String` - Stable mode label such as `native_worker` or `compatibility`.
### Explanation
Detailed rules explaining key parameters and behaviors
- The returned value is intended for diagnostics and stable output, not just debugging prints.
- It keeps mode serialization logic in one place.
- This helper is used by async runtime JSON helpers.
- Labels are more stable for telemetry and docs than ad hoc manual matching at call sites.
### How to Use
Here are some specific examples provided.
#### When Need A Stable Log Label
When the mode should be included in structured or plain logs:
```moonbit
println(async_runtime_mode_label(async_runtime_mode()))
```
In this example, the label is directly usable in diagnostics.
#### When Build Custom Serialization
When callers want to embed the mode into their own payloads:
```moonbit
let label = async_runtime_mode_label(async_runtime_mode())
```
In this example, code gets a stable string without duplicating enum matching logic.
### Error Case
e.g.:
- This API assumes a valid `AsyncRuntimeMode` input and does not expose a normal runtime error path.
- If callers need the whole runtime object rather than a string label, use `async_runtime_state()`.
+78
View File
@@ -0,0 +1,78 @@
---
name: async-runtime-mode
group: api
category: async
update-time: 20260512
description: Read the current async runtime mode and distinguish native worker behavior from compatibility behavior.
key-word:
- async
- runtime
- mode
- public
---
## Async-runtime-mode
Read the current backend-specific async runtime mode. This API is the narrowest capability probe when you only care whether the current build is running native worker semantics or compatibility behavior.
### Interface
```moonbit
pub fn async_runtime_mode() -> AsyncRuntimeMode {}
```
#### input
- `none` - No arguments are required.
#### output
- `AsyncRuntimeMode` - Either `NativeWorker` or `Compatibility`.
### Explanation
Detailed rules explaining key parameters and behaviors
- The return value is determined by the active backend implementation.
- `async_runtime_mode_label(...)` converts the enum into a stable string value.
- `async_runtime_supports_background_worker()` is a narrower boolean probe built on the same idea.
- This API is intentionally small and useful for lightweight branching.
### How to Use
Here are some specific examples provided.
#### When Need A Small Capability Branch
When behavior should differ between native worker mode and compatibility mode:
```moonbit
match async_runtime_mode() {
AsyncRuntimeMode::NativeWorker => println("native worker")
AsyncRuntimeMode::Compatibility => println("compat")
}
```
In this example, the branch is explicit and readable.
#### When Need Stable String Output
When the mode should be included in logs or telemetry labels:
```moonbit
println(async_runtime_mode_label(async_runtime_mode()))
```
In this example, the output becomes a stable string instead of an enum pattern-match requirement.
### Error Case
e.g.:
- This API does not have a normal runtime failure mode; it reflects the compiled backend behavior.
- If you need worker support as a direct boolean, use `async_runtime_supports_background_worker()` instead.
### Notes
1. Use this API for minimal mode branching.
2. Use `async_runtime_state()` when you also want worker support packaged into one object.
+69
View File
@@ -0,0 +1,69 @@
---
name: async-runtime-state-to-json
group: api
category: async
update-time: 20260512
description: Convert AsyncRuntimeState into a JSON value for runtime capability and mode diagnostics.
key-word:
- async
- state
- json
- public
---
## Async-runtime-state-to-json
Convert `AsyncRuntimeState` into a `JsonValue`. This helper exports the async runtime mode and background worker capability in a structured form.
### Interface
```moonbit
pub fn async_runtime_state_to_json(state : AsyncRuntimeState) -> @json_parser.JsonValue {}
```
#### input
- `state : AsyncRuntimeState` - Runtime capability snapshot, usually produced by `async_runtime_state()`.
#### output
- `JsonValue` - Structured JSON representation of the runtime state.
### Explanation
Detailed rules explaining key parameters and behaviors
- The output includes `mode` and `background_worker`.
- `mode` is serialized through `async_runtime_mode_label(...)`.
- This helper focuses on runtime capabilities rather than queue counters or logger lifecycle flags.
- The exported JSON is suitable for diagnostics endpoints and startup environment checks.
### How to Use
Here are some specific examples provided.
#### When Need Structured Runtime Capability Checks
When startup diagnostics should include async runtime capability data:
```moonbit
let runtime_json = async_runtime_state_to_json(async_runtime_state())
```
In this example, the runtime snapshot becomes a reusable JSON value.
#### When Need To Embed Runtime State In A Larger Payload
When async support should be one field in a bigger diagnostics object:
```moonbit
let payload = async_runtime_state_to_json(state)
```
In this example, callers can reuse the exported object directly.
### Error Case
e.g.:
- If callers expect logger queue counters or failure status, this API is too narrow and `async_logger_state_to_json(...)` should be used instead.
- If the runtime is in compatibility mode, the helper still serializes normally using the matching mode label.
+77
View File
@@ -0,0 +1,77 @@
---
name: async-runtime-state
group: api
category: async
update-time: 20260512
description: Read the current backend-specific async runtime mode and worker capability.
key-word:
- async
- runtime
- diagnostics
- public
---
## Async-runtime-state
Read the current backend-specific async runtime state for diagnostics. This API focuses on the environment-level async mode rather than any one logger instance.
### Interface
```moonbit
pub fn async_runtime_state() -> AsyncRuntimeState {}
```
#### input
- `none` - This API reads the current backend mode and does not require logger input.
#### output
- `AsyncRuntimeState` - Runtime snapshot containing `mode` and `background_worker` capability.
### Explanation
Detailed rules explaining key parameters and behaviors
- `mode` is derived from the active backend implementation.
- `background_worker` tells callers whether native worker semantics are available.
- `async_runtime_state_to_json(...)` and `stringify_async_runtime_state(...)` serialize this state.
- This API is environment-scoped and does not depend on a particular `AsyncLogger` instance.
### How to Use
Here are some specific examples provided.
#### When Need Startup Diagnostics
When startup logs should reveal async backend behavior:
```moonbit
println(stringify_async_runtime_state(async_runtime_state(), pretty=true))
```
In this example, backend mode is exposed before any logger is started.
#### When Branch Behavior By Runtime Capability
When code should react differently depending on worker support:
```moonbit
let runtime = async_runtime_state()
if runtime.background_worker {
println("native worker path")
}
```
In this example, branch decisions are based on actual runtime capability instead of assumptions.
### Error Case
e.g.:
- This API does not normally expose a dynamic error path; it reports the currently compiled backend behavior.
- If callers need richer runtime state, they should use `AsyncLogger::state()` on a logger instance instead.
### Notes
1. Use this API for environment-level diagnostics.
2. Use `AsyncLogger::state()` for logger-instance diagnostics.
@@ -0,0 +1,77 @@
---
name: async-runtime-supports-background-worker
group: api
category: async
update-time: 20260512
description: Return whether the current backend provides native async background worker support.
key-word:
- async
- runtime
- worker
- public
---
## Async-runtime-supports-background-worker
Return a boolean telling callers whether the current backend provides native background worker semantics for `bitlogger_async`. This is the narrowest capability probe when only worker support matters.
### Interface
```moonbit
pub fn async_runtime_supports_background_worker() -> Bool {}
```
#### input
- `none` - No explicit arguments are required.
#### output
- `Bool` - `true` when native background worker semantics are available, otherwise `false`.
### Explanation
Detailed rules explaining key parameters and behaviors
- `true` indicates native worker capability.
- `false` indicates compatibility-mode behavior.
- This helper is derived from backend-specific async runtime implementation choice.
- Use it when an enum branch is unnecessary and a boolean capability check is enough.
### How to Use
Here are some specific examples provided.
#### When Need A Simple Capability Branch
When logic only depends on worker availability:
```moonbit
if async_runtime_supports_background_worker() {
println("native worker available")
}
```
In this example, callers avoid a more verbose mode match.
#### When Add Diagnostics Labels
When capability should be surfaced in diagnostics:
```moonbit
println(if async_runtime_supports_background_worker() { "worker" } else { "compat" })
```
In this example, a simple boolean can drive compact status output.
### Error Case
e.g.:
- This API does not normally fail at runtime; it reflects compiled backend behavior.
- If you need the exact mode name rather than a boolean, use `async_runtime_mode()` or `async_runtime_state()`.
### Notes
1. Use this helper for minimal capability checks.
2. Prefer `async_runtime_state()` when you want the same information in a richer object.
+81
View File
@@ -0,0 +1,81 @@
---
name: build-async-logger
group: api
category: async
update-time: 20260512
description: Build an async logger from combined logger and async config without manually wiring the runtime sink.
key-word:
- async
- config
- builder
- public
---
## Build-async-logger
Build an async logger directly from `AsyncLoggerBuildConfig`. This is the config-driven async entry point that bridges synchronous logger config, sink creation, and async queue setup in one call.
### Interface
```moonbit
pub fn build_async_logger(config : AsyncLoggerBuildConfig) -> AsyncLogger[@bitlogger.RuntimeSink] {}
```
#### input
- `config : AsyncLoggerBuildConfig` - Combined synchronous logger config plus async queue/flush config.
#### output
- `AsyncLogger[RuntimeSink]` - A config-built async logger with runtime sink control preserved.
### Explanation
Detailed rules explaining key parameters and behaviors
- The `logger` section is built through the same config machinery used by synchronous configured loggers.
- The resulting async logger inherits `min_level`, `target`, and timestamp behavior from the built synchronous logger.
- File, queue, and formatter choices all come from config rather than direct code-side sink wiring.
- The returned sink type is `RuntimeSink`, which keeps configured control helpers available where relevant.
### How to Use
Here are some specific examples provided.
#### When Need Fully Config-driven Async Bootstrapping
When your application should build async logging entirely from configuration:
```moonbit
let config = parse_async_logger_build_config_text(raw) catch {
err => return
}
let logger = build_async_logger(config)
```
In this example, parsing and async runtime wiring are separated cleanly.
And the returned logger can immediately be started with `run()`.
#### When Need Runtime Sink Features After Async Build
When the sink shape is configured but runtime features still matter:
```moonbit
let logger = build_async_logger(config)
println(stringify_async_logger_state(logger.state(), pretty=true))
```
In this example, the built async logger remains introspectable even though construction was config-driven.
### Error Case
e.g.:
- If the config text was invalid, error handling should happen earlier in `parse_async_logger_build_config_text(...)`.
- If the configured sink shape is unsupported for a specific capability, the resulting runtime behavior follows the existing sink/runtime rules rather than inventing a separate builder-only failure model.
### Notes
1. Prefer this API when applications externalize both sync sink choice and async queue behavior.
2. Use `async_logger(...)` directly when you want explicit code-defined sink wiring.
+85
View File
@@ -0,0 +1,85 @@
---
name: build-logger
group: api
category: config
update-time: 20260512
description: Build a configured runtime logger from a LoggerConfig while preserving queue and file control helpers.
key-word:
- logger
- config
- runtime
- public
---
## Build-logger
Build a `ConfiguredLogger` from `LoggerConfig`. This is the main config-to-runtime bridge for synchronous logging and is the builder used before async wrapping in config-driven async flows.
### Interface
```moonbit
pub fn build_logger(config : LoggerConfig) -> ConfiguredLogger {}
```
#### input
- `config : LoggerConfig` - Fully assembled logger config including level, target, timestamp, sink, and optional queue wrapper.
#### output
- `ConfiguredLogger` - A runtime logger backed by `RuntimeSink`, with queue and file control helpers preserved.
### Explanation
Detailed rules explaining key parameters and behaviors
- `build_logger(...)` constructs the runtime sink shape based on `SinkConfig` and optional queue wrapper.
- The returned logger still supports normal logging methods because `ConfiguredLogger` is `Logger[RuntimeSink]`.
- Queue metrics and file controls remain available through forwarding helpers on the configured logger.
- This API is deterministic and data-driven, making it suitable for bootstrapping from parsed config.
### How to Use
Here are some specific examples provided.
#### When Need Structured Config-first Bootstrapping
When config is already assembled as typed values:
```moonbit
let logger = build_logger(
LoggerConfig::new(
min_level=Level::Info,
target="svc",
sink=SinkConfig::new(kind=SinkKind::TextConsole),
),
)
```
In this example, no JSON parsing is required because config objects were built directly.
And the runtime logger is ready immediately.
#### When Need Config-built Queue Or File Runtime Helpers
When the sink shape comes from config but runtime controls still matter:
```moonbit
let logger = build_logger(config)
ignore(logger.pending_count())
ignore(logger.file_runtime_state())
```
In this example, config-driven construction does not remove observability or control helpers.
### Error Case
e.g.:
- If config contains a file sink on a non-native backend, callers must still respect backend capability behavior.
- If queue is not configured, queue-related counters simply reflect the non-queued runtime shape.
### Notes
1. Use this API when config is already typed as `LoggerConfig`.
2. Use `parse_and_build_logger(...)` when the starting point is raw JSON text.
+82
View File
@@ -0,0 +1,82 @@
---
name: compose-patches
group: api
category: patching
update-time: 20260512
description: Create a reusable record patch pipeline from several ordered patches.
key-word:
- patch
- compose
- pipeline
- public
---
## Compose-patches
Create a `RecordPatch` that applies several patches in order. This helper is the standard way to build deterministic record transformation pipelines.
### Interface
```moonbit
pub fn compose_patches(patches : Array[RecordPatch]) -> RecordPatch {}
```
#### input
- `patches : Array[RecordPatch]` - Patches applied sequentially from first to last.
#### output
- `RecordPatch` - Patch that returns the final record after every nested patch has run.
### Explanation
Detailed rules explaining key parameters and behaviors
- Composition is ordered: each patch receives the result of the previous patch.
- Later patches can overwrite changes made by earlier patches.
- If the patch array is empty, the returned patch behaves like `identity_patch()`.
- This helper is useful for combining normalization, enrichment, and redaction into one reusable unit.
### How to Use
Here are some specific examples provided.
#### When Build A Stable Rewrite Pipeline
When a logger needs several transformations in one place:
```moonbit
let patch = compose_patches([
set_target("api.gateway"),
prefix_message("[safe] "),
redact_fields(["token", "password"]),
])
```
In this example, target rewrite, message prefixing, and field redaction happen in fixed order.
#### When Reuse The Same Policy Across Loggers
When several sinks should share one transformation bundle:
```moonbit
let shared_patch = compose_patches([
append_fields([field("service", "billing")]),
redact_field("secret"),
])
```
In this example, the composed patch can be attached to multiple loggers without repeating inline closures.
### Error Case
e.g.:
- If `patches` is empty, the returned patch leaves records unchanged.
- If several patches rewrite the same property, the last patch in the array determines the final value.
### Notes
1. Keep patch order explicit because composition semantics are intentionally sequential.
2. Prefer one composed patch over many ad hoc inline wrappers when the transformation policy is shared.
+74
View File
@@ -0,0 +1,74 @@
---
name: configured-logger-close
group: api
category: runtime
update-time: 20260512
description: Close the configured runtime logger sink and return whether the underlying sink reported a close action.
key-word:
- logger
- runtime
- lifecycle
- public
---
## Configured-logger-close
Close the sink behind a `ConfiguredLogger`. This helper is the config-driven runtime close surface for queue-backed or file-backed sinks.
### Interface
```moonbit
pub fn ConfiguredLogger::close(self : ConfiguredLogger) -> Bool {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose sink should be closed.
#### output
- `Bool` - Whether the underlying runtime sink reported a successful close action.
### Explanation
Detailed rules explaining key parameters and behaviors
- Queue-backed file sinks close the wrapped file sink.
- Plain file sinks forward directly to file close behavior.
- Console-style sinks usually report `true` because they do not have a meaningful close step.
- This helper delegates to `RuntimeSink::close(...)` through the configured logger wrapper.
### How to Use
Here are some specific examples provided.
#### When Need Config-driven Runtime Teardown
When a config-built logger should release its sink resources:
```moonbit
ignore(logger.close())
```
In this example, sink teardown happens through the configured logger facade.
#### When Need To Observe Close Outcome
When application code wants a success flag from runtime close behavior:
```moonbit
let closed = logger.close()
```
In this example, callers can branch on the reported close result.
### Error Case
e.g.:
- If the runtime sink has no real close action, the helper may still return `true` as a no-op success.
- If callers need a file-specific close path with queue flush nuances, `file_close()` may be the better API.
### Notes
1. This is the generic configured runtime close helper.
2. Prefer file-specific helpers when the sink shape is known to be file-backed.
+75
View File
@@ -0,0 +1,75 @@
---
name: configured-logger-drain
group: api
category: runtime
update-time: 20260512
description: Drain queued work from a configured runtime logger with optional item limits.
key-word:
- logger
- runtime
- queue
- public
---
## Configured-logger-drain
Drain queued work from a `ConfiguredLogger`. This helper is useful when config-driven queue wrapping should be advanced in a controlled, bounded way.
### Interface
```moonbit
pub fn ConfiguredLogger::drain(self : ConfiguredLogger, max_items~ : Int = -1) -> Int {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose queued work should be drained.
- `max_items : Int` - Optional upper bound on how many queued items to drain. Negative values mean no explicit bound.
#### output
- `Int` - Number of drained items.
### Explanation
Detailed rules explaining key parameters and behaviors
- Queue-wrapped sinks may drain up to `max_items` records.
- For plain file sinks, the runtime falls back to file flush behavior instead of queue draining.
- For sinks without queue semantics, the result is typically `0`.
- This helper delegates to `RuntimeSink::drain(...)` through the configured logger wrapper.
### How to Use
Here are some specific examples provided.
#### When Need Bounded Queue Progress
When queued output should be advanced in chunks:
```moonbit
let drained = logger.drain(max_items=16)
```
In this example, callers limit how much queued work is processed in one step.
#### When Need Full Manual Drain
When the configured queue should be emptied explicitly:
```moonbit
ignore(logger.drain())
```
In this example, the configured runtime logger drains without imposing an item cap.
### Error Case
e.g.:
- If the runtime sink is not queue-backed, draining may return `0` or follow fallback flush behavior.
- If callers only need generic flush semantics, `flush()` may be the simpler API.
### Notes
1. Prefer this helper when queue progress should be bounded or observable.
2. Use `pending_count()` to inspect remaining backlog after the drain call.
@@ -0,0 +1,76 @@
---
name: configured-logger-dropped-count
group: api
category: runtime
update-time: 20260512
description: Read the cumulative dropped-record count from a configured runtime logger.
key-word:
- logger
- runtime
- queue
- public
---
## Configured-logger-dropped-count
Read the cumulative dropped-record count from a `ConfiguredLogger`. This helper is useful when config-driven queue wrapping may discard records under pressure.
### Interface
```moonbit
pub fn ConfiguredLogger::dropped_count(self : ConfiguredLogger) -> Int {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose dropped-record metric should be inspected.
#### output
- `Int` - Number of dropped records reported by the runtime sink.
### Explanation
Detailed rules explaining key parameters and behaviors
- Queue-backed sinks return their live dropped-count metric.
- Non-queued sinks report `0`.
- The counter is cumulative for the runtime sink lifetime.
- This helper delegates to `RuntimeSink::dropped_count(...)` through the configured logger wrapper.
### How to Use
Here are some specific examples provided.
#### When Need Loss Visibility On Config-built Queues
When a config-driven queue may discard records:
```moonbit
if logger.dropped_count() > 0 {
println("configured logger dropped records")
}
```
In this example, the runtime logger exposes queue loss without manual sink inspection.
#### When Compare Queue Tuning Changes
When queue overflow policy should be validated operationally:
```moonbit
ignore(logger.dropped_count())
```
In this example, the helper exposes the metric needed to compare runtime queue tuning.
### Error Case
e.g.:
- If the logger is not queue-backed, the method simply returns `0`.
- If callers need queue shape and file status together, `file_runtime_state()` may carry more useful context for file sinks.
### Notes
1. This helper reports cumulative loss, not the reason for that loss.
2. Pair it with `pending_count()` and queue configuration when investigating pressure.
@@ -0,0 +1,75 @@
---
name: configured-logger-file-append-mode
group: api
category: runtime
update-time: 20260512
description: Read the current append-mode policy used by the configured runtime file sink.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-append-mode
Read the current append-mode policy used by a `ConfiguredLogger` file sink. This helper exposes whether future reopen behavior is currently append-oriented.
### Interface
```moonbit
pub fn ConfiguredLogger::file_append_mode(self : ConfiguredLogger) -> Bool {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose append-mode policy should be inspected.
#### output
- `Bool` - Current append-mode policy for the file sink.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks report their current append policy.
- Queued file sinks forward the policy from the wrapped file sink.
- Non-file sinks return `false`.
- This helper reports runtime file policy, not whether a file is currently writable.
### How to Use
Here are some specific examples provided.
#### When Need Runtime Append-policy Visibility
When diagnostics should show how future reopen behavior is configured:
```moonbit
let append = logger.file_append_mode()
```
In this example, the configured logger exposes current reopen policy directly.
#### When Validate Runtime Policy Changes
When policy mutation should be observable after a setter call:
```moonbit
ignore(logger.file_set_append_mode(true))
ignore(logger.file_append_mode())
```
In this example, callers verify the updated append-mode policy.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `false`.
- If callers need the full current file policy rather than just append mode, `file_policy()` is the better API.
### Notes
1. Use this helper when append policy is the only file setting you need to inspect.
2. Pair it with reopen helpers when debugging runtime file behavior.
@@ -0,0 +1,75 @@
---
name: configured-logger-file-auto-flush
group: api
category: runtime
update-time: 20260512
description: Read whether the configured runtime file sink currently has auto-flush enabled.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-auto-flush
Read whether auto-flush is currently enabled on a `ConfiguredLogger` file sink. This helper exposes one important runtime durability policy flag.
### Interface
```moonbit
pub fn ConfiguredLogger::file_auto_flush(self : ConfiguredLogger) -> Bool {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose auto-flush policy should be inspected.
#### output
- `Bool` - Whether auto-flush is currently enabled.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks report their current auto-flush policy.
- Queued file sinks forward the policy from the wrapped file sink.
- Non-file sinks return `false`.
- This helper exposes policy state only and does not force any flush action.
### How to Use
Here are some specific examples provided.
#### When Need Runtime Durability Visibility
When diagnostics should expose whether each write auto-flushes:
```moonbit
let enabled = logger.file_auto_flush()
```
In this example, runtime file durability policy is surfaced directly.
#### When Validate Policy Updates
When code should observe auto-flush after a setter call:
```moonbit
ignore(logger.file_set_auto_flush(true))
ignore(logger.file_auto_flush())
```
In this example, callers verify the updated policy.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `false`.
- If callers need to actually flush the file, `file_flush()` is the operational API.
### Notes
1. Use this helper to inspect runtime durability policy.
2. It complements `file_set_auto_flush(...)` rather than replacing real flush actions.
@@ -0,0 +1,76 @@
---
name: configured-logger-file-available
group: api
category: runtime
update-time: 20260512
description: Read whether the configured runtime logger currently has an available file sink behind its runtime sink shape.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-available
Read whether a `ConfiguredLogger` currently has an available file sink. This helper is useful for runtime diagnostics and recovery checks after config-driven file logger construction.
### Interface
```moonbit
pub fn ConfiguredLogger::file_available(self : ConfiguredLogger) -> Bool {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose file sink availability should be inspected.
#### output
- `Bool` - Whether an underlying file sink is available.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed runtime sinks report actual file availability.
- Non-file sinks report `false`.
- Queued file sinks still expose the availability of their wrapped file sink.
- This helper delegates to the runtime sink and does not mutate logger state.
### How to Use
Here are some specific examples provided.
#### When Need Runtime File Health Checks
When operators or code should check file sink readiness:
```moonbit
if !logger.file_available() {
println("file sink unavailable")
}
```
In this example, the configured logger exposes file health directly.
#### When Gate Recovery Logic
When reopen or fallback behavior depends on file availability:
```moonbit
let ok = logger.file_available()
```
In this example, callers can decide whether a recovery action is needed.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `false`.
- If callers need detailed failure counters rather than a simple availability flag, `file_state()` or `file_runtime_state()` is the better API.
### Notes
1. Use this helper for lightweight file sink health checks.
2. Pair it with reopen and failure-counter APIs when diagnosing file sink problems.
@@ -0,0 +1,74 @@
---
name: configured-logger-file-clear-rotation
group: api
category: runtime
update-time: 20260512
description: Disable runtime rotation on the configured file-backed logger sink.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-clear-rotation
Disable runtime rotation on a `ConfiguredLogger` file sink. This helper is the direct shortcut for clearing rotation policy.
### Interface
```moonbit
pub fn ConfiguredLogger::file_clear_rotation(self : ConfiguredLogger) -> Bool {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose rotation policy should be cleared.
#### output
- `Bool` - Whether the policy update was applied.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks clear their runtime rotation policy.
- Queued file sinks forward the update to the wrapped file sink.
- Non-file sinks return `false`.
- This helper is equivalent in intent to setting rotation to `None`, but is clearer at the call site.
### How to Use
Here are some specific examples provided.
#### When Need To Disable Rotation Explicitly
When runtime file rotation should be turned off:
```moonbit
ignore(logger.file_clear_rotation())
```
In this example, rotation policy is removed directly.
#### When Need A Clear Intent Shortcut
When code should make the disable-rotation intent obvious:
```moonbit
let ok = logger.file_clear_rotation()
```
In this example, the call site reads more clearly than a generic config setter.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `false`.
- If callers need to switch to another rotation config rather than disable rotation, `file_set_rotation(...)` is the better API.
### Notes
1. Use this helper when the desired effect is simply “rotation off”.
2. It is clearer than passing `None` through a broader setter when intent matters.
+74
View File
@@ -0,0 +1,74 @@
---
name: configured-logger-file-close
group: api
category: runtime
update-time: 20260512
description: Close the file sink behind a configured runtime logger when one is present.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-close
Close the file sink behind a `ConfiguredLogger`. This helper is the file-specific runtime close surface for config-built file loggers.
### Interface
```moonbit
pub fn ConfiguredLogger::file_close(self : ConfiguredLogger) -> Bool {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose file sink should be closed.
#### output
- `Bool` - Whether the underlying file close succeeded.
### Explanation
Detailed rules explaining key parameters and behaviors
- Plain file sinks forward directly to file close behavior.
- Queued file sinks flush queue work before closing the wrapped file sink.
- Non-file sinks return `false`.
- This helper is narrower than generic `close()` because it specifically targets file sink shutdown.
### How to Use
Here are some specific examples provided.
#### When Need File-specific Runtime Teardown
When a config-built file logger should close its file handle explicitly:
```moonbit
ignore(logger.file_close())
```
In this example, file teardown happens through the configured logger facade.
#### When Need A File-specific Close Result
When application code wants the file close outcome directly:
```moonbit
let closed = logger.file_close()
```
In this example, the result describes file close behavior rather than generic sink close behavior.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `false`.
- If callers only need generic sink teardown, `close()` is the broader API.
### Notes
1. Prefer this helper when file-backed runtime behavior matters specifically.
2. Queued file sinks may flush pending records before closing the file.
@@ -0,0 +1,74 @@
---
name: configured-logger-file-default-policy
group: api
category: runtime
update-time: 20260512
description: Read the initial default file policy associated with a configured file-backed logger.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-default-policy
Read the initial default file policy associated with a `ConfiguredLogger`. This helper exposes the baseline file policy captured when the runtime sink was created.
### Interface
```moonbit
pub fn ConfiguredLogger::file_default_policy(self : ConfiguredLogger) -> FileSinkPolicy {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose default file policy should be inspected.
#### output
- `FileSinkPolicy` - Initial default file policy.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks return the default policy captured at creation time.
- Queued file sinks forward the default policy from the wrapped file sink.
- Non-file sinks return a neutral fallback policy value.
- This helper is useful when callers need to compare runtime drift or restore defaults later.
### How to Use
Here are some specific examples provided.
#### When Need Baseline Policy Visibility
When diagnostics should show the original file policy separately from the live one:
```moonbit
let defaults = logger.file_default_policy()
```
In this example, the configured logger exposes its original file policy snapshot.
#### When Prepare For Policy Reset Logic
When tooling should capture or compare default settings explicitly:
```moonbit
let original = logger.file_default_policy()
```
In this example, callers can reason about “factory” file policy separately from runtime changes.
### Error Case
e.g.:
- If the configured sink is not file-backed, the return value is a neutral fallback policy.
- If callers only need to know whether runtime drift exists, `file_policy_matches_default()` is the simpler API.
### Notes
1. Use this helper when the original file policy matters operationally.
2. It complements `file_policy()` and `file_reset_policy()`.
@@ -0,0 +1,74 @@
---
name: configured-logger-file-flush-failures
group: api
category: runtime
update-time: 20260512
description: Read the number of flush failures recorded by the configured runtime file sink.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-flush-failures
Read the number of flush failures recorded by a `ConfiguredLogger` file sink. This helper is useful for diagnosing durability-path problems on file-backed loggers.
### Interface
```moonbit
pub fn ConfiguredLogger::file_flush_failures(self : ConfiguredLogger) -> Int {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose flush-failure counter should be inspected.
#### output
- `Int` - Number of recorded flush failures.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks report their recorded flush-failure count.
- Queued file sinks forward the metric from the wrapped file sink.
- Non-file sinks return `0`.
- The counter is cumulative until reset.
### How to Use
Here are some specific examples provided.
#### When Need Durability-path Diagnostics
When support output should show flush-path instability:
```moonbit
let count = logger.file_flush_failures()
```
In this example, the configured logger exposes whether flush attempts have been failing.
#### When Inspect Effects Of Auto-flush Policy
When runtime durability tuning should be inspected operationally:
```moonbit
ignore(logger.file_flush_failures())
```
In this example, callers can correlate flush failures with runtime file policy choices.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `0`.
- If callers need current policy and counters together, `file_state()` is the better API.
### Notes
1. Use this helper when flush-path reliability matters.
2. Pair it with `file_auto_flush()` and `file_flush()` when diagnosing durability behavior.
+74
View File
@@ -0,0 +1,74 @@
---
name: configured-logger-file-flush
group: api
category: runtime
update-time: 20260512
description: Flush the file sink behind a configured runtime logger when one is present.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-flush
Flush the file sink behind a `ConfiguredLogger`. This helper is the file-specific runtime flush surface for config-built file loggers.
### Interface
```moonbit
pub fn ConfiguredLogger::file_flush(self : ConfiguredLogger) -> Bool {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose file sink should be flushed.
#### output
- `Bool` - Whether the underlying file flush succeeded.
### Explanation
Detailed rules explaining key parameters and behaviors
- Plain file sinks forward directly to file flush behavior.
- Queued file sinks first flush queued records, then flush the wrapped file sink.
- Non-file sinks return `false`.
- This helper is narrower than generic `flush()` because it targets file sink behavior specifically.
### How to Use
Here are some specific examples provided.
#### When Need Explicit File Durability Steps
When a config-built file logger should flush to disk explicitly:
```moonbit
ignore(logger.file_flush())
```
In this example, the file-backed runtime sink is flushed directly through the configured logger.
#### When Need A File-specific Success Flag
When code should branch on the outcome of a file flush:
```moonbit
let ok = logger.file_flush()
```
In this example, callers can distinguish file flush success from a non-file sink shape.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `false`.
- If callers want generic queue or sink advancement instead of file-specific behavior, `flush()` is the broader API.
### Notes
1. Prefer this helper when the configured sink is known to be file-backed.
2. Queued file sinks may perform both queue flush and file flush work here.
@@ -0,0 +1,74 @@
---
name: configured-logger-file-open-failures
group: api
category: runtime
update-time: 20260512
description: Read the number of open failures recorded by the configured runtime file sink.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-open-failures
Read the number of open failures recorded by a `ConfiguredLogger` file sink. This helper is useful for diagnosing file-availability or reopen problems.
### Interface
```moonbit
pub fn ConfiguredLogger::file_open_failures(self : ConfiguredLogger) -> Int {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose open-failure counter should be inspected.
#### output
- `Int` - Number of recorded open failures.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks report their recorded open-failure count.
- Queued file sinks forward the metric from the wrapped file sink.
- Non-file sinks return `0`.
- The counter is cumulative until reset.
### How to Use
Here are some specific examples provided.
#### When Need File Availability Diagnostics
When operators should see whether file open or reopen failed:
```moonbit
let count = logger.file_open_failures()
```
In this example, the configured logger exposes the open-failure metric directly.
#### When Validate Recovery Logic
When tests or support code should inspect whether reopen attempts failed:
```moonbit
ignore(logger.file_open_failures())
```
In this example, the counter helps confirm whether file-open problems occurred during runtime.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `0`.
- If callers need the full file status snapshot rather than one counter, `file_state()` is the better API.
### Notes
1. Use this helper for focused file-open diagnostics.
2. Pair it with `file_reopen(...)` and `file_available()` during recovery analysis.
+74
View File
@@ -0,0 +1,74 @@
---
name: configured-logger-file-path
group: api
category: runtime
update-time: 20260512
description: Read the effective file path used by the configured runtime logger when it is file-backed.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-path
Read the effective file path used by a `ConfiguredLogger`. This helper is useful for diagnostics, support output, and confirming which file-backed runtime sink is active.
### Interface
```moonbit
pub fn ConfiguredLogger::file_path(self : ConfiguredLogger) -> String {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose file path should be inspected.
#### output
- `String` - Effective runtime file path, or an empty string for non-file sinks.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks return their current file path.
- Queued file sinks forward the wrapped file sink path.
- Non-file sinks return an empty string.
- This helper is observation-only and does not modify file state.
### How to Use
Here are some specific examples provided.
#### When Need Runtime Path Diagnostics
When diagnostics should show which file is active:
```moonbit
println(logger.file_path())
```
In this example, operators can verify the effective destination path directly.
#### When Build Support Output
When application state dumps should include file destination info:
```moonbit
let path = logger.file_path()
```
In this example, the path can be surfaced without reading broader runtime state.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns an empty string.
- If callers need richer file status than just the path, `file_state()` or `file_runtime_state()` is the better API.
### Notes
1. Use this helper for direct runtime path visibility.
2. Empty string usually means the configured sink is not file-backed.
@@ -0,0 +1,76 @@
---
name: configured-logger-file-policy-matches-default
group: api
category: runtime
update-time: 20260512
description: Read whether the current runtime file policy still matches the configured logger default policy.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-policy-matches-default
Read whether the current runtime file policy still matches the default policy of a `ConfiguredLogger`. This helper is useful for detecting operational drift.
### Interface
```moonbit
pub fn ConfiguredLogger::file_policy_matches_default(self : ConfiguredLogger) -> Bool {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose runtime policy drift should be checked.
#### output
- `Bool` - Whether the current runtime file policy still matches the default.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks compare current runtime file policy against their stored defaults.
- Queued file sinks forward the comparison from the wrapped file sink.
- Non-file sinks return `false`.
- This helper is a compact drift signal when callers do not need to compare full policy objects directly.
### How to Use
Here are some specific examples provided.
#### When Need Drift Detection
When diagnostics should report whether file policy changed after startup:
```moonbit
let unchanged = logger.file_policy_matches_default()
```
In this example, the configured logger exposes whether runtime file policy still matches the baseline.
#### When Gate Reset Logic
When code should only reset policy if drift exists:
```moonbit
if !logger.file_policy_matches_default() {
ignore(logger.file_reset_policy())
}
```
In this example, policy reset only happens when runtime state diverged from defaults.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `false`.
- If callers need the exact differences instead of a boolean drift signal, they should inspect both `file_policy()` and `file_default_policy()`.
### Notes
1. Use this helper for compact runtime policy drift checks.
2. It is especially useful before calling reset-style operations.
+75
View File
@@ -0,0 +1,75 @@
---
name: configured-logger-file-policy
group: api
category: runtime
update-time: 20260512
description: Read the current runtime file policy from a configured file-backed logger.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-policy
Read the current runtime file policy from a `ConfiguredLogger`. This helper exposes the active append, auto-flush, and rotation settings as one policy object.
### Interface
```moonbit
pub fn ConfiguredLogger::file_policy(self : ConfiguredLogger) -> FileSinkPolicy {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose current file policy should be inspected.
#### output
- `FileSinkPolicy` - Current runtime file policy.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks return their current runtime file policy.
- Queued file sinks forward the policy from the wrapped file sink.
- Non-file sinks return a neutral fallback policy value.
- This helper is broader than `file_append_mode()` or `file_auto_flush()` because it returns the whole policy object.
### How to Use
Here are some specific examples provided.
#### When Need Full Runtime Policy Visibility
When diagnostics should inspect the active file policy as one object:
```moonbit
let policy = logger.file_policy()
```
In this example, append, flush, and rotation settings are read together.
#### When Compare Current And Default Policy
When runtime drift from defaults should be inspected explicitly:
```moonbit
let current = logger.file_policy()
let defaults = logger.file_default_policy()
```
In this example, callers can compare current runtime settings with the initial policy snapshot.
### Error Case
e.g.:
- If the configured sink is not file-backed, the return value is a neutral fallback policy rather than a real active file policy.
- If callers only need one field from the policy, a narrower helper may be simpler.
### Notes
1. Use this helper when file policy should be handled as one object.
2. Pair it with `file_set_policy(...)` for roundtrip-style policy management.
@@ -0,0 +1,74 @@
---
name: configured-logger-file-reopen-append
group: api
category: runtime
update-time: 20260512
description: Reopen the file sink behind a configured runtime logger in append mode.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-reopen-append
Reopen the file sink behind a `ConfiguredLogger` in append mode. This helper is the explicit append-oriented recovery shortcut.
### Interface
```moonbit
pub fn ConfiguredLogger::file_reopen_append(self : ConfiguredLogger) -> Bool {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose file sink should be reopened in append mode.
#### output
- `Bool` - Whether reopen succeeded.
### Explanation
Detailed rules explaining key parameters and behaviors
- Plain file sinks reopen in append mode.
- Queued file sinks forward reopen behavior to the wrapped file sink.
- This helper is a specialized shortcut for a common reopen mode.
- Non-file sinks return `false`.
### How to Use
Here are some specific examples provided.
#### When Need Append-preserving Recovery
When file logging should continue appending after a reopen:
```moonbit
ignore(logger.file_reopen_append())
```
In this example, reopen behavior is fixed to append mode.
#### When Want An Explicit Append Shortcut
When code should avoid manually setting append overrides:
```moonbit
let ok = logger.file_reopen_append()
```
In this example, the call site states append intent directly.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `false`.
- If callers need truncate behavior instead, `file_reopen_truncate()` is the correct API.
### Notes
1. Use this helper for explicit append-mode reopen flows.
2. It is especially useful after transient file availability issues.
@@ -0,0 +1,74 @@
---
name: configured-logger-file-reopen-truncate
group: api
category: runtime
update-time: 20260512
description: Reopen the file sink behind a configured runtime logger in truncate mode.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-reopen-truncate
Reopen the file sink behind a `ConfiguredLogger` in truncate mode. This helper is the explicit truncate-oriented recovery or reset shortcut.
### Interface
```moonbit
pub fn ConfiguredLogger::file_reopen_truncate(self : ConfiguredLogger) -> Bool {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose file sink should be reopened in truncate mode.
#### output
- `Bool` - Whether reopen succeeded.
### Explanation
Detailed rules explaining key parameters and behaviors
- Plain file sinks reopen in truncate mode.
- Queued file sinks forward reopen behavior to the wrapped file sink.
- This helper is a specialized shortcut for a common reset-style reopen mode.
- Non-file sinks return `false`.
### How to Use
Here are some specific examples provided.
#### When Need A Fresh Output File
When a runtime file should be reopened from an empty state:
```moonbit
ignore(logger.file_reopen_truncate())
```
In this example, reopen behavior truncates the file before future writes continue.
#### When Want An Explicit Truncate Shortcut
When code should make destructive reopen intent obvious:
```moonbit
let ok = logger.file_reopen_truncate()
```
In this example, the call site expresses reset-style reopen behavior directly.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `false`.
- If callers want to preserve existing file content, `file_reopen_append()` is the correct API.
### Notes
1. Use this helper when starting from a fresh file is intentional.
2. Truncate-mode reopen is a stronger action than generic reopen recovery.
@@ -0,0 +1,74 @@
---
name: configured-logger-file-reopen-with-current-policy
group: api
category: runtime
update-time: 20260512
description: Reopen the file sink behind a configured runtime logger using its currently stored runtime policy.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-reopen-with-current-policy
Reopen the file sink behind a `ConfiguredLogger` using the currently stored runtime policy. This helper is useful when callers want recovery behavior without supplying a one-off append override.
### Interface
```moonbit
pub fn ConfiguredLogger::file_reopen_with_current_policy(self : ConfiguredLogger) -> Bool {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose file sink should be reopened with current policy.
#### output
- `Bool` - Whether reopen succeeded.
### Explanation
Detailed rules explaining key parameters and behaviors
- Plain file sinks reuse their current stored reopen policy.
- Queued file sinks forward reopen behavior to the wrapped file sink.
- This helper differs from `file_reopen(...)` because it does not accept a per-call append override.
- Non-file sinks return `false`.
### How to Use
Here are some specific examples provided.
#### When Need Policy-preserving Recovery
When a file sink should be reopened without changing runtime append behavior:
```moonbit
ignore(logger.file_reopen_with_current_policy())
```
In this example, recovery reuses the runtime policy already stored on the sink.
#### When Separate Recovery From Policy Mutation
When append mode should be controlled elsewhere:
```moonbit
let ok = logger.file_reopen_with_current_policy()
```
In this example, reopen is explicit while policy mutation stays separate.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `false`.
- If callers want to change append behavior during reopen, `file_reopen(...)` or `file_reopen_append()` / `file_reopen_truncate()` are better APIs.
### Notes
1. Use this helper when recovery should respect the currently stored runtime policy.
2. It is clearer than passing no override through a more general reopen API.
+75
View File
@@ -0,0 +1,75 @@
---
name: configured-logger-file-reopen
group: api
category: runtime
update-time: 20260512
description: Reopen the file sink behind a configured runtime logger with an optional append-mode override.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-reopen
Reopen the file sink behind a `ConfiguredLogger`. This helper is useful for recovery flows after file unavailability or policy changes.
### Interface
```moonbit
pub fn ConfiguredLogger::file_reopen(self : ConfiguredLogger, append~ : Bool? = None) -> Bool {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose file sink should be reopened.
- `append : Bool?` - Optional append-mode override used for reopen behavior.
#### output
- `Bool` - Whether reopen succeeded.
### Explanation
Detailed rules explaining key parameters and behaviors
- Plain file sinks reopen directly.
- Queued file sinks forward reopen behavior to the wrapped file sink.
- `append=None` preserves current reopen policy, while `Some(true/false)` overrides append mode.
- Non-file sinks return `false`.
### How to Use
Here are some specific examples provided.
#### When Need Recovery After File Failure
When application code should attempt to restore file logging:
```moonbit
ignore(logger.file_reopen())
```
In this example, the configured logger tries to reopen its runtime file sink using current policy.
#### When Need Explicit Append-mode Reopen
When recovery should choose append or truncate behavior explicitly:
```moonbit
let ok = logger.file_reopen(append=Some(true))
```
In this example, reopen behavior is directed by the call site.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `false`.
- If callers only need the current configured policy, `file_reopen_with_current_policy()` may be the clearer API.
### Notes
1. Use this helper for explicit recovery flows.
2. Pair it with `file_available()` and failure counters when diagnosing reopen behavior.
@@ -0,0 +1,75 @@
---
name: configured-logger-file-reset-failure-counters
group: api
category: runtime
update-time: 20260512
description: Reset the file failure counters recorded by the configured runtime file sink.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-reset-failure-counters
Reset the file failure counters recorded by a `ConfiguredLogger`. This helper clears open, write, flush, and rotation failure metrics together.
### Interface
```moonbit
pub fn ConfiguredLogger::file_reset_failure_counters(self : ConfiguredLogger) -> Bool {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose file failure counters should be cleared.
#### output
- `Bool` - Whether the reset was applied.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks clear all file failure counters together.
- Queued file sinks forward the reset behavior to the wrapped file sink.
- Non-file sinks return `false`.
- This helper is useful after diagnostics, recovery, or controlled tests.
### How to Use
Here are some specific examples provided.
#### When Need A Fresh Diagnostics Baseline
When previous failure history should be cleared before a new observation window:
```moonbit
ignore(logger.file_reset_failure_counters())
```
In this example, future failures can be measured from a clean baseline.
#### When Validate Post-recovery Behavior
When recovery logic should clear old counters before rechecking health:
```moonbit
ignore(logger.file_reset_failure_counters())
ignore(logger.file_open_failures())
```
In this example, the configured logger starts a new diagnostics window after reset.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `false`.
- If callers need the current values before clearing them, they should read the counters or `file_state()` first.
### Notes
1. Use this helper after diagnostics or recovery, not before capturing needed evidence.
2. It is the reset companion for the file failure-counter helpers.
@@ -0,0 +1,76 @@
---
name: configured-logger-file-reset-policy
group: api
category: runtime
update-time: 20260512
description: Reset the runtime file policy of a configured file-backed logger back to its original defaults.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-reset-policy
Reset the runtime file policy of a `ConfiguredLogger` back to its original defaults. This helper restores append, auto-flush, and rotation policy together.
### Interface
```moonbit
pub fn ConfiguredLogger::file_reset_policy(self : ConfiguredLogger) -> Bool {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose file policy should be restored.
#### output
- `Bool` - Whether the reset was applied.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks restore their stored default file policy.
- Queued file sinks forward the reset behavior to the wrapped file sink.
- Non-file sinks return `false`.
- This helper is the inverse of runtime policy drift, not a generic reopen or flush action.
### How to Use
Here are some specific examples provided.
#### When Need To Undo Runtime Policy Changes
When file policy should return to the original configured defaults:
```moonbit
ignore(logger.file_reset_policy())
```
In this example, append, auto-flush, and rotation settings are restored together.
#### When Use Drift-aware Recovery
When reset should only happen after runtime changes:
```moonbit
if !logger.file_policy_matches_default() {
ignore(logger.file_reset_policy())
}
```
In this example, reset is only applied when runtime policy has diverged.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `false`.
- If callers need to restore only one setting, a narrower setter may be more appropriate than a full policy reset.
### Notes
1. Use this helper when the original bundled file policy should be restored intact.
2. It pairs naturally with `file_policy_matches_default()` and `file_default_policy()`.
@@ -0,0 +1,77 @@
---
name: configured-logger-file-rotation-config
group: api
category: runtime
update-time: 20260512
description: Read the current rotation configuration used by the configured runtime file sink.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-rotation-config
Read the current rotation configuration used by a `ConfiguredLogger` file sink. This helper exposes the active runtime rotation parameters when rotation is enabled.
### Interface
```moonbit
pub fn ConfiguredLogger::file_rotation_config(self : ConfiguredLogger) -> FileRotation? {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose rotation config should be inspected.
#### output
- `FileRotation?` - Current rotation config, or `None` if rotation is disabled or the sink is not file-backed.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks return their current rotation configuration when enabled.
- Queued file sinks forward the config from the wrapped file sink.
- Non-file sinks return `None`.
- This helper is useful when callers need active runtime rotation parameters rather than only a boolean flag.
### How to Use
Here are some specific examples provided.
#### When Need Runtime Rotation Parameters
When support output should include the active rotation policy:
```moonbit
let rotation = logger.file_rotation_config()
```
In this example, the configured logger exposes live runtime rotation parameters directly.
#### When Branch On Optional Rotation Presence
When code should react differently for rotating file sinks:
```moonbit
match logger.file_rotation_config() {
Some(cfg) => ignore(cfg)
None => ()
}
```
In this example, optional return shape reflects whether rotation is active.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `None`.
- If callers only need to know whether rotation is enabled, `file_rotation_enabled()` is the simpler API.
### Notes
1. Use this helper when current runtime rotation parameters matter.
2. It is useful after policy updates or recovery flows.
@@ -0,0 +1,76 @@
---
name: configured-logger-file-rotation-enabled
group: api
category: runtime
update-time: 20260512
description: Read whether rotation is currently enabled on the configured runtime file sink.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-rotation-enabled
Read whether rotation is currently enabled on a `ConfiguredLogger` file sink. This helper exposes whether runtime rotation policy is active.
### Interface
```moonbit
pub fn ConfiguredLogger::file_rotation_enabled(self : ConfiguredLogger) -> Bool {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose rotation state should be inspected.
#### output
- `Bool` - Whether rotation is currently enabled.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks report whether a rotation config is active.
- Queued file sinks forward the state from the wrapped file sink.
- Non-file sinks return `false`.
- This helper is narrower than `file_rotation_config()` when only a yes/no check is needed.
### How to Use
Here are some specific examples provided.
#### When Need Runtime Rotation Visibility
When support output should expose whether rotation is active:
```moonbit
let rotating = logger.file_rotation_enabled()
```
In this example, callers get a direct boolean answer without inspecting config objects.
#### When Guard Rotation-specific Behavior
When logic should only run for rotating file sinks:
```moonbit
if logger.file_rotation_enabled() {
println("rotation active")
}
```
In this example, runtime policy can drive control flow.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `false`.
- If callers need the actual rotation parameters, `file_rotation_config()` is the better API.
### Notes
1. Use this helper for simple runtime rotation checks.
2. Pair it with `file_rotation_config()` when parameters also matter.
@@ -0,0 +1,74 @@
---
name: configured-logger-file-rotation-failures
group: api
category: runtime
update-time: 20260512
description: Read the number of rotation failures recorded by the configured runtime file sink.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-rotation-failures
Read the number of rotation failures recorded by a `ConfiguredLogger` file sink. This helper is useful when runtime rotation behavior should be observed operationally.
### Interface
```moonbit
pub fn ConfiguredLogger::file_rotation_failures(self : ConfiguredLogger) -> Int {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose rotation-failure counter should be inspected.
#### output
- `Int` - Number of recorded rotation failures.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks report their recorded rotation-failure count.
- Queued file sinks forward the metric from the wrapped file sink.
- Non-file sinks return `0`.
- The counter is cumulative until reset.
### How to Use
Here are some specific examples provided.
#### When Need Rotation-specific Diagnostics
When support output should reveal whether rotation is failing:
```moonbit
let count = logger.file_rotation_failures()
```
In this example, the configured logger exposes a focused metric for rotation-path health.
#### When Validate Runtime Rotation Tuning
When changed rotation settings should be checked in operation:
```moonbit
ignore(logger.file_rotation_failures())
```
In this example, callers can observe whether runtime rotation changes introduced problems.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `0`.
- If callers need both rotation config and failure metrics, they should combine this helper with `file_rotation_config()` or `file_state()`.
### Notes
1. Use this helper when diagnosing file rotation reliability.
2. It is especially relevant when runtime rotation policy can change after startup.
@@ -0,0 +1,77 @@
---
name: configured-logger-file-runtime-state
group: api
category: runtime
update-time: 20260512
description: Read combined file and queue runtime state from a configured logger when it is backed by a file sink.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-runtime-state
Read combined file and queue runtime state from a `ConfiguredLogger`. This helper is the richest file-specific diagnostics API on config-built runtime loggers.
### Interface
```moonbit
pub fn ConfiguredLogger::file_runtime_state(self : ConfiguredLogger) -> RuntimeFileState? {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose file runtime state should be inspected.
#### output
- `RuntimeFileState?` - Combined file and queue diagnostics when the runtime sink is file-backed, otherwise `None`.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks return `Some(RuntimeFileState)`.
- Queued file sinks include both file status and queue metrics in the returned state.
- Non-file sinks return `None`.
- This helper is richer than `file_state()` because it can also surface queued backlog and dropped counts.
### How to Use
Here are some specific examples provided.
#### When Need Rich File Runtime Diagnostics
When support output should include both file and queue state:
```moonbit
let state = logger.file_runtime_state()
```
In this example, callers can inspect availability, failure counters, and queue metrics together.
#### When Need To Branch On File-backed Runtime Shape
When code should behave differently for file-backed config-built loggers:
```moonbit
match logger.file_runtime_state() {
Some(state) => ignore(state)
None => ()
}
```
In this example, the optional return value reflects whether the runtime sink is file-backed.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `None`.
- If callers only need raw file status without queue context, `file_state()` may be the simpler API.
### Notes
1. Use this helper for the richest file-backed runtime diagnostics on config-built loggers.
2. It is especially useful for queued file sinks where file health and queue state both matter.
@@ -0,0 +1,76 @@
---
name: configured-logger-file-set-append-mode
group: api
category: runtime
update-time: 20260512
description: Update the append-mode policy used by the configured runtime file sink for later reopen behavior.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-set-append-mode
Update the append-mode policy used by a `ConfiguredLogger` file sink. This helper changes future reopen behavior without forcing an immediate reopen.
### Interface
```moonbit
pub fn ConfiguredLogger::file_set_append_mode(self : ConfiguredLogger, append : Bool) -> Bool {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose append-mode policy should change.
- `append : Bool` - New append-mode policy.
#### output
- `Bool` - Whether the policy update was applied.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks update their stored append policy.
- Queued file sinks forward the policy update to the wrapped file sink.
- This helper updates policy only; it does not force immediate reopen.
- Non-file sinks return `false`.
### How to Use
Here are some specific examples provided.
#### When Need To Change Future Reopen Behavior
When runtime recovery should later prefer append mode explicitly:
```moonbit
ignore(logger.file_set_append_mode(true))
```
In this example, later reopen operations will use the updated append policy.
#### When Want To Separate Policy Mutation From Reopen Timing
When code should update policy now and reopen later:
```moonbit
ignore(logger.file_set_append_mode(false))
ignore(logger.file_reopen_with_current_policy())
```
In this example, policy mutation and reopen timing remain separate decisions.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `false`.
- If callers need an immediate reopen as part of the same operation, one of the reopen helpers should be used afterward.
### Notes
1. This helper changes stored policy, not live file-handle state by itself.
2. It is useful when recovery logic wants to stage reopen behavior in advance.
@@ -0,0 +1,75 @@
---
name: configured-logger-file-set-auto-flush
group: api
category: runtime
update-time: 20260512
description: Update the auto-flush policy used by the configured runtime file sink.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-set-auto-flush
Update the auto-flush policy used by a `ConfiguredLogger` file sink. This helper changes runtime durability behavior without rebuilding the logger.
### Interface
```moonbit
pub fn ConfiguredLogger::file_set_auto_flush(self : ConfiguredLogger, enabled : Bool) -> Bool {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose auto-flush policy should change.
- `enabled : Bool` - New auto-flush setting.
#### output
- `Bool` - Whether the policy update was applied.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks update their runtime auto-flush policy.
- Queued file sinks forward the update to the wrapped file sink.
- Non-file sinks return `false`.
- This helper changes policy only; it does not itself flush pending data.
### How to Use
Here are some specific examples provided.
#### When Need Runtime Durability Tuning
When a file sink should start flushing each write automatically:
```moonbit
ignore(logger.file_set_auto_flush(true))
```
In this example, runtime policy is updated without rebuilding the configured logger.
#### When Need To Relax Flush Pressure
When a file sink should stop auto-flushing for throughput reasons:
```moonbit
let ok = logger.file_set_auto_flush(false)
```
In this example, the call site updates policy explicitly and can inspect the result.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `false`.
- If callers need an immediate flush action, `file_flush()` is the operational API.
### Notes
1. Use this helper for runtime durability tuning.
2. Pair it with `file_auto_flush()` to verify the active policy.
@@ -0,0 +1,79 @@
---
name: configured-logger-file-set-policy
group: api
category: runtime
update-time: 20260512
description: Apply a bundled runtime file policy update to a configured file-backed logger.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-set-policy
Apply a bundled runtime file policy update to a `ConfiguredLogger`. This helper updates append mode, auto-flush, and rotation together through one runtime policy object.
### Interface
```moonbit
pub fn ConfiguredLogger::file_set_policy(self : ConfiguredLogger, policy : FileSinkPolicy) -> Bool {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose file policy should change.
- `policy : FileSinkPolicy` - Bundled runtime file policy to apply.
#### output
- `Bool` - Whether the policy update was applied.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks update append, auto-flush, and rotation together.
- Queued file sinks forward the policy update to the wrapped file sink.
- Non-file sinks return `false`.
- This helper is broader than the single-setting setters because it updates the whole file policy in one call.
### How to Use
Here are some specific examples provided.
#### When Need Bundled Runtime Policy Changes
When append, flush, and rotation should change together:
```moonbit
ignore(logger.file_set_policy(FileSinkPolicy::new(
append=true,
auto_flush=false,
rotation=Some(file_rotation(2048, max_backups=2)),
)))
```
In this example, runtime file behavior is updated as one policy change.
#### When Apply A Policy Snapshot
When a previously captured or computed policy should be restored:
```moonbit
let ok = logger.file_set_policy(policy)
```
In this example, callers can reapply a whole policy object without splitting it into separate setter calls.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `false`.
- If callers only need to change one setting, a narrower setter such as `file_set_auto_flush(...)` or `file_set_rotation(...)` may be clearer.
### Notes
1. Use this helper when the runtime policy should be treated as one cohesive object.
2. It pairs naturally with `file_policy()` and `file_default_policy()`.
@@ -0,0 +1,78 @@
---
name: configured-logger-file-set-rotation
group: api
category: runtime
update-time: 20260512
description: Update the rotation configuration used by the configured runtime file sink.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-set-rotation
Update the rotation configuration used by a `ConfiguredLogger` file sink. This helper changes runtime file rotation behavior without rebuilding the logger.
### Interface
```moonbit
pub fn ConfiguredLogger::file_set_rotation(
self : ConfiguredLogger,
rotation : FileRotation?,
) -> Bool {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose rotation policy should change.
- `rotation : FileRotation?` - New rotation config, or `None` to disable rotation.
#### output
- `Bool` - Whether the policy update was applied.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks update their runtime rotation policy.
- Queued file sinks forward the update to the wrapped file sink.
- Passing `None` disables rotation.
- Non-file sinks return `false`.
### How to Use
Here are some specific examples provided.
#### When Need Runtime Rotation Tuning
When a file sink should enable or change rotation dynamically:
```moonbit
ignore(logger.file_set_rotation(Some(file_rotation(1024, max_backups=3))))
```
In this example, runtime rotation behavior is updated without rebuilding the logger.
#### When Need To Disable Rotation
When the file sink should stop rotating:
```moonbit
let ok = logger.file_set_rotation(None)
```
In this example, the runtime file sink has its rotation policy cleared explicitly.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `false`.
- If callers only want to remove rotation, `file_clear_rotation()` is the more direct API.
### Notes
1. Use this helper when setting a full runtime rotation config.
2. It is useful for operational tuning without rebuilding the logger.
+74
View File
@@ -0,0 +1,74 @@
---
name: configured-logger-file-state
group: api
category: runtime
update-time: 20260512
description: Read the current file sink snapshot from a configured runtime logger.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-state
Read the current file sink snapshot from a `ConfiguredLogger`. This helper exposes path, availability, policy flags, rotation config, and failure counters as one object.
### Interface
```moonbit
pub fn ConfiguredLogger::file_state(self : ConfiguredLogger) -> FileSinkState {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose file state snapshot should be inspected.
#### output
- `FileSinkState` - Current file sink snapshot.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks return a live snapshot of file state.
- Queued file sinks forward the snapshot from the wrapped file sink.
- Non-file sinks return a fallback empty-state snapshot.
- This helper is broader than individual file counters or policy accessors because it aggregates core file status into one read.
### How to Use
Here are some specific examples provided.
#### When Need A Full File Health Snapshot
When diagnostics should inspect runtime file state as one object:
```moonbit
let state = logger.file_state()
```
In this example, callers receive a single file-state snapshot instead of querying each property separately.
#### When Need To Export File Runtime Diagnostics
When a support path should serialize current file state:
```moonbit
println(stringify_file_sink_state(logger.file_state(), pretty=true))
```
In this example, the configured logger snapshot can be exported directly through existing JSON helpers.
### Error Case
e.g.:
- If the configured sink is not file-backed, the returned snapshot is a fallback empty-style state rather than a live file view.
- If callers also need queue context for queued file sinks, `file_runtime_state()` is the richer API.
### Notes
1. Use this helper for the main one-shot file status snapshot.
2. Prefer it over individual counters when broader file diagnostics are needed.
@@ -0,0 +1,74 @@
---
name: configured-logger-file-write-failures
group: api
category: runtime
update-time: 20260512
description: Read the number of write failures recorded by the configured runtime file sink.
key-word:
- logger
- runtime
- file
- public
---
## Configured-logger-file-write-failures
Read the number of write failures recorded by a `ConfiguredLogger` file sink. This helper is useful for diagnosing runtime write-path problems.
### Interface
```moonbit
pub fn ConfiguredLogger::file_write_failures(self : ConfiguredLogger) -> Int {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose write-failure counter should be inspected.
#### output
- `Int` - Number of recorded write failures.
### Explanation
Detailed rules explaining key parameters and behaviors
- File-backed sinks report their recorded write-failure count.
- Queued file sinks forward the metric from the wrapped file sink.
- Non-file sinks return `0`.
- The counter is cumulative until reset.
### How to Use
Here are some specific examples provided.
#### When Need Runtime Write-path Diagnostics
When support output should show whether writes have been failing:
```moonbit
let count = logger.file_write_failures()
```
In this example, callers get a focused signal for file write-path health.
#### When Compare Sink Health After Recovery
When recovery logic should verify whether new failures still occur:
```moonbit
ignore(logger.file_write_failures())
```
In this example, the metric helps measure whether runtime writes improved after intervention.
### Error Case
e.g.:
- If the configured sink is not file-backed, the method returns `0`.
- If callers need a fuller view of file health, `file_state()` or `file_runtime_state()` may be better APIs.
### Notes
1. Use this helper for focused write-failure visibility.
2. Pair it with `file_flush_failures()` when diagnosing output-path instability.
+74
View File
@@ -0,0 +1,74 @@
---
name: configured-logger-flush
group: api
category: runtime
update-time: 20260512
description: Flush a configured runtime logger and return how many queued or file-backed operations were advanced.
key-word:
- logger
- runtime
- flush
- public
---
## Configured-logger-flush
Flush a `ConfiguredLogger` and return how much work was advanced. This is the main runtime helper for forcing queued or file-backed logger output to move forward after config-driven construction.
### Interface
```moonbit
pub fn ConfiguredLogger::flush(self : ConfiguredLogger) -> Int {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose sink should be flushed.
#### output
- `Int` - Count of flushed or drained items as reported by the runtime sink.
### Explanation
Detailed rules explaining key parameters and behaviors
- For queue-wrapped sinks, this forwards to the queue drain/flush behavior.
- For plain file sinks, the return value reflects whether a file flush happened.
- For plain console-style sinks, the result is typically `0` because there is no meaningful buffered flush step.
- This helper delegates to `RuntimeSink::flush(...)` through the configured logger wrapper.
### How to Use
Here are some specific examples provided.
#### When Need Explicit Queue Progress
When config-built queue output should be advanced manually:
```moonbit
ignore(logger.flush())
```
In this example, the configured runtime logger is flushed without reaching into the sink directly.
#### When Need A Post-write Flush Barrier
When a service wants stronger delivery behavior after a burst of writes:
```moonbit
let flushed = logger.flush()
```
In this example, callers can observe how much work was advanced by the flush request.
### Error Case
e.g.:
- If the configured sink has no flushable buffering, the method may simply return `0`.
- If callers need bounded manual draining rather than generic flush behavior, `drain(...)` is the better API.
### Notes
1. Use this helper after config-driven logger construction when explicit runtime flushing matters.
2. The exact return value depends on the underlying runtime sink shape.
@@ -0,0 +1,75 @@
---
name: configured-logger-pending-count
group: api
category: runtime
update-time: 20260512
description: Read the current queued backlog count from a configured runtime logger.
key-word:
- logger
- runtime
- queue
- public
---
## Configured-logger-pending-count
Read the current queued backlog count from a `ConfiguredLogger`. This is the direct runtime metric for config-driven queue wrapping.
### Interface
```moonbit
pub fn ConfiguredLogger::pending_count(self : ConfiguredLogger) -> Int {}
```
#### input
- `self : ConfiguredLogger` - Config-driven runtime logger whose queue backlog should be inspected.
#### output
- `Int` - Current number of pending queued records.
### Explanation
Detailed rules explaining key parameters and behaviors
- Queue-backed sinks return their live pending count.
- Non-queued sinks report `0`.
- This is a point-in-time metric and may change immediately after it is read.
- This helper delegates to `RuntimeSink::pending_count(...)` through the configured logger wrapper.
### How to Use
Here are some specific examples provided.
#### When Need Configured Queue Backlog Visibility
When a config-built logger should expose queue pressure:
```moonbit
let pending = logger.pending_count()
```
In this example, queue backlog is observed without reaching into the sink internals.
#### When Verify Manual Drain Progress
When drain loops should observe remaining backlog:
```moonbit
ignore(logger.drain(max_items=8))
ignore(logger.pending_count())
```
In this example, the queue metric helps verify manual drain progress.
### Error Case
e.g.:
- If the logger is not queue-backed, the method simply returns `0`.
- If callers need richer file-plus-queue state for file sinks, `file_runtime_state()` is the better API.
### Notes
1. Use this helper for simple queue visibility on config-built loggers.
2. Pair it with `dropped_count()` when investigating loss behavior.
+75
View File
@@ -0,0 +1,75 @@
---
name: default-logger
group: api
category: global
update-time: 20260512
description: Create the shared console-backed logger value used by the global logging helpers.
key-word:
- global
- logger
- default
- public
---
## Default-logger
Create a `Logger[ConsoleSink]` from the current shared default global configuration. This is the logger value used internally by the global helper functions such as `log(...)`, `info(...)`, and `error(...)`.
### Interface
```moonbit
pub fn default_logger() -> Logger[ConsoleSink] {}
```
#### output
- `Logger[ConsoleSink]` - Logger built from the shared console sink, current default minimum level, and current default target.
### Explanation
Detailed rules explaining key parameters and behaviors
- The returned logger is built from `default_console_sink`, `default_min_level_ref`, and `default_target_ref`.
- Each call reflects the current shared configuration at that moment.
- The logger writes to the standard console sink path.
- This helper is useful when you want the same baseline behavior as the global shortcuts but still need the explicit `Logger` object for chaining or inspection.
### How to Use
Here are some specific examples provided.
#### When Start From Global Defaults But Keep A Logger Value
When code wants the default console path with later composition:
```moonbit
let logger = default_logger().with_timestamp()
logger.info("service started")
```
In this example, the logger starts from global defaults and then gains extra instance-level behavior.
#### When Inspect Current Shared Behavior
When code should branch using the same threshold as global helpers:
```moonbit
let logger = default_logger()
if logger.is_enabled(Level::Debug) {
logger.debug("debug path active")
}
```
In this example, the explicit logger mirrors the same level gate used by global shortcut calls.
### Error Case
e.g.:
- If the shared default target is empty, the returned logger is still valid and simply uses an empty target.
- Changes made later through `set_default_min_level(...)` or `set_default_target(...)` do not mutate an already-stored logger value.
### Notes
1. This helper returns a normal `Logger`, so further chaining is available.
2. It is the bridge between the simple global API and the explicit typed logger workflow.
+80
View File
@@ -0,0 +1,80 @@
---
name: field-equals
group: api
category: filtering
update-time: 20260512
description: Create a reusable record predicate that matches a field by exact key and value.
key-word:
- field
- filter
- predicate
- public
---
## Field-equals
Create a `RecordPredicate` that returns `true` when a record contains a field whose key and value both match exactly. Use it for stable attribute-based routing.
### Interface
```moonbit
pub fn field_equals(key : String, value : String) -> RecordPredicate {}
```
#### input
- `key : String` - Field key to inspect.
- `value : String` - Exact value expected for that key.
#### output
- `RecordPredicate` - Predicate that matches records containing a field with the expected key and value.
### Explanation
Detailed rules explaining key parameters and behaviors
- Matching requires both `field.key == key` and `field.value == value`.
- The predicate returns `true` on the first matching field.
- This helper is useful for routing records by environment, tenant, operation name, or fixed tags.
- It is stricter than `has_field(...)` because presence alone is not enough.
### How to Use
Here are some specific examples provided.
#### When Keep One Tenant Stream
When log routing should isolate one tenant:
```moonbit
let logger = Logger::new(console_sink())
.with_filter(field_equals("tenant", "acme"))
```
In this example, records for other tenants are excluded.
#### When Combine With Exact Target Matching
When field and target must both match:
```moonbit
let predicate = all_of([
target_is("billing"),
field_equals("region", "cn"),
])
```
In this example, only billing records tagged for the `cn` region remain.
### Error Case
e.g.:
- If `key` or `value` is empty, matching still uses exact equality and may produce no results unless records contain the same empty string.
- If a record contains the key with multiple values, any one exact match is enough for the predicate to return `true`.
### Notes
1. Prefer exact field matching over message substring matching for long-term routing rules.
2. Keep field naming stable across producers if this predicate is reused in shared configs.
+77
View File
@@ -0,0 +1,77 @@
---
name: field
group: api
category: record
update-time: 20260512
description: Create a single structured field value from a key and value pair.
key-word:
- field
- record
- helper
- public
---
## Field
Create a single `Field` value from a key and value pair. This is the basic helper used throughout logger, patch, and filter APIs whenever structured metadata needs to be attached to a record.
### Interface
```moonbit
pub fn field(key : String, value : String) -> Field {}
```
#### input
- `key : String` - Field key name.
- `value : String` - Field value text.
#### output
- `Field` - Structured field value ready to be used in a record or field array.
### Explanation
Detailed rules explaining key parameters and behaviors
- The helper constructs a `Field` directly from the provided key and value.
- No deduplication, normalization, or validation is applied.
- This is the standard primitive used by `fields(...)`, `append_fields(...)`, and all log write APIs that accept structured fields.
- The created field preserves the original input strings exactly.
### How to Use
Here are some specific examples provided.
#### When Add One Inline Event Field
When a single structured field is enough:
```moonbit
logger.info("accepted", fields=[field("user", "alice")])
```
In this example, the event carries one explicit structured attribute.
#### When Build Shared Context Fields
When binding one reusable metadata field to a logger:
```moonbit
let logger = Logger::new(console_sink(), target="audit")
.bind([field("service", "billing")])
```
In this example, the field becomes part of every later emitted record.
### Error Case
e.g.:
- If `key` is empty, the resulting field still exists and keeps the empty string key.
- If `value` is empty, the field remains valid and simply stores an empty string value.
### Notes
1. Use this helper when only one field is needed and tuple syntax would be less direct.
2. Prefer stable field keys so filters and downstream tooling remain predictable.
+76
View File
@@ -0,0 +1,76 @@
---
name: fields
group: api
category: record
update-time: 20260512
description: Build structured field arrays ergonomically from key-value tuples.
key-word:
- fields
- record
- helper
- public
---
## Fields
Create an `Array[Field]` from an array of `(String, String)` tuples. This helper reduces repetitive `field(...)` calls when binding context or constructing event fields.
### Interface
```moonbit
pub fn fields(entries : Array[(String, String)]) -> Array[Field] {}
```
#### input
- `entries : Array[(String, String)]` - Tuple entries where `.0` is the field key and `.1` is the field value.
#### output
- `Array[Field]` - Structured field array ready for logger APIs.
### Explanation
Detailed rules explaining key parameters and behaviors
- Each tuple becomes one `Field` value.
- Order is preserved.
- This helper is purely ergonomic and does not add validation beyond normal string handling.
- It is commonly used with `bind(...)`, `with_context_fields(...)`, and per-event field arguments.
### How to Use
Here are some specific examples provided.
#### When Build Reusable Context Fields
When binding stable metadata to a logger:
```moonbit
let logger = Logger::new(console_sink(), target="audit")
.bind(fields([("service", "billing"), ("scope", "login")]))
```
In this example, tuple syntax is shorter and easier to scan than repeated `field(...)` calls.
#### When Build Small Per-event Field Arrays
When logging a few fields inline:
```moonbit
logger.info("accepted", fields=fields([("user", "alice"), ("status", "ok")]))
```
In this example, the helper keeps call sites compact.
### Error Case
e.g.:
- If `entries` is empty, the result is just an empty field array.
- Duplicate keys are preserved rather than collapsed.
### Notes
1. Use `field(...)` when only one field is needed.
2. Use `fields(...)` when tuple syntax improves readability.
+81
View File
@@ -0,0 +1,81 @@
---
name: file-rotation
group: api
category: sink
update-time: 20260512
description: Create a size-based file rotation policy for native file sinks.
key-word:
- file
- rotation
- policy
- public
---
## File-rotation
Create a size-based file rotation policy for `file_sink(...)`. This helper defines how large a file may grow before rotation and how many historical backups should be retained.
### Interface
```moonbit
pub fn file_rotation(max_bytes : Int, max_backups~ : Int = 1) -> FileRotation {}
```
#### input
- `max_bytes : Int` - Maximum active file size threshold before rotation.
- `max_backups : Int` - Number of retained backup files.
#### output
- `FileRotation` - Rotation policy usable by direct file sinks or config-driven sink state.
### Explanation
Detailed rules explaining key parameters and behaviors
- `max_bytes <= 0` is normalized to `1`.
- `max_backups <= 0` is normalized to `1`.
- Rotation is size-based only.
- This policy is consumed by `file_sink(...)`, file policy helpers, and config-driven file sink assembly.
### How to Use
Here are some specific examples provided.
#### When Need Bounded Local Log Files
When a file should not grow without limit:
```moonbit
let sink = file_sink(
"app.log",
rotation=Some(file_rotation(1024 * 1024, max_backups=3)),
)
```
In this example, the file rotates after the configured size threshold.
And up to three backup files are retained.
#### When Need Runtime Policy Composition
When file sink policy is assembled explicitly:
```moonbit
let policy = FileSinkPolicy::new(rotation=Some(file_rotation(4096, max_backups=2)))
```
In this example, rotation can be bundled with append and auto-flush settings.
### Error Case
e.g.:
- If `max_bytes` is non-positive, it is clamped to `1`.
- If `max_backups` is non-positive, it is clamped to `1`.
### Notes
1. This API defines policy only; it does not open files by itself.
2. Rotation currently focuses on size thresholds rather than time schedules or compression.
+74
View File
@@ -0,0 +1,74 @@
---
name: file-sink-policy-to-json
group: api
category: runtime
update-time: 20260512
description: Convert FileSinkPolicy into a JSON value for runtime diagnostics, policy snapshots, or transport.
key-word:
- file
- policy
- json
- public
---
## File-sink-policy-to-json
Convert `FileSinkPolicy` into a `JsonValue`. This helper exports append mode, auto-flush, and optional rotation as a structured runtime policy snapshot.
### Interface
```moonbit
pub fn file_sink_policy_to_json(policy : FileSinkPolicy) -> @json_parser.JsonValue {}
```
#### input
- `policy : FileSinkPolicy` - File sink runtime policy to export.
#### output
- `JsonValue` - Structured JSON representation of the file policy.
### Explanation
Detailed rules explaining key parameters and behaviors
- The output includes `append`, `auto_flush`, and `rotation`.
- `rotation` is exported as `null` when rotation is disabled.
- This helper exports runtime file policy, not current file health counters or availability.
- The JSON value is useful for policy snapshots, comparisons, and diagnostics payloads.
### How to Use
Here are some specific examples provided.
#### When Need Structured Policy Snapshots
When file sink policy should be embedded into a larger JSON payload:
```moonbit
let value = file_sink_policy_to_json(sink.policy())
```
In this example, the runtime file policy becomes a reusable structured value.
#### When Need Policy Comparison Data
When current and default policy should be exported separately:
```moonbit
let current = file_sink_policy_to_json(sink.policy())
```
In this example, callers can compare policy snapshots without formatting text first.
### Error Case
e.g.:
- If rotation is disabled, the exported `rotation` field is `null` rather than omitted.
- If callers need direct text output, `stringify_file_sink_policy(...)` is the better API.
### Notes
1. Use this helper when downstream code expects `JsonValue` rather than text.
2. It pairs naturally with `policy()` and `default_policy()` runtime accessors.
+74
View File
@@ -0,0 +1,74 @@
---
name: file-sink-state-to-json
group: api
category: runtime
update-time: 20260512
description: Convert FileSinkState into a JSON value for file sink diagnostics and state transport.
key-word:
- file
- state
- json
- public
---
## File-sink-state-to-json
Convert `FileSinkState` into a `JsonValue`. This helper exports file path, availability, policy flags, rotation config, and failure counters in a structured form.
### Interface
```moonbit
pub fn file_sink_state_to_json(state : FileSinkState) -> @json_parser.JsonValue {}
```
#### input
- `state : FileSinkState` - File sink state snapshot to export.
#### output
- `JsonValue` - Structured JSON representation of the file sink state.
### Explanation
Detailed rules explaining key parameters and behaviors
- The output includes `path`, `available`, `append`, `auto_flush`, failure counters, and `rotation`.
- `rotation` is exported as `null` when rotation is disabled.
- This helper exports state snapshots, not mutable runtime control handles.
- It is useful when file sink state should be embedded into larger diagnostics payloads.
### How to Use
Here are some specific examples provided.
#### When Need Structured File Diagnostics
When file sink status should be composed into a larger JSON object:
```moonbit
let value = file_sink_state_to_json(sink.state())
```
In this example, callers receive a structured file-state snapshot instead of plain text.
#### When Need Runtime State Snapshots For Tooling
When support tooling should ingest file sink state programmatically:
```moonbit
let snapshot = file_sink_state_to_json(state)
```
In this example, the helper exposes all major file-state fields in machine-readable form.
### Error Case
e.g.:
- If the file is unavailable, the exported snapshot still serializes normally with `available=false`.
- If callers need direct text output, `stringify_file_sink_state(...)` is the better API.
### Notes
1. Use this helper when diagnostics consumers expect `JsonValue`.
2. It pairs naturally with `FileSink::state()` and `ConfiguredLogger::file_state()`.
+93
View File
@@ -0,0 +1,93 @@
---
name: file-sink
group: api
category: sink
update-time: 20260512
description: Create a native file sink with append, auto-flush, rotation, reopen, and runtime observability helpers.
key-word:
- file
- sink
- native
- public
---
## File-sink
Create a native file sink for text-oriented or custom-formatted file logging. This API includes lifecycle controls, rotation configuration, reopen behavior, policy inspection, and failure counters.
### Interface
```moonbit
pub fn file_sink(
path : String,
append~ : Bool = true,
auto_flush~ : Bool = true,
rotation~ : FileRotation? = None,
formatter~ : RecordFormatter = fn(rec) { format_text(rec) },
) -> FileSink {}
```
#### input
- `path : String` - Destination file path.
- `append : Bool` - Whether opening/reopening should append rather than truncate.
- `auto_flush : Bool` - Whether flush is attempted after each write.
- `rotation : FileRotation?` - Optional size-based rotation policy.
- `formatter : RecordFormatter` - Formatter used to render each record before writing.
#### output
- `FileSink` - A native-only sink with write, flush, close, reopen, policy, and state helpers.
### Explanation
Detailed rules explaining key parameters and behaviors
- This sink is only available on `native/llvm`; use `native_files_supported()` for capability detection.
- `append` is persistent policy state and also affects later reopen behavior.
- `auto_flush` trades durability for more flush work per record.
- Rotation is currently size-based and rename-retention-oriented, not time-based.
### How to Use
Here are some specific examples provided.
#### When Need Persistent Local Logs
When logs should be written to a host filesystem:
```moonbit
if native_files_supported() {
let sink = file_sink("app.log")
let logger = Logger::new(sink, target="file")
logger.info("started")
ignore(sink.flush())
}
```
In this example, the sink writes normal text-formatted records to `app.log`.
And capability detection prevents non-native misuse.
#### When Need Rotation And Runtime Inspection
When you want bounded local log retention plus observability:
```moonbit
let sink = file_sink("app.log", rotation=Some(file_rotation(1024, max_backups=3)))
let state = sink.state()
```
In this example, rotation policy and sink health can both be read through runtime helpers.
### Error Case
e.g.:
- If the backend is non-native, file availability is not provided and callers should not expect writes to succeed.
- If open, write, flush, or rotation fails, the sink records failure counters instead of exposing a large exception surface.
### Notes
1. Always pair this API with `native_files_supported()` in cross-target code.
2. Prefer `state()`, `policy()`, and failure counters when integrating diagnostics.
+77
View File
@@ -0,0 +1,77 @@
---
name: global-debug
group: api
category: global
update-time: 20260512
description: Emit a debug-level record through the shared default logger shortcut.
key-word:
- global
- debug
- default
- public
---
## Global-debug
Emit a debug-level record through the shared default logger. This is the global convenience wrapper for `log(Level::Debug, ...)`.
### Interface
```moonbit
pub fn debug(message : String, fields~ : Array[Field] = []) -> Unit {}
```
#### input
- `message : String` - Debug message text.
- `fields : Array[Field]` - Optional structured fields attached to the record.
#### output
- `Unit` - No return value. The record is handled through the shared default logger.
### Explanation
Detailed rules explaining key parameters and behaviors
- This helper delegates to `default_logger().debug(...)`.
- The record uses the current shared minimum level and target configuration.
- Debug output is typically intended for development and troubleshooting.
- This helper is best suited to small apps or code paths that intentionally rely on the shared logger.
### How to Use
Here are some specific examples provided.
#### When Need Simple Global Debug Logging
When code wants quick diagnostics without wiring a logger variable:
```moonbit
set_default_min_level(Level::Debug)
debug("cache refreshed")
```
In this example, the shared global path starts accepting debug records.
#### When Attach Structured Debug Context
When a debug event should include machine-readable detail:
```moonbit
debug("session loaded", fields=[field("user_id", "42")])
```
In this example, the global shortcut still supports structured fields.
### Error Case
e.g.:
- If the shared minimum level is above `Debug`, the record is skipped.
- If different modules need distinct targets or sinks, a shared global debug path may be too coarse.
### Notes
1. Prefer explicit loggers once application logging becomes subsystem-specific.
2. Use `set_default_min_level(...)` before expecting global debug output to appear.
+76
View File
@@ -0,0 +1,76 @@
---
name: global-error
group: api
category: global
update-time: 20260512
description: Emit an error-level record through the shared default logger shortcut.
key-word:
- global
- error
- default
- public
---
## Global-error
Emit an error-level record through the shared default logger. This is the global convenience wrapper for `log(Level::Error, ...)`.
### Interface
```moonbit
pub fn error(message : String, fields~ : Array[Field] = []) -> Unit {}
```
#### input
- `message : String` - Error message text.
- `fields : Array[Field]` - Optional structured fields attached to the record.
#### output
- `Unit` - No return value. The record is handled through the shared default logger.
### Explanation
Detailed rules explaining key parameters and behaviors
- This helper delegates to `default_logger().error(...)`.
- It uses the shared console sink, default target, and current threshold configuration.
- `Error` is the highest built-in severity in the global sync helper set.
- This helper is useful when a small app wants a direct shared failure-reporting path.
### How to Use
Here are some specific examples provided.
#### When Report A Global Failure Event
When a small application should emit an explicit failure log:
```moonbit
error("worker execution failed")
```
In this example, the shared default logger emits a high-severity error record.
#### When Attach Structured Error Context
When an error event should include machine-readable detail:
```moonbit
error("dispatch failed", fields=[field("job_id", "42")])
```
In this example, the global helper still supports structured fields.
### Error Case
e.g.:
- If the shared minimum level is above `Error`, the call still returns without writing, though this configuration is unusual.
- If one module should not share the same sink or target policy, the global helper path may be too blunt.
### Notes
1. Use this helper for simple shared error reporting.
2. Explicit `Logger` values are usually better once the application needs richer routing or ownership boundaries.
+77
View File
@@ -0,0 +1,77 @@
---
name: global-info
group: api
category: global
update-time: 20260512
description: Emit an info-level record through the shared default logger shortcut.
key-word:
- global
- info
- default
- public
---
## Global-info
Emit an info-level record through the shared default logger. This is the global convenience wrapper for `log(Level::Info, ...)`.
### Interface
```moonbit
pub fn info(message : String, fields~ : Array[Field] = []) -> Unit {}
```
#### input
- `message : String` - Informational message text.
- `fields : Array[Field]` - Optional structured fields attached to the record.
#### output
- `Unit` - No return value. The record is handled through the shared default logger.
### Explanation
Detailed rules explaining key parameters and behaviors
- This helper delegates to `default_logger().info(...)`.
- It uses the shared console sink and current default target.
- `Info` is the default global threshold unless changed through `set_default_min_level(...)`.
- This is the simplest entry point for normal app-level informational events.
### How to Use
Here are some specific examples provided.
#### When Emit Simple Global Application Events
When a small app wants direct lifecycle logging:
```moonbit
set_default_target("app")
info("service started")
```
In this example, the shared default logger emits an informational record under the `app` target.
#### When Attach Structured Informational Data
When a global info event should include metadata:
```moonbit
info("request completed", fields=[field("status", "200")])
```
In this example, the global helper still supports structured fields.
### Error Case
e.g.:
- If the shared minimum level is above `Info`, the record is skipped.
- If different components need different targets, shared global info logging may become too broad.
### Notes
1. This is the most common global write helper for small applications or scripts.
2. Prefer explicit loggers when the codebase grows beyond one shared logging path.
+77
View File
@@ -0,0 +1,77 @@
---
name: global-log
group: api
category: global
update-time: 20260512
description: Emit a record through the shared default logger with an explicit level and optional fields.
key-word:
- global
- log
- default
- public
---
## Global-log
Emit a record through the shared default logger with an explicit level and message. This is the core global write API behind the global severity-specific shortcuts.
### Interface
```moonbit
pub fn log(level : Level, message : String, fields~ : Array[Field] = []) -> Unit {}
```
#### input
- `level : Level` - Severity level for the record.
- `message : String` - Log message text.
- `fields : Array[Field]` - Optional structured fields attached to the record.
#### output
- `Unit` - No return value. The record is emitted through the current shared default logger behavior.
### Explanation
Detailed rules explaining key parameters and behaviors
- The function calls `default_logger().log(level, message, fields=fields)`.
- It uses the shared console sink and the current global default threshold and target.
- Per-call target override is not exposed by this global shortcut.
- This helper is most useful when convenience matters more than explicit logger ownership.
### How to Use
Here are some specific examples provided.
#### When Need A Simple Global Logging Entry
When application code wants a direct severity-controlled write:
```moonbit
log(Level::Info, "service started")
```
In this example, the shared default logger handles the record without requiring an explicit logger variable.
#### When Attach Structured Metadata Globally
When a global event should still include fields:
```moonbit
log(Level::Warn, "retry scheduled", fields=[field("attempt", "2")])
```
In this example, the global path still supports structured logging data.
### Error Case
e.g.:
- If the level is below the current shared minimum threshold, the write is skipped.
- If a custom target override is required, the explicit `Logger::log(...)` API is a better fit.
### Notes
1. This API is convenient but intentionally less configurable than an explicit logger value.
2. Prefer explicit loggers when different subsystems need different sink or target behavior.
+77
View File
@@ -0,0 +1,77 @@
---
name: global-trace
group: api
category: global
update-time: 20260512
description: Emit a trace-level record through the shared default logger shortcut.
key-word:
- global
- trace
- default
- public
---
## Global-trace
Emit a trace-level record through the shared default logger. This is the global convenience wrapper for `log(Level::Trace, ...)`.
### Interface
```moonbit
pub fn trace(message : String, fields~ : Array[Field] = []) -> Unit {}
```
#### input
- `message : String` - Trace message text.
- `fields : Array[Field]` - Optional structured fields attached to the record.
#### output
- `Unit` - No return value. The record is handled through the shared default logger.
### Explanation
Detailed rules explaining key parameters and behaviors
- This helper delegates to `default_logger().trace(...)`.
- Trace is the lowest built-in severity and is commonly disabled unless the shared minimum level is lowered.
- The shared default target and console sink are used.
- This helper favors convenience over explicit per-component logger ownership.
### How to Use
Here are some specific examples provided.
#### When Need Quick Global Trace Output
When a script or small app wants temporary low-level diagnostics:
```moonbit
set_default_min_level(Level::Trace)
trace("entered sync loop")
```
In this example, the shared global path begins accepting trace records.
#### When Attach Structured Trace Context
When a global trace event should carry fields:
```moonbit
trace("cache probe", fields=[field("key", "user:42")])
```
In this example, the global helper still supports structured metadata.
### Error Case
e.g.:
- If the shared minimum level is above `Trace`, the record is skipped.
- If you need per-call target control, use an explicit `Logger` instead of this helper.
### Notes
1. Global trace logging is convenient for scripts but easy to overuse in larger systems.
2. This helper always goes through the shared default logger path.
+76
View File
@@ -0,0 +1,76 @@
---
name: global-warn
group: api
category: global
update-time: 20260512
description: Emit a warn-level record through the shared default logger shortcut.
key-word:
- global
- warn
- default
- public
---
## Global-warn
Emit a warn-level record through the shared default logger. This is the global convenience wrapper for `log(Level::Warn, ...)`.
### Interface
```moonbit
pub fn warn(message : String, fields~ : Array[Field] = []) -> Unit {}
```
#### input
- `message : String` - Warning message text.
- `fields : Array[Field]` - Optional structured fields attached to the record.
#### output
- `Unit` - No return value. The record is handled through the shared default logger.
### Explanation
Detailed rules explaining key parameters and behaviors
- This helper delegates to `default_logger().warn(...)`.
- The shared current threshold and target determine whether and how the record is emitted.
- Warning logs are suited to degraded or suspicious states that do not necessarily stop execution.
- This helper offers convenience for a single shared logging path.
### How to Use
Here are some specific examples provided.
#### When Need A Quick Global Warning
When a recoverable issue should be surfaced without creating a logger variable:
```moonbit
warn("cache miss ratio increased")
```
In this example, the shared default logger emits a warning-severity record.
#### When Attach Structured Warning Context
When the warning should include machine-readable detail:
```moonbit
warn("retry scheduled", fields=[field("attempt", "3")])
```
In this example, the global helper still supports structured metadata.
### Error Case
e.g.:
- If the shared minimum level is above `Warn`, the record is skipped.
- If subsystem-specific routing is needed, a shared global warning path may be too limited.
### Notes
1. Global warnings are convenient for simple apps and scripts.
2. Warning-level global events are often the first candidate for separate monitoring or routing later.
+79
View File
@@ -0,0 +1,79 @@
---
name: has-field
group: api
category: filtering
update-time: 20260512
description: Create a reusable record predicate that checks whether a field key exists.
key-word:
- field
- filter
- predicate
- public
---
## Has-field
Create a `RecordPredicate` that returns `true` when a record contains at least one field with the given key. Use it when presence alone matters more than a specific field value.
### Interface
```moonbit
pub fn has_field(key : String) -> RecordPredicate {}
```
#### input
- `key : String` - Field key that should exist in the record.
#### output
- `RecordPredicate` - Predicate that matches records containing a field whose key equals `key`.
### Explanation
Detailed rules explaining key parameters and behaviors
- The predicate scans `rec.fields` in order and stops on the first matching key.
- Only the key is checked; the field value is ignored.
- This helper works well for optional metadata such as `request_id`, `tenant`, or `trace_id`.
- It can be combined with `field_equals(...)` when some records need stricter field matching.
### How to Use
Here are some specific examples provided.
#### When Keep Records Carrying Correlation Data
When only records with tracing context should pass:
```moonbit
let logger = Logger::new(console_sink())
.with_filter(has_field("trace_id"))
```
In this example, records without `trace_id` are filtered out.
#### When Combine With Severity Rules
When contextual records should also meet a level threshold:
```moonbit
let predicate = all_of([
has_field("request_id"),
level_at_least(Level::Warn),
])
```
In this example, only warning-or-higher records with request context remain.
### Error Case
e.g.:
- If `key` is empty, the predicate only matches fields whose key is also empty.
- If the same key appears multiple times, the predicate still returns `true` after the first match.
### Notes
1. Use this helper when field presence is meaningful even if the actual value changes every time.
2. Field ordering does not change the result, only the early return cost.
+76
View File
@@ -0,0 +1,76 @@
---
name: identity-patch
group: api
category: patching
update-time: 20260512
description: Create a reusable record patch that returns records unchanged.
key-word:
- patch
- transform
- record
- public
---
## Identity-patch
Create a `RecordPatch` that returns the input record unchanged. This helper is useful as a neutral default, a placeholder in configuration, or a composition baseline.
### Interface
```moonbit
pub fn identity_patch() -> RecordPatch {}
```
#### output
- `RecordPatch` - Patch function that returns the original record without modification.
### Explanation
Detailed rules explaining key parameters and behaviors
- The returned patch is a pure pass-through transformation.
- It does not allocate new fields or rewrite existing properties.
- This helper is useful when a patch slot must be provided but no mutation is currently needed.
- It also works as a safe baseline inside `compose_patches(...)` pipelines.
### How to Use
Here are some specific examples provided.
#### When Need A Neutral Patch
When a logger pipeline expects a patch but no rewrite is required yet:
```moonbit
let logger = Logger::new(console_sink())
.with_patch(identity_patch())
```
In this example, the logger shape stays consistent while records remain unchanged.
#### When Build Patches Conditionally
When a branch may or may not enable a real patch:
```moonbit
let patch = if enable_redaction {
redact_field("token")
} else {
identity_patch()
}
```
In this example, caller code can still treat the result as a normal `RecordPatch`.
### Error Case
e.g.:
- `identity_patch()` has no failure path; it simply returns the original record.
- If a caller expects visible transformation, using this patch will intentionally produce none.
### Notes
1. Use this helper when you want a no-op patch with explicit intent instead of a custom inline closure.
2. It is especially useful in conditional or generated patch pipelines.
+207
View File
@@ -0,0 +1,207 @@
---
name: api-index
group: api
category: index
update-time: 20260512
description: API navigation index for BitLogger and bitlogger_async.
key-word:
- api
- index
- logger
- async
---
## Api-index
BitLogger API navigation.
## Core logger
- [logger-new.md](./logger-new.md)
- [logger-with-target.md](./logger-with-target.md)
- [logger-child.md](./logger-child.md)
- [logger-with-min-level.md](./logger-with-min-level.md)
- [logger-with-timestamp.md](./logger-with-timestamp.md)
- [logger-with-context-fields.md](./logger-with-context-fields.md)
- [logger-bind.md](./logger-bind.md)
- [logger-with-filter.md](./logger-with-filter.md)
- [logger-with-patch.md](./logger-with-patch.md)
- [logger-with-queue.md](./logger-with-queue.md)
## Logger write APIs
- [logger-is-enabled.md](./logger-is-enabled.md)
- [logger-log.md](./logger-log.md)
- [logger-trace.md](./logger-trace.md)
- [logger-debug.md](./logger-debug.md)
- [logger-info.md](./logger-info.md)
- [logger-warn.md](./logger-warn.md)
- [logger-error.md](./logger-error.md)
## Global logger helpers
- [set-default-min-level.md](./set-default-min-level.md)
- [set-default-target.md](./set-default-target.md)
- [default-logger.md](./default-logger.md)
- [global-log.md](./global-log.md)
- [global-trace.md](./global-trace.md)
- [global-debug.md](./global-debug.md)
- [global-info.md](./global-info.md)
- [global-warn.md](./global-warn.md)
- [global-error.md](./global-error.md)
## Formatter and fields
- [field.md](./field.md)
- [text-formatter.md](./text-formatter.md)
- [text-formatter-config.md](./text-formatter-config.md)
- [text-formatter-config-to-json.md](./text-formatter-config-to-json.md)
- [stringify-text-formatter-config.md](./stringify-text-formatter-config.md)
- [fields.md](./fields.md)
## Record and level
- [record-new.md](./record-new.md)
- [level-priority.md](./level-priority.md)
- [level-label.md](./level-label.md)
- [level-enabled.md](./level-enabled.md)
## Sink and file
- [file-sink.md](./file-sink.md)
- [file-rotation.md](./file-rotation.md)
- [file-sink-policy-to-json.md](./file-sink-policy-to-json.md)
- [stringify-file-sink-policy.md](./stringify-file-sink-policy.md)
- [file-sink-state-to-json.md](./file-sink-state-to-json.md)
- [stringify-file-sink-state.md](./stringify-file-sink-state.md)
- [runtime-file-state-to-json.md](./runtime-file-state-to-json.md)
- [stringify-runtime-file-state.md](./stringify-runtime-file-state.md)
- [sink-config.md](./sink-config.md)
- [sink-config-to-json.md](./sink-config-to-json.md)
- [stringify-sink-config.md](./stringify-sink-config.md)
## Predicates and helpers
- [level-at-least.md](./level-at-least.md)
- [target-is.md](./target-is.md)
- [target-has-prefix.md](./target-has-prefix.md)
- [message-contains.md](./message-contains.md)
- [has-field.md](./has-field.md)
- [field-equals.md](./field-equals.md)
- [not.md](./not.md)
- [all-of.md](./all-of.md)
- [any-of.md](./any-of.md)
- [identity-patch.md](./identity-patch.md)
- [set-target.md](./set-target.md)
- [prefix-message.md](./prefix-message.md)
- [append-fields.md](./append-fields.md)
- [redact-field.md](./redact-field.md)
- [redact-fields.md](./redact-fields.md)
- [compose-patches.md](./compose-patches.md)
## Config build flow
- [queue-config.md](./queue-config.md)
- [queue-config-to-json.md](./queue-config-to-json.md)
- [stringify-queue-config.md](./stringify-queue-config.md)
- [logger-config.md](./logger-config.md)
- [logger-config-to-json.md](./logger-config-to-json.md)
- [stringify-logger-config.md](./stringify-logger-config.md)
- [parse-logger-config-text.md](./parse-logger-config-text.md)
- [build-logger.md](./build-logger.md)
- [parse-and-build-logger.md](./parse-and-build-logger.md)
## Async logger
- [async-logger.md](./async-logger.md)
- [async-logger-run.md](./async-logger-run.md)
- [async-logger-log.md](./async-logger-log.md)
- [async-logger-trace.md](./async-logger-trace.md)
- [async-logger-debug.md](./async-logger-debug.md)
- [async-logger-info.md](./async-logger-info.md)
- [async-logger-warn.md](./async-logger-warn.md)
- [async-logger-error.md](./async-logger-error.md)
## Async composition
- [async-logger-with-target.md](./async-logger-with-target.md)
- [async-logger-child.md](./async-logger-child.md)
- [async-logger-with-min-level.md](./async-logger-with-min-level.md)
- [async-logger-with-timestamp.md](./async-logger-with-timestamp.md)
- [async-logger-with-context-fields.md](./async-logger-with-context-fields.md)
- [async-logger-with-filter.md](./async-logger-with-filter.md)
- [async-logger-with-patch.md](./async-logger-with-patch.md)
## Async lifecycle and state
- [async-logger-pending-count.md](./async-logger-pending-count.md)
- [async-logger-dropped-count.md](./async-logger-dropped-count.md)
- [async-logger-is-closed.md](./async-logger-is-closed.md)
- [async-logger-is-running.md](./async-logger-is-running.md)
- [async-logger-has-failed.md](./async-logger-has-failed.md)
- [async-logger-last-error.md](./async-logger-last-error.md)
- [async-logger-flush-policy.md](./async-logger-flush-policy.md)
- [async-logger-state.md](./async-logger-state.md)
- [async-logger-state-to-json.md](./async-logger-state-to-json.md)
- [stringify-async-logger-state.md](./stringify-async-logger-state.md)
- [async-logger-close.md](./async-logger-close.md)
- [async-logger-wait-idle.md](./async-logger-wait-idle.md)
- [async-logger-shutdown.md](./async-logger-shutdown.md)
## Async runtime and config
- [async-runtime-mode.md](./async-runtime-mode.md)
- [async-runtime-mode-label.md](./async-runtime-mode-label.md)
- [async-runtime-supports-background-worker.md](./async-runtime-supports-background-worker.md)
- [async-runtime-state.md](./async-runtime-state.md)
- [async-runtime-state-to-json.md](./async-runtime-state-to-json.md)
- [stringify-async-runtime-state.md](./stringify-async-runtime-state.md)
- [async-logger-config.md](./async-logger-config.md)
- [async-logger-config-to-json.md](./async-logger-config-to-json.md)
- [stringify-async-logger-config.md](./stringify-async-logger-config.md)
- [parse-async-logger-build-config-text.md](./parse-async-logger-build-config-text.md)
- [build-async-logger.md](./build-async-logger.md)
- [async-logger-build-config-to-json.md](./async-logger-build-config-to-json.md)
- [stringify-async-logger-build-config.md](./stringify-async-logger-build-config.md)
## Configured logger runtime
- [configured-logger-flush.md](./configured-logger-flush.md)
- [configured-logger-drain.md](./configured-logger-drain.md)
- [configured-logger-close.md](./configured-logger-close.md)
- [configured-logger-pending-count.md](./configured-logger-pending-count.md)
- [configured-logger-dropped-count.md](./configured-logger-dropped-count.md)
## Configured logger file runtime
- [configured-logger-file-available.md](./configured-logger-file-available.md)
- [configured-logger-file-path.md](./configured-logger-file-path.md)
- [configured-logger-file-state.md](./configured-logger-file-state.md)
- [configured-logger-file-runtime-state.md](./configured-logger-file-runtime-state.md)
- [configured-logger-file-policy.md](./configured-logger-file-policy.md)
- [configured-logger-file-default-policy.md](./configured-logger-file-default-policy.md)
- [configured-logger-file-policy-matches-default.md](./configured-logger-file-policy-matches-default.md)
- [configured-logger-file-rotation-config.md](./configured-logger-file-rotation-config.md)
- [configured-logger-file-rotation-enabled.md](./configured-logger-file-rotation-enabled.md)
- [configured-logger-file-append-mode.md](./configured-logger-file-append-mode.md)
- [configured-logger-file-auto-flush.md](./configured-logger-file-auto-flush.md)
- [configured-logger-file-open-failures.md](./configured-logger-file-open-failures.md)
- [configured-logger-file-write-failures.md](./configured-logger-file-write-failures.md)
- [configured-logger-file-flush-failures.md](./configured-logger-file-flush-failures.md)
- [configured-logger-file-rotation-failures.md](./configured-logger-file-rotation-failures.md)
## Configured logger file control
- [configured-logger-file-flush.md](./configured-logger-file-flush.md)
- [configured-logger-file-close.md](./configured-logger-file-close.md)
- [configured-logger-file-reopen.md](./configured-logger-file-reopen.md)
- [configured-logger-file-reopen-append.md](./configured-logger-file-reopen-append.md)
- [configured-logger-file-reopen-truncate.md](./configured-logger-file-reopen-truncate.md)
- [configured-logger-file-reopen-with-current-policy.md](./configured-logger-file-reopen-with-current-policy.md)
- [configured-logger-file-set-policy.md](./configured-logger-file-set-policy.md)
- [configured-logger-file-reset-policy.md](./configured-logger-file-reset-policy.md)
- [configured-logger-file-set-rotation.md](./configured-logger-file-set-rotation.md)
- [configured-logger-file-clear-rotation.md](./configured-logger-file-clear-rotation.md)
- [configured-logger-file-set-append-mode.md](./configured-logger-file-set-append-mode.md)
- [configured-logger-file-set-auto-flush.md](./configured-logger-file-set-auto-flush.md)
- [configured-logger-file-reset-failure-counters.md](./configured-logger-file-reset-failure-counters.md)
+79
View File
@@ -0,0 +1,79 @@
---
name: level-at-least
group: api
category: filtering
update-time: 20260512
description: Create a reusable record predicate that keeps records at or above a minimum level.
key-word:
- level
- filter
- predicate
- public
---
## Level-at-least
Create a `RecordPredicate` that returns `true` when a record level is greater than or equal to a minimum threshold. This is the main helper for severity-based filtering.
### Interface
```moonbit
pub fn level_at_least(min_level : Level) -> RecordPredicate {}
```
#### input
- `min_level : Level` - The lowest level that should remain enabled.
#### output
- `RecordPredicate` - Predicate that keeps records whose `priority()` is at least the given minimum.
### Explanation
Detailed rules explaining key parameters and behaviors
- Matching is based on `Level::priority()`, not string comparison.
- Records at the exact same level as `min_level` are included.
- This helper is useful when a sink or child logger needs a stricter threshold than the parent logger.
- It composes cleanly with `all_of(...)` and `any_of(...)`.
### How to Use
Here are some specific examples provided.
#### When Keep Warnings And Errors
When a logger should keep only important records:
```moonbit
let logger = Logger::new(console_sink())
.with_filter(level_at_least(Level::Warn))
```
In this example, `Warn` and `Error` records continue through the filter.
#### When Combine With Target Routing
When both severity and namespace matter:
```moonbit
let predicate = all_of([
target_has_prefix("service.api"),
level_at_least(Level::Info),
])
```
In this example, the predicate can be reused by multiple loggers or sinks.
### Error Case
e.g.:
- If `min_level` is `Level::Trace`, the predicate effectively allows all normal log records.
- If `min_level` is higher than the record level, the predicate returns `false` without modifying the record.
### Notes
1. Use this helper when you want filtering logic to remain explicit instead of embedding level checks inline.
2. This predicate is separate from a logger's own `min_level`, so both can be combined.

Some files were not shown because too many files have changed in this diff Show More