Logback日志配置教程

在Logback中,通过用户号(如userId)动态生成独立日志文件,需结合 MDC(上下文映射) ​ 和 动态文件名策略​ 实现。以下是完整方案,包含多用户并发处理、性能优化及完整代码示例:


一、核心实现原理

  1. 用户号注入

    在请求处理链(如Filter/Interceptor)中提取用户号,存入MDC(线程级上下文)。

  2. 动态文件名配置

    fileNamePattern中使用%X{userCode}引用MDC中的用户号,结合SiftingAppender实现按用户分片。


二、完整配置步骤

1. 自定义SiftingAppender(支持多用户并发)
复制代码
<!-- logback.xml -->
<configuration>
    <!-- 定义日志存储路径 -->
    <property name="LOG_PATH" value="./logs" />

    <!-- SiftingAppender按用户号分片 -->
    <appender name="USER_BASED_SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
        <discriminator>
            <key>userCode</key>
            <defaultValue>ANONYMOUS</defaultValue> <!-- 匿名用户默认值 -->
        </discriminator>
        <sift>
            <appender name="USER_ROLLING_FILE"
                      class="ch.qos.logback.core.rolling.RollingFileAppender">
                <file>${LOG_PATH}/${userCode}.log</file>

                <!-- 滚动策略:按天分割,单文件最大100MB -->
                <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                    <fileNamePattern>${LOG_PATH}/${userCode}-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
                    <maxHistory>30</maxHistory>
                    <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                        <maxFileSize>100MB</maxFileSize>
                    </timeBasedFileNamingAndTriggeringPolicy>
                </rollingPolicy>

                <encoder>
                    <pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
                </encoder>
            </appender>

        </sift>
    </appender>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    <!-- 根Logger绑定SiftingAppender -->
    <root level="root">
        <appender-ref ref="USER_BASED_SIFT" />
        <appender-ref ref="STDOUT" />
    </root>
</configuration>
2. 用户号注入Filter(关键)

通过Filter将用户号存入MDC,确保线程安全:

复制代码
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

public class UserCodeFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String userCode = "ANONYMOUS"; // 默认匿名用户
        
        // 从请求头/Session中提取用户号(根据业务调整)
        if (httpRequest.getSession(false) != null) {
            userCode = httpRequest.getSession().getAttribute("userCode").toString();
        }

        // 将用户号存入MDC(线程绑定)
        MDC.put("userCode", userCode);
        try {
            chain.doFilter(request, response);
        } finally {
            MDC.remove("userCode"); // 请求结束后清理
        }
    }
}
3. 注册Filter(Spring Boot)

通过配置类绑定Filter到所有请求:

复制代码
@Configuration
public class WebConfig {
    @Bean
    public FilterRegistrationBean<UserCodeFilter> userCodeFilter() {
        FilterRegistrationBean<UserCodeFilter> filterRegBean = new FilterRegistrationBean<>();
        filterRegBean.setFilter(new UserCodeFilter());
        filterRegBean.addUrlPatterns("/*"); // 拦截所有请求
        filterRegBean.setOrder(1); // 优先级高于其他Filter
        return filterRegBean;
    }
}

三、高级优化方案

1. 异步日志写入

通过AsyncAppender减少主线程阻塞:

复制代码
<appender name="ASYNC_USER_FILE" class="ch.qos.logback.classic.AsyncAppender">
    <appender-ref ref="USER_BASED_SIFT" />
    <queueSize>256</queueSize> <!-- 队列容量 -->
    <discardingThreshold>0</discardingThreshold> <!-- 不丢弃日志 -->
</appender>
2. 用户号黑名单过滤

忽略特定用户日志(如测试账号):

复制代码
<turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
    <Marker>BLOCKED_USER</Marker>
    <OnMatch>DENY</OnMatch>
</turboFilter>
3. 动态日志级别控制

按用户号设置不同日志级别(需结合Spring AOP):

复制代码
@Aspect
@Component
public class LogLevelAspect {
    @Around("@annotation(com.example.LogLevelControl)")
    public Object controlLogLevel(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String userCode = request.getSession().getAttribute("userCode").toString();
        
        // 动态调整日志级别(示例:VIP用户开启DEBUG)
        if ("VIP_USER".equals(userCode)) {
            LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
            Logger logger = loggerContext.getLogger("com.example.service");
            logger.setLevel(Level.DEBUG);
        }
        
        return joinPoint.proceed();
    }
}

四、关键配置解析

配置项 作用
%X{userCode} 从MDC中获取用户号,动态插入文件名
SiftingAppender 根据Discriminator值(用户号)分片,每个用户独立Appender
TimeBasedRollingPolicy 按时间滚动日志文件,配合SizeAndTimeBasedFNATP实现按大小分割
GZIP压缩 文件名后缀.gz启用压缩,减少存储空间

五、性能与注意事项

  1. 线程安全

    MDC是线程绑定的,需确保Filter中正确清理上下文(MDC.remove())。

  2. 文件句柄管理

    高并发场景下,每个用户独立文件可能导致文件句柄耗尽。建议:

    • 限制最大用户数

    • 定期归档旧用户日志

  3. 监控与告警

    通过JMX监控Logback的SiftingAppender状态,及时发现异常。


六、完整流程示例

  1. 用户登录

    服务端生成用户号并存入Session。

  2. 请求处理

    Filter拦截请求,提取用户号存入MDC。

  3. 日志记录

    日志框架根据MDC中的用户号生成对应文件(如/var/log/user/1001.log)。

  4. 日志滚动

    每天或文件达100MB时生成新文件(如1001-2025-12-02.1.log.gz)。


通过上述方案,可实现高效、灵活的用户级日志分片,适用于多租户系统、用户行为分析等场景。实际应用中可根据需求调整分片策略(如结合时间+用户号)。

相关推荐
yumgpkpm6 小时前
腾讯TBDS和CMP(Cloud Data AI Platform,类Cloudera CDP,如华为鲲鹏 ARM 版)比较的缺陷在哪里?
hive·hadoop·elasticsearch·zookeeper·oracle·kafka·hbase
Aevget7 小时前
界面控件DevExpress WPF中文教程:Data Grid - 虚拟源限制
hadoop·wpf·界面控件·devexpress·ui开发
SelectDB技术团队8 小时前
Apache Doris 在小米统一 OLAP 和湖仓一体的实践
数据仓库·数据分析·apache·数据库开发
心止水j8 小时前
hive案例
数据仓库·hive·hadoop
mn_kw9 小时前
Hive 统计信息自动收集机制深度解析
数据仓库·hive·hadoop
en-route9 小时前
数据仓库中的维度、指标、度量与属性
大数据·数据仓库
她说彩礼65万9 小时前
WPF 样式
大数据·hadoop·wpf
世界尽头与你9 小时前
Hadoop 未授权访问漏洞
大数据·hadoop·分布式
mn_kw9 小时前
Hive On Spark 统计信息收集深度解析
hive·hadoop·spark