请设计并实现一个 Go 语言高性能异步日志库(类似 zap 但更轻量),用于公司内部多项目复用。
一、核心目标
构建一个 production-ready 的日志系统,要求:
- 高性能(目标 <500ns/op)
- 异步写入(非阻塞业务线程)
- 支持 batch flush
- 可配置 rotatelogs 文件滚动
- JSON 结构化输出
- 支持 trace_id(context 贯穿)
- 支持 metrics(write/drop/flush)
- 支持 caller 信息(file/line/func)
二、架构要求
必须采用以下架构:
Application
↓
Logger API(Info/Error/Warn)
↓
context(trace_id)
↓
bounded channel buffer(异步队列)
↓
batch worker(flush loop)
↓
rotatelogs file writer
三、关键设计约束(重要)
1. 异步模型
- 使用 buffered channel
- producer 非阻塞(满则 drop)
- metrics 统计 drop 数
2. batch flush 机制
必须支持两种触发条件:
- batch size 达到 FlushSize
- 或 FlushInterval 定时触发
3. buffer 设计
- BufferSize 控制最大排队日志数量
- 需要支持高并发 burst
推荐:
BufferSize ≈ FlushSize × 500~2000
4. 时间设计(重要优化点)
时间字段必须支持可配置:
- 默认:int64(Unix ms)
- 可选:Human readable(带毫秒)
Human 格式:
"2006-01-02 15:04:05.000"
要求:
- 内部必须始终存 int64
- 格式化必须发生在 encoder 层
- 不允许影响写入性能路径
5. caller 信息
必须提供:
- file(只保留文件名,不要全路径)
- line
- func name
6. trace_id
必须支持:
- 基于 context 传递
- log 自动携带
- 不允许每个 log 重新生成
7. metrics
必须提供:
- WriteCount
- DropCount
- FlushCount
四、性能优化要求(关键)
必须实现以下优化:
- zero reflection JSON encoding
- sync.Pool buffer reuse
- batch write file(减少 IO syscall)
- 避免 stack trace(禁止)
- 避免 interface 过度抽象
五、rotatelogs 要求
使用:
github.com/lestrrat-go/file-rotatelogs
要求:
- 按天切割
- 支持 MaxAge
- 支持 RotationTime
六、日志结构要求
logItem 必须包含:
- Time (int64)
- Level
- Message
- TraceID
- File
- Line
- Func
- Fields map
七、输出 JSON 示例
Unix模式:
{
"time": 1714200000000,
"msg": "login"
}
Human模式:
{
"time": "2026-04-27 12:30:00.123",
"msg": "login"
}
八、测试要求
必须提供:
- 单测(basic / panic / concurrent)
- benchmark(ns/op + alloc)
- 压力测试(count=5)
- metrics 输出验证
九、并发与稳定性要求
必须满足:
- 高并发写入不 panic
- buffer 满时可控 drop
- worker 不阻塞 producer
- flush loop 稳定运行
十、最终输出要求
请输出:
- 完整 Go 工程代码(可运行)
- 清晰目录结构
- 初始化示例
- 使用示例
- benchmark 测试方法
- 设计说明(为什么这么设计)
十一、额外优化目标(可选)
如果可能,请进一步优化:
- 降低 alloc(目标 <5 alloc/op)
- 提高吞吐(>1M logs/sec)
- 支持 adaptive batch(进阶)
- 支持 ring buffer(无 drop 模式)
核心原则总结:
- 性能优先(async + batch)
- 内存可控(bounded buffer)
- IO 最小化(batch write)
- 结构简单(avoid over-engineering)
- 可扩展(time / format / metrics)
claude.ai 根据此 prompt 生成
实测 Benchmark(2-vCPU 沙盒)
Benchmarkns/opB/opallocs/opBenchmarkLoggerInfo17657060BenchmarkLoggerInfoFields19349330BenchmarkLoggerParallel22128930BenchmarkLoggerDrop59300BenchmarkEncoder13500BenchmarkEncoderHuman19000
生产环境 8 核机器预期:Logger.Info ≈ 300~500 ns/op,吞吐 >1M logs/sec,encoder 纯编码 <150 ns。
核心设计决策
① 异步 channel + 非阻塞 drop
select { case ch <- item: default: drop } 让 producer 永远不阻塞。buffer 满时 drop 并计数,不引入 back-pressure 到业务线程。
② Batch = 单次 syscall
worker 将所有待写 item 合并进一个 []byte(来自 pool),一次 Write() 写入。N 条日志 → 1 次 syscall,极大减少 IO 开销。
③ 零反射 JSON 编码器
encodeItem 纯手写 JSON,只用 strconv.AppendInt + append(dst, ...),没有 encoding/json,没有 interface{},没有反射。
④ 两级 sync.Pool
logItem 对象 + encode []byte buffer 各有独立 Pool。热路径实现 0 allocs/op。
⑤ Caller PC 缓存
runtime.FuncForPC 很慢,用 sync.RWMutex map 将 PC 映射到 {file,line,func},warm-up 后降为一次 RLock + map lookup。
⑥ time 永远存 int64
logItem.TimeMs 始终是 Unix 毫秒。Human 格式化仅发生在 encodeItem 内,不碰写入路径。
⑦ trace_id 零拷贝
context.Value(ctxKey{}) + 类型断言,key 不存在时零分配。