## 1. 简介

Logback是由log4j的创始人Ceki Gülcü设计的日志框架,是SLF4J的原生实现。它分为三个模块:

  • logback-core: 核心模块,为其他两个模块奠定基础
  • logback-classic: 完整实现了SLF4J API
  • logback-access: 与Servlet容器集成,提供HTTP访问日志功能

2. 依赖配置

Maven依赖

<dependencies>
    <!-- Logback Classic (包含core) -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.4.14</version>
    </dependency>
    
    <!-- SLF4J API (通常已被logback-classic包含) -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>2.0.9</version>
    </dependency>
</dependencies>

Gradle依赖

dependencies {
    implementation 'ch.qos.logback:logback-classic:1.4.14'
    implementation 'org.slf4j:slf4j-api:2.0.9'
}

3. 基本使用

3.1 简单示例

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogbackExample {
    private static final Logger logger = LoggerFactory.getLogger(LogbackExample.class);
    
    public static void main(String[] args) {
        logger.trace("这是TRACE级别日志");
        logger.debug("这是DEBUG级别日志");
        logger.info("这是INFO级别日志");
        logger.warn("这是WARN级别日志");
        logger.error("这是ERROR级别日志");
        
        // 带参数的日志
        String name = "张三";
        int age = 25;
        logger.info("用户信息: 姓名={}, 年龄={}", name, age);
        
        // 异常日志
        try {
            int result = 10 / 0;
        } catch (Exception e) {
            logger.error("计算出错", e);
        }
    }
}

3.2 日志级别

Logback支持以下日志级别(从低到高):

  • TRACE: 最详细的信息,通常只在开发时使用
  • DEBUG: 调试信息
  • INFO: 一般信息
  • WARN: 警告信息
  • ERROR: 错误信息

4. 配置文件

4.1 配置文件查找顺序

Logback按以下顺序查找配置文件:

  1. logback-test.xml (测试环境)
  2. logback.groovy
  3. logback.xml
  4. 如果都没找到,使用默认配置

4.2 基本配置示例 (logback.xml)

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 控制台输出 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    
    <!-- 文件输出 -->
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>logs/application.log</file>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    
    <!-- 根日志器 -->
    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="FILE"/>
    </root>
</configuration>

5. 高级配置

5.1 滚动文件配置

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 滚动文件输出 -->
    <appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/application.log</file>
        
        <!-- 滚动策略 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 文件名模式 -->
            <fileNamePattern>logs/application.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!-- 保留天数 -->
            <maxHistory>30</maxHistory>
            <!-- 总大小限制 -->
            <totalSizeCap>1GB</totalSizeCap>
            
            <!-- 按大小分割 -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    
    <root level="INFO">
        <appender-ref ref="ROLLING_FILE"/>
    </root>
</configuration>

5.2 异步日志配置

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 同步文件输出 -->
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>logs/application.log</file>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    
    <!-- 异步包装器 -->
    <appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 队列大小 -->
        <queueSize>512</queueSize>
        <!-- 丢弃阈值 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 包含调用者信息 -->
        <includeCallerData>false</includeCallerData>
        <!-- 引用同步appender -->
        <appender-ref ref="FILE"/>
    </appender>
    
    <root level="INFO">
        <appender-ref ref="ASYNC_FILE"/>
    </root>
</configuration>

5.3 多环境配置

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 定义属性 -->
    <property name="LOG_HOME" value="logs"/>
    <property name="APP_NAME" value="myapp"/>
    
    <!-- 根据环境变量选择配置 -->
    <springProfile name="dev">
        <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
            </encoder>
        </appender>
        <root level="DEBUG">
            <appender-ref ref="CONSOLE"/>
        </root>
    </springProfile>
    
    <springProfile name="prod">
        <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${LOG_HOME}/${APP_NAME}.log</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${LOG_HOME}/${APP_NAME}.%d{yyyy-MM-dd}.log</fileNamePattern>
                <maxHistory>30</maxHistory>
            </rollingPolicy>
            <encoder>
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
            </encoder>
        </appender>
        <root level="INFO">
            <appender-ref ref="FILE"/>
        </root>
    </springProfile>
</configuration>

6. 常用模式和格式

6.1 日志格式说明

  • %d{pattern}: 日期时间
  • %thread: 线程名
  • %level / %-5level: 日志级别
  • %logger{length}: Logger名称
  • %msg: 日志消息
  • %n: 换行符
  • %class: 类名
  • %method: 方法名
  • %line: 行号
  • %file: 文件名

6.2 常用格式模板

<!-- 简洁格式 -->
<pattern>%d{HH:mm:ss} %-5level %logger{36} - %msg%n</pattern>

<!-- 详细格式 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] - %msg%n</pattern>

<!-- JSON格式 -->
<pattern>{"timestamp":"%d{yyyy-MM-dd HH:mm:ss.SSS}","level":"%-5level","thread":"%thread","logger":"%logger","message":"%msg"}%n</pattern>

<!-- 彩色输出(控制台) -->
<pattern>%d{HH:mm:ss.SSS} %highlight(%-5level) %cyan(%logger{36}) - %msg%n</pattern>

