参与工作也有大半年的时间了,在日常的项目开发中,感触很深的是——日志对于系统的重要性。本科那会儿做项目,最喜用System.out.println、System.err.println
以及一场对象的printStrackTrace
来显示相关信息。当项目日益庞大,如果仍然采用控制台输出,恐怕控制台都要炸了。这样的输出根本用不了日后的日志分析。
试想,当你的系统崩溃的时候,若是没有任何的日志支持,该是多么令人崩溃的一件事!以前总觉得源码是万能的,出了bug
,只要从源头开始追溯一步步设断点debug
下来,总可以找到原因所在。想着即使我们的项目已都到了服务器上,通过IDEA的远程debug功能也能一步步追溯。这样没有好好利用日志快速定位bug的做法实属费时费力。况且如果项目使用了Docker,AKS,K8S
部署到生产环境,上面这种断点调试的方式也就不可行了。
若是一个拥有多个节点的分布式系统,系统日志能准确快速地定位出是我方节点问题还是对方节点问题或者是第三方jar
包的问题还是是网络譬如RPC
调用的问题
那么应该如何记录有必要,非冗余,有切实利用价值的日志呢?首先,一个功能模块的开始和结束,这样的日志起到了对模块的启动和结束的监控作用,是否进入了该模块以及是否从该模块正常退出。其次,是系统的一些关键性调用操作,譬如通过rpc调用其它应用的某服务,其入参和出参等重要信息也应该被记录以便排查问题。再者,是系统进行try-catch
操作时catch
住的异常信息。
了解了需要在什么时候记录日志后,一条简洁明了有价值的日志应该如何记录呢?个人建议采用较为统一的格式记录日志(较为统一的日志格式便于日后的日志统计以及适应广大码农的强迫症=。=)下面是一类本人比较青睐的日志格式:时间-[线程名][日志等级]-日志输出位置(全类名,方法名-日志信息(传递的参数等)。最好能在模块的开始和结束使用StopWatch记录该模块的运行持续时间,以便后续了解在哪个模块持续的时间较长,从而有针对性地分析。
眼尖的朋友看到了上面的日志等级,按照惯例,我们会将日志分门别类,分别会有:DEBUG
,INFO
,WARN
和ERROR
。DEBUG
:系统调试信息,通常用于开发过程中对系统运行情况的监控,在实际运行环境中不进行输出(否则日志就太多太多了!)。INFO
:系统运行的关键性信息,通常用于对系统运行情况的监控。WARN
:告警信息,系统存在潜在的问题,有可能引起运行异常,但此时并未产生异常。ERROR
:系统错误信息,需要进行及时处理和优化。
在Java开发过程中,会有很多日志框架提供了便利的日志记录功能,譬如LogBack,log4j等,通过配置文件或者是Java代码,可以定义不同的Appender使得日志输出到控制台,日志落地,或将日志投递到loghub,kafka等日志服务产品上进行后续的日志数据分析。
逼逼叨叨写了这么些,真的是在工作中感受到了良好的日志收集对解决bug的重要性。希望每一位码农同学都能养成写日志的好习惯噢。