应该如何正确的打印日志?

  |   0 评论   |   0 浏览

前言

之前讲到因为日志原因,差点引起一个事故,那今天来讲讲应该怎么来打印日志?如果还没看过上一篇文章的可以回顾下上一篇的内容:记一次日志打印差点引起的事故

日志的作用

我们经常讲:研发人员有两只眼睛,一只是监控平台,另一只是日志平台。监控平台一部分能力是基于日志平台的。

日志非常重要,记录应用系统运行情况、查找异常信息并且提升定位问题的效率、提前预警防范、分析系统运行情况、用户行为数据分析、记录用户的操作行为等都需要用到日志。

注意点

1、日志并非越多越好,一些无用的日志打印,只会给系统增加负担,给排查问题增加难度。

2、日志是把双刃剑,只有合理运用才能发挥其特有的作用及价值。

调试

在开发、测试环境,有时候可以通过各种异常堆栈信息来进行调试。

定位问题

通过日志,来定位线上问题, 具体是数据问题,还是网络问题,又或者是机器问题,大部分的问题都可以通过日志来排查。

数据分析

日志里面包含很多用户的行为数据,比如浏览记录,喜欢什么,可以对日志进行分析,来丰富用户的画像。

支撑监控

日志可以作为监控平台的数据输入,通过这些数据,我们可以对业务,错误,耗时等一些异常行为进行报警。

操作行为

我们可以记录用户在我们系统里面的操作,可以方便知道用户做了什么,审计的时候可以使用。

谁来看日志?

像产品支持、运维人员,开发人员,测试人员都需要查看日志。

常见的一些日志框架

看这里:java日志体系详解

如何打印日志?

我们可以通过框架层面、打印系统日志规范、操作日志这几个方面来介绍应该如何打印日志。

框架层面

1、应用中不可直接使用日志系统(Log4j、Logback)中的 API,而应依赖使用日志框架 SLF4J 中的 API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。

2、如果同步打印影响了吞吐量,那么可以考虑使用异步,但是在一些极端情况下可能会丢失部分日志。

3、一般定义3个类型,info、warn、error

error:出现了异常,影响了程序的正常运行,需要人工干预;

warn:不应该出现,但是不影响程序运行;

info:正常的系统运行信息,一些外部接口的日志,通常用于定位逻辑BUG;

4、避免层层打印日志,比如methodA->methodB,methodB出现error了,打印了error日志,methodA也打印了error日志,等同于一个错误日志打印了2边。

如何解决:可以从架构层面做改造,提供错误日志上下文封装,只打印一份error日志。

5、不要使用 e.printStackTrace()

对系统的性能会有一定的影响

6、线上环境禁止开启debug

debug的日志会比较多,会把磁盘打满。

7、不要记录了异常,又抛出异常

这样相当于对异常信息打印了2次,因为异常统一拦截那边也会打印异常日志。

8、禁用System.out.println

9、预防空指针

在打印日志的时候,可能会使用某个对象的某个属性,如果这个时候对象为null,那么就会出现空指针。

10、定期清理服务器上的日志文件,防止磁盘被占满。这个被清理的日志需要备份到线下机器或者同步到日志系统里,类似ELK这种,方便排查历史问题。

系统日志规范

1、日志文件分类,比如错误日志,缓存访问日志,MQ消息日志,http请求日志,定时任务日志,RPC调用日志,dao层访问日志等等。这样方便查找,也不会让整个日志文件过于庞大,也方便日志上报时处理简单。文件命名可以进行约定,不做强制要求,类似common-xxx.log,举个例子:common-cache.log(缓存日志),common-rocketmq.log(MQ日志),common-error.log(错误日志)等等

2、日志使用占位符,禁止使用字符串拼接。

原因说明:logger.debug("i am debug"+id+"object:"+object);虽然没有打印日志,但是会进行拼接,导致不必要的系统消耗。还有字符串拼接本身对性能就是会有影响。

3、避免重复的打印日志,浪费磁盘空间,增加IO,如果日志很大的话,会导致系统CPU增加(看这篇文章:记一次日志打印差点引起的事故)务必在 log4j.xml 中设置 additivity=false。

4、异常信息应该包括两类信息: 案发现场信息和异常堆栈信息,如果没有捕获,那么就往上抛。

反例:logger.error("出异常了");

正例:logger.error(各类参数或者对象+ e.getMessage(), e);

关于error日志尽可能的描述完整,尽可能的描述具体,尽可能的描述直接。

5、生产环境不使用debug日志,至少要info级别。日志不是打印的越多越好,记录日志时请思考: 这些日志真的有人看吗? 看到这条日志你能做什么? 能不能给问题排查带来好处?

6、可以使用 warn 日志级别来记录用户输入参数错误的情况,避免用户投诉时,无所适从。注意日志输出的级别,error 级别只记录系统逻辑出错、异常等重要的错误信息。如非必要,请不要在此场景打出 error 级别。

7、在接口/方法的入口/出口处,打印请求及响应参数日志,不要只打印特殊字符或数字的情况,比如“+++++++++++”“----------------------”等。

