当前位置: 首页 > news >正文

Spring Boot 日志体系 Logback + SLF4J 深入剖析

📑Spring Boot 日志体系 Logback + SLF4J 深入剖析

文章目录

  • 📑Spring Boot 日志体系 Logback + SLF4J 深入剖析
  • 🎯 一、概述:为什么使用抽象层 SLF4J?
    • 💡 日志抽象层的重要性
  • 🔄 二、SLF4J → Logback:职责与关系
    • 🏗️ SLF4J + Logback 协作架构
  • ⚙️ 三、Logback 核心组件解析
    • 🔧 Logback 架构核心
    • 📊 核心组件详解
  • 🚀 四、Spring Boot 默认日志引导
    • 📦 Spring Boot 日志自动配置
  • 💻 五、Logback 配置实战
    • ⚙️ 完整的 logback-spring.xml 配置
    • 🔧 条件化配置(Profile 特定)
  • 🔍 六、MDC 与分布式追踪日志关联
    • 🎯 MDC 在分布式系统中的应用
    • 🔄 异步环境下的 MDC 传递
    • 📊 结构化日志输出配置
  • 📊 七、日志切割与归档策略
    • ⏰ 基于时间的滚动策略
    • 📏 大小+时间混合策略
  • ⚡ 八、日志性能优化技巧
    • 🚀 异步日志配置最佳实践
    • 📈 日志采样配置
  • 🔒 九、日志安全与合规
    • 🛡️ 日志脱敏配置
    • 📝 安全审计日志
  • 🐛 十、生产排查范例
    • 🔧 常用日志分析命令
    • 📊 Spring Boot Actuator 日志管理
  • 🔄 十一、替换实现与高级主题
    • 📦 切换至 Log4J2

🎯 一、概述:为什么使用抽象层 SLF4J?

💡 日志抽象层的重要性

​​SLF4J 的架构价值​​:

应用程序
SLF4J API
Logback 绑定
Log4J2 绑定
JUL 绑定
Logback 实现
Log4J2 实现
Java Util Logging

​​SLF4J 的优势对比​​:

// ❌ 传统方式:直接绑定具体实现
import org.apache.log4j.Logger;
public class OldService {private static final Logger logger = Logger.getLogger(OldService.class);
}// ✅ SLF4J 方式:面向接口编程
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ModernService {private static final Logger logger = LoggerFactory.getLogger(ModernService.class);
}

抽象层的实际收益​​:

  • ​​实现无关性​​:无需修改代码即可切换日志实现 ​​
  • 统一的 API​​:一致的编程体验 ​​
  • 桥接旧系统​​:通过适配器兼容
  • Log4J、JUL 等 ​​性能优化​​:参数化日志语句避免不必要的字符串拼接

🔄 二、SLF4J → Logback:职责与关系

🏗️ SLF4J + Logback 协作架构

​​组件协作流程图​​:

ApplicationSLF4J APILoggerFactoryLogback BindingLogback LoggerLogback ContextAppenderLoggerFactory.getLogger()获取ILoggerFactory返回LogbackLoggerFactory获取/创建Logger返回LogbackLogger实例logger.info("Message")过滤、级别检查调用Appender格式化、输出ApplicationSLF4J APILoggerFactoryLogback BindingLogback LoggerLogback ContextAppender

​​Spring Boot 日志依赖树​​:

<!-- spring-boot-starter-logging 依赖关系 -->
<dependencies><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId>  <!-- SLF4J 实现 + Logback --></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-to-slf4j</artifactId>   <!-- Log4J2 → SLF4J 桥接 --></dependency><dependency><groupId>org.slf4j</groupId><artifactId>jul-to-slf4j</artifactId>       <!-- JUL → SLF4J 桥接 --></dependency>
</dependencies>

⚙️ 三、Logback 核心组件解析

🔧 Logback 架构核心

​​组件关系图​​:

