深入理解 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