Java日志实践

日志是一个业务系统的重要组成部分。因为日志通常不属于系统的核心功能,所以常常不被开发人员所重视,然而一旦需要用到日志时,大家又会生出诸多吐槽:想要的日志没有;无用的日志一大堆;有用的日志被大量无效的日志信息淹没,查找起来非常困难。

打印日志简单,打印好日志很难。写好每一条日志,与君共勉!

1 日志是什么

日志:记录离散的事件,包含程序执行到某一点或某一阶段的详细信息。

日志的作用:

  • 快速定位问题:包括线上问题的定位和线下环境的开发调试;
  • 记录用户的操作行为:主要用于安全审计,合规要求,大数据分析,场景回溯等;
  • 采集程序的运行状态:比如接口流量、耗时、成功率,JVM信息等;

2 Java日志框架

SLF4J(Simple Logging Facade for Java)是日志门面框架,仅提供日志记录的API,不实现日志记录的功能。Logback、Log4j2分别是两种日志框架实现。

代码中不可直接使用Logback或Log4j2中的API,而应依赖使用SLF4J中的API。这样能够提升可移植性,在使用不同日志框架实现的应用之间能够做到无缝的适配,同时应用在切换日志框架实现时无需代码改造。

3 日志记录什么

3.1 日志格式

日志格式分为元信息和日志内容两部分:

  • 元信息由日志框架实现打印,包括日志时间、日志级别、线程名、opentracing标识、位置信息(类名、方法名、文件名、行号)等;
  • 日志内容由业务方打印,根据业务场景打印合适的内容,团队内部需要一些约定进行统一,通过代码评审持续改进;

重要的信息统一用key=value格式输出,前后空格分离,这是很多log处理工具(splunk,logentries)的推荐。

3.2 日志级别

事有轻重缓急,日志的输出也是分级别的,不同的级别打印不同的日志。

常用的日志级别有四个,按照优先级从高到低分别是ERROR、WARN、INFO、DEBUG:

  • ERROR(错误):表明系统出现了异常,无法正常工作,比如请求或跑批运行失败等。异常错误信息(Throwable)记录在ERROR日志中,方便后续人工回溯解决。
  • WARN(警告):表明系统出现了不应该出现的问题,但不影响正常工作,比如请求参数错误等。WARN级别日志也需给予足够关注,当WARN日志超过一定阈值时,应当及时介入。
  • INFO(通知):记录系统正常工作期间关键运行信息,该级别日志主要用于生产环境的日志输出。
  • DEBUG(调试):该级别日志只在开发或测试环境开启,输出调试性质的内容,便于在开发、测试阶段出现异常或问题时,对其进行分析、定位和诊断。

3.3 日志信息

理想的日志中应该记录不多不少的信息。

  • 不多,是指不要在日志中记录无用的信息。过多的信息会干扰我们的视听。
  • 不少,是指对于日志的使用者,能够从日志中得到所有需要的信息。信息太少不足以满足我们的需求。

INFO(通知)中建议记录的日志有:

  • 用户的交互
  • 重要的启动配置
  • 持久化数据的更改,重要的状态更改
  • 主要系统模块间的请求和响应
  • 长时间运行任务的进度,需要很长时间才会满足条件的等待
  • 重要的逻辑和条件判断分支

不建议记录的日志有:

  • 方法入口:不要在函数的入口打印日志,除非它是重要的
  • 内容非常大的消息或文件:文件或一大段消息的内容:可以精简或总结其中重要的信息打印
  • “良性”的错误:不是真正错误的错误会混淆日志信息,当异常处理是成功执行流程的一部分时容易发生这种情况
  • 在循环中打印日志:这会造成日志打印过多,建议在循环外打印精简总结后的日志

记录多少的日志信息是最合理的?这个尺度很难把握,对开发人员而言这是最大的挑战。记录日志时请先思考:这些日志真的有人看吗?看到这条日志你能做什么?能不能给你带来用处?

4 日志红线

4.1 不能影响系统正常工作

一定要确保不会因为Log语句的问题而抛出异常造成程序中断。举个例子,如果request为null,就会抛空指针异常。

log.info("execute failed, id={}", request.getId());

4.2 不允许输出敏感信息

日志中不能打印用户的姓名,手机号,身份证号等敏感信息。

4.3 生产环境禁止开启DEBUG级别日志

DEBUG日志太多,不仅会影响业务系统的性能,甚至将磁盘打满,影响业务系统的正常运行。

5 反面case

  1. 使用字符串拼接:会产生很多String对象,占用空间,影响性能,而且使用字符串拼接的可读性和可维护性都比较差,建议使用占位符。
  2. 使用标准输出:不要使用System.out或System.err 输出日志,这个只会打印到控制台,不方便管理日志,且标准输出的元信息不全,很难排查问题。
  3. 使用e.printStackTrace():它会通过System.error打印到控制台,且会对System.error加锁从而影响性能。
  4. 打印错误日志后又抛出异常:这会造成重复打印日志,如果捕获异常后又抛出了自定义业务异常,此时无需打印错误日志,由最终捕获方进行异常处理。
  5. 错误日志信息不全:比如只打印异常的基本描述信息,未打印异常的堆栈信息,不利于排查问题。每一条错误日志都应该是独立的,尽可能完整、具体、直接说明何种场景下发生了什么错误,由什么原因导致,要采用什么措施或步骤。
  6. 参数校验错误打印ERROR日志:对于用户自己操作不当,如请求参数错误等,推荐打印WARN日志。
    在这里插入图片描述
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值