参考地址:https://github.com/yurishkuro/opentracing-tutorial/tree/master/go
jaeger是一个比较有名的分布式链路追踪系统,底层用golang实现,兼容opentracing标准,这里利用其go-client来实现一个最简单的demo,仅供参考。
1. 安装必要的包:
"github.com/opentracing/opentracing-go"
"github.com/uber/jaeger-client-go"
"github.com/uber/jaeger-client-go/config"
2. 安装部署jaeger整套:
这里利用jaeger提供的docker,集成了整套环境,利用内存存储:docker hub地址:https://hub.docker.com/r/jaegertracing/all-in-one
直接运行一下命令启动docker:
docker run -d --name jaeger \
-e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \
-p 5775:5775/udp \
-p 6831:6831/udp \
-p 6832:6832/udp \
-p 5778:5778 \
-p 16686:16686 \
-p 14268:14268 \
-p 9411:9411 \
jaegertracing/all-in-one:1.9
运行ok后我们docker ps看一下是否正常运行:
现在可以访问localhost:16686来查看jaeger的UI界面:
3. 编写demo
先编写一个初始化jaeger tracer的initJaeger方法:
此时我们要在reporter中配置jaeger Agent的ip与端口,以便将tracer的信息发布到agent中。
配置LocalAgentHostPort参数为127.0.0.1:6381,6381接口是接受压缩格式的thrift协议数据。
采样率暂且设置为1。
func initJaeger(service string) (opentracing.Tracer, io.Closer) {
cfg := &config.Configuration{
Sampler: &config.SamplerConfig{
Type: "const",
Param: 1,
},
Reporter: &config.ReporterConfig{
LogSpans: true,
LocalAgentHostPort:"127.0.0.1:6831",
},
}
tracer, closer, err := cfg.New(service, config.Logger(jaeger.StdLogger))
if err != nil {
panic(fmt.Sprintf("ERROR: cannot init Jaeger: %v\n", err))
}
return tracer, closer
}
然后我们在main函数中创建调用InitJaeger,并创建一个root span,调用两个函数,分别表示调用两个分布式服务。
我们用ContextWithSpan来创建一个新的ctx,将span的信息与context关联,传到foo3中时,需要创建一个子span,父span是ctx中的span。
我们在foo3中调用StartSpanFromContext时,忽略了第二个参数,这是利用子span创建的新的context,当我们在foo3中再调用别的比如foo5时,我们应该使用新的context,而不是传入的ctx。
注意StartSpanFromContext会用到opentracing.SetGlobalTracer()来启动新的span,所以在main函数中需要调用。
func foo3(req string, ctx context.Context) (reply string){
//1.创建子span
span, _ := opentracing.StartSpanFromContext(ctx, "span_foo3")
defer func() {
//4.接口调用完,在tag中设置request和reply
span.SetTag("request", req)
span.SetTag("reply", reply)
span.Finish()
}()
println(req)
//2.模拟处理耗时
time.Sleep(time.Second/2)
//3.返回reply
reply = "foo3Reply"
return
}
//跟foo3一样逻辑
func foo4(req string, ctx context.Context) (reply string){
span, _ := opentracing.StartSpanFromContext(ctx, "span_foo4")
defer func() {
span.SetTag("request", req)
span.SetTag("reply", reply)
span.Finish()
}()
println(req)
time.Sleep(time.Second/2)
reply = "foo4Reply"
return
}
func main() {
tracer, closer := initJaeger("jaeger-demo")
defer closer.Close()
opentracing.SetGlobalTracer(tracer)//StartspanFromContext创建新span时会用到
span := tracer.StartSpan("span_root")
ctx := opentracing.ContextWithSpan(context.Background(), span)
r1 := foo3("Hello foo3", ctx)
r2 := foo4("Hello foo4", ctx)
fmt.Println(r1, r2)
span.Finish()
}
4. 运行结果:
运行完提交的span信息会被log打印出来:
2019/02/26 13:21:44 Initializing logging reporter
Hello foo3
2019/02/26 13:21:45 Reporting span 8acae1d479b9829:12f2820e87c75e51:8acae1d479b9829:1
Hello foo4
2019/02/26 13:21:45 Reporting span 8acae1d479b9829:7cca0d1cc894735:8acae1d479b9829:1
foo3Reply foo4Reply
2019/02/26 13:21:45 Reporting span 8acae1d479b9829:8acae1d479b9829:0:1
Process finished with exit code 0
同时jaeger UI上会发现对应的记录:
可以发现有很明显的分层,时间耗时也很明显,接口先后调用也很清晰。
NEXT~~~~~
进阶版:我们现在只是在同一个服务中实现了jaeger的demo,如果在分布式的服务中,如何实现jaeger呢?
请参考:opentracing: jaeger在grpc中的简单实现