结构化日志库 - MoonBit CCF开源创新大赛参赛作品
| 类型 | 处理器 | 说明 |
|---|---|---|
| 输出 | ConsoleHandler | 控制台输出(支持 stdout/stderr 切换) |
| 输出 | FileHandler | 缓冲批量输出,自动 flush |
| 输出 | JsonHandler | JSON 格式输出 |
| 输出 | TextHandler | 带前缀的文本输出 |
| 输出 | RotatingFileHandler | 按大小/文件数自动轮转 |
| 存储 | MemoryHandler | 内存存储,支持检索/统计 |
| 存储 | AuditHandler | 审计日志,支持过滤/搜索/导出 |
| 存储 | RingBufferHandler | 环形缓冲区,支持 drain |
| 控制 | SamplingHandler | 采样(1/N 比例) |
| 控制 | DedupHandler | 去重(基于消息哈希) |
| 控制 | RateLimitedHandler | 速率限制(时间窗口) |
| 控制 | ThrottledHandler | 节流(最小间隔) |
| 控制 | LevelFilteredHandler | 级别过滤 |
| 条件 | ConditionHandler | 条件谓词过滤 |
| 统计 | CountingHandler | 按级别计数统计 |
| 空操作 | NullHandler | 丢弃所有日志 |
| 组合 | MultiHandler | 多处理器路由分发 |
| 函数式 | HandlerFn | 闭包包装器 |
| 异步 | AsyncLogger | 批量队列异步日志 |
| 转换 | EntryTransformer | 日志条目转换器 |
| 异步 | BatchingLogger | 超时+批量双触发 flush |
# 编译检查(零警告)
moon check --target all --deny-warn
# 运行全部 163 个测试
moon test --target all
# 格式化代码
moon fmt
# 构建 WASM-GC
moon build --target wasm-gc --release
# 构建 JS
moon build --target js --releaseimport {
"leppard/moonbit-log" @log
}[deps]
leppard/moonbit-log = { version = "1.0.0" }fn main {
@log.init_default_console()
@log.g_info("Hello, moonbit-log!")
@log.g_info("User login", [("user_id", "42"), ("ip", "10.0.0.1")])
}@log.init_default_json()
@log.g_info("Order created", [
("order_id", "ORD-001"),
("amount", "299.00"),
("currency", "CNY")
])let fmt = @log.audit_formatter("|")
let audit = @log.AuditHandler::new(@log.Level::Info, fmt, 100)
let logger = @log.Logger::new()
logger.add_handler(@log.make_handler(fn(e) { audit.log(e) }, fn() {}, fn() {}))
logger.log_with(@log.Level::Info, "数据导出", [("user", "admin"), ("records", "1000")])
println(audit.entries().length())let handler = @log.FileHandler::new(
@log.Level::Info,
@log.json_formatter(),
100
)
let logger = @log.Logger::new()
logger.add_handler(@log.make_handler(fn(e) { handler.log(e) }, fn() { handler.flush() }, fn() { handler.close() }))
logger.info("写入缓冲")let handler = @log.RotatingFileHandler::new(
@log.Level::Info,
@log.text_formatter(),
10,
5
)
let logger = @log.Logger::new()
logger.add_handler(@log.make_handler(fn(e) { handler.log(e) }, fn() { handler.flush() }, fn() { handler.close() }))
// 超过 10 行自动轮转,保留 5 个历史文件let handler = @log.ConsoleHandler::new(@log.Level::Debug, @log.compact_formatter())
let batch = @log.AsyncLogger::new(
@log.make_handler(fn(e) { handler.log(e) }, fn() { handler.flush() }, fn() { handler.close() }),
64
)
batch.log(@log.LogEntryBuilder::new(@log.Level::Info, "异步消息").build())
batch.flush()let r = @log.benchmark("计算测试", 1000, fn() {
let mut x = 0
x = x + 1
@log.ignore(x)
})
println(@log.benchmark_report(r))@log.configure(
level: @log.Level::Debug,
format: "compact",
output: "console"
)
@log.g_debug("配置已生效")| 方法 | 签名 | 说明 |
|---|---|---|
| new() | Logger | 创建 Logger |
| add_handler(HandlerFn) | Unit | 添加处理器 |
| debug/info/warn/error/fatal(msg, fields?) | Unit | 按级别记录 |
| log_with(Level, msg, fields?) | Unit | 指定级别记录 |
| set_level(Level) | Unit | 设置最低级别 |
| 方法 | 返回 | 说明 |
|---|---|---|
| new() | Stopwatch | 创建并启动计时 |
| elapsed_ms() | Int64 | 已过毫秒数 |
| elapsed_us() | Int64 | 已过微秒数 |
| elapsed_s() | Double | 已过秒数 |
| lap(msg) | Int64 | 记录分段并返回耗时(ms) |
| reset() | Unit | 重置计时 |
| laps() | Array[(String, Int64)] | 返回全部分段记录 |
| report() | String | 生成可读报告 |
| 字段 | 类型 | 说明 |
|---|---|---|
| level | Level | 日志级别 |
| message | String | 日志消息 |
| fields | Array[(String, String)] | 键值对字段 |
| timestamp | Int64 | Unix 时间戳(ms) |
| module | String | 模块名 |
| file | String | 源文件名 |
| line | Int | 行号 |
moonbit-log/
├── logger.mbt # Logger 核心
├── log_entry.mbt # LogEntry / LogEntryBuilder
├── level.mbt # Level 枚举 / enabled / from_string
├── handler.mbt # HandlerFn 函数式 Handler
├── formatter.mbt # text / compact / json / audit / custom
├── console_handler.mbt # ConsoleHandler
├── file_handler.mbt # FileHandler (缓冲批量输出)
├── json_handler.mbt # JsonHandler
├── text_handler.mbt # TextHandler (带前缀)
├── memory_handler.mbt # MemoryHandler (内存存储+检索)
├── audit_handler.mbt # AuditHandler (审计日志)
├── multi_handler.mbt # MultiHandler (多路分发)
├── advanced_handlers.mbt # RotatingFile / LevelFilter / Sampling / Dedup / RingBuffer / RateLimited
├── extra_handler_utils.mbt # Null / Condition / Throttled / Counting / kv / banner / csv
├── extra_formatters.mbt # logfmt / xml / pretty(ANSI)
├── template_formatter.mbt # pattern / stats / multi_line
├── async_logger.mbt # AsyncLogger / BatchingLogger / EntryTransformer
├── config.mbt # LogConfig + 工厂方法 + JSON 配置
├── global_logger.mbt # 全局 Logger 单例
├── stopwatch.mbt # Stopwatch / Benchmark / ThroughputMeter
├── entry_utils.mbt # 条目工具函数
├── log_test.mbt # 基础测试 (~50 用例)
├── extended_test.mbt # 扩展测试 (~50 用例)
├── edge_case_test.mbt # 边界情况测试 (~63 用例)
├── cmd/example/main.mbt # CLI 示例
├── moon.mod # 模块元数据
└── moon.pkg # 包配置| 维度 | xlog | MoonLogTrace | BitLogger | moonbit-log |
|---|---|---|---|---|
| 发布日期 | 2025 | 2025 | 2025 | 2026 |
| 构建状态 | 失败 | 成功 | 成功 | 成功 |
| 零依赖 | - | + | - | + |
| 测试数 | ? | ? | ? | 163 |
| 审计日志 | - | - | - | + |
| 文件轮转 | - | - | - | + |
| 去重/限速 | - | - | - | + |
| 性能基准 | - | - | - | + |
| Span 追踪 | - | + | - | - |
| 代码规模 | ~500 | ~3k | ~1.5k | 4.1k |
fn BatchingLogger::new(inner : HandlerFn, batch_size : Int, flush_interval_us : Int64) -> BatchingLoggerpub(all) struct BenchmarkResult {
name : String
iterations : Int
total_time_us : Double
min_time_us : Double
max_time_us : Double
}pub(all) struct CountingHandler {
inner : HandlerFn
debug_count : Int
info_count : Int
warn_count : Int
error_count : Int
fatal_count : Int
}pub(all) struct HandlerFn {
log_fn : (LogEntry) -> Unit
flush_fn : () -> Unit
close_fn : () -> Unit
}pub(all) enum Level {
Debug
Info
Warn
Error
Fatal
}fn LevelFilteredHandler::new(inner : HandlerFn, min_level : Level, max_level : Level) -> LevelFilteredHandlerpub(all) struct LogConfig {
level : Level
format_type : String
output_type : String
batch_size : Int
max_files : Int
max_lines : Int
ansi_color : Bool
audit_separator : String
}fn LogEntryBuilder::with_field(self : LogEntryBuilder, key : String, value : String) -> LogEntryBuilderfn LogEntryBuilder::with_fields(self : LogEntryBuilder, extras : Array[(String, String)]) -> LogEntryBuilderfn LogEntryBuilder::with_location(self : LogEntryBuilder, file : String, line : Int) -> LogEntryBuilderpub(all) struct RateLimitedHandler {
inner : HandlerFn
max_per_second : Int
window_count : Int
window_start : Int64
window_duration : Int64
}fn RingBufferHandler::new(level : Level, fmt : (LogEntry) -> String, capacity : Int) -> RingBufferHandlerfn RotatingFileHandler::new(level : Level, fmt : (LogEntry) -> String, base_path : String, max_lines : Int, max_files : Int) -> RotatingFileHandlerfn benchmark_compare(name_a : String, name_b : String, iterations : Int, f_a : () -> Unit, f_b : () -> Unit) -> Stringfn benchmark_warmup(name : String, iterations : Int, warmup : Int, f : () -> Unit) -> BenchmarkResultfn init_default_console() -> Unitfn init_default_json() -> Unitfn measure_time(f : () -> Unit) -> Doublefn measure_time_ms(f : () -> Unit) -> Double结构化日志库 - MoonBit CCF开源创新大赛参赛作品