Go gin API routing middleware Jaeger link tracing

Summary

First, synchronize the following project overview:



The previous article shared the routing middleware Jaeger link tracking (Theory).

Let's share this article: routing Middleware - Jaeger link tracking (practical part).

To be honest, this article really keeps you waiting for a long time, mainly because there are some technical points that have just been studied and are not in stock.

Let's first look at what we want to achieve:


The API calls 5 services, including 4 gRPC services and 1 HTTP service. The services and services call each other:

Speak service, and then call Listen service and Sing service.

Read service, and then call Listen service and Sing service.

Write service, and then call Listen service and Sing service.

What we want to achieve is to check the link of API calls.

About some theoretical things, you can go to the last article or consult some materials, this article is how to use.

OK, turn it on.

Jaeger deployment

Let's use the way of All in one to deploy locally.

Download address: https://www.jaegertracing.io/download/

My computer is Mac OS selection - > binaries - > Mac OS

After downloading and decompressing, you will find the following files:

    example-hotrod

    jaeger-agent

    jaeger-all-in-one

    jaeger-collector

    jaeger-ingester

    jaeger-query

 


Enter the directory after decompression to execute:

./jaeger-all-in-one

 



After visual start, access address:

http://127.0.0.1:16686/



By now, Jaeger has been deployed successfully.

Prepare test service

The five test services prepared are as follows:
listen

Port: 9901

Communication: gRPC

speak

Port: 9902

Communication: gRPC

read

Port: 9903

Communication: gRPC

write

Port: 9904

Communication: gRPC

sing

Port: 9905

Communication: HTTP

Listening, speaking, reading, writing and singing took a long time to think about the names of these services~

By default, everyone will write grpc service. If you can't, you can check my original article Go gRPC Hello World.

Application example

instantiation Tracer

    func NewJaegerTracer(serviceName string, jaegerHostPort string) (opentracing.Tracer, io.Closer, error) {    
        cfg := &jaegerConfig.Configuration {    
            Sampler: &jaegerConfig.SamplerConfig{    
                Type  : "const", //Fixed sampling    
                Param : 1,       //1 = full sampling, 0 = no sampling    
            },    
            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 injection

    injectErr := jaeger.Tracer.Inject(span.Context(), opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(req.Header))    
    if injectErr != nil {    
        log.Fatalf("%s: Couldn't inject headers", err)    
    }


HTTP intercept

    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 injection

    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 intercept

    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)    
        }    
    }

 


Above are some core codes. I will upload all the codes involved to github for download.

Function
Startup service

 // Start the Listen service    
    cd listen && go run main.go    
    // Start the Speak service    
    cd speak && go run main.go    
    // Start Read service    
    cd read && go run main.go    
    // Start Write service    
    cd write && go run main.go    
    // Start Sing service    
    cd sing && go run main.go    
    // Start go gin API service    
    cd go-gin-api && go run main.go

 


Access routing

http://127.0.0.1:9999/jaeger_test

 



Effect




It's basically realized. Let's get there.

Tags: Go Mac github

Posted on Sat, 09 Nov 2019 05:44:35 -0800 by WhiteCube