8、可以使用全局唯一的traceId来进行日志跟踪。

9、如果日志打印出现阻塞,那可以调整日志打印级别。

10、每条日志在语义上可独立被理解,减少上下文关联理解。

11、能合并打印的就合并打印,比如:

INFO 【xxx业务】xxxService请求参数:a=1,b=2

INFO 【xxx业务】xxxService请求响应:c=1,d=2

可以合并为:INFO 【xxx业务】xxxService请求参数:a=1,b=2;请求响应:c=1,d=2。

12、尽量对日志进行简化、压缩、缩写

13、打印日志信息要完善,能够帮助你排查问题,否则就不要打日志

14、日志要脱敏,不要打印一些敏感信息在日志里,比如:用户密码,身份证、手机号、银行卡、姓名、住址、邮箱等信息,关于怎么脱敏,后面在开篇幅进行细讲。

15、日志格式

时间:作为日志产生的日期和时间,精确到毫秒

日志级别:INFO,WARN,ERROR

业务标识:用来区分日志属于哪块业务,因为日志都是跟业务相关联的,通过该部分内容便于按业务进行日志归类聚合。

调用链标识:联一个请求在整个系统中的调用日志。

线程名称:输出该日志的线程名称,一般在一个应用中一个同步请求由同一线程完成,输出线程名称可以在各个请求产生的日志中进行分类,便于分清当前请求上下文的日志。

日志记录器名称:日志记录器名称一般使用类名,日志文件中可以输出简单的类名即可。

日志内容:格式可以自行约定,只要能够通过看日志就能大概知道是什么场景什么问题就可以。比如可以定义为这样的输出格式:[具体业务{必填}] [方法名{必填}] [错误现象{必填}] [条件{必填}] [可能原因{选填}] [需要怎么做{选填}][栈信息]

异常堆栈(不一定有):异常堆栈一般会出现在 ERROR 或者 WARN 级别的日志中,异常堆栈含有方法调用链的系统,以及异常产生的根源。

操作日志

主要面向用户、运营操作人,要求简单易懂,反映出用户所做的动作。通过操作日志可以查到:某人在某时干了某事,比如:

用户名

用户名用户id业务模块操作类型操作说明请求方法请求参数创建时间
张三1订单系统新增下单xxxxxx2022-01-01 12:12:12
李四2用户中心修改改头像xxxxxx2022-02-01 10:10:10

这个日志需要特殊的实现,实现方式有很多,后面有时间可以整理下设计思路。

什么时候打日志?

流程分支

在关键代码流程分支上打印日志。

调用外部接口

在调用外部接口的时候,需要打印请求参数、响应值相关信息。

系统初始化

系统初始化需要依赖一些关键配置参数,这些参数决定系统的启动状态,应该把这些系统初始化信息记录起来。

核心业务操作

系统用户进行核心业务操作的行为,也应该进行记录,便于进行操作审计。比如一些管理端危险的操作都可以打印日志,也可以记录到表里,方便以后排查。

可预期的异常

这类异常应该有效记录起来,通过警告方式反馈给相关人员加以关注,避免频繁发生,最终演化为不可控的错误。

预期外的错误

这类异常发生时,要有详尽记录,并通知相关人员介入处理,第一时间作出响应,因为这种错误已经影响系统的正常使用。

如何落地推广?

规范制定好了,那么要怎么让这个规范很好的落地呢?如果没有进行推广落地,那你制定出来就是一个摆设,没有人知道有这个规范。如果你是领导,那么你可以进行强推,大家心里有一万个不愿意,也只能默默的忍耐。但是你不是领导,只是被选中来做这个事情,那要怎么来推广呢?

1、主动服务

你可以找一些问题比较严重的系统,阐述会对系统造成哪些影响。一对一的进行说明,应该怎么改。把问题比较严重的应用改完,最好是有改完之后的数据对比和效果,那可以为你接下来全公司推广有很大的帮助。

2、持续改进规范

规范是持续不断改进的,在服务的过程中需要不断的优化,这样你的规范会更加的完善,在后面大型推广的时候,也不会遇到太多的阻碍。

3、对日志进行分析

可以对日志进行分析,找出一些不合规的日志,然后找到相应的系统负责人,对日志打印进行整改。也可以制定一些指标,对系统来进行排名。当然一开始这个指标不需要太细,这样反而会给大家带来很多不必要的负担,指标也可以循序渐进。初期:ERROR级别日志条数,WARN级别日志条数,非ERROR级别日志堆栈条数等,后期的指标:单笔事务日志中出现重复日志(重合度=100%且>1条),单条日志中出现特殊符号(特殊符号占比=100%)等等,比如:订单系统单日 ERROR 级别日志 888 条(占日志总量 0.05%),(TOP1)90%在 com.OrderService 的第 88 行。(TOP2)10%在 com.PayService 的第 188 行。

按照这样的方式去推广,可以增加你推广的成功率。

也可以关注我的公众号:程序之声
图片
关注公众号,领取更多 资源

本文为博主原创文章,未经博主允许不得转载。