Jaeger全链路go实现,包含http和消息队列的链式传递

Jaeger全链路go实现,包含http和消息队列的链式传递

完整代码

https://github.com/werbenhu/jaeger-go-demo
同时,我提供了一个封装好的版本,更方便使用请参考
https://github.com/werbenhu/jaeger-go

本地链路

本地链路,不涉及到trace-id跨服务器传递。
通过opentracing.StartSpanFromContext即可完成,父span和子span关系
如下代码:

	tracer := opentracing.GlobalTracer()
	//创建根span
	rootSpan, rootCtx := opentracing.StartSpanFromContext(context.Background(), "root-span")
	//...
	//创建子span
	subSpan, subCtx := opentracing.StartSpanFromContext(rootCtx, "sub-span")
	//...
	//...
	subSpan.Finish()
	//...
	rootSpan.Finish()
	//...
http跨服务

http跨服务需要解决trace-id传递的问题,参考下面的文档
https://github.com/opentracing/opentracing-go
https://opentracing.io/docs/overview/inject-extract/

客户端请求的时候需要将trace-id放到header中

	client := &http.Client{}
	req, _ := http.NewRequest("GET","http://localhost:9002/server_two",nil)

	// refer to https://github.com/opentracing/opentracing-go
	// refer to https://opentracing.io/docs/overview/inject-extract/
	tracer := opentracing.GlobalTracer()
	// 生成一个请求的span
	clientSpan, clientCtx := opentracing.StartSpanFromContext(ctx, "http-one-req")
	carrier := opentracing.HTTPHeadersCarrier{}
	tracer.Inject(clientSpan.Context(), opentracing.HTTPHeaders, carrier)

	// 将当前span的trace-id传递到http header中
	for key, value := range carrier {
		req.Header.Add(key, value[0])
	}

	// 发送请求
	resp, _ := client.Do(req)
	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)

	//结束当前请求的span
	clientSpan.Finish()

服务器端要拿到客户端传递过来的trace-id,然后创建一个基于该trace-id的子span
也就是认客户端为父

	// 从http头中提取trace-id
	// refer to https://github.com/opentracing/opentracing-go
	// refer to https://opentracing.io/docs/overview/inject-extract/
	carrier := opentracing.HTTPHeadersCarrier{}
	carrier.Set("uber-trace-id", c.GetHeader("uber-trace-id"))

	tracer := opentracing.GlobalTracer()
	wireContext, err := tracer.Extract(
		opentracing.HTTPHeaders,
		opentracing.HTTPHeadersCarrier(c.Request.Header))
	if err != nil {
		log.Fatal(err)
	}

	// 由传递过来的trace-id作为父span
	serverSpan := opentracing.StartSpan(
		"server-two-http-root",
		ext.RPCServerOption(wireContext))

	ctx := opentracing.ContextWithSpan(context.Background(), serverSpan)
	selfCall(ctx)

		c.JSON(200, gin.H{
			"message": "server two response",
		})
		serverSpan.Finish()
消息队列实现全链路


这里以nsq为例
生产者将trace-id封装到msg中

	tracer := opentracing.GlobalTracer()
	clientSpan, clientCtx := opentracing.StartSpanFromContext(ctx, "nsq-one-req")
	carrier := opentracing.HTTPHeadersCarrier{}
	tracer.Inject(clientSpan.Context(), opentracing.HTTPHeaders, carrier)

	// 将trace-id封装到消息中,由消息队列,传给消费者
	msg, _ := json.Marshal(carrier)
	// 生产消息
	Produce(TopicName, string(msg))

	clientSpan.Finish()
	return clientCtx

消费者将trace-id取出,并创建基于该trace-id的子span,相当于认生产者为父

// 消费者消息处理,处理server-one发送过来的消息
func eventHandler(message string) error {
	fmt.Printf("event msg:%s
", message)

	jaeger := initJaeger("two1")
	defer jaeger.Close()

	// 读取消息中的trace-id
	var carrier opentracing.HTTPHeadersCarrier
	json.Unmarshal([]byte(message), &carrier)

	tracer := opentracing.GlobalTracer()
	wireContext, err := tracer.Extract(
		opentracing.HTTPHeaders,
		carrier)
	if err != nil {
		log.Fatal(err)
	}

	// 由传递过来的trace-id作为父span
	serverSpan := opentracing.StartSpan(
		"nsq_two",
		ext.RPCServerOption(wireContext))

	ctx := opentracing.ContextWithSpan(context.Background(), serverSpan)
	selfCall(ctx)
	serverSpan.Finish()

	return nil
}
原文地址:https://www.cnblogs.com/werben/p/14362974.html