一、日志作用

  • 打印调试:即可以用日志来记录变量或者某一段逻辑。记录程序运行的流程,即程序运行了哪些代码,方便排查逻辑问题。
  • 问题定位:程序出异常或者出故障时快速的定位问题,方便后期解决问题。因为线上生产环境无法 debug,在测试环境去模拟一套生产环境,费时费力;所以依靠日志记录的信息定位问题,这点非常重要。
  • 用户行为日志:记录用户的操作行为,用于大数据分析,比如监控、风控、推荐等。这种日志,一般是给其他团队分析使用,而且可能是多个团队,因此一般会有一定的格式要求,开发者应该按照这个格式来记录,便于其他团队的使用。
  • 根因分析:即在关键地方记录日志,方便在和各个终端定位问题时。

二、日志分级

主要使用如下的四个级别:

  • DEBUG:DEUBG 级别的主要输出调试性质的内容,该级别日志主要用于在开发、测试阶段输出。该级别的日志应尽可能地详尽,开发人员可以将各类详细信息记录到 DEBUG 里,起到调试的作用,包括参数信息,调试细节信息,返回值信息等等,便于在开发、测试阶段出现问题或者异常时,对其进行分析。
  • INFO:INFO 级别的主要记录系统关键信息,旨在保留系统正常工作期间关键运行指标,开发人员可以将初始化系统配置、业务状态变化信息,或者用户业务流程中的核心处理记录到INFO日志中,方便日常运维工作以及错误回溯时上下文场景复现。建议在项目完成后,在测试环境将日志级别调成 INFO,然后通过 INFO 级别的信息看看是否能了解这个应用的运用情况,如果出现问题后是否这些日志能否提供有用的排查问题的信息。
  • WARN:WARN 级别的主要输出警告性质的内容,这些内容是可以预知且是有规划的,比如,某个方法入参为空或者该参数的值不满足运行该方法的条件时。在 WARN 级别的时应输出较为详尽的信息,以便于事后对日志进行分析。
  • ERROR:ERROR 级别主要针对于一些不可预知的信息,诸如:错误、异常等,比如,在 catch 块中抓获的网络通信、数据库连接等异常,若异常对系统的整个流程影响不大,可以使用 WARN 级别日志输出。在输出 ERROR 级别的日志时,尽量多地输出方法入参数、方法执行过程中产生的对象等数据,在带有错误、异常对象的数据时,需要将该对象一并输出。

三、常用框架

  • Log4j & Log4j2: Log4j 和 Log4j2 也都是 Apache 的开源日志框架,Log4j 2.0 以后的版本称为 Log4j2 是 Log4 1.x 的升级版,Log4j 1.x 版在 2015.08.05 停止维护了。Log4j2 参考了 Logback 的一些优秀的设计,并修复了老版的问题,整体提升很大,特别是异步方面的性能提升。 Log4j2 与 Log4j 发生了很大的变化,log4j2 不兼容 Log4j。
  • Logback: Logback是由log4j创始人设计的又一个开源日记组件。logback当前分成三个模块:logback-core、logback- classic和logback-access。logback-core是其它两个模块的基础模块。logback-classic是log4j的一个 改良版本。此外logback-classic完整实现SLF4J API使你可以很方便地更换成其它日记系统如log4j或JDK14 Logging。
  • java.util.logging: JDK内置的日志接口和实现,功能比较简单。
  • Slf4j : 日志门面框架,其仅提供日志记录的API,而不实现日志记录的功能,slf4j需要通过适配库适配到log4j或logback等日志系统来实现日志的记录。使用slf4j api能够提升代码和应用的可移植性,在使用不同日志系统的应用之间能够做到无缝的适配。

四、日志规范

  1. 应用中不可直接使用日志系统(Log4j、Logback)中的 API,而应依赖使用日志框架SLF4J 中的 API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。
  2. 输出Exception的全部Throwable信息,不然会丢失掉最重要的StackTrace信息,如下代码:

    1
    2
    3
    4
    5
    6
    7
    try {
    //
    } catch (Exception e) {
    log.error("Error Message", e); //正确示范
    log.error(e.getMessage()); //错误示范
    log.error("Error Message", e.getMessage()); //错误示范
    }
  3. 不允许记录日志后又抛出异常;如捕获异常后又抛出了自定义业务异常,此时无需记录错误日志,不然会造成重复输出日志。如下代码:

    1
    2
    3
    4
    5
    6
    try {
    //
    } catch (Exception e) {
    log.error("Error Message", e);
    throw new LogException("Error Message", e);
    }
  4. 不允许使用标准输出;例如System.out.println()语句,因为这个输出只会打印到控制台,而不会记录到日志文件中,不方便管理日志。

    1
    2
    3
    4
    5
    6
    try {
    //
    } catch (Exception e) {
    System.out.println(e.getMessage()); //错误示范
    log.error("Bad Things", e); //正确示范
    }
  5. 不允许出现printStackTrace;因为printStackTrace()打印出的堆栈日志跟正常输出或者业务代码执行日志是交错混合在一起的,查看异常日志比较非常困难。

    1
    2
    3
    4
    5
    6
    try {
    //
    } catch (Exception e) {
    e.printStackTrace(); //错误示范
    log.error("Bad Things", e); //正确示范
    }
  6. 禁止线上环境开启 debug 级别日志,有选择地输出 info 日志;因为线上环境日志频繁输出会对性能造成一定影响,还会增大线上日志存储的容量。

  7. 打印有意义的日志;如前端传递的数据、程序运行消耗时间、重要变量的状态变化等日志。

最后更新: 2021年08月29日 11:38

原始链接: http://blog.minhow.com/articles/java/log-specification/

× 请我吃糖~
打赏二维码