spring cloud整合zipkin新增自定義引數
阿新 • • 發佈:2019-01-22
需要在客戶端新增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) {
}
};
}
}