7. 过滤器和条件配置

7.1 级别过滤器

<appender name="ERROR_FILE" class="ch.qos.logback.core.FileAppender">
    <file>logs/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>
</appender>

7.2 阈值过滤器

<appender name="WARN_FILE" class="ch.qos.logback.core.FileAppender">
    <file>logs/warn.log</file>
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>WARN</level>
    </filter>
    <encoder>
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
</appender>

7.3 自定义过滤器

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.spi.FilterReply;

public class CustomFilter extends Filter<ILoggingEvent> {
    @Override
    public FilterReply decide(ILoggingEvent event) {
        if (event.getMessage().contains("sensitive")) {
            return FilterReply.DENY;
        }
        return FilterReply.NEUTRAL;
    }
}

8. MDC (Mapped Diagnostic Context) 使用

8.1 MDC基本用法

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

public class MDCExample {
    private static final Logger logger = LoggerFactory.getLogger(MDCExample.class);
    
    public void processUser(String userId) {
        // 设置MDC
        MDC.put("userId", userId);
        MDC.put("requestId", UUID.randomUUID().toString());
        
        try {
            logger.info("开始处理用户请求");
            // 业务逻辑
            logger.info("用户处理完成");
        } finally {
            // 清理MDC
            MDC.clear();
        }
    }
}

8.2 MDC配置格式

<encoder>
    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{requestId}] [%X{userId}] %logger{36} - %msg%n</pattern>
</encoder>

9. 特定Logger配置

9.1 包级别配置

<configuration>
    <!-- 特定包的日志级别 -->
    <logger name="com.example.service" level="DEBUG"/>
    <logger name="com.example.dao" level="WARN"/>
    
    <!-- 第三方库日志控制 -->
    <logger name="org.springframework" level="WARN"/>
    <logger name="org.hibernate" level="WARN"/>
    <logger name="org.apache.http" level="INFO"/>
    
    <!-- 关闭特定Logger的继承 -->
    <logger name="com.example.noisy" level="ERROR" additivity="false">
        <appender-ref ref="ERROR_FILE"/>
    </logger>
    
    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
    </root>
</configuration>

10. 实际应用示例

10.1 Spring Boot集成

// application.yml
logging:
  level:
    com.example: DEBUG
    org.springframework: WARN
  pattern:
    console: "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
    file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
  file:
    name: logs/application.log

10.2 Web应用日志配置

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <property name="LOG_HOME" value="logs"/>
    
    <!-- 控制台输出 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} %highlight(%-5level) [%X{requestId}] %cyan(%logger{36}) - %msg%n</pattern>
        </encoder>
    </appender>
    
    <!-- 应用日志 -->
    <appender name="APP_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}/app.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}/app.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxHistory>30</maxHistory>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{requestId}] %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    
    <!-- 错误日志 -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}/error.log</file>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{requestId}] %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    
    <!-- 业务日志 -->
    <logger name="com.example.business" level="INFO" additivity="false">
        <appender-ref ref="APP_FILE"/>
    </logger>
    
    <!-- 第三方库 -->
    <logger name="org.springframework" level="WARN"/>
    <logger name="org.hibernate" level="WARN"/>
    
    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="APP_FILE"/>
        <appender-ref ref="ERROR_FILE"/>
    </root>
</configuration>

11. 性能优化

11.1 异步日志最佳实践

<!-- 高性能异步配置 -->
<appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
    <queueSize>1024</queueSize>
    <discardingThreshold>0</discardingThreshold>
    <includeCallerData>false</includeCallerData>
    <neverBlock>true</neverBlock>
    <appender-ref ref="FILE"/>
</appender>

11.2 条件日志记录

// 避免不必要的字符串拼接
if (logger.isDebugEnabled()) {
    logger.debug("复杂计算结果: {}", expensiveOperation());
}

// 使用参数化日志
logger.info("用户 {} 执行了操作 {}", userId, operation);

// 避免
logger.info("用户 " + userId + " 执行了操作 " + operation);

12. 最佳实践

12.1 Logger声明

// 推荐:使用类名作为Logger名称
private static final Logger logger = LoggerFactory.getLogger(MyClass.class);

// 或者使用字符串(适用于静态工具类)
private static final Logger logger = LoggerFactory.getLogger("com.example.util");

12.2 日志级别使用指南

public class LoggingBestPractices {
    private static final Logger logger = LoggerFactory.getLogger(LoggingBestPractices.class);
    
    public void demonstrateLogLevels() {
        // ERROR: 系统错误,需要立即关注
        logger.error("数据库连接失败", exception);
        
        // WARN: 潜在问题,但不影响系统运行
        logger.warn("缓存未命中,使用数据库查询");
        
        // INFO: 重要的业务流程信息
        logger.info("用户 {} 登录成功", userId);
        
        // DEBUG: 调试信息,生产环境通常关闭
        logger.debug("方法参数: param1={}, param2={}", param1, param2);
        
        // TRACE: 最详细的跟踪信息
        logger.trace("进入方法 processData()");
    }
}

12.3 结构化日志

// 使用结构化的日志格式
logger.info("用户操作 - 用户ID: {}, 操作: {}, 结果: {}, 耗时: {}ms", 
    userId, operation, result, duration);

