SpringCloud:日志traceId错乱

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

目录

一、问题背景

二、排查过程

三、解决方案

总结


提示:以下是本篇文章正文内容,下面案例可供参考

一、问题背景

springcloud项目,对外提供的都是restful协议,为了方便日志的查询与管理,在filter中设置了traceId属性,并在logback日志配置文件中进行输出。

近期总是碰到生产环境有好多请求的日志,日志中的traceId不一致,例如一次完整的请求,在filter中输出的日志和正式的业务日志里的traceId就不同。

二、排查过程

1、排查方向:有另外一个地方设置了新的traceId

排查结果:没有找到其他设置traceId的地方,将Filter中唯一的设置位置屏蔽之后,日志中不再输出traceId。

2、怀疑是MDC的问题

排查结果:更换为ThreadLocal、查看MDC的源码,均没有找到问题所在

而且生产环境中,这种情况也不是必现,一度陷入了僵局......

3、偶然发现有个奇怪的现象

①Filter日志输出请求参数

②业务日志

③Filter日志输出响应结果

发现出现不一致的情况时,该请求的完整日志输出中,①和③的traceId一致,②的traceId居然和1中的请求头里的某个属性 hc-traceid 一致。

有了这个发现,我本机做了一个测试。

当请求头里包含hc-traceid属性时,对应的请求的业务日志中,traceId与请求头里的一致。

当请求头里不包含hc-traceid属性时,①②③中的traceId一致。

hc-traceid,从命名上来看,我猜是公司里某个公共jar包里引用的,将其屏蔽掉之后,请求里就没有这个属性了。正常情况下,就顺着情况一或者是多线程方向去找,一般都没有问题。

三、解决方案

有两个思路

1、修改请求头里的属性,将该属性移除。

2、不改变原有请求头里的属性,改变获取方法的实现

这里我们给出第二个方案的代码示例:

public class ContentCacheRequestWrapper extends HttpServletRequestWrapper {

    private byte[] body;

    private BufferedReader reader;

    private ServletInputStream inputStream;

    private Map<String, String> headerMap = new HashMap<>();
    private Map<String , String[]> params = new HashMap<>();

    public ContentCacheRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        //读一次 然后缓存起来
        body = IOUtils.toByteArray(request.getInputStream());
        inputStream = new RequestCachingInputStream(body);
        this.params.putAll(request.getParameterMap());
    }


    public byte[] getBody() {
        return body;
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (inputStream != null) {
            return inputStream;
        }
        return super.getInputStream();
    }

    @Override
    public BufferedReader getReader() throws IOException {
        if (reader == null) {
            reader = new BufferedReader(new InputStreamReader(inputStream, getCharacterEncoding()));
        }
        return reader;
    }

    //代理一下ServletInputStream 里面真是内容为当前缓存的bytes
    private static class RequestCachingInputStream extends ServletInputStream {

        private final ByteArrayInputStream inputStream;

        public RequestCachingInputStream(byte[] bytes) {
            inputStream = new ByteArrayInputStream(bytes);
        }

        @Override
        public int read() throws IOException {
            return inputStream.read();
        }

        @Override
        public boolean isFinished() {
            return inputStream.available() == 0;
        }

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setReadListener(ReadListener readlistener) {
        }

    }

    @Override
    public String getHeader(String name) {
        if (Objects.equals(name, "hc-traceid")) {
            return MDC.get("traceId");
        }
        String headerValue = super.getHeader(name);
        if (headerMap.containsKey(name)) {
            headerValue = headerMap.get(name);
        }
        return headerValue;
    }

}

这里说明一下,我们在原来的基础上,修改getHeader的实现,覆盖原有实现,当要获取hc-traceid属性的值时,返回的是我们自己设置的traceId值,至此,问题得以解决。


总结

这个问题困扰挺久了,终于解决了!

相关推荐

  1. SpringCloud日志traceId错乱

    2024-02-19 13:56:01       27 阅读
  2. 分布式微服务架构日志调用链路跟踪-traceId

    2024-02-19 13:56:01       46 阅读
  3. springcloud学习过程错误

    2024-02-19 13:56:01       22 阅读
  4. traceId:SkyWalking的traceId生成策略

    2024-02-19 13:56:01       29 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-19 13:56:01       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-19 13:56:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-19 13:56:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-19 13:56:01       18 阅读

热门阅读

  1. Redis为什么被设计为单线程

    2024-02-19 13:56:01       29 阅读
  2. python_数据分析_numpy库

    2024-02-19 13:56:01       28 阅读
  3. redis键的过期删除策略

    2024-02-19 13:56:01       27 阅读
  4. 第1章 计算机系统概述(2)

    2024-02-19 13:56:01       29 阅读
  5. 突破编程_C++_面试(变量与常量)

    2024-02-19 13:56:01       28 阅读
  6. httpclient发送post请求、httpclient上传文件

    2024-02-19 13:56:01       23 阅读
  7. C语言之删除字符串中间和后面的*

    2024-02-19 13:56:01       31 阅读
  8. c++ 6

    c++ 6

    2024-02-19 13:56:01      25 阅读
  9. Kubernetes基础(二十一)-k8s的服务发现机制

    2024-02-19 13:56:01       27 阅读
  10. 速盾网络:CDN用几天关了可以吗?安全吗?

    2024-02-19 13:56:01       27 阅读