jaegeropentracing的Java-client完整分布式追踪链,在分布式系统中透传trace信息

之前文章记录了jaegeropentracing的Java-client追踪链在单系统中的调用示例,现在记录下在分布式系统是如何实现一个完整的调用链的.

这篇文章是基于我之前的两篇文章编写了,链接如下:

Spring整合CXF webservice restful 实例

jaegeropentracing的Java-client

下面是代码:

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,坐下简单记录,有问题可以留言交流。

 

posted on 2018-10-12 18:06  汉有游女,君子于役  阅读(984)  评论(0编辑  收藏  举报