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 } } }
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())); } }
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); } } }
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); } }
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) { } }; } }
注意:是添加到客服端服务,添加到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
所有内容皆为个人总结或转载别人的文章,只为学习技术。 若您觉得文章有用,欢迎点赞分享! 若无意对您的文章造成侵权,请您留言,博主看到后会及时处理,谢谢。