应用日志规范

为什么会有这篇文章?

日志无论在什么时候,都是一个重要的工具。而一个好的日志规范,可以避免/解决很多问题:

  • 低成本。一次配置,一次学习即可
  • 适用性强。解决对接各个开源组件,云厂商
  • 好用/便捷。

日志文件存放在 /data/logs/,如果 linux 系统如果不存在这个路径,创建出来这个路径。

路径下最多会有 2 个日志文件。

  • App1-20240115.log 此文件为当天日志写入的文件。app 名称不允许重复,可以使用 git 仓库名 group1-app1 来确保唯一。
  • App1-20240114.log 此文件为前 1 天的备份文件,在轮转日志的时候,保证日志完整采集

例如 golang 的 lumberjack,当前写入的文件名为 App1.log,没有日期后缀也是可以正常处理的。参考下面的日志处理部分

字段含义:

  • time 记录时间: 2024-01-08T15:30:45.123+08:00 标准的 iso 8601 时间戳,方便阅读
  • level 日志等级: Information, Debug 枚举有限的值
  • source 调用源/异常点: csharpProperties.SourceContextgolangcaller 这样的值
  • msg 具体信息: xxx登录成功了

控制台输出格式

  • logfmt 格式。方便明白每个字段的含义
  • 因兼容性问题,关闭色彩

shell

time=2024-01-08T15:30:45.123+08:00 level=info source=main.go:112 msg="xxx登录成功了" xx=oo

文件输出格式

  • json 格式。方便解析
  • 单行方便分割

json

{"time":"2024-01-08T15:30:45.123+08:00","level":"info","source":"main.go:112","message":"xxx登录成功了","xx":"oo"}
配置项
日志目录/data/logs/
日志文件名服务名.log
日志记录等级info
轮转规则1
日志格式 - 控制台 stdoutlogfmt
日志格式 - 文件 filejson
字段time/level/source/msg + 自定义字段

日志采集/分析程序现状:

  • 几乎都支持 /path/*.log 采集
    • 我们采集 /data/logs/*.log 日志。
  • 不是都支持轮转
    • 我们程序必须自己轮转

日志轮转通常分 2 种。

  1. copy,truncate。现拷贝一份文件,然后 truncate 清理源文件。
    • 我本来认为这一种会更好。因为文件不动,应用不收到影响。而其他的文件随时可删。可是我们在 copy 和 truncate 的短暂间隙,可能日志还没来得及采集,会丢失数据!
  2. rename,create。重命名现有的文件,然后创建一个新的文件。、
    • 这个方法没有上面的缺点。但需要应用程序主动写入新的文件。需要采集程序监听这种文件的变化,避免不释放文件描述符和采集不到的情况。
    • 现实情况是,我们的程序可以自己控制。而采集程序都支持通过 inotify 来监听这种变化,消除了第二种方式的缺点。

很多工具, 比如 grafana-Promtail 对第二种方式都有良好的支持. 因此我们设计每天写入一个新 log 文件是好的实践。