I'm trying to figure out the proper way to propagate a context.Context for the purposes of tracing with OpenTelemetry when using Gin.
I currently have a gin handler that calls a function and passes a *gin.Context, like so:
func (m Handler) doSomething(ginCtx *gin.Context, name string) {
ctx, span := otel.Tracer("mytracer").Start(ginCtx.Request.Context(), "doSomething")
defer span.End()
// ...
}
This actually results in incorrect spans, since before doSomething() is called, I create a new context.Context in the calling function with the parent span information (similar to the snippet above).
In most of my code, I'm passing around a context.Context, but figured I could make use of gin's Context. Otherwise I have to pass both types of contexts:
func (m Handler) doSomething(ctx context.Context, ginCtx *gin.Context, name string) {
ctx, span := otel.Tracer("mytracer").Start(ctx, "doSomething")
defer span.End()
// ...
}
This feels wrong since the Request stored in the *gin.Context is out of sync with what I'm passing around as a parameter via context.Context. However, I'm afraid to set the Request on the *gin.Context with a new Request that has the updated Context because
- It's only for this function and I'd have to un-set it (maybe through a
defer()?) - It doesn't seem like it'd be thread-safe (though I assume I'd need to
Copy()the gin Context in this scenario anyway)
Is the proper way to handle this just Copying the *gin.Context and modifying the Request with the new context.Context, then passing the *gin.Context around instead of context.Context?
I don't know what the implications are of Copying a gin.Context from the text:
Copy returns a copy of the current context that can be safely used outside the request's scope. This has to be used when the context has to be passed to a goroutine.
Can I still Abort() through a copied *gin.Context, and is the old one still usable after copying? I just need something that behaves like a stack in the same way that passing context.Contexts around does, where simply returning from the function "pops" the context off and I'm left with the old one.