logback实战详解fileNamePattern配置问题%d多级日期文件夹

logback实战详解fileNamePattern配置问题%d多级日期文件夹

为什么写这个呢?

因为我遇到了一个问题多个%d的问题,日志文件要么不按照日期文件目录划分,要么日志文件名字不变,结果处理了好久

原来是因为logback只会根据第一个%d去划分,所以需要忽略前面的%d,添加一个

,aux

很关键,这样他就会忽略前面的按照后面的来滚动划分,具体看实战案例

以下是 基于Logback 1.5.12logback.xml完整配置详解,涵盖核心组件、常用场景和该版本的注意事项。

实战案例

及其简略的案例,可以生产直接使用

<?xml version="1.0" encoding="utf-8"?> <configuration> <contextName>com.cmit</contextName> <property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L -[%X{TRACE_ID}] - %msg %n"/> <property name="LOG_HOME" value="logs"/> <property name="PROJECT_NAME" value="project-name"/> <property name="MAX_FILE_SIZE" value="10MB" /> <property name="MAX_HISTORY" value="200" /> <!-- 控制台输出 --> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>${pattern}</pattern> </encoder> </appender> <!-- 文件输出 --> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_HOME}/${PROJECT_NAME}.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <fileNamePattern>${LOG_HOME}/%d{yyyy-MM,aux}/${PROJECT_NAME}/${PROJECT_NAME}-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern> <maxFileSize>${MAX_FILE_SIZE}</maxFileSize> <maxHistory>${MAX_HISTORY}</maxHistory> <cleanHistoryOnStart>true</cleanHistoryOnStart> </rollingPolicy> <encoder> <pattern>${pattern}</pattern> </encoder> </appender> <root level="INFO"> <appender-ref ref="CONSOLE"/> <appender-ref ref="FILE"/> </root> </configuration>

文件基础结构

<?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- 属性定义 --> <property name="LOG_HOME" value="./logs"/> <property name="APP_NAME" value="myapp"/> <!-- Appender 定义 --> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> ... </appender> <!-- Logger 定义 --> <logger name="com.example" level="DEBUG"/> <!-- 根 Logger --> <root level="INFO"> <appender-ref ref="CONSOLE"/> </root> </configuration>

核心组件详解

<configuration>根标签属性

属性说明示例
scan是否自动扫描配置文件变更scan="true"
scanPeriod扫描间隔,默认 60 秒scanPeriod="30 seconds"
debug是否打印 logback 内部状态debug="false"
<configuration scan="true" scanPeriod="30 seconds" debug="false">

<property>属性定义

<!-- 直接定义 --> <property name="LOG_PATH" value="/var/log/myapp"/> <!-- 引用系统属性 --> <property name="LOG_PATH" value="${user.home}/logs"/> <!-- 默认值语法(属性不存在时使用默认值) --> <property name="LOG_LEVEL" value="${LOG_LEVEL:-INFO}"/>

Appender 详解

ConsoleAppender(控制台输出)

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <!-- 日志立即刷新,性能会略降但确保不丢失 --> <immediateFlush>true</immediateFlush> <!-- 编码器 --> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> <charset>UTF-8</charset> </encoder> <!-- 过滤器:只输出 INFO 及以上 --> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter> </appender>

常用 Pattern 符号:

