spring cloud整合zipkin添加自定义参数

需要在客户端添加5个类:

1.ResponseWrapper.java

 
 
 
import java.io.ByteArrayOutputStream;
import java.io.IOException;
 
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
 
 
/**
 * 返回值输出代理类
 */
public class ResponseWrapper extends HttpServletResponseWrapper {
 
    private ByteArrayOutputStream buffer;
 
    private ServletOutputStream out;
 
    public ResponseWrapper(HttpServletResponse httpServletResponse) {
        super(httpServletResponse);
        buffer = new ByteArrayOutputStream();
        out = new WrapperOutputStream(buffer);
    }
 
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return out;
    }
 
    @Override
    public void flushBuffer() throws IOException {
        if (out != null)
        {
            out.flush();
        }
    }
 
    public byte[] getContent() throws IOException {
        flushBuffer();
        return buffer.toByteArray();
    }
 
    class WrapperOutputStream extends ServletOutputStream {
        private ByteArrayOutputStream bos;
 
        public WrapperOutputStream(ByteArrayOutputStream bos) {
            this.bos = bos;
        }
 
        @Override
        public void write(int b) throws IOException {
            bos.write(b);
        }
 
        @Override
        public boolean isReady() {
            // TODO Auto-generated method stub
            return false;
        }
 
        @Override
        public void setWriteListener(WriteListener arg0) {
            // TODO Auto-generated method stub
        }
    }
 
}
View Code

2.CustomHttpServletResponseSpanInjector.java

 
 
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanTextMap;
import org.springframework.cloud.sleuth.instrument.web.ZipkinHttpSpanInjector;
 
public class CustomHttpServletResponseSpanInjector extends ZipkinHttpSpanInjector {
    @Override
    public void inject(Span span, SpanTextMap carrier) {
        super.inject(span, carrier);
        carrier.put(Span.TRACE_ID_NAME, span.traceIdString());
        carrier.put(Span.SPAN_ID_NAME, Span.idToHex(span.getSpanId()));
    }
}
View Code

3.HttpResponseInjectingTraceFilter.java(关键代码)

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
 
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.web.filter.GenericFilterBean;
 
import com.alibaba.fastjson.JSONObject;
 
public class HttpResponseInjectingTraceFilter extends GenericFilterBean {
    private static final Logger logger = LoggerFactory
            .getLogger(HttpResponseInjectingTraceFilter.class);
 
    private final Tracer tracer;
 
    public HttpResponseInjectingTraceFilter(Tracer tracer) {
        this.tracer = tracer;
    }
 
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain filterChain) throws IOException, ServletException {
        Span currentSpan = this.tracer.getCurrentSpan();
        HttpServletRequest httpRequest = (HttpServletRequest) request;
 
        // 添加头部信息
        Map<String, String> headerMap = new HashMap<String, String>();
        Enumeration<String> enume = httpRequest.getHeaderNames();
        while (enume.hasMoreElements()) {
            String key = enume.nextElement();
            String value = httpRequest.getHeader(key);
            headerMap.put(key, value);
        }
        if (headerMap.size() > 0) {
            currentSpan.tag("http.head", JSONObject.toJSONString(headerMap));
        }
 
 
        //方法名
        String method = httpRequest.getMethod();
        currentSpan.tag("request.method", method);
        
        RequestWrapper wrapperRequest = new RequestWrapper(httpRequest);// 转换成代理类
        ResponseWrapper wrapperResponse = new ResponseWrapper(
                (HttpServletResponse) response);// 转换成代理类
        // 拦截返回
        filterChain.doFilter(wrapperRequest, wrapperResponse);
 
        // 添加参数信息
        String params = this.getRequestParameter(wrapperRequest);
        currentSpan.tag("http.params", params);
 
        // 添加返回值信息
        byte[] content = wrapperResponse.getContent();// 获取返回值
        // 判断是否有值
        if (content.length > 0) {
            try {
                String result = new String(content, "UTF-8");
                currentSpan.tag("http.result", result);
            } catch (Exception e) {
                logger.error("添加返回值信息异常", e);
            }
        }
 
        // 把返回值输出到客户端
        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
        } catch (Exception e) {
        } finally {
            try {
                if (out != null) {
                    out.write(content);
                    out.flush();
                    out.close();
                }
            } catch (IOException e) {
            }
        }
    }
 
    /**
     * 方法功能说明: 获取请求参数包括form表单和json参数 
     */
    public String getRequestParameter(RequestWrapper wrapperRequest) {
        if (null == wrapperRequest) {
            return null;
        }
        String params = null;
        String method = wrapperRequest.getMethod();
        if (StringUtils.isNotBlank(method) && "GET".equals(method.toUpperCase())) {
            // 获取请求体中的字符串(get)
            params = wrapperRequest.getQueryString();
            try {
                if (StringUtils.isNotBlank(params))
                    params = URLDecoder.decode(params, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                // Logger.error("获取到的请求参数解码错误 : {}", e.getMessage());
            }
            return params;
        }else {
            return wrapperRequest.getBodyString(wrapperRequest);
        }
    }
 
}
View Code

