TLog icon indicating copy to clipboard operation
TLog copied to clipboard

请问spirngboot中自定义的容器怎么获取TraceId?

Open SaulJWu opened this issue 2 years ago • 1 comments

package com.elite.common.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


/**
 * 记录完整请求响应日志
 *
 */
@Slf4j
@Configuration
public class WebConfig {

    @Bean
    public OncePerRequestFilter contentCachingRequestFilter() {
        return new OncePerRequestFilter() {

            @Override
            protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws ServletException, IOException {
                ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
                ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper(response);
                filterChain.doFilter(wrappedRequest, wrappedResponse);
                log.info("http request:{}", new String(wrappedRequest.getContentAsByteArray()));
                log.info("http response:{}", new String(wrappedResponse.getContentAsByteArray()));
                wrappedResponse.copyBodyToResponse();
            }
        };
    }

}

如上,我这里打印了http请求和响应日志,但是并没有traceId

SaulJWu avatar Dec 13 '22 16:12 SaulJWu

你如果用到了 tlog-web-spring-boot-starter 这个引入方式, TLog默认使用的是TLogWebInterceptor拦截器操作TLogContext上下文信息,因为过滤器前置是先于拦截器前置执行的,所以过滤器链调用前置操作的log输出打印不出来,对于过滤器链调用后置操作的log是因为过滤器的后置是晚于拦截器的后置执行的,已经被TLogWebInterceptor后置操作清除了,所以也打印不出来,这个是实现机制导致的,有三种解决办法:

  1. 将自己的Filter使用Interceptor替换,并晚于TLogWebInterceptor执行
  2. 启动类屏蔽TLogWebInterceptor的注册,同时启用 TLogServletFilter,需要确保TLogServletFilter先执行
@SpringBootApplication(exclude = {TLogWebAutoConfiguration.class})
package com.example.demo;

import com.yomahub.tlog.web.filter.TLogServletFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;

@Configuration
public class LogFilterConfig {

    @Bean
    public FilterRegistrationBean<Filter> tLogServletFilter() {
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new TLogServletFilter());
        registration.addUrlPatterns("/*");
        return registration;
    }

}
  1. TLogWebInterceptor的前置操作会在response中放置tlogTraceId响应头参数,可以自行在Filter后置操作中获取,手动打印
package com.example.demo;

import com.yomahub.tlog.constant.TLogConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author Oct
 */
@Slf4j
@Component
public class NormalFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.debug("normal-filter - before");
        filterChain.doFilter(servletRequest, servletResponse);
        String traceId = null;
        if (servletResponse instanceof HttpServletResponse) {
            traceId = ((HttpServletResponse) servletResponse).getHeader(TLogConstants.TLOG_TRACE_KEY);
        }
        log.debug("[{}] normal-filter - after", traceId);
    }

}

ShuningWan avatar Oct 16 '23 03:10 ShuningWan