1..n
0..1
0..1
0..n
«interface»
Logger
+trace(), debug(), info(), warn(), error()
+getName() : String
+getLevel() : Level
«interface»
Appender
+doAppend(ILoggingEvent event)
+setLayout(Layout layout)
+addFilter(Filter filter)
«interface»
Layout
+doLayout(ILoggingEvent event) : String
«interface»
Encoder
+encode(ILoggingEvent event) : byte[]
«interface»
Filter
+decide(ILoggingEvent event) : FilterReply

📊 核心组件详解

​​Logger 层次结构​​:

// Logback 的 Logger 层次结构示例
Logger rootLogger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
Logger comLogger = LoggerFactory.getLogger("com");
Logger comExampleLogger = LoggerFactory.getLogger("com.example");
Logger comExampleServiceLogger = LoggerFactory.getLogger("com.example.Service");// 层次关系:root → com → com.example → com.example.Service
// 级别继承:子Logger继承父Logger的级别(除非显式设置)

​​Appender 附加器类型​​:

// 常用 Appender 实现
ConsoleAppender    // 控制台输出
FileAppender       // 文件输出
RollingFileAppender // 滚动文件输出
SMTPAppender       // 邮件发送
DBAppender         // 数据库存储
SocketAppender     // 网络套接字

🚀 四、Spring Boot 默认日志引导

📦 Spring Boot 日志自动配置

​​Logback 自动配置流程​​:

@Configuration
@ConditionalOnClass(Logger.class)
@EnableConfigurationProperties(LoggingProperties.class)
public class LogbackAutoConfiguration {@Bean@ConditionalOnMissingBeanpublic LoggingSystem loggingSystem() {return new LogbackLoggingSystem();}@Beanpublic LoggingApplicationListener loggingApplicationListener() {return new LoggingApplicationListener();}
}

​​Spring Boot 日志属性绑定​​:

# application.yml 日志配置
logging:level:root: INFOcom.example: DEBUGorg.springframework.web: INFOorg.hibernate.SQL: DEBUGfile:name: logs/app.log    # 日志文件路径max-size: 10MB        # 单个文件最大大小max-history: 30       # 保留天数pattern:console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n"file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"logback:rollingpolicy:max-file-size: 10MBclean-history-on-start: false

💻 五、Logback 配置实战

⚙️ 完整的 logback-spring.xml 配置

​​生产级 Logback 配置​​:

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds"><!-- 属性定义 --><property name="APP_NAME" value="my-application"/><property name="LOG_PATH" value="logs"/><property name="LOG_LEVEL" value="INFO"/><!-- 控制台输出 --><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern><charset>UTF-8</charset></encoder><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>DEBUG</level></filter></appender><!-- 异步文件输出 --><appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender"><discardingThreshold>0</discardingThreshold><queueSize>1024</queueSize><neverBlock>true</neverBlock><appender-ref ref="FILE"/></appender><!-- 文件输出(JSON格式) --><appender name="FILE_JSON" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${LOG_PATH}/${APP_NAME}.json</file><encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder"><providers><timestamp><timeZone>UTC</timeZone></timestamp><logLevel/><loggerName/><message/><mdc/><stackTrace><throwableConverter class="net.logstash.logback.stacktrace.ShortenedThrowableConverter"><maxDepthPerThrowable>30</maxDepthPerThrowable><maxLength>2048</maxLength><shortenedClassNameLength>20</shortenedClassNameLength><rootCauseFirst>true</rootCauseFirst></throwableConverter></stackTrace><pattern><pattern>{"app": "${APP_NAME}", "thread": "%thread"}</pattern></pattern></providers></encoder><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><fileNamePattern>${LOG_PATH}/archive/${APP_NAME}-%d{yyyy-MM-dd}.%i.json.gz</fileNamePattern><maxFileSize>100MB</maxFileSize><maxHistory>30</maxHistory><totalSizeCap>3GB</totalSizeCap></rollingPolicy></appender><!-- 错误日志单独输出 --><appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${LOG_PATH}/error.log</file><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.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${LOG_PATH}/archive/error-%d{yyyy-MM-dd}.log.gz</fileNamePattern><maxHistory>90</maxHistory></rollingPolicy></appender><!-- 日志采样:高流量时减少日志量 --><appender name="SAMPLING" class="ch.qos.logback.classic.AsyncAppender"><appender-ref ref="CONSOLE"/><filter class="ch.qos.logback.core.filter.EvaluatorFilter"><evaluator><expression>(System.currentTimeMillis() - Long.valueOf(loggerContext.getObject("lastLogTime"))) > 1000</expression></evaluator><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter></appender><!-- Root Logger 配置 --><root level="${LOG_LEVEL}"><appender-ref ref="ASYNC_FILE"/><appender-ref ref="ERROR_FILE"/><if condition='property("spring.profiles.active").contains("dev")'><then><appender-ref ref="CONSOLE"/></then></if></root><!-- 特定包日志级别 --><logger name="com.example.service" level="DEBUG" additivity="false"><appender-ref ref="FILE_JSON"/></logger><logger name="org.hibernate.SQL" level="DEBUG" additivity="false"><appender-ref ref="SQL_FILE"/></logger>
</configuration>

