友情提示, jaeger 的 standalone 部署方式, 可以快速开启试用.
本文通过两个简单的示例, 说明如何使用 java 的 API 构建一个简单的调用链. 相关代码见 GitHub, 更多连载请关注《小姐姐味道》.
https://github.com/sayhiai/example-jaeger-opentracing-tutorial-001-002
由于 jaeger 是基于 OpenTracing 的, 所以只要你的应用只要支持 OpenTracing 协议, 就可以和 Jaeger 集成起来.
OpenTracing 的地址是
https://opentracing.io/
编写一个 HelloWorld
一, maven 依赖
首先, 创建一个普通 maven 工程. 然后加入依赖:
- opentracing-util 0.32.0
- jaeger-client 0.35.0
- logback-classic 1.2.3
我们主要用到了 opentracing 相关的 jar 包, 而且用到了 jaeger 的 java 客户端实现.
二, 一段简单的代码
我们创建一个简单的 loveyou 类, 里面有一个简单的方法 hello . 本部分之与 OpenTracing 有关, 与 Jaeger 无关.
在 hello 方法体的前后, 加入几行简单的代码, 主要是根据 OpenTracing 规范定义的 API 进行一些内容的添加.
- public class LoveYou {
- Tracer tracer;
- public LoveYou() {
- tracer = JaegerTracerHelper.initTracer("loveYouService");
- }
- public void hello(String name) {
- Span span = tracer.buildSpan("hello").start();
- span.setTag("name", name);
- System.out.println("Hello" + name);
- span.log("Love service say hello to" + name);
- span.finish();
- }
- public static void main(String[] args) {
- new LoveYou().hello("小姐姐味道");
- }
- }
代码主要加入了以下几个重要的信息.
span tag 附着
执行代码后, 可以在 jaeger 的 ui 端看到这次的调用信息. 如下:
三, 构建 jaeger 实现
- public class JaegerTracerHelper {
- public static JaegerTracer initTracer(String service) {
- final String endPoint = "http://10.30.94.8:14268/api/traces";
- final CompositeReporter compositeReporter = new CompositeReporter(
- new RemoteReporter.Builder()
- .withSender(new HttpSender.Builder(endPoint).build())
- .build(),
- new LoggingReporter()
- );
- final Metrics metrics = new Metrics(new NoopMetricsFactory());
- JaegerTracer.Builder builder = new JaegerTracer.Builder(service)
- .withReporter(compositeReporter)
- .withMetrics(metrics)
- .withExpandExceptionLogs()
- .withSampler(new ConstSampler(true));
- return builder.build();
- }
- }
我们的 OpenTracing 数据是如何构建, 并发送到 Jaeger 的 server 端呢? 就是上面的代码完成的.
JaegerTracer 的参数很多, 本篇不做详细介绍. 要完成示例构建需要以下简单步骤:
构建 Reporter, 指发送到 server 的方式, 代码中构建了一个 http endpoint, 越过 jaeger-agent 直接发送到 jaeger-collector
构建一个 Sampler, 指定要收集的信息, 由于本次要收集所有的信息. 所以使用默认的 ConstSampler
哦对了, 为了便于调试和发现, 代码还加入了一个 LoggingReporter, 用于将 span 输出到控制台. 效果如下:
到此为止, 一个简单的示例 java 示例九完成了. 以上代码, 见 GitHub:
实现一个 2 层深度的链
以上代码, 仅产生了一个 span, 也就是一个方法调用. 接下来, 我们看一下如何完成一个多层的调用链条.
接下俩还是要修改我们的 LoveYou 类. 我们把调用方法 hello 拆解一下, 拆成 dispatch 和 hello 两个方法, 并在 hello 方法里 sleep 一秒钟.
- dispatch
- public void dispatch(String cmd, String content) {
- Span span = tracer.buildSpan("dispatch").start();
- tracer.activateSpan(span);
- if (cmd.equals("hello")) {
- this.hello(content);
- }
- if (null != span) {
- span.setTag("cmd", cmd);
- span.finish();
- }
- }
- hello
- public void hello(String name) {
- Span span = tracer.buildSpan("hello").start();
- tracer.activateSpan(span);
- System.out.println("Hello" + name);
- try {
- Thread.sleep(TimeUnit.SECONDS.toMillis(1));
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- span.setTag("name", name);
- span.log("Love service say hello to" + name);
- span.finish();
- }
与示例一不同的是, 每次生成 span 之后, 我们还要将其激活一下
tracer.activateSpan(span);
它的目的主要是让 span 实例在当前的 ctx 里面保持活跃 (比如一个线程). 这样, 如果新的 span 判断当前有活跃的 span, 则将其设置成它的 parent. 这样, 链条就串起来了.
以下是程序运行后的效果.
通过 OpenTracing 的 API, 可以很容易的实现调用链功能. 但可以看到, 由于存在各种各样的客户端, 主要工作量就集中在对这些客户端的兼容上. 比如线程池, SpringCloud,MQ, 数据库连接池等等等等.
使用 Aop 可以省去一些编码和侵入, 可控制性会更弱一些.
接下来, 我们给一个简单的 OkHttp+SpringBoot 调用, 添加 trace 功能.
来源: http://www.tuicool.com/articles/zeIn6bq