Go Engineering - Foundation - Log - Design
功能需求
基础功能
- 支持基本的日志信息:时间戳、文件名、行号、日志级别、日志内容
- 支持不同的日志级别:Trace(可选)、Debug、Info、Warn、Error、Panic(可选)、Fatal
- 期望级别:
glog.Info("This is info message")
- 开关级别:
glog -v=4
,只有日志级别高于等于 4 的日志才会被打印
- 期望级别:
- 支持自定义配置:不同的运行环境,需要不同的日志输出配置,在不重新编译代码的情况下,改变记录日志的行为
- 支持输出到标准输出(实时读取)和本地文件(采集索引)
高级功能
- 支持多种日志格式:TEXT、JSON
- 按日志级别分类输出:至少 Error 级别的日志输出到独立的文件中
- 支持结构化日志:使用 JSON 或者其它编码方式使日志结构化
- 支持日志轮转:借助 Linux Logrotate 来完成,不在日志包中实现
- 具备 Hook 能力
- 例如:当 Error 级别的日志产生时,发送邮件或者调用告警接口进行告警
- 日志告警的最佳方案:通过旁路功能,将日志采集到第三方组件(如 ES),日志包功能应尽量内聚
1 | package main |
1 | {"level":"info","ts":1651416552.427618,"caller":"log/zap.go:14","msg":"failed to fetch URL","url":"http://marmotedu.com","attempt":3,"backoff":1} |
可选功能
非核心功能,主要为了增强日志包的易用性
- 支持颜色输出:开发测试环境开启,生产关闭(提高性能)
- 兼容标准库 log 包
- 支持输出到不同的位置:ES、Kafka 等下游组件
- 或者通过 Filebeat 或者 Fluentd 采集磁盘上的日志文件,进而投递到下游组件
总是将日志记录到本地文件,为了与日志中心解耦
设计要点
- 高性能:被频繁调用,不能成为应用的性能瓶颈
- 并发安全:并发记录日志
- 插件化:自定义输出格式、自定义存储位置、自定义错误发生时的行为
- 日志参数控制:初始化配置(Init 函数) + 运行时配置(SetOptions、SetLevel 等函数,支持动态 Debug 开关)
日志记录
日志包只是工具,日志记录才是灵魂
何处打印日志
日志主要是用来定位问题的
- 分支语句
- 写操作(必须)
- 循环语句:循环内记录要点 + 循环外打印总结
- 在错误产生的最原始位置打印日志,方便追踪到日志的根源
- 在上层追加一些必要的信息,有助于了解错误产生的影响
- 直接返回下层日志,可以减少重复的日志打印
1 | package main |
1 | E0501 23:18:51.066465 27194 log_where.go:32] read: end of input. |
调用第三方包的函数出错时,打印错误信息
1 | if err := os.Chdir("/root"); err != nil { |
打印日志级别
Level | Desc |
---|---|
Debug | 打印大量日志,拖累应用性能,上线时必须禁止 |
Info | 不是越多越好,也不是越少越好,以满足需求为主要目的,现网的日志级别一般为 Info 级别 |
Warn | 一般是业务级的警告日志,需要关注起来 |
Error | 记录每一个 Error 级别的日志 |
Panic | 很少使用,场景:需要错误堆栈 或者 defer 处理错误 |
Fatal | 很少使用,通常是系统级的错误 |
记录日志内容
- 不记录敏感信息
- commit 前,删除临时的 Debug 日志
- 小写开头,
.
结尾 - 为了提高性能,使用明确的类型
- 推荐:
log.Warnf("init datastore: %s", err.Error())
- 不推荐:
log.Warnf("init datastore: %v", err)
- 推荐:
- 包含通用字段:Trace Id(Span Id)+ 用户行为
- 日志级别要正确
EFK
Filebeat 相比于 Logstash,更轻量级,占用资源更少
常见的 Shipper:Logstash Shipper、Flume、Fluentd、Filebeat
Logstash 包括 Logstash Shipper 和 Logstash indexer
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.