java 日志系统

时间:2025-08-27 15:42:01来源:互联网

下面小编就为大家分享一篇java 日志系统,具有很好的参考价值,希望对大家有所帮助。

日志系统概述

日志可以帮助我们快速的定位问题,记录程序运行过程中的情况,以便项目的监控和优化。我们在日常开发中主要使用的java日志框架组件是:log4j、SLF4J、Commons Logging

日志系统由三个重要的组件构成:日志信息的优先级,日志信息的输出目的地,日志信息的输出格式。这些信息可以在 properties的文件中进行配置

一般来说日志分为两种:业务日志和异常日志

slf4j-api、slf4j-log4j12以及log4j之间的关系

slf4j入口就是众多接口的集合,它不负责具体的日志实现,只在编译时负责寻找合适的日志系统进行绑定。它只服务于各种各样的日志系统,具体有哪些接口,全部都定义在slf4j-api中。

slf4j-log4j12是链接slf4j-api和log4j中间的适配器。

log4j是具体的日志系统。通过slf4j-log4j12初始化Log4j,达到最终日志的输出。

Apache common logging

common logging和slf4j是相同的功能,都是负责寻找合适的日志系统进行绑定

日志级别

日志级别一般分为7个打印级别:

  • OFF-关闭所有日志;
  • FATAL-记录严重的错误,并且会导致应用程序退出;
  • ERROR-记录严重的错误,但不会影响程序的运行;
  • WARN-记录警告;
  • INFO-记录程序中比较有意义的信息;
  • DEBUG-记录程序中的细节信息;
  • ALL-记录所有的日志;

logback

logback同样是由log4j的作者设计完成的,拥有更好的特性,用来取代log4j的一个日志框架。是slf4j的原生实现。

logback是直接实现了slf4j的接口,而log4j不是对slf4j的原生实现,所以slf4j api在调用log4j时需要一个适配层。

 

日志系统使用规范

采用slf4j作为日志API,采用logback作为日志输出工具,用slf4j桥接方式替换掉log4j和commons-logging。

 

特殊的记录,需要大批量写入日志文件,应该采用异步线程写文件。

各级别日志使用原则

1、fatal(致命错误)使用原则

 

fatal为系统级别的异常,发生fatal错误,代表服务器整个或者核心功能已经无法工作了!!

1)在服务器启动时就应该检查,如果存在致命错误,直接抛异常,让服务器不要启动起来(启动了也无法正常工作,不如不启动)。

  • 如果在服务器启动之后,发生了致命的错误,则记录fatal级别的错误日志,最好是同时触发相关的修复和告警工作(比如,给开发和维护人员发送告警邮件)。

 

2、error(错误)使用原则

error为功能或者逻辑级别的严重异常,发生error级别的异常,代表功能或者重要逻辑遇到问题、无法正常工作。

 

3、warn(警告)使用原则

warn用在某些逻辑非常规,发生了一些小故障但是没有大的影响,或者重要数据被修改,或者某些操作需要引起重视。

 

4、info(信息)使用原则

info用于记录一些有用的、关键的信息,一般这些信息出现得不频繁,只是在初始化的地方或者重要操作的地方才记录。

 

 

5、debug(调试)使用原则

debug用于记录一些调试信息,为了方便查看程序的执行过程和相关数据、了解程序的动态。

 

 

6、trace(跟踪)使用原则

trace用于记录一些更详细的调试信息,这些信息无需每次调试时都打印出来,只在需要更详细的调试信息时才开启。

 

项目稳定运行时的日志量

1)正常情况下,trace日志至少是debug日志的100倍,

trace级别的日志量 : debug级别的日志量  >  100 : 1,

也就是说trace日志非常多,debug日志相对较少。

 

2)debug级别的日志量 : info级别的日志量 > 1000 : 1,

也就是说正常情况下,info日志很少,只在部分重要位置会输出 info日志。

 

error日志和warn日志,正常情况下,几乎为0,当出现异常时,error日志和warn日志量 也在可控范围,不会超过debug级别的最大日志量。

 

各环境默认日志定义

 

