概要
首先,同步项目摘要:
在上一篇文章中共享的路由中间件- 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
效果
基本实现了,就到这吧。