4.HttpSpanConfig.java

package com.keeplotus.config;
 
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
import com.keeplotus.filter.HttpResponseInjectingTraceFilter;
 
@Configuration
public class HttpSpanConfig {
    @Bean
    HttpResponseInjectingTraceFilter responseInjectingTraceFilter(Tracer tracer) {
        return new HttpResponseInjectingTraceFilter(tracer);
    }
}
View Code

5.RequestWrapper.java

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.Enumeration;
 
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
 
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.StreamUtils;
public class RequestWrapper extends HttpServletRequestWrapper {
    private final byte[] body;
 
    public RequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        String sessionStream = getBodyString(request);
        body = sessionStream.getBytes(Charset.forName("UTF-8"));
    }
 
    /**
     * 获取请求Body
     *
     * @param request
     * @return
     */
    public String getBodyString(final ServletRequest request) {
        String contentType = request.getContentType(); 
        String bodyString ="";
        
        if (StringUtils.isNotBlank(contentType) && 
                (contentType.contains("multipart/form-data") || 
                        contentType.contains("x-www-form-urlencoded"))){
 
            Enumeration<String> pars=request.getParameterNames();
 
            while(pars.hasMoreElements()){
 
                String n=pars.nextElement();
    
                bodyString+=n+"="+request.getParameter(n)+"&";
 
            }
 
            bodyString=bodyString.endsWith("&")?bodyString.substring(0, bodyString.length()-1):bodyString;
 
            return bodyString;
 
        }
        
        try {
            byte[] byteArray = StreamUtils.copyToByteArray(request.getInputStream());
            bodyString = new String(byteArray, "UTF-8");
        } catch (IOException e) {
        }
        
        return bodyString;
    }
 
    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }
 
    @Override
    public ServletInputStream getInputStream() throws IOException {
 
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
 
        return new ServletInputStream() {
 
            @Override
            public int read() throws IOException {
                return bais.read();
            }
 
            @Override
            public boolean isFinished() {
                return false;
            }
 
            @Override
            public boolean isReady() {
                return false;
            }
 
            @Override
            public void setReadListener(ReadListener readListener) {
            }
        };
    }
}
View Code

注意:是添加到客服端服务,添加到zipkin-server服务端无效,也就是集成zipkin的客户端都需要添加,大家可以打成jar包的形式添加到项目中,也可以上传到maven仓库。

源码地址:https://download.csdn.net/download/u011974797/12357644

如果是servlet项目可以参考:https://download.csdn.net/download/u011974797/12357915

spring cloud中文官网参考地址:https://springcloud.cc/spring-cloud-dalston.html#_custom_sa_tag_in_zipkin

posted @ 2021-03-18 10:22  YoungDeng  阅读(514)  评论(0编辑  收藏  举报