opentracing: jaeger的简单实现

参考地址:https://github.com/yurishkuro/opentracing-tutorial/tree/master/go

jaeger是一个比较有名的分布式链路追踪系统,底层用golang实现,兼容opentracing标准,这里利用其go-client来实现一个最简单的demo,仅供参考。

1. 安装必要的包:

  "github.com/opentracing/opentracing-go"

  "github.com/opentracing/opentracing-go/log"

  "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

现在可以访问localhost:16686来查看jaeger的UI界面:

 

 

 

3. 编写demo

先编写一个初始化jaeger tracer的initJaeger方法:

此时我们要在reporter中配置jaeger Agent的ip与端口,以便将tracer的信息发布到agent中。

配置接口是接受压缩格式的thrift协议数据。

采样率暂且设置为1

 

然后我们在main函数中创建调用InitJaeger,并创建一个root span,调用两个函数,分别表示调用两个分布式服务。

我们用ContextWithSpan来创建一个新的ctx,将span的信息与context关联,传到formatstring中时,需要创建一个子span,父span是ctx中的span。

我们在formatstring中调用StartSpanFromContext时,忽略了第二个参数,这是利用子span创建的新的context,当我们在formatstring中再调用别的比如服务时,我们应该使用新的context,而不是传入的ctx。

注意StartSpanFromContext会用到opentracing.SetGlobalTracer()来启动新的span,所以在main函数中需要调用。
代码:

  

func main() {
if len(os.Args) != 2{
panic("ERROR: Expecting one argument")
}

tracer, cloer := Init("hello-world")
defer cloer.Close()
opentracing.SetGlobalTracer(tracer)

helloTo := os.Args[1]

span := tracer.StartSpan("say-hello")
span.SetTag("hello-to", helloTo)
defer span.Finish()

ctx := opentracing.ContextWithSpan(context.Background(), span)

helloStr := formatString(ctx, helloTo)

printHello(ctx, helloStr)

//helloStr := fmt.Sprintf("Hello, %s!", helloTo)


}

func formatString(ctx context.Context, helloTo string) string {
span, _ := opentracing.StartSpanFromContext(ctx, "formatString")
defer span.Finish()

v := url.Values{}
v.Set("helloTo", helloTo)
url := "http://localhost:8081/format?" + v.Encode()
req, err := http.NewRequest("GET", url, nil)
if err != nil {
panic(err.Error())
}
xhttp := &http.Client{}
resp, err := xhttp.Do(req)
if err != nil {
panic(err.Error())
}

defer resp.Body.Close()

buf, err := ioutil.ReadAll(resp.Body)

helloStr := string(buf)

span.LogFields(
log.String("event", "string-format"),
log.String("value", helloStr),
)

return helloStr
}

func printHello(ctx context.Context, helloStr string) {
span, _ := opentracing.StartSpanFromContext(ctx, "printHello")
defer span.Finish()

v := url.Values{}
v.Set("helloStr", helloStr)
url := "http://localhost:8082/publish?" + v.Encode()
req, err := http.NewRequest("GET", url, nil)
if err != nil {
panic(err.Error())
}


xhttp := &http.Client{}
_, err = xhttp.Do(req)
if err != nil {
panic(err.Error())
}

}



// Init returns an instance of Jaeger Tracer that samples 100% of traces and logs all spans to stdout.
func Init(service string) (opentracing.Tracer, io.Closer) {
cfg := &config.Configuration{
Sampler: &config.SamplerConfig{
Type: "const",
Param: 1,
},
Reporter: &config.ReporterConfig{
LogSpans: true,
},
}
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
}

运行结果:

192:client small_lei_it$ go run main.go xiaolei
2020/03/04 10:18:55 Initializing logging reporter
2020/03/04 10:18:55 Reporting span 7329f9cac13f0f0f:4398534377caaa9a:7329f9cac13f0f0f:1
2020/03/04 10:18:55 Reporting span 7329f9cac13f0f0f:6eaefac21f1e1179:7329f9cac13f0f0f:1
2020/03/04 10:18:55 Reporting span 7329f9cac13f0f0f:7329f9cac13f0f0f:0:1

同时jaeger UI上会发现对应的记录:

可以发现有很明显的分层,时间耗时也很明显,接口先后调用也很清晰

 

调用树结构图:

 

posted @ 2020-03-04 10:38  small_lei_it  阅读(685)  评论(0)    收藏  举报