jaegeropentracing的Java-client完整分布式追踪链,在分布式系统中透传trace信息
之前文章记录了jaegeropentracing的Java-client追踪链在单系统中的调用示例,现在记录下在分布式系统是如何实现一个完整的调用链的.
这篇文章是基于我之前的两篇文章编写了,链接如下:
Spring整合CXF webservice restful 实例
下面是代码:
client端代码如下:
public static void main(String[] args) throws InterruptedException { Configuration conf = new Configuration("EK Demo Jaeger."); //配置全局configuration //发送sender configuration Configuration.SenderConfiguration senderConf = new Configuration.SenderConfiguration(); senderConf.withAgentHost("192.168.1.111"); senderConf.withAgentPort(5775); Sender sender = senderConf.getSender(); log.info("[ sender ] : "+sender); conf.withReporter( new Configuration.ReporterConfiguration() .withSender(senderConf) .withFlushInterval(100) .withLogSpans(false) ); conf.withSampler( new Configuration.SamplerConfiguration() .withType("const") .withParam(1) ); Tracer tracer = conf.getTracer(); log.info(tracer.toString()); GlobalTracer.register(tracer); Tracer.SpanBuilder spanBuilder = GlobalTracer.get().buildSpan("EK Demo P"); Span parent = spanBuilder.start(); parent.log(100, "before Controller Method is running......"); log.info("before Controller Method is running......"); Tracer.SpanBuilder childB = GlobalTracer.get().buildSpan("EK Demo child").asChildOf(parent); Span child = childB.start(); JaegerSpanContext context = (JaegerSpanContext) child.context(); child.log("......"+context.contextAsString()); String url = "http://localhost:8080/jeeek/services/phopuService/getUserPost"; HttpClient httpClient = HttpClients.createSystem(); final HttpPost httpPost = new HttpPost(url); httpPost.addHeader("Content-Type", "text/plain"); StringEntity se = null; String weatherInfo = null; try { //透传context到服务端 tracer.inject(parent.context(), Format.Builtin.TEXT_MAP, new TextMap() { @Override public Iterator<Map.Entry<String, String>> iterator() { throw new UnsupportedOperationException("TextMapInjectAdapter should only be used with Tracer.inject()"); } @Override public void put(String key, String value) { log.info(key+",----------------------- "+value); httpPost.setHeader(key, value); } }); se = new StringEntity("101010500"); se.setContentType("text/plain"); httpPost.setEntity(se); HttpResponse response = null; response = httpClient.execute(httpPost); int status = response.getStatusLine().getStatusCode(); log.info("[接口返回状态吗] : " + status); weatherInfo = getReturnStr(response); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } log.info("[接口返回信息] : " + weatherInfo); Thread.sleep(5000); child.finish(); Thread.sleep(5000); parent.finish(); log.info("after Controller Method is running......."); Thread.sleep(10000); }
服务端代码如下:
@POST @Produces(MediaType.APPLICATION_JSON) //指定返回数据的类型 json字符串 //@Consumes(MediaType.TEXT_PLAIN) //指定请求数据的类型 文本字符串 @Path("/getUserPost") public User getUserPost(String userId) { this.logger.info("Call getUserPost() method...." + userId); Configuration conf = new Configuration("EK Demo Jaeger."); //配置全局configuration //发送sender configuration Configuration.SenderConfiguration senderConf = new Configuration.SenderConfiguration(); senderConf.withAgentHost("192.168.1.111"); //senderConf.withAgentHost("192.168.3.22"); senderConf.withAgentPort(5775); Sender sender = senderConf.getSender(); logger.info("[ sender ] : "+sender); conf.withReporter( new Configuration.ReporterConfiguration() .withSender(senderConf) .withFlushInterval(100) .withLogSpans(false) ); conf.withSampler( new Configuration.SamplerConfiguration() .withType("const") .withParam(1) ); Tracer tracer = conf.getTracer(); logger.info(tracer.toString()); if (!GlobalTracer.isRegistered()) GlobalTracer.register(tracer); Tracer.SpanBuilder spanBuilder = tracer.buildSpan("server Span"); /** * 由于此处只是一个restful接口,所以自己通过request获取头信息然后封装到map中,才作为参数传递 * 在实际的RPC分布式系统中,可以直接调用 request.getAttachments() 来返回头信息的trace信息 **/ //获取客户端透传的traceId,然后绑定span到该trace对应的span上 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); String traceId = request.getHeader("uber-trace-id");//此处可以根据实际遍历header来获取,header的key有可能会发生变化[不确定] Map<String, String> map = new HashMap<>();//将header信息放到map中 map.put("uber-trace-id", traceId); logger.info("--------------------"+traceId); try { //new TextMapExtractAdapter(map)此处参数是个map,在分布式系统中直接调用request.getAttachments() SpanContext spanContext = tracer.extract(Format.Builtin.TEXT_MAP, new TextMapExtractAdapter(map)); if (spanContext != null) { spanBuilder.asChildOf(spanContext); } } catch (Exception e) { spanBuilder.withTag("Error", "extract from request fail, error msg:" + e.getMessage()); } User user = new User(); user.setUserName("中文"); user.setAge(26); user.setSex("m"); Span span = spanBuilder.start(); span.log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); span.finish(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } return user; }
在springMVC系统中手动获取request,需要配置web.xml,如下:
<listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener>
当然,这只是一个demo,坐下简单记录,有问题可以留言交流。