概要

首先,同步项目摘要:

在上一篇文章中共享的路由中间件- Jaeger链路跟踪(理论篇)。

在本文中,让我们共享路由中间件- Jaeger链路跟踪(实战篇)。

老实说,这篇文章确实让大家等了很久。 主要是里面刚研究过,没有库存。

首先,让我们来看看我们要实现的:

API调用五个服务,其中四个gRPC服务,一个HTTP服务,服务和服务之间又相互调用。

Speak服务调用了侦听服务和Sing服务。

Read服务调用了侦听服务和Sing服务。

Write服务调用了侦听服务和Sing服务。

我们要实现的是看到API调用的链接。

关于理论上的东西,看看前面的报道,或者查一下资料吧。 这篇文章是实现如何使用。

OK,重新打开。

部署Jaeger

我们用All in one的方式进行当地的引进吧。

下载地址: https://www.jaeger tracing.io/download /

我的电脑是macOS选择- Binaries - macOS

下载并解压缩后,将找到以下文件:

快速热读

jaeger-agent

jaeger-all-in-one

jaeger-collector

jaeger-ingester

jaeger-query

导航到解压缩后的目录并运行:

./jaeger-all-in-one

目视启动后,访问地址:

http://127.0.0.1:16686/

这里还准备了一份学习图和资料。 如下所示。

现在,Jaeger已成功部署。

准备测试服务

准备的五项测试服务包括:

听(listen ) )。

端口: 9901

通信: gRPC

说(speak ) )。

端口: 9902

通信: gRPC

阅读(读取)。

端口: 9903

通信: gRPC

写入(write )

端口: 9904

通信: gRPC

唱歌(sing ) )

端口: 9905

通信: HTTP

听、说、读、写、唱,花了很长时间思考这些服务的名称~

默认情况下,大家都写grpc服务,但如果写不出来,请查看原始文章《Go gRPC Hello World》。

应用示例

实例化跟踪器

funcnewjaegertracer (服务名称字符串,jaeger主机端口字符串) ) opentracing.Tracer,io.Closer,error

CFG :=jaeger config.configuration {

sampler : jaeger config.sampler config {

类型: ' const ',//固定采样

Param : 1,//1=所有采样,0=不采样

(,

reporter : jaeger config.reporter config {

log spans :真,

本地主机端口3360 jaeger主机端口,

(,

服务名称:服务名称、

}

tracer,closer,err :=CFG.new tracer (jaeger config.logger ) Jaeger.STDlogger ) )

if err!=nil {

panic (fmt.sprintf (error : cannotinitjaeger : % v\n ),err ) )

}

open tracing.set全局跟踪器(跟踪器) )。

返回跟踪器,关闭器,err

}

HTTP注入

injecterr :=jaeger.tracer.inject (span.context (,opentracing.HTTPHeaders,opentracing.httpheaderscarrier

if喷射器!=nil {

log.Fa

talf("%s: Couldn't inject headers", err)

}

HTTP 拦截

spCtx, err := opentracing.GlobalTracer().Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(c.Request.Header))

if err != nil {

ParentSpan = Tracer.StartSpan(c.Request.URL.Path)

defer ParentSpan.Finish()

} else {

ParentSpan = opentracing.StartSpan(

c.Request.URL.Path,

opentracing.ChildOf(spCtx),

opentracing.Tag{Key: string(ext.Component), Value: "HTTP"},

ext.SpanKindRPCServer,

)

defer ParentSpan.Finish()

}

gRPC 注入

func ClientInterceptor(tracer opentracing.Tracer, spanContext opentracing.SpanContext) grpc.UnaryClientInterceptor {

return func(ctx context.Context, method string,

req, reply interface{}, cc *grpc.ClientConn,

invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {

span := opentracing.StartSpan(

"call gRPC",

opentracing.ChildOf(spanContext),

opentracing.Tag{Key: string(ext.Component), Value: "gRPC"},

ext.SpanKindRPCClient,

)

defer span.Finish()

md, ok := metadata.FromOutgoingContext(ctx)

if !ok {

md = metadata.New(nil)

} else {

md = md.Copy()

}

err := tracer.Inject(span.Context(), opentracing.TextMap, MDReaderWriter{md})

if err != nil {

span.LogFields(log.String("inject-error", err.Error()))

}

newCtx := metadata.NewOutgoingContext(ctx, md)

err = invoker(newCtx, method, req, reply, cc, opts...)

if err != nil {

span.LogFields(log.String("call-error", err.Error()))

}

return err

}

}

gRPC 拦截

func serverInterceptor(tracer opentracing.Tracer) grpc.UnaryServerInterceptor {

return func(ctx context.Context,

req interface{},

info *grpc.UnaryServerInfo,

handler grpc.UnaryHandler) (resp interface{}, err error) {

md, ok := metadata.FromIncomingContext(ctx)

if !ok {

md = metadata.New(nil)

}

spanContext, err := tracer.Extract(opentracing.TextMap, MDReaderWriter{md})

if err != nil && err != opentracing.ErrSpanContextNotFound {

grpclog.Errorf("extract from metadata err: %v", err)

} else {

span := tracer.StartSpan(

info.FullMethod,

ext.RPCServerOption(spanContext),

opentracing.Tag{Key: string(ext.Component), Value: "gRPC"},

ext.SpanKindRPCServer,

)

defer span.Finish()

ParentContext = opentracing.ContextWithSpan(ctx, span)

}

return handler(ParentContext, req)

}

}

上面是一些核心的代码,涉及到的全部代码我都会上传到 github,供下载。

运行

启动服务

// 启动 Listen 服务

cd listen && go run main.go

// 启动 Speak 服务

cd speak && go run main.go

// 启动 Read 服务

cd read && go run main.go

// 启动 Write 服务

cd write && go run main.go

// 启动 Sing 服务

cd sing && go run main.go

// 启动 go-gin-api 服务

cd go-gin-api && go run main.go

访问路由

http://127.0.0.1:9999/jaeger_test

效果

基本实现了,就到这吧。