最简单的日志记录 日志记录的最佳实践

简介

日志(Log)是由系统在运行过程中产生的结构化或者非结构化的文字信息。通常情况,可以将其视为应用程序对某个事件(Event)的记录。日志通常可以帮助我们发现一些微服务架构系统的非预期或突发的行为。 Logging作为 Observability(可观察性,在IT和云计算中,它是根据系统生成的数据,例如日志、指标和数据链追踪等来衡量系统当前状态的能力)的重要组成部分,在我们的系统开发、维护中起到无法替代的作用。

最简单的日志记录 日志记录的最佳实践(1)

Pillars of Observability

日志的重要性

要理解为什么日志在产品或者系统中扮演着重要的角色,我们必须了解它的价值。至少到现在,日志被应用最广泛的是报警、故障排除和业务数据可视化

报警

日志可以作为我们业务系统监控的重要数据来源;成熟的产品系统都有报警系统,如果系统中出现超过某个已定义的某个指标的问题,日志系统会自动将报警信息发送到通知平台,On-call 的人就可以根据报警信息定位解决问题了。

故障排除

这种情况非常普遍;想象一下你最近负责开发维护的系统被他人发现有问题,在你梳理完思路之后第一件事是干什么?肯定是查看系统信息验证自己的假设是否成立,这里打印在服务器上的日志就是最好的辅助信息。而作为程序员的我们,日志是我们最熟悉不过的解决问题的利器。

业务数据可视化

很多公司可以利用存储在自己数据库里的生产环境的日志,结合相应的工具可以对业务进行业务数据可视化。这里最典型的代表是 Grafana 和 SumoLogic。

怎么做

模板化

为了更好支持上面的各种情况,我们需要对我们的日志格式进行梳理,按照一定的规范来写日志,而不是随便写一句废话。

最简单的日志记录 日志记录的最佳实践(2)

Log Format

  • 基础版本
    • 对于日志,时间,日志级别,和日志信息最为重要,所以一个合格的日志应该至少包含这些信息。
  • 高级版本
    • 在基础版的基础上,加入线程名,主机名,方法名,类名,方法对应的行数;
    • 线程名:多数应用的用户都不是单一的,对于单实例的服务对同一个接口很多用户访问应用会将在不同的线程中执行,这时如果要区分对应用户的业务流程,那么通过线程名是最好的。
    • 主机名:现在的应用大多部署在 Cloud 中,都是多实例的,所以在单节点的基础上,日志在多实例上就需要实例级别的区分,而主机名是最好的区分方式。
    • 方法名:打印了日志的方法名,方便区分相同日志的出处。
    • 类名:打印了日志的类名,方便快速定位业务流程。
    • 行数:打印了日志的行数,方便快速定位日志的具体位置。

格式化

为了提高日志的可读性,我们可以对日志进行修饰。

  • 对日志级别、主机名和线程名前后加中括号
  • 对方法名所在的类名和行号加括号,并在类名与行号中间用冒号隔开;
  • 在行号和日志信息中间加入一个横线来分隔;
  • 对于日志信息也可以进行特定的格式化对于常规的请求(Request)、响应(Response)或者其他业务日志,可以在自定义信息和参数之间用下划线分隔;多个参数之间用逗号分隔,当然参数也是可选的;对于错误信息格式化,也可以按照 Key:Value 的形式进行组织。

链式追踪

记录下了日志,如果只是一行行简单的文字说明,那是没有太大意义的。在复杂系统或业务操作频繁的系统中,会产生非常多的日志,在这种情况下,我们就得花时间去过滤出相关的日志。解决上面问题的最好办法是日志的链式追踪;简单说就是,在每条日志中加入业务系统中的一个或者多个唯一的 ID,这样在定位业务问题的时候可以通过这些唯一的 ID 和 其他条件(e.g. 时间)快速过滤出相关的日志。

按需记录日志

日志级别

最简单的日志记录 日志记录的最佳实践(3)

Log Level

日志的输出都是分级别的,不同的场景需要打印不同级别的日志;以下是几个比较重要的日志级别。

  • Debug: 记录技术细节,和一些帮助理解系统运行的日志;
  • Info: 记录业务信息的日志;
  • Warn: 非紧急且可控的可接受的错误信息;
  • Error: 非期望的错误或者系统表现,通常是由系统bug或者环境问题导致。

同时不是所有的日志都需要记录,我们要做到按需记录。下表是在不同的环境选择不同日志级别的推荐。

Environment

Log Leave

Dev

Debug

Test

Debug

UAT

Info

Prod

Info

日志位置

有了日志级别,日志打印的位置也需要明确。一般情况下:

  • 其他系统调用自有系统时需要在收到请求和完成请求时各打印一次日志;
  • 自有系统调用第三方系统的接口前和收到返回信息后各打印一次日志;
  • 在系统中任何有异常的地方需要打印日志;

还有一种特殊情况是,像消息传递之类的系统,为了节省日志存储和减少查看干扰,大多时候我们不需要在收到消息后直接打印该消息,一般建议在收到消息后,如果系统处理有异常,在异常中将原始消息打印。

工具推荐

不同的编程语言有不同的日志工具;比较著名的是 Apache 的 log4j, Log4j是高度可配置的,并可通过在运行时的外部文件配置。它根据记录的优先级别,并提供机制以指示记录信息到许多的目的地,诸如:数据库,文件,控制台,UNIX系统日志等;而且 log4j 已经被移植到了其他编程语言中了,如 Python 中的 logging, NodeJS 中的log4js, Rust 中的log4rs。

注意点
  • 避免打印或记录任何敏感信息,包括但不限于各种PII,PCI信息,一定要记得遵守当地的各种法律法规,如中国的《个人信息保护法》(PILI),欧洲的一般数据保护条例GDPR等
  • 按需选择合适的日志级别和日志位置
  • ……
总结

好的日志不仅可以为程序开发提供便利,为故障排除提供最重要的辅助信息,更可以为业务或基础设施提供优化建议或数据统计。

参考材料
  • THE TOP 25 GRAFANA DASHBOARD EXAMPLES
  • Grafana lab
  • SumoLogic
  • Log4j

文/Thoughtworks 谷中仁

更多精彩洞见,请关注公众号Thoughtworks洞见

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页