深入理解 Logback 日志框架:从 logger.info()到日志输出的完整生命周期Logback 是 Java
Logback 是 Java 中最常用的日志框架之一,广泛应用于各种项目中。了解 Logback 的内部机制,尤其是在调用 logger.info("message") 之后,日志是如何被处理、过滤,并最终输出的,对于优化和扩展日志系统至关重要。本文将结合各个细节,从日志调用开始,一直到日志输出,详细剖析 Logback 的整个生命周期,包括涉及的类、方法及其处理过程。
一、Logback 日志处理的整体流程
当在代码中调用 logger.info("message") 时,Logback 背后执行了一系列复杂的操作,这些操作大致可以分为以下几个步骤:
- 调用日志方法:通过 SLF4J 提供的
Logger接口调用日志方法(如logger.info("message"))。 - 日志事件封装:创建一个
LoggingEvent对象,封装日志信息,如消息内容、日志级别、时间戳、线程信息等。 - 日志过滤:日志事件在传递给附加器(
Appender)之前,经过配置的TurboFilter和Filter进行过滤。 - 日志输出:经过过滤的日志事件被
Appender输出到相应的目标(如控制台、文件等)。

二、LoggingEvent 的创建与属性封装
LoggingEvent 是 Logback 用于封装日志事件的核心类。通过 logger.info("message") 方法调用后,会创建一个 LoggingEvent 对象,并在构造函数中初始化所有相关属性,包括:
- 时间戳(timeStamp):通过
System.currentTimeMillis()方法获取当前时间戳,并赋值给timeStamp属性。 - 线程名称(threadName):通过
Thread.currentThread().getName()方法获取当前线程的名称,并赋值给threadName属性。 - 日志级别(level):日志级别(如 INFO、DEBUG)由调用方法时传递的参数决定,并封装到
LoggingEvent中。 - 日志消息(message):日志内容作为参数传递,并封装在
LoggingEvent对象中。 - 可变参数(params):如果日志记录方法包含可变参数,这些参数也会被封装进
LoggingEvent中。
这些属性的封装发生在 LoggingEvent 构造函数中,确保了日志事件包含了所有必要的上下文信息。
三、日志过滤的执行:Filter 和 TurboFilter
在 Logback 中,Filter 和 TurboFilter 都用于日志事件的过滤,但它们的执行顺序和作用范围不同:
-
TurboFilter:TurboFilter是在日志系统的更高层次进行全局过滤。它的设计初衷是为了提供更高性能的过滤机制,适用于全局性或性能敏感的过滤逻辑。TurboFilter在日志事件被传递到具体的Appender之前就会被执行,因此它的决策能够避免不必要的日志处理,提升性能。可以通过继承
TurboFilter类来创建自定义的过滤器,例如:public class CustomTurboFilter extends TurboFilter { @Override public FilterReply decide(Marker marker, Logger logger, Level level, String format, Object[] params, Throwable t) { if (marker != null && marker.contains("SECURITY")) { return FilterReply.ACCEPT; } return FilterReply.NEUTRAL; } }该过滤器基于
Marker值进行过滤,只有当Marker包含 “SECURITY” 时才接受日志。 -
Filter:Filter是在具体的Appender上进行配置的。每个Appender可以拥有多个Filter,这些过滤器会在日志事件被真正输出前对其进行判断。如果需要在日志事件到达Appender之前对其进行修改或阻止输出,可以通过自定义Filter实现。举例来说,如果希望在日志事件传递给
Appender之前修改其日志级别,可以实现一个自定义Filter并在其中进行修改:public class LevelChangingFilter extends Filter<ILoggingEvent> { @Override public FilterReply decide(ILoggingEvent event) { if (event.getLevel().equals(Level.INFO)) { event.setLevel(Level.DEBUG); // 修改日志级别 } return FilterReply.NEUTRAL; } }但是,如果通过
Filter修改了LoggingEvent中的level属性,且希望在某些情况下跳过执行Appender,可以返回FilterReply.DENY,这样就不会继续调用后续的Appender。
四、自定义 TurboFilter 的加载与应用
TurboFilter 的加载发生在 Logback 的初始化阶段。通常,TurboFilter 可以通过 logback.xml 配置文件进行配置,但如果希望自动为所有应用配置自定义的 TurboFilter,可以通过 Spring Boot 自动配置机制实现。
自动配置 TurboFilter
当希望在一个 JAR 包中定义自定义的 TurboFilter,并希望其他项目在加载该 JAR 包后自动应用这个 TurboFilter 时,可以通过以下步骤实现:
-
创建自定义
TurboFilter:如前文所述,实现自定义的TurboFilter。 -
通过 Spring Boot 自动配置:在 JAR 包中提供自动配置类,并确保在 Spring Boot 项目中加载该类时自动注册
TurboFilter:@Configuration public class LogbackAutoConfiguration { @PostConstruct public void addCustomTurboFilter() { LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); TurboFilter customTurboFilter = new CustomTurboFilter(); loggerContext.addTurboFilter(customTurboFilter); } }通过此配置,当其他项目加载该 JAR 包时,自定义的
TurboFilter会被自动注册到日志系统中。 -
声明自动配置类:在
spring.factories文件中声明自动配置类:org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.logging.LogbackAutoConfiguration
五、LoggerContext 的角色与日志系统初始化
LoggerContext 是 Logback 中管理日志相关配置的核心类。在一个 Spring Boot 项目中,LoggerContext 实例是全局唯一的,这意味着整个应用的日志配置都在同一个上下文中进行管理。
LoggerContext 在日志系统初始化时加载配置文件(如 logback.xml),并初始化所有 Logger、Appender、Filter 和 TurboFilter。自定义的日志过滤逻辑(如 TurboFilter)通常需要在日志系统初始化之后,应用其他部分开始记录日志之前执行,以确保这些逻辑生效。
在 Spring Boot 项目中,通过 Spring Boot 自动配置机制,可以在日志系统初始化时将自定义 TurboFilter 添加到 LoggerContext 中,确保日志记录时自定义过滤逻辑得到执行。
六、深入理解日志记录的细节:Marker 和 LoggingEvent
在日志记录过程中,Marker 是一个重要的概念,用于标记日志事件的特定类别或上下文。虽然 logger.info("message") 方法不直接使用 Marker 参数,但 Logback 提供了支持 Marker 的日志记录方法,例如:
logger.info(marker, "This is a marker log message");
当使用带 Marker 的日志方法时,Marker 会被传递给 LoggingEvent 对象,并在后续的过滤和处理过程中进行处理。
LoggingEvent 对象不仅包含 Marker,还封装了其他关键信息,如时间戳、线程名称、日志级别、日志消息等。这些信息在 LoggingEvent 的构造函数中被初始化,并通过一系列方法进行处理和传递。
七、总结
本文全面探讨了 Logback 日志框架的内部工作原理,涵盖了从 logger.info("message") 到日志输出的全过程。我们深入剖析了 LoggingEvent 的创建与属性封装、Filter 和 TurboFilter 的执行顺序,以及如何通过 Spring Boot 自动配置机制实现自定义日志过滤逻辑。还详细讨论了 LoggerContext 的角色与日志系统初始化、Marker 的处理过程。
通过理解这些底层机制,可以更高效地使用 Logback,尤其是在处理复杂的日志记录需求时。合理的日志系统配置和扩展能够显著提升应用的可维护性、可调试性,并确保日志记录系统的性能与稳定性。
转载自:https://juejin.cn/post/7403627317332869146