openTracing java API


中文官方的中文手册
API简介

一、opentracing的概念与术语

opentracing 本质是一套tracing字段的规范,并不是监控产品。
这么做是希望各种监控产品能对接进去。
opentracing的概念与术语

二、opentracing 的规范

规范
为了被各厂家支持,opentracing 模糊定义了必要的字段,由使用者具体决定。
其他字段基本上是清晰定义了。

2.1 模糊定义的部分

各个APM产品的调用链关键字段描述都有差异。但是共识是
要有调用链标识operationName(名称),span的标识上游span的标识时间戳span耗时
示例
如下是一个例子,在一级字段例定义了如下格式。但是其他监控产品有可能把traceId换成trace_Id。所以这部分opentracing是模糊定义的

名称描述
traceId调用链唯一标识uint64
spanId本次调用的唯一标识uint64
parentSpanId上游调用块的标识uint64
start请求开始的时间string
duration请求耗时,单位为毫秒uint64
operationString span的名称string

baggages

一级字段可以为空一个Map类型,这个字段要求所有要在trace所有的span中流动。这个字段不管是进程间,还是跨应用调用,都应该在span间传递。

2.2 清晰定义的部分

tags和logs是也是一级字段,但是可以为空。
不在span间传递,最终被和生成的span存储进数据库中。
tags是span的标签,标识关键信息。
logs偏重于日志的输出。

2.2.1 tags & logs 表 (耳机标签)

tags
tags是应该被应用到整个Span的属性。比如某个时间范围内的,而不是一个特殊的时刻。比如component=spring并不会针对特定的span,而是对span而言这个模块产生的消息就是spring框架产生的。像事件event等一些特殊的应该放在logs字段中。

Span tag nameTypeNotes and examples
componentstring软件包,框架,库,或者模块 eg., "grpc", "django", "JDBI".
db.instancestring数据库实例的名称. eg., 如果jdbc.url="jdbc:mysql://127.0.0.1:3306/customers", ,那么实例名称应该是"customers".
db.statementstring数据库的查询语句。eg., 对于db.type="sql", "SELECT * FROM wuser_table"; 对于 db.type="redis","SET mykey 'WuValue'".
db.typestring数据库的类型., "sql"代表SQL 类型的database。其他数据库, eg. "cassandra", "hbase""redis"
db.userstring访问数据的用户名eg., "readonly_user" 或者 "reporting_user"
errorbooltrue 意味应用的程序出现了问题
http.methodstringHTTP method 的请求类型 Span. eg., "GET", "POST"
http.status_codeintegerHTTP 相应的状态码. eg., 200, 503, 404
http.urlstring请求的 URL。eg., "https://domain.net/path/|to?resource=here"
message_bus.destinationstring用来交换信息的地址。eg. 一条Kafka 的记录 和 "topic name" 可以被 采集器的 producer 或者 consumer 解析、存储在这个tag
peer.addressstring远程的“address”,适合网络通信。他的值可能是ip:port、一个hostname, FQDN, 沈甚至一个JDBC子字符串类似 "mysql://prod-db:3306"
peer.hostnamestring远程的hostname eg., "opentracing.io", "internal.dns.name"
peer.ipv4string远程的 IPv4 eg., “127.0.0.1”
peer.ipv6string远程的 IPv6 eg.,"2001:0db8:85a3:0000:0000:8a2e:0370:7334"
peer.portinteger远程的 port. eg.,80
peer.servicestring远程的 service name ,eg., "elasticsearch", "a_custom_microservice", "memcache"
sampling.priorityinteger如果 > 0, 选中,\<0, 丢弃掉 。
span.kindstring类型"client""server" 对于 RPC, 或者合适的语义比如"producer","consumer"在消息服务

logs
每个span的LOG字段都有时间戳。想日志一箱,