🔧 条件化配置(Profile 特定)

​​logback-spring.xml 中的 Profile 支持​​:


<!-- 开发环境配置 -->
<springProfile name="dev"><logger name="com.example" level="DEBUG"/><include resource="console-appender.xml"/>
</springProfile><!-- 生产环境配置 -->
<springProfile name="prod"><logger name="com.example" level="INFO"/><include resource="json-appender.xml"/><!-- 生产环境启用监控 --><jmxConfigurator/>
</springProfile><!-- 条件判断 -->
<if condition='property("LOG_ASYNC").equals("true")'><then><appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"><!-- 异步配置 --></appender></then>
</if>

🔍 六、MDC 与分布式追踪日志关联

🎯 MDC 在分布式系统中的应用

​​MDC 设置与清理模式​​:

@Component
@Slf4j
public class DistributedLoggingService {/*** 在请求入口处设置 MDC*/@Componentpublic static class LoggingFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {try {// 1. 生成追踪IDString traceId = generateTraceId();String spanId = generateSpanId();// 2. 设置 MDC 上下文MDC.put("traceId", traceId);MDC.put("spanId", spanId);MDC.put("userId", getCurrentUserId());MDC.put("clientIp", getClientIp(request));// 3. 记录请求开始log.info("Request started: {} {}", ((HttpServletRequest) request).getMethod(),((HttpServletRequest) request).getRequestURI());chain.doFilter(request, response);} finally {// 4. 清理 MDC(重要!避免内存泄漏)MDC.clear();}}}/*** 业务服务中使用 MDC*/@Servicepublic static class BusinessService {public void processOrder(Order order) {// 自动包含 MDC 信息log.info("Processing order: {}", order.getId());try {inventoryService.checkStock(order);paymentService.processPayment(order);log.info("Order processed successfully");} catch (Exception e) {log.error("Order processing failed", e);throw e;}}}
}

🔄 异步环境下的 MDC 传递

​​线程池 MDC 传递解决方案​​:

@Configuration
@Slf4j
public class MdcAwareThreadPoolConfig {/*** 支持 MDC 传递的 ThreadPoolTaskExecutor*/@Beanpublic ThreadPoolTaskExecutor mdcAwareTaskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(10);executor.setMaxPoolSize(50);executor.setQueueCapacity(1000);executor.setThreadNamePrefix("MDC-Aware-");executor.setTaskDecorator(new MdcTaskDecorator());executor.initialize();return executor;}/*** MDC 任务装饰器*/public static class MdcTaskDecorator implements TaskDecorator {@Overridepublic Runnable decorate(Runnable runnable) {// 捕获当前线程的 MDCMap<String, String> context = MDC.getCopyOfContextMap();return () -> {try {// 在新线程中恢复 MDCif (context != null) {MDC.setContextMap(context);}runnable.run();} finally {MDC.clear();}};}}/*** @Async 异步方法支持*/@Async("mdcAwareTaskExecutor")public CompletableFuture<String> asyncProcess(String data) {log.info("Processing asynchronously with traceId: {}", MDC.get("traceId"));// 异步处理逻辑return CompletableFuture.completedFuture("processed");}
}

📊 结构化日志输出配置

​​JSON 日志格式配置​​:

<!-- 专用于 ELK 的 JSON 输出 -->
<appender name="ELK_JSON" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>logs/elk.json</file><encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder"><providers><!-- 时间戳 --><timestamp><fieldName>@timestamp</fieldName><timeZone>UTC</timeZone></timestamp><!-- 日志级别 --><logLevel><fieldName>level</fieldName></logLevel><!-- 日志内容 --><message><fieldName>message</fieldName></message><!-- 记录器名称 --><loggerName><fieldName>logger</fieldName></loggerName><!-- 线程信息 --><threadName><fieldName>thread</fieldName></threadName><!-- MDC 上下文 --><mdc><fieldName>context</fieldName></mdc><!-- 堆栈跟踪 --><stackTrace><fieldName>stack_trace</fieldName><throwableConverter class="net.logstash.logback.stacktrace.ShortenedThrowableConverter"><maxDepthPerThrowable>10</maxDepthPerThrowable></throwableConverter></stackTrace><!-- 自定义模式 --><pattern><pattern>{"app": "${APP_NAME}","env": "${SPRING_PROFILES_ACTIVE:-default}","version": "${APP_VERSION:-unknown}"}</pattern></pattern></providers></encoder>
</appender>

📊 七、日志切割与归档策略

⏰ 基于时间的滚动策略

​​TimeBasedRollingPolicy 配置​​:

<appender name="TIME_BASED" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>logs/application.log</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!-- 按天滚动,保留30天 --><fileNamePattern>logs/archive/application-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern><!-- 保留时间 --><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>

📏 大小+时间混合策略

​​SizeAndTimeBasedRollingPolicy 配置

<appender name="SIZE_TIME_BASED" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>logs/application.log</file><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!-- 按时间和大小滚动 --><fileNamePattern>logs/archive/application-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern><!-- 单个文件最大大小 --><maxFileSize>100MB</maxFileSize><!-- 保留天数 --><maxHistory>30</maxHistory><!-- 总大小限制 --><totalSizeCap>20GB</totalSizeCap></rollingPolicy><!-- 触发策略:立即滚动 --><triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"><maxFileSize>100MB</maxFileSize></triggeringPolicy>
</appender>

⚡ 八、日志性能优化技巧

🚀 异步日志配置最佳实践

​​高性能 AsyncAppender 配置​​:

<appender name="ASYNC_PERF" class="ch.qos.logback.classic.AsyncAppender"><!-- 不丢弃任何日志 --><discardingThreshold>0</discardingThreshold><!-- 队列大小(根据内存调整) --><queueSize>8192</queueSize><!-- 永不阻塞(丢日志优于阻塞应用) --><neverBlock>true</neverBlock><!-- 包含调用者数据(性能开销,谨慎使用) --><includeCallerData>false</includeCallerData><!-- 最大刷新等待时间(秒) --><maxFlushTime>5</maxFlushTime><!-- 引用实际的Appender --><appender-ref ref="FILE_JSON"/>
</appender>

📈 日志采样配置

​​高流量场景下的采样策略​​:

<!-- 采样过滤器:每100条日志采样1条 -->
<appender name="SAMPLING" class="ch.qos.logback.core.rolling.RollingFileAppender"><filter class="ch.qos.logback.core.filter.SamplingFilter"><!-- 采样间隔 --><allowedSamplingPeriod>100</allowedSamplingPeriod></filter><!-- 其他配置 -->
</appender><!-- 基于时间的采样 -->
<appender name="TIME_SAMPLING" class="ch.qos.logback.core.rolling.RollingFileAppender"><filter class="ch.qos.logback.core.filter.EvaluatorFilter"><evaluator><expression>// 每秒最多记录10条相同级别的日志long lastTime = Long.parseLong(String.valueOf(loggerContext.getObject("LAST_LOG_TIME_" + level)) );int count = Integer.parseInt(String.valueOf(loggerContext.getObject("LOG_COUNT_" + level)));long currentTime = System.currentTimeMillis();if (currentTime - lastTime > 1000) {loggerContext.putObject("LAST_LOG_TIME_" + level, currentTime);loggerContext.putObject("LOG_COUNT_" + level, 1);return true;} else {int newCount = count + 1;loggerContext.putObject("LOG_COUNT_" + level, newCount);return newCount <= 10;}</expression></evaluator><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter>
</appender>

🔒 九、日志安全与合规

🛡️ 日志脱敏配置

​​敏感信息过滤配置​​:

<!-- 日志脱敏过滤器 -->
<appender name="SECURE_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><filter class="com.example.SensitiveDataFilter"/><encoder><pattern>%msg%n</pattern></encoder>
</appender><!-- 自定义脱敏过滤器 -->
public class SensitiveDataFilter extends Filter<ILoggingEvent> {private static final Pattern PATTERN = Pattern.compile("(\"password\":\")([^\"]+)(\")|(\\b\\d{16}\\b)|(\\b\\d{3}-\\d{2}-\\d{4}\\b)");@Overridepublic FilterReply decide(ILoggingEvent event) {// 脱敏处理String message = event.getFormattedMessage();String sanitized = PATTERN.matcher(message).replaceAll("$1***$3");// 创建脱敏后的事件LoggingEvent sanitizedEvent = new LoggingEvent(event.getClass().getName(),(ch.qos.logback.classic.Logger) event.getLogger(),event.getLevel(),sanitized,event.getThrowableProxy(),event.getArgumentArray());return FilterReply.NEUTRAL;}
}

📝 安全审计日志

​​审计日志专用配置​​:

<!-- 审计日志专用Appender -->
<appender name="AUDIT" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>logs/audit.log</file><!-- 审计日志立即刷盘,确保不丢失 --><immediateFlush>true</immediateFlush><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} | AUDIT | %msg%n</pattern></encoder><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>logs/archive/audit-%d{yyyy-MM-dd}.log</fileNamePattern><maxHistory>365</maxHistory> <!-- 审计日志保留1年 --></rollingPolicy>
</appender><!-- 审计日志Logger -->
<logger name="AUDIT_LOGGER" level="INFO" additivity="false"><appender-ref ref="AUDIT"/>
</logger>

🐛 十、生产排查范例

🔧 常用日志分析命令

​​实时日志监控​​:

# 1. 实时跟踪日志
tail -f logs/application.log# 2. 查找错误日志
grep -E "ERROR|Exception" logs/application.log# 3. 按时间范围搜索
sed -n '/2023-10-01 14:00:00/,/2023-10-01 15:00:00/p' logs/application.log# 4. JSON日志分析
cat logs/elk.json | jq '. | select(.level == "ERROR")'# 5. 统计错误数量
grep -c "ERROR" logs/application.log# 6. 查找慢请求(耗时大于1秒)
grep "Processing time" logs/application.log | awk '$NF > 1000 {print}'# 7. 追踪特定请求
grep "traceId:abc-123" logs/application.log# 8. 内存使用分析
jq 'select(.message | contains("GC"))' logs/elk.json

​​性能问题排查脚本​​:

#!/bin/bash
# analyze_logs.sh - 日志分析工具LOG_FILE=$1
TRACE_ID=$2analyze_slow_requests() {echo "=== 慢请求分析 ==="grep "Processing time" $LOG_FILE | awk '$NF > 1000 { count++; total+=$NF; if ($NF > max) max=$NF } END { print "总慢请求:", count; print "平均耗时:", total/count, "ms"; print "最大耗时:", max, "ms" }'
}analyze_errors() {echo "=== 错误分析 ==="grep -c "ERROR" $LOG_FILE | awk '{print "总错误数:", $1}'echo "=== 异常类型统计 ==="grep -oE "[A-Za-z]*Exception" $LOG_FILE | sort | uniq -c | sort -nr
}trace_request() {echo "=== 请求追踪: $TRACE_ID ==="grep $TRACE_ID $LOG_FILE | while read line; dotimestamp=$(echo $line | cut -d' ' -f1,2)service=$(echo $line | grep -oE '\[[^]]+\]' | head -2 | tail -1)echo "$timestamp $service - $line"done
}# 执行分析
analyze_slow_requests
analyze_errors
if [ ! -z "$TRACE_ID" ]; thentrace_request
fi

📊 Spring Boot Actuator 日志管理

​​动态日志级别调整​​:

# application.yml
management:endpoints:web:exposure:include: loggers,metrics,healthendpoint:loggers:enabled: true# 动态调整日志级别
curl -X POST http://localhost:8080/actuator/loggers/com.example \-H "Content-Type: application/json" \-d '{"configuredLevel": "DEBUG"}'# 查看当前日志级别
curl http://localhost:8080/actuator/loggers

🔄 十一、替换实现与高级主题

📦 切换至 Log4J2

​​Maven 依赖调整​​:

<!-- 排除默认的 Logback -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions>
</dependency><!-- 添加 Log4J2 Starter -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

​​Log4J2 配置示例​​:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN"><Appenders><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/></Console><RollingFile name="RollingFile" fileName="logs/app.log"filePattern="logs/archive/app-%d{yyyy-MM-dd}-%i.log.gz"><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/><Policies><TimeBasedTriggeringPolicy /><SizeBasedTriggeringPolicy size="100 MB"/></Policies></RollingFile></Appenders><Loggers><Root level="info"><AppenderRef ref="Console"/><AppenderRef ref="RollingFile"/></Root></Loggers>
</Configuration>
http://www.dtcms.com/a/541402.html

相关文章:

  • Perl 格式化输出
  • 网站建设三种方法广州h5网站制作
  • 一文讲透BOM、MRP、WMS
  • ai最新的发展趋势有哪些
  • 简化AI服务构建的Python框架leptonai
  • 解决 Vray for 3ds Max 三大常见生产问题,提升渲染工作流效率
  • 做网站搭建环境网站建设在学校中的作用
  • 优秀的网站建设吉林建设厅官方网站
  • STM32H742-ARM例程32-LCD
  • 基于谱图特征解析与机器学习模型融合的非靶向污染物识别策略
  • 下载| Windows 11 ARM版10月官方ISO系统映像 (适合部分笔记本、苹果M系列芯片电脑、树莓派和部分安卓手机平板)
  • 【u-boot】重定位(ARM32)-relocate_code
  • Java Web 开发的核心组件:Servlet, JSP,Filter,Listener
  • 怎么做qq分享网站深圳中瑞建设集团官方网站
  • 20251028在荣品RD-RK3588-MID开发板的Android13系统下解决关机的时候最近打开的应用不关的问题
  • 网站建设功能套餐表怎样创建网站桌面快捷方式
  • 当 Claude Code 登陆浏览器:我们如何用 Gateone.ai 把“移动编码”从炫技变成生产力核弹
  • Labview多种通信集合
  • 炫酷文字制作网站网站建设最快多长时间
  • 【自然资源】宅地基误划为永久基本农田怎么办?
  • Python:批量下载已知gene symbol蛋白的PDB文件
  • 废旧台式机变身私有NAS
  • 探索Agent工具调用时的高熵时刻
  • c 转网站开发电脑培训网上培训班
  • 2022/07 JLPT听力原文 问题四
  • 互联网网站运营网站建设博客作业
  • 破解多数据库并存难题!电科金仓异构多活架构铸就安全底座
  • 网站在线解压小程序入口qq浏览器
  • 中国工程项目网站网站模版带后台
  • JavaWeb后端-MySQL