符号含义
%d{...}日期时间
%thread线程名
%-5level日志级别,左对齐占5字符
%logger{36}Logger 名,最长36字符
%msg/%m日志消息
%n换行
%line/%L输出代码行号(性能开销大,生产慎用
%M方法名(性能开销大

FileAppender(单文件输出)

<appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>${LOG_HOME}/app.log</file> <append>true</append> <!-- true=追加,false=覆盖 --> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %level %logger - %msg%n</pattern> </encoder> </appender>

RollingFileAppender(滚动日志)⭐最常用

<appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 当前正在写入的文件 --> <file>${LOG_HOME}/app.log</file> <!-- 滚动策略 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 归档文件名格式,%d 触发按天滚动 --> <fileNamePattern>${LOG_HOME}/app.%d{yyyy-MM-dd}.log</fileNamePattern> <!-- 保留最近 30 天的归档日志 --> <maxHistory>30</maxHistory> <!-- 启动时清理超期日志 --> <cleanHistoryOnStart>true</cleanHistoryOnStart> <!-- 单个归档文件最大 100MB(TimeBasedRollingPolicy 不支持,需用 SizeAndTimeBasedRollingPolicy) --> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender>

SizeAndTimeBasedRollingPolicy(按时间和大小双重滚动)⭐推荐

<appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_HOME}/app.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!-- %i 是序号,同一天内超过大小则递增 --> <fileNamePattern>${LOG_HOME}/app.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!-- 单个文件最大 100MB --> <maxFileSize>100MB</maxFileSize> <!-- 保留 30 天的日志 --> <maxHistory>30</maxHistory> <!-- 所有日志总大小上限(防止磁盘满) --> <totalSizeCap>10GB</totalSizeCap> <!-- 启动时清理 --> <cleanHistoryOnStart>true</cleanHistoryOnStart> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender>

注意SizeAndTimeBasedRollingPolicyTimeBasedRollingPolicy的子类,功能更强大,生产环境建议直接使用这个

Logger 层级配置

<!-- 设置特定包的日志级别 --> <logger name="com.example.dao" level="DEBUG" additivity="false"> <appender-ref ref="CONSOLE"/> <appender-ref ref="ROLLING_FILE"/> </logger> <!-- Spring 框架日志 --> <logger name="org.springframework" level="WARN"/> <logger name="org.springframework.jdbc" level="DEBUG"/> <!-- MyBatis 日志 --> <logger name="com.ibatis" level="DEBUG"/> <logger name="java.sql" level="DEBUG"/> <!-- 根 Logger,所有日志的默认配置 --> <root level="INFO"> <appender-ref ref="CONSOLE"/> <appender-ref ref="ROLLING_FILE"/> </root>

additivity="false"的重要性:

  • true(默认):日志会同时输出到当前 logger 的 appender 和父 logger(root)的 appender,导致重复打印

  • false:只输出到当前 logger 配置的 appender

过滤器(Filter)

<!-- 级别过滤器:精确匹配级别 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <!-- 阈值过滤器:该级别及以上通过 --> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>WARN</level> </filter>

高级配置

异步日志(AsyncAppender)

<!-- 先定义同步 appender --> <appender name="FILE_SYNC" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_HOME}/app.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <fileNamePattern>${LOG_HOME}/app.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <maxFileSize>100MB</maxFileSize> <maxHistory>30</maxHistory> </rollingPolicy> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <!-- 包装为异步 appender --> <appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender"> <!-- 队列大小,默认 256 --> <queueSize>512</queueSize> <!-- 队列满时的策略:false=丢弃,true=阻塞 --> <discardingThreshold>0</discardingThreshold> <!-- 不丢失日志事件 --> <neverBlock>false</neverBlock> <!-- 引用同步 appender --> <appender-ref ref="FILE_SYNC"/> </appender> <root level="INFO"> <appender-ref ref="ASYNC_FILE"/> </root>

按日志级别分离文件

<!-- INFO 及以上 --> <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_HOME}/info.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_HOME}/info.%d{yyyy-MM-dd}.log</fileNamePattern> <maxHistory>30</maxHistory> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} %level %logger - %msg%n</pattern> </encoder> </appender> <!-- 仅 ERROR --> <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_HOME}/error.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_HOME}/error.%d{yyyy-MM-dd}.log</fileNamePattern> <maxHistory>90</maxHistory> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %logger{36} - %msg%n%ex{full}</pattern> </encoder> </appender>

彩色控制台输出(Logback 1.5.x 支持)

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} %highlight(%-5level) %cyan(%logger{36}) - %msg%n</pattern> </encoder> </appender>

高亮颜色:

  • %highlight():根据级别自动着色(ERROR=红,WARN=黄,INFO=绿等)

  • %cyan()%magenta()%yellow()

Logback 1.5.x 版本注意事项

安全性增强

  • 1.5.x 修复了CVE-2023-6378(序列化漏洞)等安全问题

  • 建议确保logback.xml不要配置从 JNDI / 远程加载配置,避免被利用

maxHistorycleanHistoryOnStart的行为

  • maxHistory归档文件时间戳计算,不是按文件创建时间

  • cleanHistoryOnStart=true只在应用启动时执行一次清理

  • 如果应用长期不重启,超期文件不会被自动清理(需依赖定时任务或确保会重启)

推荐的最小完整配置

<?xml version="1.0" encoding="UTF-8"?> <configuration scan="true" scanPeriod="60 seconds" debug="false"> <property name="LOG_HOME" value="${user.home}/logs/myapp"/> <property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"/> <!-- 控制台 --> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} %highlight(%-5level) %cyan(%logger{36}) - %msg%n</pattern> <charset>UTF-8</charset> </encoder> </appender> <!-- 文件滚动 --> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_HOME}/app.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <fileNamePattern>${LOG_HOME}/app.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <maxFileSize>100MB</maxFileSize> <maxHistory>30</maxHistory> <totalSizeCap>5GB</totalSizeCap> <cleanHistoryOnStart>true</cleanHistoryOnStart> </rollingPolicy> <encoder> <pattern>${LOG_PATTERN}</pattern> <charset>UTF-8</charset> </encoder> </appender> <!-- 第三方框架降噪 --> <logger name="org.springframework" level="WARN"/> <logger name="org.apache.http" level="WARN"/> <logger name="com.zaxxer.hikari" level="INFO"/> <root level="INFO"> <appender-ref ref="CONSOLE"/> <appender-ref ref="FILE"/> </root> </configuration>