开发环境

1)默认日志级别定义为:

    app包为TRACE级别。日志的ROOT Level为DEBUG级别。

2)

启用 System.out 控制台输出日志;

启用error.log为错误和警告日志、app.log为应用日志(包括app包下的日志和其他INFO级别以上的日志)。

 

 

测试环境

1)默认日志级别定义为:

    app包为DEBUG级别。日志的ROOT Level为DEBUG级别。

2)

禁用 System.out 控制台输出日志;

启用error.log为错误和警告日志、app.log为应用日志(包括app包下的日志和其他INFO级别以上的日志)。

 

生产环境

1)默认日志级别定义为:

    app包为DEBUG级别。日志的ROOT Level为INFO级别。

2)

禁用 System.out 控制台输出日志;

启用error.log为错误和警告日志、app.log为应用日志(包括app包下的日志和其他INFO级别以上的日志)。

基本的Logger编码规范

  • 在一个对象中通常只使用一个Logger对象,Logger应该是static final的,只有在少数需要在构造函数中传递logger的情况下才使用private final。
  • 输出Exceptions的全部Throwable信息,因为logger.error(msg)和logger.error(msg,e.getMessage())这样的日志输出方法会丢失掉最重要的StackTrace信息。
  • 不允许记录日志后又抛出异常,因为这样会多次记录日志,只允许记录一次日志。
  • 不允许出现System print(包括out.println和System.error.println)语句。
  • 不允许出现printStackTrace。

 

日志性能的考虑,如果代码为核心代码,执行频率非常高,则输出日志建议增加判断,尤其是低级别的输出<debug、info、warn>。

debug日志太多后可能会影响性能,有一种改进方法是:

但更好的方法是Slf4j提供的最佳实践:

一方面可以减少参数构造的开销,另一方面也不用多写两行代码。

7.有意义的日志

通常情况下在程序日志里记录一些比较有意义的状态数据:程序启动,退出的时间点;程序运行消耗时间;耗时程序的执行进度;重要变量的状态变化。

初次之外,在公共的日志里规避打印程序的调试或者提示信息。

 

8.【强制】应用中不可直接使用日志系统(Log4j、Logback)中的API,而应依赖使用日志框架

SLF4J中的API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

private static final Logger logger = LoggerFactory.getLogger(Abc.class);

  1. 【强制】日志文件推荐至少保存15天,因为有些异常具备以“周”为频次发生的特点。
  2.  【强制】应用中的扩展日志(如打点、临时监控、访问日志等)命名方式:

appName_logType_logName.log。logType:日志类型,推荐分类有stats/desc/monitor/visit等;logName:日志描述。这种命名的好处:通过文件名就可知道日志文件属于什么应用,什么类型,什么目的,也有利于归类查找。

 

说明:推荐对日志进行分类,错误日志和业务日志尽量分开存放,便于开发人员查看,也便于通过日志对系统进行及时监控。

 

  1. 【强制】避免重复打印日志,浪费磁盘空间,务必在xml中设置additivity=false
  2.  【强制】异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么往上抛。

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

 

  1. 输出的POJO类必须重写toString方法,否则只输出此对象的hashCode值(地址值),没啥参考意义。
  2. 【推荐】可以使用warn日志级别来记录用户输入参数错误的情况,避免用户投诉时,无所适从。注意日志输出的级别,error级别只记录系统逻辑出错、异常、或者重要的错误信息。如非必要,请不要在此场景打出error级别,避免频繁报警。
  3. 【推荐】谨慎地记录日志。生产环境禁止输出debug日志;有选择地输出info日志;如果使用warn来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘撑爆,并记得及时删除这些观察日志。解读:深入理解日志级别含义,以及应该如何选择合适的等级。

说明:大量地输出无效日志,不利于系统性能提升,也不利于快速定位错误点。纪录日志时请思考:这些日志真的有人看吗?看到这条日志你能做什么?能不能给问题排查带来好处?

本站部分内容转载自互联网,如果有网站内容侵犯了您的权益,可直接联系我们删除,感谢支持!