diff --git a/README.md b/README.md
index 784c556..292af81 100644
--- a/README.md
+++ b/README.md
@@ -26,6 +26,7 @@ BitLogger 是一个使用 MoonBit 编写的结构化日志库
- 🧷 可绑定上下文: 支持 `bind(...)` 与 `fields(...)`, 便于复用上下文字段.
- 📮 显式队列: 支持 `queued_sink(...)` / `with_queue(...)`, 支持有界积压和溢出策略.
- 🧾 可配置文本格式: 支持 `text_formatter(...)`, `format_text(...)`, `text_console_sink(...)`, `formatted_callback_sink(...)` 和模板化 `template` 输出.
+- 🎨 轻量样式标签: 支持 `color_mode`, inline markup, `TextStyle`, `StyleTagRegistry`, 自定义标签与内置标签覆盖.
- 💾 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 模型保持一致.
@@ -177,6 +178,25 @@ logger.info("hello", fields=[field("mode", "pretty")])
+inline style tag 示例
+
+```moonbit
+let formatter = text_formatter(
+ show_timestamp=false,
+ color_mode=ColorMode::Always,
+).with_style_tags(
+ default_style_tag_registry()
+ .set_tag("accent", fg=Some("#4cc9f0"), bold=true)
+ .define_alias("danger", "red"),
+)
+
+let logger = Logger::new(text_console_sink(formatter), target="styled")
+
+logger.info("styled> output and alert>")
+```
+
+
+
JSON 配置加载示例
```moonbit
@@ -243,6 +263,10 @@ match logger.file_runtime_state() {
- `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`
- `TextFormatter` / `TextFormatterConfig` 提供 `color_mode = Never | Auto | Always`, 可控制 ANSI 文本着色
+- `message` 支持轻量 inline style tag: `...>`, `...>`, `<#ff0000>...>`, `...>`
+- 运行期样式标签 API: `TextStyle`, `StyleTagRegistry`, `style_tag_registry()`, `default_style_tag_registry()`, `set_tag(...)`, `define_alias(...)`
+- 样式标签优先级: formatter 局部 `style_tags` > 全局 style tag registry > 内置标签
+- 自定义 style tag 当前仅支持运行期 API, 还不支持通过 JSON config 声明
- `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 模式
diff --git a/bitlogger/README.mbt.md b/bitlogger/README.mbt.md
index fcc856c..26e364e 100644
--- a/bitlogger/README.mbt.md
+++ b/bitlogger/README.mbt.md
@@ -42,6 +42,8 @@ BitLogger 是一个使用 MoonBit 编写的结构化日志库.
- 支持 `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` 文本输出
+- lightweight style tags via `color_mode`, inline markup, `TextStyle`, `StyleTagRegistry`, custom tags, and builtin-tag overrides
+- 支持 `color_mode`, inline markup, `TextStyle`, `StyleTagRegistry`, 自定义标签与内置标签覆盖
- JSON config parsing via `parse_logger_config_text(...)` and `stringify_logger_config(...)`
- 支持 `parse_logger_config_text(...)`, `stringify_logger_config(...)` 进行最小 JSON 配置读写
- `TextFormatter` / `TextFormatterConfig` now support `color_mode = Never | Auto | Always`
@@ -189,6 +191,21 @@ test {
}
```
+```mbt check
+test {
+ let formatter = text_formatter(
+ show_timestamp=false,
+ color_mode=ColorMode::Always,
+ ).with_style_tags(
+ default_style_tag_registry()
+ .set_tag("accent", fg=Some("#4cc9f0"), bold=true)
+ .define_alias("danger", "red"),
+ )
+ let logger = Logger::new(text_console_sink(formatter), target="styled")
+ logger.info("styled> output and alert>")
+}
+```
+
```mbt check
test {
let config = parse_logger_config_text(
@@ -204,6 +221,10 @@ test {
- supported tokens / 支持的 token: `{timestamp}`, `{timestamp_ms}`, `{level}`, `{target}`, `{message}`, `{fields}`
- `color_mode` / `color_mode`: `never`, `auto`, `always`
+- inline style tags / inline 样式标签: `...>`, `...>`, `<#ff0000>...>`, `...>`
+- runtime style tags / 运行期样式标签: `TextStyle`, `StyleTagRegistry`, `style_tag_registry()`, `default_style_tag_registry()`, `set_tag(...)`, `define_alias(...)`
+- style tag priority / 标签优先级: formatter local `style_tags` > global style tag registry > builtin tags
+- custom style tags are runtime-only for now / 自定义样式标签当前仅支持运行期 API
- disabled or missing parts render as empty text / 被关闭或缺失的部分会渲染为空字符串
- `template` is intentionally a simple token replacement layer, not a full DSL / `template` 使用轻量 token 替换方式, 不是完整 DSL
diff --git a/docs/README-en.md b/docs/README-en.md
index d0371d6..9787503 100644
--- a/docs/README-en.md
+++ b/docs/README-en.md
@@ -25,6 +25,7 @@ BitLogger currently provides:
- 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
+- lightweight style tags via `color_mode`, inline markup, `TextStyle`, `StyleTagRegistry`, custom tags, and builtin-tag overrides
- 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
@@ -165,6 +166,23 @@ let logger = Logger::new(text_console_sink(formatter), target="pretty")
logger.info("hello", fields=[field("mode", "pretty")])
```
+Inline style tags:
+
+```moonbit
+let formatter = text_formatter(
+ show_timestamp=false,
+ color_mode=ColorMode::Always,
+).with_style_tags(
+ default_style_tag_registry()
+ .set_tag("accent", fg=Some("#4cc9f0"), bold=true)
+ .define_alias("danger", "red"),
+)
+
+let logger = Logger::new(text_console_sink(formatter), target="styled")
+
+logger.info("styled> output and alert>")
+```
+
JSON config loading:
```moonbit
@@ -227,6 +245,10 @@ match logger.file_runtime_state() {
- `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`.
- `TextFormatter` and `TextFormatterConfig` now include `color_mode = Never | Auto | Always` for ANSI text coloring control.
+- `message` also supports lightweight inline style tags such as `...>`, `...>`, `<#ff0000>...>`, and `...>`.
+- Runtime style-tag APIs now include `TextStyle`, `StyleTagRegistry`, `style_tag_registry()`, `default_style_tag_registry()`, `set_tag(...)`, and `define_alias(...)`.
+- Style-tag lookup priority is formatter-local `style_tags` > global style tag registry > builtin tags.
+- Custom style tags are runtime-only for now and are not yet part of the JSON config schema.
- `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.
diff --git a/examples/basic/main.mbt b/examples/basic/main.mbt
index 046dcf9..12e71c2 100644
--- a/examples/basic/main.mbt
+++ b/examples/basic/main.mbt
@@ -68,6 +68,21 @@ fn main {
)
pretty_logger.info("custom text format", fields=[@lib.field("mode", "pretty")])
+ let styled_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 styled_logger = @lib.Logger::new(
+ @lib.text_console_sink(styled_formatter),
+ min_level=@lib.Level::Info,
+ target="styled",
+ )
+ styled_logger.info("styled> output and alert>")
+
if @lib.native_files_supported() {
let file_logger = @lib.Logger::new(
@lib.file_sink(