MoonBit 运行时计时与指标观测 SDK,提供 Stopwatch、链路计时、指标聚合、基准检测基础设施
与已有 moonbench 差异化说明: moonbench 面向 moon bench,专注源码内单元式基准测试、CI 性能比对; moonbit-observe 面向程序运行时动态计时,核心能力为 Stopwatch、分段Lap打点、异步任务计时,适用于业务代码埋点、多流程分段耗时观测,二者使用场景、核心目标完全不同。
[deps]
"668xin/moonbit-observe" = "0.1.0"moon add 668xin/moonbit-observeimport "668xin/moonbit-observe/src/lib" as libfn main {
// 创建秒表
let sw = @lib.Stopwatch::new()
// 启动
let sw1 = sw.start()
// 读取耗时
println("纳秒: {sw1.elapsed_nanos()}")
println("毫秒: {sw1.elapsed_millis()}")
println("格式化: {sw1.elapsed_fmt()}")
// 暂停
let sw2 = sw1.stop()
// 恢复
let sw3 = sw2.resume()
// 重置
let sw4 = sw3.reset()
}┌─ Stopwatch ──────────────────────────────┐
│ Stopwatch::new() 创建未启动秒表 │
│ .start() 启动 │
│ .stop() 暂停 │
│ .resume() 恢复 │
│ .reset() 重置 │
│ .elapsed_nanos() 纳秒 │
│ .elapsed_micros() 微秒 │
│ .elapsed_millis() 毫秒 │
│ .elapsed_secs() 秒(浮点数) │
│ .elapsed_fmt() 可读字符串 │
│ .is_running() 是否运行中 │
│ .lap(label) 记录分段 │
│ .list_laps() 获取所有分段 │
│ .clear_laps() 清空分段 │
│ .lap_count() 分段数量 │
└──────────────────────────────────────────┘pub struct LapRecord {
label : String // 分段标签
lap_nanos : Int64 // 本段耗时(纳秒)
total_nanos : Int64 // 累计耗时(纳秒)
}// 创建配置:预热5次,正式运行10次
let config = @lib.BenchmarkConfig::new(5, 10)
let runner = @lib.BenchmarkRunner::new(config)
let result = runner.run(fn() { /* 被测函数 */ })
// 打印结果
@lib.print_table(result)
// JSON 导出
let json = @lib.result_to_json(result)// 纳秒格式化:自动单位切换
@lib.format_nanos(1500L) // → "1 μs"
@lib.format_nanos(1_500_000L) // → "1.5 ms"
@lib.format_nanos(1_500_000_000L) // → "1.5 s"
// 时间格式化:HH:MM:SS.mmm
@lib.format_time(3661.123) // → "01:01:01.123"// 默认系统时钟
let sw = @lib.Stopwatch::new()
// 自定义时钟函数(如单调时钟、Mock 时钟)
let sw = @lib.Stopwatch::new_with_clock(fn() { 1_700_000_000_000L })
// ClockProvider — 统一时钟注入
let provider = @lib.ClockProvider::system()
let sw = @lib.Stopwatch::new_with_provider(provider)
// ClockBackwardDetector — 检测系统时钟回退
let detector = @lib.ClockBackwardDetector::new()
let (detector, went_back) = detector.check(1_700_000_000_000L)
detector.backward_count() // → 回退次数let clock = @lib.MockClock::new(0L).advance_millis(100L)
clock.now() // → 100_000_000// Tag — key-value 标签体系
let tags = @lib.Tags::new()
.add_pair("service", "api")
.add_pair("version", "v1")
tags.get("service") // → Some("api")
// TaggedStopwatch — 携带标签的计时器
let tw = @lib.TaggedStopwatch::new(tags).start()
let tw = tw.stop()
tw.tags().count() // → 2
// SharedStopwatch — 共享计时器(多协程安全,带唯一 ID)
let shared = @lib.SharedStopwatch::new().start()
let shared = shared.stop()
shared.id() // → 唯一实例 IDlet timer = @lib.AsyncTimer::new()
let timer = timer.start()
// ... async task ...
let (timer, elapsed_ns) = timer.stop()// StatisticalSummary — 累加式计算
let summary = @lib.StatisticalSummary::new()
.add(100L).add(200L).add(300L)
// 均值 / 方差 / 标准差
summary.mean() // → Some(200)
summary.variance() // → Some(10000)
summary.stddev() // → Some(100)
// 滑动窗口 — 固定容量环形缓冲
let window = @lib.SlidingWindow::new(5)
.add(50L).add(10L).add(30L).add(20L).add(40L)
window.median() // → Some(30)
// 对数直方图 — P50/P90/P99 分位数
let hist = @lib.LogHistogram::new()
.record(100L).record(200L).record(300L)
hist.percentile(50) // → P50// 记录基线
let summary = @lib.StatisticalSummary::new().add(100L).add(200L)
let store = @lib.BaselineStore::new().add("compute_task", summary)
// 检测退化(阈值 110%)
let detector = @lib.RegressionDetector::new(store, 110)
let current = @lib.StatisticalSummary::new().add(180L)
match detector.detect("compute_task", current) {
Some(r) => if r.is_regression() { println("性能退化!") }
None => println("无基线数据")
}let parent = @lib.Span::new("request_handler").start()
let child = @lib.Span::new("db_query").start()
let child = child.stop()
let parent = parent.add_child(child).stop()
parent.total_elapsed_nanos() // 含子树累计let pt = @lib.PhaseTimer::new()
.begin_phase("receive")
.begin_phase("process") // 自动结束 receive
.begin_phase("respond") // 自动结束 process
.end_phase()
pt.phases().length() // → 3
pt.total_elapsed_nanos()let reporter = @lib.ConsoleReporter::new()
reporter.report_stopwatch("request", 1500000L, [])
// 输出: === Stopwatch Report ===
// Name: request
// Elapsed: 1.5 ms
// 可选单位 / 是否显示分段 / 是否显示标题
let reporter = @lib.ConsoleReporter::with_options(
@lib.TimeUnit::milliseconds(), false, true,
)let reporter = @lib.JsonReporter::new()
reporter.report_stopwatch("api", 1500L, [])
reporter.report_benchmark(result)
println(reporter.output())
// 输出: [{"type":"stopwatch","name":"api",...},...]
reporter.reset() // 清空累积let snap = @lib.Snapshot::new(1234567890L)
.add_timing("request", 1500L, [])
.add_benchmark(result)
let json = snap.to_json() // → JSON 字符串
let restored = @lib.Snapshot::from_json(json) // → 反序列化let composite = @lib.CompositeReporter::new()
let console = @lib.ConsoleReporter::new()
let json = @lib.JsonReporter::new()
composite.add_console(console) // 添加 Console 输出
composite.add_json(json) // 同时添加 JSON 输出
// 一次调用同时输出到 Console + JSON
composite.report_stopwatch("task", 1500L, [])
println(json.output())moon run examples/basic_usage
moon run examples/lap_demo
moon run examples/bench_demo
moon run examples/async_timer_demo
moon run examples/span_demo
moon run examples/regression_demo
moon run demomoon run src/cli -- --demo# 构建
moon build
# 测试
moon test
# 命令行工具
moon run src/cli -- --demo| 指标 | 数值 |
|---|---|
| 单元测试 | 138 个(正常流程 + 边界场景全覆盖) |
| 源码规模 | ~4,000+ LOC |
| 外部依赖 | 仅 MoonBit 标准库(零第三方依赖) |
Install
Download zipMoonBit 运行时计时与指标观测 SDK,提供 Stopwatch、链路计时、指标聚合、基准检测基础设施