1. Logback基础配置与快速上手第一次接触Logback时我被它的零配置特性惊艳到了。作为log4j的继承者它确实在易用性上做了很多改进。记得当时我刚把一个Spring Boot项目从Log4j迁移到Logback整个过程只用了不到10分钟。最简单的控制台日志输出只需要在pom.xml中添加logback-classic依赖dependency groupIdch.qos.logback/groupId artifactIdlogback-classic/artifactId version1.3.0/version /dependency然后在代码中直接使用SLF4J的APIprivate static final Logger logger LoggerFactory.getLogger(MyClass.class); public void doSomething() { logger.debug(调试信息); logger.info(业务操作记录); logger.error(错误警报, new RuntimeException(测试异常)); }这时候你会发现控制台已经输出了格式化的日志信息。这是因为Logback在没有配置文件时会自动使用BasicConfigurator进行最小化配置。这种默认配置相当于configuration appender nameSTDOUT classch.qos.logback.core.ConsoleAppender encoder pattern%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n/pattern /encoder /appender root levelDEBUG appender-ref refSTDOUT / /root /configuration在实际项目中我建议即使是开发环境也至少配置一个简单的logback.xml文件。有次我在排查一个线上问题时发现开发环境能看到的DEBUG日志在生产环境全部消失了就是因为生产环境用了默认的INFO级别。基础配置应该明确指定日志级别避免环境差异带来的困扰。2. 日志输出到文件的完整方案当项目进入测试阶段后仅靠控制台日志就远远不够了。这时候我们需要配置文件日志输出。根据我的经验文件日志配置有几个关键点需要注意首先是日志文件的存放位置。新手常犯的错误是使用相对路径property nameLOG_DIR value./logs / !-- 不推荐 --这会导致日志文件出现在不同目录下取决于启动路径。建议使用绝对路径或者在Spring Boot项目中可以这样配置property nameLOG_DIR value${user.home}/app_logs /按天滚动日志是最常用的策略配置示例如下appender nameFILE classch.qos.logback.core.rolling.RollingFileAppender file${LOG_DIR}/app.log/file rollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicy fileNamePattern${LOG_DIR}/app.%d{yyyy-MM-dd}.log/fileNamePattern maxHistory30/maxHistory /rollingPolicy encoder pattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n/pattern /encoder /appender这里有几个实用技巧maxHistory设置日志保留天数避免磁盘被占满初始日志文件名与滚动文件名分开配置便于日志采集工具监控生产环境建议加上prudenttrue/prudent确保多JVM写入同一文件时的安全性对于高并发系统我推荐按大小和时间双重滚动策略rollingPolicy classch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy fileNamePattern${LOG_DIR}/app.%d{yyyy-MM-dd}.%i.log/fileNamePattern maxFileSize100MB/maxFileSize maxHistory30/maxHistory totalSizeCap5GB/totalSizeCap /rollingPolicy3. 精细化日志控制策略随着项目规模扩大我们需要更精细的日志控制。Logback的Logger继承体系非常强大但容易踩坑。假设我们有如下包结构com └── example ├── service │ ├── UserService.java │ └── OrderService.java └── web └── UserController.java对应的日志配置可以是logger namecom.example.web levelDEBUG/ logger namecom.example.service levelINFO/ logger nameorg.springframework levelWARN/ logger nameorg.hibernate.SQL levelDEBUG/这里有个常见的坑点additivity属性。默认情况下Logger会继承父Logger的Appender导致日志重复输出。比如logger namecom.example.web levelDEBUG appender-ref refWEB_FILE / /logger root levelINFO appender-ref refFILE / /root这样com.example.web的日志会同时输出到WEB_FILE和FILE。解决方法logger namecom.example.web levelDEBUG additivityfalse appender-ref refWEB_FILE / /logger另一个实用技巧是MDCMapped Diagnostic Context可以在日志中嵌入上下文信息MDC.put(userId, 12345); logger.info(用户操作); MDC.remove(userId);然后在pattern中加入%X{userId}pattern%d{ISO8601} [%thread] [%X{userId}] %-5level %logger{36} - %msg%n/pattern4. 高性能异步日志实现当系统QPS达到一定规模时同步日志会成为性能瓶颈。这时候就需要异步日志出场了。根据我的压力测试结果合理配置的异步日志可以将日志性能提升5-10倍。基础异步配置很简单appender nameASYNC_FILE classch.qos.logback.classic.AsyncAppender appender-ref refFILE / /appender但这样的配置在高负载下会有两个问题队列满时会丢弃TRACE/DEBUG级别的日志默认队列大小(256)可能不够优化后的配置应该这样appender nameASYNC_FILE classch.qos.logback.classic.AsyncAppender appender-ref refFILE / queueSize1024/queueSize discardingThreshold0/discardingThreshold includeCallerDatatrue/includeCallerData /appender关键参数说明queueSize: 根据系统吞吐量调整一般设置为每秒最大日志量的2-3倍discardingThreshold: 设为0表示队列剩余20%空间时就丢弃DEBUG级别日志避免阻塞includeCallerData: 获取调用者信息会有性能损耗只在必要时开启对于核心业务日志我建议使用同步异步混合模式appender nameIMPORTANT_LOG classch.qos.logback.core.rolling.RollingFileAppender !-- 重要日志同步写入 -- /appender appender nameASYNC_DEBUG classch.qos.logback.classic.AsyncAppender !-- 调试日志异步写入 -- /appender logger namecom.example.order levelDEBUG additivityfalse appender-ref refIMPORTANT_LOG / appender-ref refASYNC_DEBUG / /logger最后分享一个真实案例某次大促前我们发现日志系统成为瓶颈。通过将日志改为异步并调整队列参数系统吞吐量从800QPS提升到了2500QPS。关键配置是appender nameASYNC classch.qos.logback.classic.AsyncAppender appender-ref refFILE / queueSize2048/queueSize discardingThreshold0/discardingThreshold maxFlushTime2000/maxFlushTime /appender记得在调整异步日志参数后一定要进行充分的压力测试确保不会因为日志队列堆积导致内存溢出。