日志系统自动配置全解析
概述
Spring Boot 的日志系统自动配置是启动过程中最早的初始化步骤之一。通过 LoggingApplicationListener 监听启动事件,在 ApplicationStartingEvent 阶段即完成日志框架的选择、配置文件的加载和日志级别的设置,确保整个后续启动流程都有日志输出。
本文将深入拆解日志系统自动配置的 8 个关键细节,涵盖日志初始化触发时机、LoggingSystem SPI、Logback 配置加载顺序、配置属性、运行时动态修改、LoggerGroups 批量管理、springProperty 扩展、文件滚动策略等核心内容。
本文基于 Spring Boot 3.2.5 + Logback 1.5.x 源码分析。
1. LoggingApplicationListener 的 onApplicationStartEvent() 监听
LoggingApplicationListener 是 Spring Boot 启动过程中最早激活的监听器之一,在 ApplicationStartingEvent 发布时即开始初始化日志系统。
public class LoggingApplicationListener implements GenericApplicationListener {
// 优先级最高(在所有其他监听器之前执行)
public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10;
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationStartingEvent startingEvent) {
// ① 在 ApplicationStartingEvent 时初始化日志系统
onApplicationStartingEvent(startingEvent);
} else if (event instanceof ApplicationEnvironmentPreparedEvent preparedEvent) {
// ② 在 Environment 就绪后应用日志配置属性
onApplicationEnvironmentPreparedEvent(preparedEvent);
} else if (event instanceof ApplicationPreparedEvent preparedEvent) {
// ③ 在 context 加载完毕后使用 LOG 记录启动信息
onApplicationPreparedEvent(preparedEvent);
} else if (event instanceof ApplicationFailedEvent failedEvent) {
// ④ 启动失败时关闭日志系统
onApplicationFailedEvent(failedEvent);
}
}
private void onApplicationStartingEvent(ApplicationStartingEvent event) {
// 1. 从 SpringApplication 中获取 classLoader
ClassLoader classLoader = event.getApplication().getClassLoader();
// 2. 通过 LoggingSystemFactory SPI 创建 LoggingSystem
this.loggingSystem = LoggingSystem.get(classLoader);
// 3. 初始化日志系统(加载配置文件)
this.loggingSystem.beforeInitialize();
}
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
if (this.loggingSystem == null) {
this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader());
}
// 1. 应用 logging.* 配置属性
Environment environment = event.getEnvironment();
String configLocation = environment.getProperty("logging.config");
if (configLocation != null) {
// 用户自定义日志配置文件路径
this.loggingSystem.setConfigLocation(environment, configLocation);
}
// 2. 应用日志级别配置(logging.level.*)
LoggingProperties loggingProperties = new LoggingProperties(environment);
initializeLoggingSystem(loggingProperties);
// 3. 设置系统属性(用于日志配置文件中的占位符)
setSystemProperties(environment, loggingSystem);
}
}LoggingApplicationListener 的注册:
// 通过 SpringFactoriesLoader SPI 加载
// META-INF/spring/org.springframework.boot.SpringApplicationRunListener.imports 中
// 实际上 LoggingApplicationListener 是作为 ApplicationListener SPI 注册的
// spring.factories 中:
// org.springframework.context.ApplicationListener=\
// org.springframework.boot.context.logging.LoggingApplicationListener启动阶段日志事件时间线:
ApplicationStartingEvent
↓ ← LoggingApplicationListener.onApplicationStartingEvent()
LoggingSystem.beforeInitialize()
↓ 日志系统初始化完成(此时已有控制台日志输出)
ApplicationEnvironmentPreparedEvent
↓ ← LoggingApplicationListener.onApplicationEnvironmentPreparedEvent()
应用 logging.* 配置 → 设置日志级别 → 配置文件路径
↓
后续所有启动步骤均有日志输出2. LoggingSystemFactory 的 SPI 加载
LoggingSystemFactory 负责根据 classpath 中的日志框架自动选择合适的 LoggingSystem 实现。
// LoggingSystem.get() 静态工厂方法
public abstract class LoggingSystem {
public static LoggingSystem get(ClassLoader classLoader) {
// 从 spring.factories 加载所有 LoggingSystemFactory
List<LoggingSystemFactory> factories = SpringFactoriesLoader.loadFactories(
LoggingSystemFactory.class, classLoader);
// 遍历所有工厂,返回第一个可用的 LoggingSystem
for (LoggingSystemFactory factory : factories) {
LoggingSystem system = factory.getLoggingSystem(classLoader);
if (system != null) {
return system;
}
}
// 兜底:使用 Java Util Logging
return new JavaLoggingSystem(classLoader);
}
}LoggingSystemFactory 接口:
@FunctionalInterface
public interface LoggingSystemFactory {
// 根据 classLoader 创建 LoggingSystem
// 如果当前 classpath 中没有对应的日志框架,返回 null
@Nullable
LoggingSystem getLoggingSystem(ClassLoader classLoader);
}内置的 LoggingSystemFactory 实现:
// LogbackLoggingSystemFactory
public class LogbackLoggingSystemFactory implements LoggingSystemFactory {
@Override
public LoggingSystem getLoggingSystem(ClassLoader classLoader) {
// 检查 classpath 中是否存在 ch.qos.logback.classic.Logger
try {
Class<?> testClass = classLoader.loadClass("ch.qos.logback.classic.Logger");
return new LogbackLoggingSystem(classLoader);
} catch (ClassNotFoundException ex) {
return null; // Logback 不在 classpath 中
}
}
}
// Log4J2LoggingSystemFactory
public class Log4J2LoggingSystemFactory implements LoggingSystemFactory {
@Override
public LoggingSystem getLoggingSystem(ClassLoader classLoader) {
// 检查 classpath 中是否存在 org.apache.logging.log4j.LogManager
try {
Class<?> testClass = classLoader.loadClass("org.apache.logging.log4j.LogManager");
return new Log4J2LoggingSystem(classLoader);
} catch (ClassNotFoundException ex) {
return null; // Log4j2 不在 classpath 中
}
}
}选择优先级:
spring.factories 中的注册顺序(按 @Order 排序):
① LogbackLoggingSystemFactory ← 默认包含在 spring-boot-starter 中
② Log4J2LoggingSystemFactory ← 需手动引入 log4j2 依赖
③ JavaLoggingSystem ← JDK 内置(兜底)
选择策略:按顺序遍历,第一个 classpath 中存在的框架被选中3. LogbackLoggingSystem 的日志配置加载
LogbackLoggingSystem 负责加载 Logback 配置文件,遵循特定的文件查找顺序。
public class LogbackLoggingSystem extends AbstractLoggingSystem {
private static final String CONFIG_FILE_PROPERTY = "logging.config";
private static final String LOGBACK_TEST_LOCATION = "logback-test.xml";
private static final String LOGBACK_SPRING_LOCATION = "logback-spring.xml";
private static final String LOGBACK_LOCATION = "logback.xml";
@Override
protected String[] getStandardConfigLocations() {
// 标准配置文件查找顺序
return new String[] {
LOGBACK_TEST_LOCATION, // ① logback-test.xml(测试配置)
LOGBACK_SPRING_LOCATION, // ② logback-spring.xml(Spring 扩展配置)
LOGBACK_LOCATION // ③ logback.xml(标准配置)
};
}
@Override
public void beforeInitialize() {
// 在启动早期初始化 LoggerContext
LoggerContext loggerContext = getLoggerContext();
if (loggerContext.isStarted()) {
// 停止并重置 LoggerContext,准备重新加载配置
loggerContext.stop();
}
// 注册 Spring Boot 特有的 Logback 转换器(如 %clr 彩色输出)
registerSpringBootConverters(loggerContext);
// 加载配置文件
loadConfiguration(getPackagedConfig(), loggerContext);
}
private void loadConfiguration(LoggerContext loggerContext) {
// 配置文件查找优先级:
// 1. logging.config 系统属性(用户指定路径)
// 2. logback-test.xml(测试目录)
// 3. logback-spring.xml(推荐,支持 Spring 扩展)
// 4. logback.xml(标准 Logback 配置)
// 5. 如果以上都不存在,使用 Spring Boot 提供的 base.xml(基础配置)
String location = System.getProperty(CONFIG_FILE_PROPERTY);
if (location != null) {
// 使用用户指定的配置
loadFromLocation(location, loggerContext);
return;
}
URL config = findConfig(getStandardConfigLocations());
if (config != null) {
loadFromUrl(config, loggerContext);
} else {
// 使用 Spring Boot 内置的 base.xml 作为默认配置
loadDefaultConfig(loggerContext);
}
}
}Spring Boot 内置的 base.xml(位于 spring-boot.jar 中):
<!-- org/springframework/boot/logging/logback/base.xml -->
<included>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</included>配置文件查找顺序:
① logging.config 属性(用户显式指定)
↓ 存在 → 使用指定路径
② logback-test.xml(测试用)
↓ 存在 → 使用测试配置
③ logback-spring.xml(推荐)
↓ 存在 → 使用 Spring 扩展配置(支持 <springProperty> <springProfile> 等)
④ logback.xml(标准配置)
↓ 存在 → 使用标准 Logback 配置
⑤ 无配置文件 → 使用 Spring Boot 内置的 base.xmldefaults.xml 中的默认格式:
<!-- 控制台输出格式 -->
<conversionRule conversionWord="clr"
converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
<property name="CONSOLE_LOG_PATTERN"
value="%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd'T'HH:mm:ss.SSS}}){faint}
%clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta}
%clr(---){faint}
%clr([%15.15t]){faint}
%clr(%-40.40logger{39}){cyan}
%clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>4. Spring Boot 的日志配置属性
Spring Boot 通过 LoggingProperties 类将 application.properties / application.yml 中的 logging.* 配置映射到日志系统。
@ConfigurationProperties(prefix = "logging")
public class LoggingProperties {
// 日志级别配置:logging.level.com.example=DEBUG
private final Map<String, LogLevel> level = new LinkedHashMap<>();
// 日志组配置:logging.group.tomcat=org.apache.catalina,org.apache.tomcat
private final Map<String, List<String>> group = new LinkedHashMap<>();
// 日志文件路径配置:logging.file.path=/var/log/myapp
private String filePath;
// 日志文件名配置:logging.file.name=myapp.log
private String fileName;
// 控制台日志格式:logging.pattern.console=%d{...} [%thread] %-5level %logger{36} - %msg%n
private String patternConsole;
// 文件日志格式:logging.pattern.file=%d{...} [%thread] %-5level %logger{36} - %msg%n
private String patternFile;
// 日志级别模式:logging.pattern.level=%5p
private String patternLevel;
// 日期格式:logging.pattern.dateformat=yyyy-MM-dd HH:mm:ss.SSS
private String patternDateformat;
// 日志文件最大大小:logging.logback.rollingpolicy.max-file-size=10MB
// 日志文件最大历史:logging.logback.rollingpolicy.max-history=7
// 日志文件总大小上限:logging.logback.rollingpolicy.total-size-cap=1GB
private final LogbackRollingPolicy rollingPolicy = new LogbackRollingPolicy();
// 字符编码:logging.charset.console=UTF-8
// 文件编码:logging.charset.file=UTF-8
private final CharsetConfig charset = new CharsetConfig();
}常用配置:
# application.properties
# 日志级别
logging.level.root=WARN
logging.level.com.example=DEBUG
logging.level.org.springframework.web=TRACE
# 日志文件
logging.file.path=/var/log/myapp
logging.file.name=myapp.log
# 日志格式
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
logging.pattern.level=%5p
# 滚动策略
logging.logback.rollingpolicy.max-file-size=10MB
logging.logback.rollingpolicy.max-history=7
logging.logback.rollingpolicy.total-size-cap=1GB
# 字符编码
logging.charset.console=UTF-8
logging.charset.file=UTF-8配置应用到 Logback 的过程:
// LogbackLoggingSystem.initialize() 中
protected void initialize(LoggingProperties properties, LogFile logFile) {
LoggerContext context = getLoggerContext();
// 1. 将 logging.pattern.* 设为系统属性,logback.xml 可通过 ${CONSOLE_LOG_PATTERN} 读取
setSystemProperties(context, properties);
// 2. 将 logging.level.* 应用到 Logger
for (Map.Entry<String, LogLevel> entry : properties.getLevel().entrySet()) {
setLogLevel(entry.getKey(), entry.getValue());
}
// 3. 配置日志文件
if (logFile != null) {
configureFileAppender(context, logFile);
}
}5. LoggerConfiguration 的运行时修改
Spring Boot 支持在运行时修改日志级别,无需重启应用。
// LoggingSystem 的 setLogLevel 方法
public abstract class LoggingSystem {
// 设置指定 Logger 的级别
public void setLogLevel(String loggerName, LogLevel level) {
// 默认实现:不进行任何操作
// 具体实现由子类负责(LogbackLoggingSystem / Log4J2LoggingSystem)
}
}
// LogbackLoggingSystem 的实现
public class LogbackLoggingSystem extends AbstractLoggingSystem {
@Override
public void setLogLevel(String loggerName, LogLevel level) {
LoggerContext context = getLoggerContext();
// 1. 获取或创建 Logger 实例
ch.qos.logback.classic.Logger logger = context.getLogger(loggerName);
// 2. 将 Spring Boot 的 LogLevel 转换为 Logback 的 Level
ch.qos.logback.classic.Level logbackLevel = convertToLogbackLevel(level);
// 3. 设置 Logger 级别(直接调用 Logback 原生 API)
logger.setLevel(logbackLevel);
}
}Actuator 集成:
Spring Boot Actuator 暴露了 /actuator/loggers 端点,允许通过 HTTP 修改日志级别。
@Endpoint(id = "loggers")
public class LoggersEndpoint {
private final LoggingSystem loggingSystem;
@ReadOperation
public Map<String, Object> loggers() {
// 返回所有 Logger 的当前级别信息
}
@WriteOperation
public void configureLogLevel(@Selector String name, LogLevel level) {
// POST /actuator/loggers/com.example
// Body: { "configuredLevel": "DEBUG" }
loggingSystem.setLogLevel(name, level);
}
}运行时修改:
# 查询当前日志级别
curl http://localhost:8080/actuator/loggers/com.example
# 响应:
# {
# "configuredLevel": "INFO",
# "effectiveLevel": "INFO"
# }
# 修改日志级别(无需重启)
curl -X POST http://localhost:8080/actuator/loggers/com.example \
-H "Content-Type: application/json" \
-d '{"configuredLevel": "DEBUG"}'LoggerConfiguration 展示信息:
public final class LoggerConfiguration {
private final String name; // Logger 名称(如 com.example.service.UserService)
private final LogLevel configuredLevel; // 配置的级别(可为 null)
private final LogLevel effectiveLevel; // 实际生效的级别(继承父级)
public LoggerConfiguration(String name, @Nullable LogLevel configuredLevel, LogLevel effectiveLevel) {
this.name = name;
this.configuredLevel = configuredLevel;
this.effectiveLevel = effectiveLevel;
}
}6. LoggerGroups 的批量管理
LoggerGroups 允许将多个 Logger 组合为一个组,通过一个配置项统一管理日志级别。
public class LoggerGroups {
// 内置预定义的日志组
public static final String TOMCAT = "tomcat";
public static final String WEB = "web";
public static final String SQL = "sql";
public static final String CACHE = "cache";
// 默认组定义(硬编码在 LoggingApplicationListener 中)
static final Map<String, List<String>> DEFAULT_GROUPS;
static {
Map<String, List<String>> defaultGroups = new LinkedHashMap<>();
defaultGroups.put(TOMCAT, Arrays.asList(
"org.apache.catalina", "org.apache.coyote", "org.apache.tomcat"));
defaultGroups.put(WEB, Arrays.asList(
"org.springframework.web", "org.springframework.web.servlet",
"org.springframework.web.client", "org.springframework.web.reactive"));
defaultGroups.put(SQL, Arrays.asList(
"org.springframework.jdbc", "org.springframework.orm",
"org.springframework.transaction"));
DEFAULT_GROUPS = Collections.unmodifiableMap(defaultGroups);
}
private final Map<String, List<String>> groups = new LinkedHashMap<>();
// 添加自定义组
public void addGroup(String name, List<String> members) {
groups.put(name, members);
}
// 获取组中所有 Logger 名称
public List<String> getMembers(String groupName) {
List<String> members = groups.get(groupName);
return members != null ? members : Collections.emptyList();
}
}配置示例:
# 自定义日志组
logging.group.tomcat=org.apache.catalina,org.apache.coyote,org.apache.tomcat
logging.group.myapp=com.example.controller,com.example.service,com.example.repository
# 为整个组设置日志级别(一行设置所有成员)
logging.level.tomcat=WARN # 将组内三个 Logger 全部设为 WARN
logging.level.myapp=DEBUG # 将 com.example 下三个子包全部设为 DEBUG等价于:
# 不使用组的等效配置(需要逐一设置)
logging.level.org.apache.catalina=WARN
logging.level.org.apache.coyote=WARN
logging.level.org.apache.tomcat=WARN
logging.level.com.example.controller=DEBUG
logging.level.com.example.service=DEBUG
logging.level.com.example.repository=DEBUGLoggerGroups 的应用:
// LoggingApplicationListener 中
private void initializeLoggingSystem(LoggingProperties properties) {
LoggerGroups loggerGroups = new LoggerGroups();
// 1. 添加默认组
loggerGroups.addGroup("web", DEFAULT_WEB_GROUP);
// 2. 添加用户自定义组(从 logging.group.* 配置读取)
for (Map.Entry<String, List<String>> entry : properties.getGroup().entrySet()) {
loggerGroups.addGroup(entry.getKey(), entry.getValue());
}
// 3. 设置日志级别
for (Map.Entry<String, LogLevel> entry : properties.getLevel().entrySet()) {
String name = entry.getKey();
LogLevel level = entry.getValue();
// 检查是否是 group 名称
List<String> members = loggerGroups.getMembers(name);
if (!members.isEmpty()) {
// 是 group → 为组内所有成员设置级别
for (String member : members) {
loggingSystem.setLogLevel(member, level);
}
} else {
// 是单个 Logger → 直接设置
loggingSystem.setLogLevel(name, level);
}
}
}7. Logback 的 springProperty 扩展
Spring Boot 为 Logback 提供了 <springProperty> 扩展标签,允许在 logback-spring.xml 中直接读取 Spring 的配置属性。
<!-- logback-spring.xml -->
<configuration>
<!-- 读取 spring.application.name 属性 -->
<springProperty name="appName" source="spring.application.name"
defaultValue="unknown-app"/>
<!-- 读取 logging.file.path 属性 -->
<springProperty name="logPath" source="logging.file.path"
defaultValue="/var/log/myapp"/>
<!-- 读取 server.port 属性 -->
<springProperty name="port" source="server.port"
defaultValue="8080"/>
<!-- 在 Appender 中使用 Spring 配置 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/${appName}-${port}.log</file>
<!-- ... -->
</appender>
<!-- 使用 springProfile 根据 profile 切换配置 -->
<springProfile name="dev">
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
</root>
</springProfile>
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="FILE"/>
</root>
</springProfile>
</configuration><springProperty> 的实现:
// SpringBoot 自定义的 Logback 标签解析
public class SpringPropertyAction extends Action {
@Override
public void begin(InterpretationContext ec, String name, Attributes attributes) {
// 1. 获取 source 属性(对应 Spring 配置中的属性名)
String source = attributes.getValue("source");
// 2. 获取 scope(context / local / system)
String scope = attributes.getValue("scope");
// 3. 获取 defaultValue(配置不存在时使用的默认值)
String defaultValue = attributes.getValue("defaultValue");
// 4. 从 Spring Environment 中读取属性值
String value = environment.getProperty(source);
// 5. 如果 Spring 中不存在,使用 defaultValue
if (value == null) {
value = defaultValue;
}
// 6. 将值设置到 Logback 的上下文变量中
if (scope != null && "system".equals(scope)) {
System.setProperty(source, value);
} else if (scope != null && "context".equals(scope)) {
ec.getContext().putProperty(source, value);
} else {
// local scope(默认)
ec.addSubstitutionProperty(source, value);
}
}
}支持的 Logback 扩展:
| 扩展标签 | 说明 | 示例 |
|---|---|---|
<springProperty> | 读取 Spring 配置属性 | <springProperty name="appName" source="spring.application.name"/> |
<springProfile> | 按 Profile 条件切换 | <springProfile name="dev,test">...</springProfile> |
8. LogFile 的文件滚动策略
LogFile 封装了日志文件的配置信息,并委托 Logback 的 SizeAndTimeBasedRollingPolicy 实现文件滚动。
public class LogFile {
private final String fileName; // 日志文件名(如 myapp.log)
private final String path; // 日志文件路径(如 /var/log/myapp)
public LogFile(String fileName, String path) {
// fileName 优先级高于 path
this.fileName = (fileName != null) ? fileName
: path + "/spring.log"; // 默认文件名 spring.log
this.path = (path != null) ? path
: new File(fileName).getAbsoluteFile().getParent();
}
// 返回完整的日志文件路径
public File getFile() {
return new File(path, fileName);
}
}LogbackLoggingSystem 中配置文件 Appender:
public class LogbackLoggingSystem {
private static final String FILE_APPENDER_NAME = "FILE";
private static final String ROLLING_POLICY_BEAN_NAME = "rollingPolicy";
private void configureFileAppender(LoggerContext context, LogFile logFile) {
// 1. 创建 RollingFileAppender
RollingFileAppender<ILoggingEvent> appender = new RollingFileAppender<>();
appender.setContext(context);
appender.setName(FILE_APPENDER_NAME);
appender.setFile(logFile.getFile().toString());
// 2. 创建 SizeAndTimeBasedRollingPolicy
SizeAndTimeBasedRollingPolicy<ILoggingEvent> rollingPolicy =
new SizeAndTimeBasedRollingPolicy<>();
rollingPolicy.setContext(context);
rollingPolicy.setParent(appender);
// 3. 配置文件名模式(按日期和序号滚动)
// 如: myapp.2026-07-26.0.log, myapp.2026-07-26.1.log
rollingPolicy.setFileNamePattern(
logFile.getFile().getAbsolutePath()
+ ".%d{yyyy-MM-dd}.%i.gz");
// 4. 设置单个文件大小上限(默认 10MB)
rollingPolicy.setMaxFileSize(
getRollingProperty("max-file-size", "10 MB"));
// 5. 设置最大历史天数(默认 7 天)
rollingPolicy.setMaxHistory(
Integer.parseInt(getRollingProperty("max-history", "7")));
// 6. 设置总日志大小上限(默认 1 GB)
rollingPolicy.setTotalSizeCap(
getRollingProperty("total-size-cap", "1 GB"));
rollingPolicy.start();
appender.setRollingPolicy(rollingPolicy);
// 7. 设置日志格式
appender.setEncoder(createEncoder(context));
appender.start();
// 8. 将 FILE Appender 添加到 Root Logger
Logger rootLogger = context.getLogger(Logger.ROOT_LOGGER_NAME);
rootLogger.addAppender(appender);
}
}配置属性与 Logback 映射:
| Spring Boot 属性 | Logback 属性 | 默认值 |
|---|---|---|
logging.logback.rollingpolicy.max-file-size | maxFileSize | 10 MB |
logging.logback.rollingpolicy.max-history | maxHistory | 7 |
logging.logback.rollingpolicy.total-size-cap | totalSizeCap | 1 GB |
logging.logback.rollingpolicy.file-name-pattern | fileNamePattern | ${file}.%d{yyyy-MM-dd}.%i.gz |
文件滚动示例:
# 日志目录结构
/var/log/myapp/
spring.log ← 当前活跃的日志文件
spring.2026-07-20.0.log.gz ← 7 月 20 日(7 天前的被清理)
spring.2026-07-21.0.log.gz
spring.2026-07-22.0.log.gz
spring.2026-07-23.0.log.gz ← 超过 1GB 总大小时,最旧的被删除
spring.2026-07-24.0.log.gz
spring.2026-07-25.0.log.gz
spring.2026-07-26.0.log ← 今日第 1 个
spring.2026-07-26.1.log ← 今日第 2 个(达到 10MB 后滚动)滚动触发时机:
文件写入 → 判断文件大小 ≥ 10MB? → 否 → 继续写入当前文件
→ 是 → 创建新文件 .1.log
→ 将当前文件压缩为 .0.log.gz
→ 检查 maxHistory(7 天)→ 删除过期文件
→ 检查 totalSizeCap(1GB)→ 从最旧开始删除总结
日志系统自动配置的 8 个细节点总结如下:
| # | 细节点 | 核心类/机制 |
|---|---|---|
| ① | LoggingApplicationListener 的 onApplicationStartingEvent() 监听 | 在 ApplicationStartingEvent 发生时初始化日志,优先级最高 |
| ② | LoggingSystemFactory 的 SPI 加载 | 从 spring.factories 加载所有 LoggingSystemFactory → 按 classpath 检测 |
| ③ | LogbackLoggingSystem 的日志配置加载 | logback-test.xml → logback-spring.xml → logback.xml → 内置 base.xml |
| ④ | Spring Boot 的日志配置属性 | logging.level.* / logging.pattern.* / logging.file.* 映射到 Logback 系统属性 |
| ⑤ | LoggerConfiguration 的运行时修改 | LoggingSystem.setLogLevel() → Logback Logger.setLevel(),Actuator 端点支持 |
| ⑥ | LoggerGroups 的批量管理 | logging.group.tomcat=org.apache.catalina,... → 一次配置一组成员的级别 |
| ⑦ | Logback 的 springProperty 扩展 | <springProperty name="appName" source="spring.application.name"/> 读取 Spring 属性 |
| ⑧ | LogFile 的文件滚动策略 | SizeAndTimeBasedRollingPolicy → maxHistory / totalSizeCap / maxFileSize |