[Series] - go-gin-api routing Middleware - Jaeger link tracking

Summary

Firstly, the project overview is synchronized:

Last article shared, Routing Middleware - Jaeger Link Tracking (theoretical article), this article we will continue to share: Routing Middleware - Jaeger Link Tracking (practical article).

This article, indeed, has kept you waiting for a long time, mainly because there are some technical points that have just been studied and there is no inventory.

Let's first look at what we are going to achieve:

The API calls five services, including four gRPC services and one HTTP service. The services and services call each other again:

  • Speak service calls Listen service and Sing service.
  • Read service calls Listen service and Sing service.
  • Write service, and then call Listen service and Sing service.

All we need to do is look at the API call link.

About some theoretical things, you can go to see an article or consult some information, this article is how to achieve the use.

OK, open up.

Jaeger deployment

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

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

My computer is macOS Selection - > Binaries - > macOS

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 decompressed directory to execute:

./jaeger-all-in-one

After visual inspection is started, access address:

http://127.0.0.1:16686/

By now, Jaeger has been deployed successfully.

Preparing Test Services

The five test services are as follows:

listen

  • Port: 9901
  • Communication: gRPC

Speech

  • 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.~

I default that everyone will write grpc service, if not, you can check my original article< Go gRPC Hello World>.

Application example

Instantiate 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 interception

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 interception

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

The above is some core code, all the code involved will be uploaded to github for download.

Function

Startup service

// Start the Listen service
cd listen && go run main.go

// Start Speak Service
cd speak && go run main.go

// Start Read Service
cd read && go run main.go

// Start the 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

That's it.

API source address

https://github.com/xinliangno...

Service source address

https://github.com/xinliangno...

go-gin-api series of articles

Keywords: Go github

Added by drakal30 on Sat, 28 Sep 2019 17:21:16 +0300