📝 Polish onboarding and add feature examples

This commit is contained in:
Nanaloveyuki
2026-05-20 11:40:23 +08:00
parent 5f12991592
commit e019db11d6
16 changed files with 244 additions and 22 deletions
+25 -4
View File
@@ -35,13 +35,26 @@ BitLogger 是一个使用 MoonBit 编写的结构化日志库,目标是提供
## 🚀 快速开始 ## 🚀 快速开始
```moonbit ```moonbit
let logger = Logger::new(console_sink(), min_level=Level::Info, target="demo") let logger = build_logger(
.with_timestamp() with_queue(
.with_context_fields([field("service", "bitlogger")]) text_console(
min_level=Level::Info,
target="demo",
text_formatter=TextFormatterConfig::new(show_timestamp=false, separator=" | "),
),
max_pending=32,
overflow=QueueOverflowPolicy::DropOldest,
),
)
logger.info("starting", fields=[field("port", "8080")]) logger.info("starting", fields=[field("port", "8080")])
ignore(logger.flush())
``` ```
推荐先从 `presets + build_logger(...)` 路径开始:`console(...)` / `json_console(...)` / `text_console(...)` / `file(...)` 负责拼装 `LoggerConfig``with_queue(...)` / `with_file_rotation(...)` 负责做小范围组合,然后再交给 `build_logger(...)` 构建运行时 logger。
当你需要 `fanout``split``callback``patch` 这类自定义 sink 图组合时,再优先使用 `Logger::new(...)` 直接进行运行时拼装。
异步入口示例: 异步入口示例:
```moonbit ```moonbit
@@ -58,7 +71,13 @@ let logger = async_logger(console_sink(), target="async.demo")
- `src/`: 主日志库 package。 - `src/`: 主日志库 package。
- `src-async/`: 基于 `moonbitlang/async` 的异步日志层。 - `src-async/`: 基于 `moonbitlang/async` 的异步日志层。
- `docs/api/`: 单接口粒度 API 文档。 - `docs/api/`: 单接口粒度 API 文档。
- `examples/basic/`: 最小同步示例 - `examples/basic/`: breadth 示例;文件开头就是推荐的 presets + `build_logger(...)` 同步入口,后续继续覆盖更广能力面
- `examples/console_basic/`: console 与 json console 最小输出示例。
- `examples/text_formatter/`: text formatter / template 示例。
- `examples/style_tags/`: style tag / colored formatter 示例。
- `examples/file_rotation/`: file sink / rotation 示例。
- `examples/config_build/`: `build_logger(...)` 配置驱动示例。
- `examples/presets/`: presets + `build_logger(...)` 示例。
- `examples/async_basic/`: 异步 logger 示例。 - `examples/async_basic/`: 异步 logger 示例。
## 🔗 文档入口 ## 🔗 文档入口
@@ -67,3 +86,5 @@ let logger = async_logger(console_sink(), target="async.demo")
- [English README](./docs/README-en.md) - [English README](./docs/README-en.md)
- [src package README](./src/README.mbt.md) - [src package README](./src/README.mbt.md)
- [API 索引](./docs/api/index.md) - [API 索引](./docs/api/index.md)
- 推荐起步 API: `text_console(...)` / `file(...)` / `with_queue(...)` / `build_logger(...)`
- facade API: `build_application_logger(...)` / `build_library_logger(...)` / `build_application_async_logger(...)`
+27 -4
View File
@@ -29,13 +29,26 @@ BitLogger is designed to provide composable, configurable, and cross-target logg
## Quick Start ## Quick Start
```moonbit ```moonbit
let logger = Logger::new(console_sink(), min_level=Level::Info, target="demo") let logger = build_logger(
.with_timestamp() with_queue(
.with_context_fields([field("service", "bitlogger")]) text_console(
min_level=Level::Info,
target="demo",
text_formatter=TextFormatterConfig::new(show_timestamp=false, separator=" | "),
),
max_pending=32,
overflow=QueueOverflowPolicy::DropOldest,
),
)
logger.info("starting", fields=[field("port", "8080")]) logger.info("starting", fields=[field("port", "8080")])
ignore(logger.flush())
``` ```
Start new synchronous code with `presets + build_logger(...)`: use `console(...)`, `json_console(...)`, `text_console(...)`, or `file(...)` to assemble `LoggerConfig`, optionally extend it with `with_queue(...)` or `with_file_rotation(...)`, then call `build_logger(...)`.
Switch to `Logger::new(...)` when you need direct runtime sink composition such as `fanout`, `split`, `callback`, or custom patch/filter graphs.
Async entry example: Async entry example:
```moonbit ```moonbit
@@ -52,7 +65,13 @@ let logger = async_logger(console_sink(), target="async.demo")
- `src/`: core logging package. - `src/`: core logging package.
- `src-async/`: async logging layer built on `moonbitlang/async`. - `src-async/`: async logging layer built on `moonbitlang/async`.
- `docs/api/`: one-file-per-interface API documentation. - `docs/api/`: one-file-per-interface API documentation.
- `examples/basic/`: minimal synchronous example. - `examples/basic/`: breadth example; starts with the recommended presets-based sync path and then sweeps broader capabilities.
- `examples/console_basic/`: minimal console and JSON console output.
- `examples/text_formatter/`: text formatter and template example.
- `examples/style_tags/`: style tag and colored formatter example.
- `examples/file_rotation/`: file sink and rotation example.
- `examples/config_build/`: config-driven `build_logger(...)` example.
- `examples/presets/`: presets-based construction example.
- `examples/async_basic/`: async logger example. - `examples/async_basic/`: async logger example.
## Documentation Entry Points ## Documentation Entry Points
@@ -60,11 +79,15 @@ let logger = async_logger(console_sink(), target="async.demo")
- [Mooncake package page](https://mooncakes.io/docs/Nanaloveyuki/BitLogger) - [Mooncake package page](https://mooncakes.io/docs/Nanaloveyuki/BitLogger)
- [Chinese README](../README.md) - [Chinese README](../README.md)
- [src package README](../src/README.mbt.md) - [src package README](../src/README.mbt.md)
- Recommended sync starting APIs: `text_console(...)`, `file(...)`, `with_queue(...)`, `build_logger(...)`
- Selected API docs in `docs/api/`: - Selected API docs in `docs/api/`:
- [logger-new.md](./api/logger-new.md) - [logger-new.md](./api/logger-new.md)
- [async-logger.md](./api/async-logger.md) - [async-logger.md](./api/async-logger.md)
- [build-logger.md](./api/build-logger.md) - [build-logger.md](./api/build-logger.md)
- [build-async-logger.md](./api/build-async-logger.md) - [build-async-logger.md](./api/build-async-logger.md)
- [build-application-logger.md](./api/build-application-logger.md)
- [build-library-logger.md](./api/build-library-logger.md)
- [build-application-async-logger.md](./api/build-application-async-logger.md)
## Notes ## Notes
+17 -10
View File
@@ -1,8 +1,25 @@
fn main { fn main {
let preset_logger = @lib.build_logger(
@lib.with_queue(
@lib.text_console(
min_level=@lib.Level::Info,
target="preset",
text_formatter=@lib.TextFormatterConfig::new(show_timestamp=false, separator=" | "),
),
max_pending=2,
overflow=@lib.QueueOverflowPolicy::DropOldest,
),
)
preset_logger.info("queued one")
preset_logger.info("queued two")
preset_logger.info("queued three")
ignore(preset_logger.flush())
@lib.set_default_min_level(@lib.Level::Debug) @lib.set_default_min_level(@lib.Level::Debug)
@lib.set_default_target("bitlogger") @lib.set_default_target("bitlogger")
@lib.info("hello from BitLogger", fields=[@lib.field("mode", "demo")]) @lib.info("hello from BitLogger", fields=[@lib.field("mode", "demo")])
// Direct Logger::new(...) composition stays useful for custom sink graphs.
let logger = @lib.Logger::new(@lib.console_sink(), min_level=@lib.Level::Trace, target="custom") let logger = @lib.Logger::new(@lib.console_sink(), min_level=@lib.Level::Trace, target="custom")
.with_context_fields([@lib.field("service", "bitlogger")]) .with_context_fields([@lib.field("service", "bitlogger")])
logger.debug("custom logger ready", fields=[@lib.field("sink", "console")]) logger.debug("custom logger ready", fields=[@lib.field("sink", "console")])
@@ -136,16 +153,6 @@ fn main {
])) ]))
patched_logger.info("login", fields=[@lib.field("user", "alice"), @lib.field("token", "secret")]) patched_logger.info("login", fields=[@lib.field("user", "alice"), @lib.field("token", "secret")])
let queued_logger = @lib.Logger::new(
@lib.console_sink(),
min_level=@lib.Level::Info,
target="queue",
).with_queue(max_pending=2, overflow=@lib.QueueOverflowPolicy::DropOldest)
queued_logger.info("queued one")
queued_logger.info("queued two")
queued_logger.info("queued three")
ignore(queued_logger.sink.flush())
let config_logger = @lib.parse_and_build_logger( let config_logger = @lib.parse_and_build_logger(
"{\"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\"}}", "{\"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\"}}",
) catch { ) catch {
+17
View File
@@ -0,0 +1,17 @@
fn main {
let config = @lib.parse_logger_config_text(
"{\"min_level\":\"debug\",\"target\":\"demo.config\",\"sink\":{\"kind\":\"text_console\",\"text_formatter\":{\"show_timestamp\":false,\"separator\":\" | \",\"template\":\"[{level}] {target} {message}\"}},\"queue\":{\"max_pending\":2,\"overflow\":\"DropOldest\"}}",
) catch {
err => {
ignore(err)
println("invalid config")
return
}
}
let logger = @lib.build_logger(config)
logger.info("queued one")
logger.info("queued two")
logger.info("queued three")
ignore(logger.flush())
}
+7
View File
@@ -0,0 +1,7 @@
import {
"Nanaloveyuki/BitLogger/src" @lib,
}
options(
"is-main": true,
)
+8
View File
@@ -0,0 +1,8 @@
fn main {
let logger = @lib.Logger::new(@lib.console_sink(), min_level=@lib.Level::Info, target="demo.console")
.with_context_fields([@lib.field("service", "bitlogger")])
logger.info("hello console", fields=[@lib.field("mode", "basic")])
let structured = @lib.Logger::new(@lib.json_console_sink(), min_level=@lib.Level::Info, target="demo.json")
structured.info("hello json", fields=[@lib.field("kind", "structured")])
}
+7
View File
@@ -0,0 +1,7 @@
import {
"Nanaloveyuki/BitLogger/src" @lib,
}
options(
"is-main": true,
)
+19
View File
@@ -0,0 +1,19 @@
fn main {
if !@lib.native_files_supported() {
println("native file sink is not available on this backend")
return
}
let logger = @lib.Logger::new(
@lib.file_sink(
"bitlogger-example.log",
auto_flush=true,
rotation=Some(@lib.file_rotation(128, max_backups=2)),
),
min_level=@lib.Level::Info,
target="demo.file",
)
logger.info("file rotation ready", fields=[@lib.field("kind", "file")])
ignore(logger.sink.flush())
ignore(logger.sink.close())
}
+7
View File
@@ -0,0 +1,7 @@
import {
"Nanaloveyuki/BitLogger/src" @lib,
}
options(
"is-main": true,
)
+27
View File
@@ -0,0 +1,27 @@
fn main {
let config = @lib.with_queue(
@lib.with_file_rotation(
@lib.file(
"preset-example.log",
min_level=@lib.Level::Info,
target="demo.preset",
auto_flush=true,
),
256,
max_backups=2,
),
max_pending=4,
overflow=@lib.QueueOverflowPolicy::DropOldest,
) catch {
err => {
ignore(err)
println("invalid preset config")
return
}
}
let logger = @lib.build_logger(config)
logger.info("preset logger ready", fields=[@lib.field("kind", "preset")])
ignore(logger.flush())
ignore(logger.file_close())
}
+7
View File
@@ -0,0 +1,7 @@
import {
"Nanaloveyuki/BitLogger/src" @lib,
}
options(
"is-main": true,
)
+16
View File
@@ -0,0 +1,16 @@
fn main {
let formatter = @lib.text_formatter(
show_timestamp=false,
color_mode=@lib.ColorMode::Always,
).with_style_tags(
@lib.default_style_tag_registry()
.set_tag("accent", fg=Some("#4cc9f0"), bold=true)
.define_alias("danger", "red"),
)
let logger = @lib.Logger::new(
@lib.text_console_sink(formatter),
min_level=@lib.Level::Info,
target="demo.style",
)
logger.info("<accent>styled</> output with <danger>alert</>")
}
+7
View File
@@ -0,0 +1,7 @@
import {
"Nanaloveyuki/BitLogger/src" @lib,
}
options(
"is-main": true,
)
+14
View File
@@ -0,0 +1,14 @@
fn main {
let formatter = @lib.text_formatter(
show_timestamp=false,
separator=" | ",
field_separator=",",
template="[{level}] {target} {message} :: {fields}",
)
let logger = @lib.Logger::new(
@lib.text_console_sink(formatter),
min_level=@lib.Level::Info,
target="demo.formatter",
)
logger.info("formatted output", fields=[@lib.field("user", "alice"), @lib.field("request_id", "42")])
}
+7
View File
@@ -0,0 +1,7 @@
import {
"Nanaloveyuki/BitLogger/src" @lib,
}
options(
"is-main": true,
)
+32 -4
View File
@@ -21,13 +21,31 @@ BitLogger 是一个使用 MoonBit 编写的结构化日志库.
```moonbit ```moonbit
test { test {
let logger = Logger::new(console_sink(), min_level=Level::Debug, target="demo") let logger = build_logger(
.with_timestamp() text_console(
.with_context_fields([field("service", "bitlogger")]) min_level=Level::Debug,
target="demo",
text_formatter=TextFormatterConfig::new(show_timestamp=false, separator=" | "),
),
)
logger.info("starting", fields=[field("port", "8080")]) logger.info("starting", fields=[field("port", "8080")])
ignore(logger.flush())
} }
``` ```
Recommended sync path / 推荐同步起步路径:
- start with `console(...)`, `json_console(...)`, `text_console(...)`, or `file(...)`
- 先用这些 presets 组装 `LoggerConfig`
- then apply small config helpers such as `with_queue(...)` or `with_file_rotation(...)`
- 再按需叠加 `with_queue(...)` / `with_file_rotation(...)`
- finally call `build_logger(...)` to get the runtime logger
- 最后交给 `build_logger(...)` 构建运行时 logger
Use `Logger::new(...)` instead when you need direct sink composition such as `fanout_sink(...)`, `split_by_level(...)`, `callback_sink(...)`, or custom patch/filter graphs.
如果你需要 `fanout_sink(...)``split_by_level(...)``callback_sink(...)` 或更自由的 patch/filter 组合,再改用 `Logger::new(...)` 直接拼装运行时 sink 图。
Project command note / 项目命令说明: Project command note / 项目命令说明:
- use `moon check` / `moon test` for local project verification - use `moon check` / `moon test` for local project verification
@@ -39,13 +57,23 @@ Project command note / 项目命令说明:
- examples / 示例: - examples / 示例:
- `../examples/basic/` - `../examples/basic/`
- `../examples/console_basic/`
- `../examples/text_formatter/`
- `../examples/style_tags/`
- `../examples/file_rotation/`
- `../examples/config_build/`
- `../examples/presets/`
- `../examples/async_basic/` - `../examples/async_basic/`
- package-level API docs / 单接口 API 文档: - package-level API docs / 单接口 API 文档:
- `../docs/api/` - `../docs/api/`
- common entry points / 常用入口: - common entry points / 常用入口:
- `text_console(...)` + `build_logger(...)`
- `file(...)` + `with_file_rotation(...)` + `build_logger(...)`
- `Logger::new(...)` - `Logger::new(...)`
- `async_logger(...)`
- `build_logger(...)` - `build_logger(...)`
- `build_application_logger(...)`
- `build_library_logger(...)`
- `async_logger(...)`
- `build_async_logger(...)` - `build_async_logger(...)`
## Notes / 说明 ## Notes / 说明