// 使用MDC增加上下文信息
MDC.put("traceId", traceId);
MDC.put("userId", userId);
logger.info("业务操作完成");

13. 常见问题和解决方案

13.1 日志文件权限问题

# 确保日志目录存在且有写权限
mkdir -p logs
chmod 755 logs

13.2 日志文件过大问题

<!-- 使用滚动策略控制文件大小 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
    <fileNamePattern>logs/app.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
    <maxFileSize>50MB</maxFileSize>
    <maxHistory>30</maxHistory>
    <totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>

13.3 内存泄漏问题

// 在Web应用中正确清理MDC
public class MDCCleanupFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        try {
            chain.doFilter(request, response);
        } finally {
            MDC.clear(); // 重要:清理MDC避免内存泄漏
        }
    }
}

13.4 配置重载

<!-- 启用配置文件自动重载 -->
<configuration scan="true" scanPeriod="30 seconds">
    <!-- 配置内容 -->
</configuration>

14. 监控和调试

14.1 JMX监控

<configuration>
    <!-- 启用JMX -->
    <jmxConfigurator/>
    <!-- 其他配置 -->
</configuration>

14.2 状态监听器

<configuration>
    <!-- 添加状态监听器 -->
    <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener"/>
    <!-- 其他配置 -->
</configuration>

14.3 调试配置

<!-- 开启调试模式 -->
<configuration debug="true">
    <!-- 配置内容 -->
</configuration>

15. 与其他框架集成

15.1 Spring Boot自动配置

# application.properties
logging.level.com.example=DEBUG
logging.pattern.console=%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
logging.file.name=logs/application.log
logging.logback.rollingpolicy.max-file-size=100MB
logging.logback.rollingpolicy.max-history=30

15.2 与ELK Stack集成

<!-- Logstash编码器 -->
<dependency>
    <groupId>net.logstash.logback</groupId>
    <artifactId>logstash-logback-encoder</artifactId>
    <version>7.4</version>
</dependency>
<appender name="LOGSTASH" class="ch.qos.logback.core.FileAppender">
    <file>logs/logstash.json</file>
    <encoder class="net.logstash.logback.encoder.LogstashEncoder">
        <includeContext>true</includeContext>
        <includeMdc>true</includeMdc>
        <customFields>{"service":"my-app"}</customFields>
    </encoder>
</appender>

16. 代码级配置

Logback支持通过代码进行编程式配置,这在以下场景特别有用:

  • 需要动态配置日志

  • 配置逻辑复杂,XML难以表达

  • 需要根据运行时条件调整配置

  • 集成到框架或库中

  • 需要更精细的控制

    import ch.qos.logback.core.rolling.RollingFileAppender;
    import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
    import ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP;
    
    private static RollingFileAppender createRollingFileAppender(LoggerContext context) {
        RollingFileAppender rollingFileAppender = new RollingFileAppender();
        rollingFileAppender.setContext(context);
        rollingFileAppender.setName("ROLLING_FILE");
        rollingFileAppender.setFile("logs/app.log");
        
        // 配置滚动策略
        TimeBasedRollingPolicy rollingPolicy = new TimeBasedRollingPolicy();
        rollingPolicy.setContext(context);
        rollingPolicy.setParent(rollingFileAppender);
        rollingPolicy.setFileNamePattern("logs/app.%d{yyyy-MM-dd}.%i.log");
        rollingPolicy.setMaxHistory(30);
        rollingPolicy.setTotalSizeCap(FileSize.valueOf("1GB"));
        
        // 配置大小和时间触发策略
        SizeAndTimeBasedFNATP triggeringPolicy = new SizeAndTimeBasedFNATP();
        triggeringPolicy.setMaxFileSize(FileSize.valueOf("100MB"));
        rollingPolicy.setTimeBasedFileNamingAndTriggeringPolicy(triggeringPolicy);
        
        rollingPolicy.start();
        rollingFileAppender.setRollingPolicy(rollingPolicy);
        
        // 配置编码器
        PatternLayoutEncoder encoder = new PatternLayoutEncoder();
        encoder.setContext(context);
        encoder.setPattern("%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n");
        encoder.start();
        
        rollingFileAppender.setEncoder(encoder);
        rollingFileAppender.start();
        
        return rollingFileAppender;
    }
    

17. 总结

Logback是一个功能强大且灵活的日志框架,主要优势包括:

  1. 高性能: 异步日志记录,减少对应用性能的影响
  2. 灵活配置: 支持XML、Groovy等多种配置方式
  3. 丰富功能: 滚动文件、过滤器、MDC等高级特性
  4. 良好集成: 与Spring Boot等框架无缝集成
  5. 可扩展性: 支持自定义Appender、Filter等组件

配置建议

  • 生产环境使用INFO级别,开发环境使用DEBUG
  • 合理使用异步日志提高性能
  • 配置日志滚动策略避免磁盘空间问题
  • 使用MDC增加日志上下文信息
  • 定期监控日志文件大小和系统性能

通过合理配置和使用Logback,可以为应用提供高效、可靠的日志记录功能。