Span log field nameTypeNotes and examples
error.kindstring这个类型仅仅是("error"). eg.,"Exception", "OSError"
error.objectobject针对与特定语言的支持 (比如., Java, Python),真实的lThrowable/Exception/Error. eg., java的java.lang.UnsupportedOperationException , python的a pythonexceptions.NameErrorinstance
eventstring对span生命周期内,一些特定的事件的标识。例如,在浏览器页面加载过程中,获得或释放一个互斥锁就是一个特定的事件域, 标准. E.g., 比如 Zipkin的"cs", "sr", "ss", or "cr". 或者"initialized" 、 "timed out"、"error"
messagestring一个简洁的人类可读的,只有一行的消息"Could not connect to backend", "Cache invalidation succeeded"
stackstring栈信息最终,具体语言相关,先错代码出错的行数,但是不一定是一个error。E.g., "File \"example.py\", line 7, in \<module\>\ncaller()\nFile \"example.py\", line 5, in caller\ncallee()\nFile \"example.py\", line 2, in callee\nraise Exception(\"Yikes\")\n"

2.2.2 解释

1 描述特殊模型的变量,比如rpc
  • span.kind。 如"client" or “server”,标识rpc的访问端
  • Peer Tags。记录地址信息peer.address, peer.hostname, peer.ipv4, peer.ipv6, peer.port, peer.service
2 HTTP Server Tags
  • http.url- string
    • URL 分布式追踪中,这一阶段的调用的URL地址, 参考 standard URI format.
    • Protocol 协议,可选
    • Examples:
