消除迷宫:异境入侵官方中文版
· 2025-11-02
日志可以帮助我们快速的定位问题,记录程序运行过程中的情况,以便项目的监控和优化。我们在日常开发中主要使用的java日志框架组件是:log4j、SLF4J、Commons Logging
日志系统由三个重要的组件构成:日志信息的优先级,日志信息的输出目的地,日志信息的输出格式。这些信息可以在 properties的文件中进行配置
一般来说日志分为两种:业务日志和异常日志
slf4j入口就是众多接口的集合,它不负责具体的日志实现,只在编译时负责寻找合适的日志系统进行绑定。它只服务于各种各样的日志系统,具体有哪些接口,全部都定义在slf4j-api中。
slf4j-log4j12是链接slf4j-api和log4j中间的适配器。
log4j是具体的日志系统。通过slf4j-log4j12初始化Log4j,达到最终日志的输出。
common logging和slf4j是相同的功能,都是负责寻找合适的日志系统进行绑定
日志级别一般分为7个打印级别:
logback同样是由log4j的作者设计完成的,拥有更好的特性,用来取代log4j的一个日志框架。是slf4j的原生实现。
logback是直接实现了slf4j的接口,而log4j不是对slf4j的原生实现,所以slf4j api在调用log4j时需要一个适配层。
采用slf4j作为日志API,采用logback作为日志输出工具,用slf4j桥接方式替换掉log4j和commons-logging。
特殊的记录,需要大批量写入日志文件,应该采用异步线程写文件。
fatal为系统级别的异常,发生fatal错误,代表服务器整个或者核心功能已经无法工作了!!
1)在服务器启动时就应该检查,如果存在致命错误,直接抛异常,让服务器不要启动起来(启动了也无法正常工作,不如不启动)。
error为功能或者逻辑级别的严重异常,发生error级别的异常,代表功能或者重要逻辑遇到问题、无法正常工作。
warn用在某些逻辑非常规,发生了一些小故障但是没有大的影响,或者重要数据被修改,或者某些操作需要引起重视。
info用于记录一些有用的、关键的信息,一般这些信息出现得不频繁,只是在初始化的地方或者重要操作的地方才记录。
debug用于记录一些调试信息,为了方便查看程序的执行过程和相关数据、了解程序的动态。
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级别以上的日志)。
日志性能的考虑,如果代码为核心代码,执行频率非常高,则输出日志建议增加判断,尤其是低级别的输出<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);
appName_logType_logName.log。logType:日志类型,推荐分类有stats/desc/monitor/visit等;logName:日志描述。这种命名的好处:通过文件名就可知道日志文件属于什么应用,什么类型,什么目的,也有利于归类查找。
说明:推荐对日志进行分类,错误日志和业务日志尽量分开存放,便于开发人员查看,也便于通过日志对系统进行及时监控。
正例:logger.error(各类参数或者对象toString + "_" + e.getMessage(), e);
说明:大量地输出无效日志,不利于系统性能提升,也不利于快速定位错误点。纪录日志时请思考:这些日志真的有人看吗?看到这条日志你能做什么?能不能给问题排查带来好处?