Overview
First synchronization under the project:
the article to share, routing middleware - Jaeger link track (theory section).
This article we share: routing middleware - Jaeger link tracking (actual combat piece).
To be honest, this article does everyone waiting, the main point is there are just some of the technical research, there is no inventory.
Look at what we want to achieve:
API call five services, between 4 gRPC service, an HTTP service, service and service and call each other:
Speak services, and service calls Listen and Sing services.
Read the service, and the service is called Listen and Sing services.
Write service, and service calls Listen and Sing services.
We want to achieve is to look at the link API call.
Something about the theory, we can go and see the article or access to some information, this article is to realize how to use.
OK, open the whole.
Jaeger deployment
use All in one way for local deployment.
Download: https: //www.jaegertracing.io/download/
My computer is macOS select -> Binaries -> macOS
Download and unzip, you will find the following files:
example-hotrod 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
读(read)
端口:9903
通讯:gRPC
写(write)
端口:9904
通讯:gRPC
唱(sing)
端口:9905
通讯:HTTP
听、说、读、写、唱,想这几个服务的名称就花了好久 ~
我默认大家都会写 grpc 服务,如果不会写的,可以查看下我原来的文章《Go gRPC Hello World》。
应用示例
实例化 Tracer func NewJaegerTracer(serviceName string, jaegerHostPort string) (opentracing.Tracer, io.Closer, error) { cfg := &jaegerConfig.Configuration { Sampler: &jaegerConfig.SamplerConfig{ Type : "const", //固定采样 Param : 1, //1=全采样、0=不采样 }, Reporter: &jaegerConfig.ReporterConfig{ LogSpans : true, LocalAgentHostPort : jaegerHostPort, }, ServiceName: serviceName, } tracer, closer, err := cfg.NewTracer(jaegerConfig.Logger(jaeger.StdLogger)) if err != nil { panic(fmt.Sprintf("ERROR: cannot init Jaeger: %v\n", err)) } opentracing.SetGlobalTracer(tracer) return tracer, closer, err } HTTP 注入 injectErr := jaeger.Tracer.Inject(span.Context(), opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(req.Header)) if injectErr != nil { log.Fatalf("%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
效果
基本实现了,就到这吧。