3

I am trying to distribute tracing between 2 Go microservices using Opentelemetry and Gin-Gonic.

Please help, I have come across Otelhttp examples, but I couldn't find examples with Otelgin.

Using "go.opentelemetry.io/otel/sdk/trace" as tracesdk

Microservice 1

func TracerProvider() (*tracesdk.TracerProvider, error) {
    otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
    exporter, _:= stdouttrace.New(stdouttrace.WithPrettyPrint())
    tp := tracesdk.NewTracerProvider(
        tracesdk.WithSampler(tracesdk.AlwaysSample()),
        tracesdk.WithBatcher(exporter),
        tracesdk.WithResource(resource.NewWithAttributes(
            semconv.ServiceNameKey.String("microservice-1"),
            attribute.String("environment", "test"),
        )),
    )

    otel.SetTracerProvider(tp)
    return tp, nil
}
func main() {
    TracerProvider()
    resty := resty.New()

    router := gin.Default()
    router.Use(otelgin.Middleware("microservice-1"))
    {
        
        router.GET("/ping", func(c *gin.Context) {
            result := Result{}
            req := resty.R().SetHeader("Content-Type", "application/json")
            ctx := req.Context()
            span := trace.SpanFromContext(ctx)
            defer span.End()
            otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(req.Header))
            resp, _ := req.Get("http://localhost:8088/pong")

        json.Unmarshal([]byte(resp.String()), &result)
            c.IndentedJSON(200, gin.H{
                "message": result.Message,
            })
        })
    }
    router.Run(":8085")

}

// Microservice 2

//TracerProvider func is the same as Microservice 1

//main

TracerProvider()
router := gin.Default()
router.Use(otelgin.Middleware("microservice-2"))
{
    router.GET("/pong", func(c *gin.Context) {
        ctx := c.Request.Context()
        span := trace.SpanFromContext(otel.GetTextMapPropagator().Extract(ctx, propagation.HeaderCarrier(c.Request.Header)))
        defer span.End()

        c.IndentedJSON(200, gin.H{
            "message": "pong",
        })
    })
}
router.Run(":8088")

2 Answers2

2

There is an example of go-gin instrumentation in the official repository of OpenTelemetry Go Contrib: https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/instrumentation/github.com/gin-gonic/gin/otelgin/example

Basically, you need use the package:
"go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"

And you can also add the otelgin.HTML to render your response.

HTML will trace the rendering of the template as a child of the span in the given context.
This is a replacement for gin.Context.HTML function - it invokes the original function after setting up the span.

As detailed in its implementation: https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/instrumentation/github.com/gin-gonic/gin/otelgin/gintrace.go

Juliano Costa
  • 2,175
  • 2
  • 18
  • 30
0

It might be a bit late but it will still be useful. In the 1st microservice, you need to put:

req := resty.R().SetHeader("Content-Type", "application/json")
req.SetContext(c.Request.Context())

That will fix the problem. On this screenshot you are able to see the 2 spans on the 1st microservice

enter image description here

Lord-Y
  • 132
  • 2
  • 8