1. https://domain.net/path/to?resource=here
2. domain.net/path/to/resource
3. http://user:pass@domain.org:8888

   
   

    +http.method - string
    + HTTP 请求被处理的方法.
    + Case-insensitive 大小写敏感
    + Examples:

    GET, POST, HEAD
    
       
       
      • http.status_code - integer
        • HTTP 返回值
        • Examples:
      200, 503
      
         
         

        +span.kind - string
        server 定义这是服务端类型的span (see “Component Identification, 框架定义”)

        3 Captured errors

        捕获错误
        示例
        比如捕获错误的对象

        event="error"
        error.object=<error object instance>
        
           
           

          示例

          vent="error"
          message="..."
          stack="..." (optional)
          error.kind="..." (optional)
          
             
             
            4 描述database

            +db.type, db.instance, db.user, and db.statement: as described in the table above

            • peer.address, peer.hostname, peer.ipv4, peer.ipv6, peer.port, peer.service: optional
            • tags that describe the database peer
              span.kind: "client"
            5 Message Bus 信息交换

            一般可以按照如下的方式组合

            • message_bus.destination: 如表中描述
              +span.kind: either "producer"or "consumer".
              +peer.address, peer.hostname, peer.ipv4, peer.ipv6, peer.port, peer.service: 可选的标签 描述消息broker

            三、opentracing 代码结构

            3.1 代码结构

            代码结构
            在这里插入图片描述
            在maven 仓库里

            名称描述依赖
            opentracing-api是一个纯粹的API没有任何依赖-
            opentracing-noop实现了API,但是是空实现什么也不干opentracing-api
            opentracing-util包含了一个GlobalTracer和基于Thread_local的简单实现ScopeManageropentracing-api; opentracing.noop
            opentracing-mockmock测试,包含一个简单的MockTracer,将数据存褚进内存opentracing-api; opentracing.noop;opentracing-util

            一个存在在测试是的包,用于测试和尝试新特性opentracing-testbed

            3.2 核心组件概念介绍

            大致将各个模块的作用
            代码模型
            java-api
            在这里插入图片描述
            opentracing里主要包含以下几个组件:

            Tracer

            Tracer是一个调用链生成器,他应该是全局的。最佳实践是应用在启动时,创建一个Tracer的实例。可以被其他线程访问到,去生成消息。

            ScopeManager

            这个类是0.30版本之后新加入的组件,这个组件的作用是能够通过它获取当前线程中启用的Span信息,并且可以启用一些处于未启用状态的span。在一些场景中,我们在一个线程中可能同时建立多个span,但是同一时间统一线程只会有一个span在启用,其他的span可能处在下列的状态中:

            1. 等待子span完成
            2. 等待某种阻塞方法
            3. 创建并未开始

            对于一个线程Thread来说,一个时刻只有一个span是激活状态的(active)。其他spans,可能是这个span的上游,或者等待资源(I/O或者childspan的完成)等,这些spans的特点是,开始了(start)但是没有结束(end)。
            这个时候获取当前的span是很不方便的,所以就有scopeManager()来管理每个span的scope。获取当前的span可以使用

            io.opentracing.Tracer tracer = ...;
            ...
            Span span = tracer.scopeManager().activeSpan();
            if (span != null) {
                span.log("...");
            }
            
               
               
            • 1
            • 2
            • 3
            • 4
            • 5
            • 6

            Span

            表示分布式调用链条中的一个调用单元,比方说某个dubbo的调用provider,或者是个http调用的服务提供方,他的边界包含一个请求进到服务内部再由某种途径(http/dubbo等)从当前服务出去。一个span一般会记录这个调用单元内部的一些信息,例如:

            1 生成一个新的span:

            spans是树状的,一个span要么是根span,要么来源于另外一个span。

            
            io.opentracing.Tracer tracer = ...;
            ...
            Span span = tracer.buildSpan("someWork").start();
            try (Scope scope = tracer.scopeManager().activate(span)) {
                // Do things.
            } catch(Exception ex) {
                Tags.ERROR.set(span, true);
                span.log(Map.of(Fields.EVENT, "error", Fields.ERROR_OBJECT, ex, Fields.MESSAGE, ex.getMessage()));
            } finally {
                span.finish();
            }
            
               
               
              1 无视存在激活状态span:

              那么新的span,将会以激活的span做为parent。这是如果想无视激活的span想指定具体的parent。可以使用

              io.opentracing.Tracer tracer = ...;
              ...
              Span span = tracer.buildSpan("someWork").ignoreActiveSpan().start();
              
                3 异步的span:

                考虑一下一个异步的span,模型如下

                 [ ServiceHandlerSpan                                 ]
                 |·FunctionA·|·····waiting on an RPC······|·FunctionB·|
                

                -> time

                • 1
                • 2
                • 3
                • 4

                ServiceHandlerSpan在运行时被FunctionA激活了,在FunctionB继续执行。但是如果是一个RPC,span的生成就必须等待FunctionB
                ScopeManager的API可以让在FunctionA中激活,然后在FunctionB中获取之前的span,让它再次被激活。
                步骤如下

                • 开始一个span
                • closure/Runnable/Future等线程函数开始之初,调用tracer.scopeManager().activate(span),去重新激活Span,并且拿到一个新的Scope,然后当span不激活时close()
                • 调用span.finish()结束
                io.opentracing.Tracer tracer = ...;
                ...
                // STEP 1 ABOVE: start the Span.
                final Span span = tracer.buildSpan("ServiceHandlerSpan").start();
                try (Scope scope = tracer.scopeManager().activate(span)) {
                    // Do work.
                    ...
                
                future <span class="token operator">=</span> CompletableFuture<span class="token punctuation">.</span><span class="token function">supplyAsync</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">&gt;</span> <span class="token punctuation">{<!-- --></span>
                
                    <span class="token comment">// STEP 2 ABOVE: reactivate the Span in the callback.</span>
                    <span class="token keyword">try</span> <span class="token punctuation">(</span>Scope scope <span class="token operator">=</span> tracer<span class="token punctuation">.</span><span class="token function">scopeManager</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">activate</span><span class="token punctuation">(</span>span<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
                    <span class="token punctuation">}</span>
                <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">thenRun</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">&gt;</span> <span class="token punctuation">{<!-- --></span>
                    <span class="token comment">// STEP 3 ABOVE: finish the Span when the work is done.</span>
                    span<span class="token punctuation">.</span><span class="token function">finish</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                

                }

                  SpanContext

                  表示一个span对应的上下文,span和spanContext基本上是一一对应的关系,上下文存储的是一些需要跨越边界的一些信息,例如:

                  1. spanId 当前这个span的id
                  2. traceId 这个span所属的traceId(也就是这次调用链的唯一id)
                  3. baggage 其他的能过跨越多个调用单元的信息
                    这个SpanContext可以通过某些媒介和方式传递给调用链的下游来做一些处理(例如子Span的id生成、信息的继承打印日志等等)

                  Carrier

                  表示的是一个承载spanContext的媒介,比方说在http调用场景中会有HttpCarrier,在dubbo调用场景中也会有对应的DubboCarrier

                  Formatter

                  这个接口负责了具体场景中序列化反序列化上下文的具体逻辑,例如在HttpCarrier使用中通常就会有一个对应的HttpFormatter。Tracer的注入和提取就是委托给了Formatter

                  3.3 opentracing-api 详解

                  这就是opentracing-api的所有类
                  在这里插入图片描述

                  3.3.1 log & tag

                  log.Fields

                  log仅有一个类

                  public class Fields {
                      private Fields() {
                      }
                      public static final String ERROR_KIND = "error.kind";
                      public static final String ERROR_OBJECT = "error.object";
                      public static final String EVENT = "event";
                      public static final String MESSAGE = "message";
                      public static final String STACK = "stack";
                  }
                  
                   
                   
                    tag

                    在这里插入图片描述
                    tag仅有一个接口

                    public interface Tag<T> {
                        String getKey();
                        void set(Span span, T value);
                    }
                    
                     
                     

                      tags封装了所有的属性
                      在这里插入图片描述

                      3.3.2 propagation

                      负责 放入和解析的类。这里仅仅定义了接口,没有定义实现。
                      在这里插入图片描述

                      3.3.2.1 Carrier

                      存放消息的载体。

                      Map结构的Carrier
                      TextMap是Map结构的Carrier
                      在这里插入图片描述
                      TextMapInject 定义了 put接口
                      TextMapExtract 定义了一个获取Map迭代器的方法。

                      TextMapInjectAdapter 接受map,并写入数据

                      public class TextMapInjectAdapter implements TextMapInject {
                          protected final Map<String, ? super String> map;
                      
                      <span class="token keyword">public</span> <span class="token function">TextMapInjectAdapter</span><span class="token punctuation">(</span><span class="token keyword">final</span> Map<span class="token operator">&lt;</span>String<span class="token punctuation">,</span> <span class="token operator">?</span> <span class="token keyword">super</span> String<span class="token operator">&gt;</span> map<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                          <span class="token keyword">this</span><span class="token punctuation">.</span>map <span class="token operator">=</span> map<span class="token punctuation">;</span>
                      <span class="token punctuation">}</span>
                      
                      <span class="token annotation punctuation">@Override</span>
                      <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">put</span><span class="token punctuation">(</span>String key<span class="token punctuation">,</span> String value<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                          <span class="token keyword">this</span><span class="token punctuation">.</span>map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> value<span class="token punctuation">)</span><span class="token punctuation">;</span>
                      <span class="token punctuation">}</span>
                      

                      }

                        TextMapInjectAdapter 接受map,获取迭代器

                        public class TextMapExtractAdapter implements TextMapExtract {
                            protected final Map<String,String> map;
                        
                        <span class="token keyword">public</span> <span class="token function">TextMapExtractAdapter</span><span class="token punctuation">(</span><span class="token keyword">final</span> Map<span class="token generics function"><span class="token punctuation">&lt;</span>String<span class="token punctuation">,</span>String<span class="token punctuation">&gt;</span></span> map<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                            <span class="token keyword">this</span><span class="token punctuation">.</span>map <span class="token operator">=</span> map<span class="token punctuation">;</span>
                        <span class="token punctuation">}</span>
                        <span class="token annotation punctuation">@Override</span>
                        <span class="token keyword">public</span> Iterator<span class="token operator">&lt;</span>Map<span class="token punctuation">.</span>Entry<span class="token generics function"><span class="token punctuation">&lt;</span>String<span class="token punctuation">,</span> String<span class="token punctuation">&gt;</span></span><span class="token operator">&gt;</span> <span class="token function">iterator</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                            <span class="token keyword">return</span> map<span class="token punctuation">.</span><span class="token function">entrySet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">iterator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                        <span class="token punctuation">}</span>
                        

                          二进制结构的Carrier

                          在这里插入图片描述
                          首先ByteBuffer是java的nio的类,内置一个byte[]数组,length就是Carrier的大小。

                          +injectionBuffer是返回一个ByteBuffer对象,用于用于SpanContext的注入。当调用Tracer.inject()会调用到这个方法。

                          • extractionBuffer返回SpanContext的Carrier。Tracer.extract()`会调到。
                          3.3.2.2 Format

                          TextMap定义了,解析和放置的行为,比如解析RPC协议和Http协议,就是不同实现类,真正的定义的行为。
                          Format更像是一个工厂,里面保存了各种TextMap的实现。
                          在这里插入图片描述

                          *Tracer tracer = ...
                            io.opentracing.propagation.HttpHeaders httpCarrier = new AnHttpHeaderCarrier(httpRequest);
                           *SpanContext spanCtx = tracer.extract(Format.Builtin.HTTP_HEADERS, httpCarrier)
                          
                           
                           
                          • 1
                          • 2
                          • 3

                          类似与解码器,下载一个包含多种视频格式的解码器。播放软件,只需将解码器和视频流导入,就能解析固定的格式。
                          作为开发者,重点要放在TextMap的定义上

                          3.3.3 References

                          代表了span的关系。

                          • child_of 父子关系
                          • follows_from 兄弟关系,先后关系
                          public final class References {
                              private References(){}
                          
                          <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">final</span> String CHILD_OF <span class="token operator">=</span> <span class="token string">"child_of"</span><span class="token punctuation">;</span>
                          
                          <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">final</span> String FOLLOWS_FROM <span class="token operator">=</span> <span class="token string">"follows_from"</span><span class="token punctuation">;</span>
                          

                            3.3.4 SpanContext

                            SpanContext代表了span的状态信息。它必须要被传递给后代的span。
                            SpanContext的内容可以分为两块:

                            • user-level 的 Baggage,他要被传递给下游span,可以为空。
                            • 必要的trace信息,作为span和trace的标识,必须要被携带。比如trace_id, span_id, sampled 等

                            在这里插入图片描述

                            3.3.5 Span

                            在这里插入图片描述

                            • 必须要包含一个SpanContext
                            • 其余都是放置属性的方法

                            3.3.6 Scope

                            代表了一个激活和被激活状态的span 。
                            往往一个span从开始到finsh完成,期间要等chid_span先完成。child_span运行时,当前的span就处于一个没有激活的状态。
                            所以Scope就可以理解代表了附加状态的一个span,也被用来获取span。也负责一个span的关闭

                            public interface Scope extends Closeable {
                               	// 仅有一个方法
                                void close();
                            }
                            
                             
                             
                            • 1
                            • 2
                            • 3
                            • 4

                            3.3.7 ScopeManager

                            用来在运行过程中管理Span。
                            在这里插入图片描述

                            • activate 方法
                              对于当前的环境(通常是一个Thread),把传入的Span设置为当前的span,就是active激活的,然后返回一个Scope来管理这Span。通常的用法为
                                     Span span = tracer.buildSpan("...").start();
                                     try (Scope scope = tracer.scopeManager().activate(span)) {
                                         span.setTag("...", "...");
                                         ...
                                     } catch (Exception e) {
                                         span.log(...);
                                     } finally {
                                         // Optionally finish the Span if the operation it represents
                                         // is logically completed at this point.
                                         span.finish();
                                     }
                            
                             
                             

                              推荐把Scope放在try-catch资源中,方便最终调用close方法关掉。

                              3.3.7 Tracer

                              在这里插入图片描述
                              生成调用链信息的,建议是创建一个全局的tracer。方法就如方法名所示。

                              四、 api的实现

                              4.1 opentracing-noop

                              什么也不做的实现
                              在这里插入图片描述
                              什么也不做的实现,比如如下,就可以看出,span的函数什么也不做

                              final class NoopSpanImpl implements NoopSpan {
                              
                              <span class="token annotation punctuation">@Override</span>
                              <span class="token keyword">public</span> SpanContext <span class="token function">context</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> NoopSpanContextImpl<span class="token punctuation">.</span>INSTANCE<span class="token punctuation">;</span> <span class="token punctuation">}</span>
                              
                              <span class="token annotation punctuation">@Override</span>
                              <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">finish</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token punctuation">}</span>
                              
                              <span class="token annotation punctuation">@Override</span>
                              <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">finish</span><span class="token punctuation">(</span><span class="token keyword">long</span> finishMicros<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token punctuation">}</span>
                              
                              <span class="token annotation punctuation">@Override</span>
                              <span class="token keyword">public</span> NoopSpan <span class="token function">setTag</span><span class="token punctuation">(</span>String key<span class="token punctuation">,</span> String value<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
                              
                              <span class="token annotation punctuation">@Override</span>
                              <span class="token keyword">public</span> NoopSpan <span class="token function">setTag</span><span class="token punctuation">(</span>String key<span class="token punctuation">,</span> <span class="token keyword">boolean</span> value<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
                              
                              <span class="token annotation punctuation">@Override</span>
                              <span class="token keyword">public</span> NoopSpan <span class="token function">setTag</span><span class="token punctuation">(</span>String key<span class="token punctuation">,</span> Number value<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
                              
                              <span class="token annotation punctuation">@Override</span>
                              <span class="token keyword">public</span> <span class="token generics function"><span class="token punctuation">&lt;</span>T<span class="token punctuation">&gt;</span></span> NoopSpan <span class="token function">setTag</span><span class="token punctuation">(</span>Tag<span class="token generics function"><span class="token punctuation">&lt;</span>T<span class="token punctuation">&gt;</span></span> tag<span class="token punctuation">,</span> T value<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
                              
                              <span class="token annotation punctuation">@Override</span>
                              <span class="token keyword">public</span> NoopSpan <span class="token function">log</span><span class="token punctuation">(</span>Map<span class="token operator">&lt;</span>String<span class="token punctuation">,</span> <span class="token operator">?</span><span class="token operator">&gt;</span> fields<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
                              
                              <span class="token annotation punctuation">@Override</span>
                              <span class="token keyword">public</span> NoopSpan <span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">long</span> timestampMicroseconds<span class="token punctuation">,</span> Map<span class="token operator">&lt;</span>String<span class="token punctuation">,</span> <span class="token operator">?</span><span class="token operator">&gt;</span> fields<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
                              
                              <span class="token annotation punctuation">@Override</span>
                              <span class="token keyword">public</span> NoopSpan <span class="token function">log</span><span class="token punctuation">(</span>String event<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
                              
                              <span class="token annotation punctuation">@Override</span>
                              <span class="token keyword">public</span> NoopSpan <span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">long</span> timestampMicroseconds<span class="token punctuation">,</span> String event<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
                              
                              <span class="token annotation punctuation">@Override</span>
                              <span class="token keyword">public</span> NoopSpan <span class="token function">setBaggageItem</span><span class="token punctuation">(</span>String key<span class="token punctuation">,</span> String value<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
                              
                              <span class="token annotation punctuation">@Override</span>
                              <span class="token keyword">public</span> String <span class="token function">getBaggageItem</span><span class="token punctuation">(</span>String key<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> null<span class="token punctuation">;</span> <span class="token punctuation">}</span>
                              
                              <span class="token annotation punctuation">@Override</span>
                              <span class="token keyword">public</span> NoopSpan <span class="token function">setOperationName</span><span class="token punctuation">(</span>String operationName<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
                              
                              <span class="token annotation punctuation">@Override</span>
                              <span class="token keyword">public</span> String <span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> NoopSpan<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">.</span><span class="token function">getSimpleName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
                              

                                4.2 opentracing-util

                                一个简单的实现
                                在这里插入图片描述

                                4.2.1 ThreadLocalScope & ThreadLocalScopeManager

                                在这里插入图片描述
                                Scope和ScopeManager基于ThreadLocal 的实现。
                                场景
                                应用启动了开始产生trace消息,他的行为一定是这样的

                                1. mainThread线程,产生一个ThreadLocal<ThreadLocalScopeManager> MA
                                2. 请求过来,产生子线程 subThread, 子线程复制一个ThreadLocal<ThreadLocalScopeManager> subMA
                                3. subThreadsubMA 产生(activate)第一个spanA。此时当前span为A,subMA中保留A相关scopeA的引用,所以subMA.activeSpan()返回 A
                                4. spanA产生(activate)子span B。此时B中先保存A的引用,然后BsubMA中的原先A的引用,替换成自己。所以当获取当前Span时,就会拿到B的引用。
                                5. Bspan的生命周期结束了,然后将subMA中保留的B的引用,再次替换成A
                                6. 然后A的生名周期结束了,将subMA中引用置为null。
                                7. 子线程 subThread结束了,subMA的生命周期结束了

                                总结
                                ThreadLocalScopeManager 作为一个全局scope的管理者,保留有当前span的scope的引用。

                                ThreadLocalscope 需要保留当前ThreadLocalScopeManager的引用,和父或者上一个span的引用,并且生成时将ThreadLocalScopeManager中当前scope替换成自己。
                                ThreadLocalscope 结束时利用之前保留的引用进行还原。
                                这样就实现了一层一层的span

                                源码

                                public class ThreadLocalScope implements Scope {
                                    private final ThreadLocalScopeManager scopeManager;
                                    private final Span wrapped;
                                    private final ThreadLocalScope toRestore;
                                
                                <span class="token function">ThreadLocalScope</span><span class="token punctuation">(</span>ThreadLocalScopeManager scopeManager<span class="token punctuation">,</span> Span wrapped<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                                    <span class="token keyword">this</span><span class="token punctuation">.</span>scopeManager <span class="token operator">=</span> scopeManager<span class="token punctuation">;</span>
                                    <span class="token keyword">this</span><span class="token punctuation">.</span>wrapped <span class="token operator">=</span> wrapped<span class="token punctuation">;</span>
                                    <span class="token keyword">this</span><span class="token punctuation">.</span>toRestore <span class="token operator">=</span> scopeManager<span class="token punctuation">.</span>tlsScope<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                                    scopeManager<span class="token punctuation">.</span>tlsScope<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                                <span class="token punctuation">}</span>
                                
                                <span class="token annotation punctuation">@Override</span>
                                <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                                    <span class="token keyword">if</span> <span class="token punctuation">(</span>scopeManager<span class="token punctuation">.</span>tlsScope<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">this</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                                        <span class="token comment">// This shouldn't happen if users call methods in the expected order. Bail out.</span>
                                        <span class="token keyword">return</span><span class="token punctuation">;</span>
                                    <span class="token punctuation">}</span>
                                
                                    scopeManager<span class="token punctuation">.</span>tlsScope<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>toRestore<span class="token punctuation">)</span><span class="token punctuation">;</span>
                                <span class="token punctuation">}</span>
                                
                                Span <span class="token function">span</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                                    <span class="token keyword">return</span> wrapped<span class="token punctuation">;</span>
                                <span class="token punctuation">}</span>
                                

                                }

                                  public class ThreadLocalScopeManager implements ScopeManager {
                                      final ThreadLocal<ThreadLocalScope> tlsScope = new ThreadLocal<ThreadLocalScope>();
                                  
                                  <span class="token annotation punctuation">@Override</span>
                                  <span class="token keyword">public</span> Scope <span class="token function">activate</span><span class="token punctuation">(</span>Span span<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                                      <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">ThreadLocalScope</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> span<span class="token punctuation">)</span><span class="token punctuation">;</span>
                                  <span class="token punctuation">}</span>
                                  
                                  <span class="token annotation punctuation">@Override</span>
                                  <span class="token keyword">public</span> Span <span class="token function">activeSpan</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                                      ThreadLocalScope scope <span class="token operator">=</span> tlsScope<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                                      <span class="token keyword">return</span> scope <span class="token operator">==</span> null <span class="token operator">?</span> null <span class="token operator">:</span> scope<span class="token punctuation">.</span><span class="token function">span</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                                  <span class="token punctuation">}</span>
                                  

                                  }

                                    4.2.2 GlobalTracer

                                    在这里插入图片描述
                                    应用启动后,维持一个单例GlobalTracer
                                    在这里插入图片描述
                                    内部维持一个单例 Tracer,默认是NoopTracer
                                    所以使用时一般是先注册register新的单测实例。
                                    然后使用get获取
                                    然后就正常使用。

                                    4.3. opentracing-mock

                                    一个仅仅在内存中放置trace消息的测试程序
                                    在这里插入图片描述
                                    基于opentracing-util的包,产生了两个span。父子关系。

                                    public class MockTest {
                                        public static void main(String[] args) {
                                            // Initialize MockTracer with the default values.
                                            MockTracer tracer = new MockTracer();
                                            MockSpan span = tracer.buildSpan("root").start();
                                            try (Scope scope = tracer.scopeManager().activate(span)) {
                                                // Do things.
                                                span.setTag(Tags.COMPONENT, "my-own-application");
                                                System.out.println("current: "+tracer.scopeManager().activeSpan().toString());
                                    
                                            <span class="token comment">// 第二个</span>
                                    
                                            MockSpan subspan <span class="token operator">=</span> tracer<span class="token punctuation">.</span><span class="token function">buildSpan</span><span class="token punctuation">(</span><span class="token string">"sub"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                                            <span class="token keyword">try</span> <span class="token punctuation">(</span>Scope subscope <span class="token operator">=</span> tracer<span class="token punctuation">.</span><span class="token function">scopeManager</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">activate</span><span class="token punctuation">(</span>subspan<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                                                subspan<span class="token punctuation">.</span><span class="token function">setTag</span><span class="token punctuation">(</span>Tags<span class="token punctuation">.</span>COMPONENT<span class="token punctuation">,</span> <span class="token string">"my-own-application2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                                                System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"current: "</span><span class="token operator">+</span>tracer<span class="token punctuation">.</span><span class="token function">scopeManager</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">activeSpan</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                                                subspan<span class="token punctuation">.</span><span class="token function">finish</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                                            <span class="token punctuation">}</span>
                                    
                                    
                                        <span class="token punctuation">}</span> <span class="token keyword">catch</span><span class="token punctuation">(</span>Exception ex<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                                            Tags<span class="token punctuation">.</span>ERROR<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>span<span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                                            span<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>System<span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token string">"errormsg"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                                        <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{<!-- --></span>
                                            span<span class="token punctuation">.</span><span class="token function">finish</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                                        <span class="token punctuation">}</span>
                                    
                                        List<span class="token generics function"><span class="token punctuation">&lt;</span>MockSpan<span class="token punctuation">&gt;</span></span> spans <span class="token operator">=</span> tracer<span class="token punctuation">.</span><span class="token function">finishedSpans</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                                        <span class="token keyword">for</span><span class="token punctuation">(</span>MockSpan espan<span class="token operator">:</span>spans<span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span>
                                            System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>espan<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                                        <span class="token punctuation">}</span>
                                    
                                    <span class="token punctuation">}</span>
                                    

                                    }

                                      打印

                                      current: {traceId:1, spanId:2, parentId:0, operationName:"root"}
                                      current: {traceId:1, spanId:3, parentId:2, operationName:"sub"}
                                      {traceId:1, spanId:3, parentId:2, operationName:"sub"}
                                      {traceId:1, spanId:2, parentId:0, operationName:"root"}
                                      
                                       
                                       
                                        • 0
                                          点赞
                                        • 1
                                          收藏
                                          觉得还不错? 一键收藏
                                        • 0
                                          评论
                                        评论
                                        添加红包

                                        请填写红包祝福语或标题

                                        红包个数最小为10个

                                        红包金额最低5元

                                        当前余额3.43前往充值 >
                                        需支付:10.00
                                        成就一亿技术人!
                                        领取后你会自动成为博主和红包主的粉丝 规则
                                        hope_wisdom
                                        发出的红包
                                        实付
                                        使用余额支付
                                        点击重新获取
                                        扫码支付
                                        钱包余额 0

                                        抵扣说明:

                                        1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
                                        2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

                                        余额充值