You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot日志冗余问题:如何提取有效请求路径?

问题场景

Spring Boot应用日志存在冗余内容,包含乱码和无效字符,例如日志条目:

"\u0006stdout\u0010��������\u0017\u001a�\u00012023-05-20 08:48:38.366 [http-nio-8080-exec-5] DEBUG o.s.w.f.CommonsRequestLoggingFilter - REQUEST DATA : GET /dg/public/course]\u0000\u0000\u0000�\u0000\u0000\u0000�"

仅需提取其中的GET /dg/public/course部分。当前使用的Logback配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

  <property name="LOGS" value="/tmp/logs" />

  <appender name="Console"
    class="ch.qos.logback.core.ConsoleAppender">
    <layout class="ch.qos.logback.classic.PatternLayout">
      <Pattern>
        %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable
      </Pattern>
    </layout>
  </appender>

  <appender name="RollingFile"
    class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${LOGS}/spring-boot-logger.log</file>
    <encoder
      class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
      <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
    </encoder>

    <rollingPolicy
      class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- rollover daily and when the file reaches 10 MegaBytes -->
      <fileNamePattern>${LOGS}/archived/spring-boot-logger-%d{yyyy-MM-dd}.%i.log
      </fileNamePattern>
      <timeBasedFileNamingAndTriggeringPolicy
        class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
        <maxFileSize>10MB</maxFileSize>
      </timeBasedFileNamingAndTriggeringPolicy>
    </rollingPolicy>
  </appender>

  <!-- LOG everything at INFO level -->
  <root level="info">
    <appender-ref ref="RollingFile" />
    <appender-ref ref="Console" />
  </root>

  <!-- LOG "com.teaching.gradzee*" at TRACE level -->
  <logger name="com.teaching.gradzee" level="trace" additivity="false">
    <appender-ref ref="RollingFile" />
    <appender-ref ref="Console" />
  </logger>
  <logger name="org.hibernate.SQL" level="ERROR" />
  <logger name="org.springframework.web.filter.CommonsRequestLoggingFilter" level="DEBUG"/>
<!--  <logger name="org.zalando.logbook" level="TRACE" />-->
</configuration>

日志采集使用New Relic,Agent部署在EC2上,应用运行在Docker容器中,需实现仅提取目标请求路径的需求。


解决方案

1. 修复乱码根源

乱码多由Docker容器与EC2主机字符编码不一致导致,先统一编码:

  • 在Docker启动命令或Dockerfile中添加环境变量:ENV LANG=C.UTF-8,强制容器使用UTF-8编码。
  • 检查New Relic Agent配置,确保日志采集时以UTF-8编码解析内容。

2. 自定义CommonsRequestLoggingFilter输出

直接修改过滤器日志格式,只输出需要的内容:

  • 创建自定义过滤器子类,重写日志输出逻辑:
import org.springframework.web.filter.CommonsRequestLoggingFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;

public class CustomRequestLoggingFilter extends CommonsRequestLoggingFilter {
    private static final Logger logger = LoggerFactory.getLogger(CustomRequestLoggingFilter.class);

    @Override
    protected void beforeRequest(HttpServletRequest request, String message) {
        // 仅输出请求方法和路径
        logger.debug("REQUEST DATA : {} {}", request.getMethod(), request.getRequestURI());
    }
}
  • 在Spring Boot配置类中注册自定义过滤器,替换默认实现:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {
    @Bean
    public CustomRequestLoggingFilter customRequestLoggingFilter() {
        CustomRequestLoggingFilter filter = new CustomRequestLoggingFilter();
        filter.setIncludeQueryString(false); // 不需要查询字符串则关闭
        filter.setIncludePayload(false); // 不需要请求体则关闭
        return filter;
    }
}

3. Logback层面过滤修改日志

无需修改业务代码,通过Logback的TurboFilter处理日志内容:

  • 在Logback配置中添加自定义TurboFilter:
<configuration>
    <!-- 原有配置保持不变 -->
    
    <turboFilter class="com.teaching.gradzee.filter.LogMessageFilter" />
</configuration>
  • 实现日志过滤类,提取目标内容:
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.turbo.TurboFilter;
import ch.qos.logback.core.spi.FilterReply;
import org.slf4j.Marker;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class LogMessageFilter extends TurboFilter {
    private static final Pattern REQUEST_PATTERN = Pattern.compile("REQUEST DATA : (GET|POST|PUT|DELETE) ([^\\]]+)");

    @Override
    public FilterReply decide(Marker marker, ch.qos.logback.classic.Logger logger, Level level, String format, Object[] params, Throwable t) {
        if (logger.getName().equals("org.springframework.web.filter.CommonsRequestLoggingFilter") && level == Level.DEBUG) {
            if (params != null && params.length > 0) {
                String originalMsg = params[0].toString();
                Matcher matcher = REQUEST_PATTERN.matcher(originalMsg);
                if (matcher.find()) {
                    // 替换为提取后的内容
                    params[0] = matcher.group(1) + " " + matcher.group(2);
                } else {
                    // 匹配失败则过滤该日志
                    return FilterReply.DENY;
                }
            }
        }
        return FilterReply.NEUTRAL;
    }
}

4. New Relic控制台配置解析规则

若上述方法无法实现,可在New Relic端处理:

  • 登录New Relic控制台,找到对应日志数据源。
  • 创建日志解析规则,使用正则表达式REQUEST DATA : (GET|POST|PUT|DELETE) ([^\]]+)提取目标字段,将提取后的内容设为日志主消息,或存储为自定义属性。

内容的提问来源于stack exchange,提问作者Alpit Anand

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 04:35:24