v2/tracing.go (64 lines of code) (raw):
package shuttle
import (
"context"
"go.opentelemetry.io/otel"
"github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus"
shuttleotel "github.com/Azure/go-shuttle/v2/otel"
"go.opentelemetry.io/otel/trace"
)
const (
serviceTracerName = "go-shuttle"
defaultReceiverHandleSpanName = "receiver.Handle"
)
type TracingHandlerOpts struct {
spanStartOptions []trace.SpanStartOption
traceProvider trace.TracerProvider
// spanNameFormat allows formatting the name of the span started in NewTracingHandler based on the received message.
// If not set, span name will be defaultReceiverHandleSpanName.
spanNameFormat func(defaultSpanName string, message *azservicebus.ReceivedMessage) string
}
func (t *TracingHandlerOpts) tracer() trace.Tracer {
if t.traceProvider == nil {
return otel.Tracer(serviceTracerName)
}
return t.traceProvider.Tracer(serviceTracerName)
}
// NewTracingHandler is a shuttle middleware that extracts the context from the message Application property if available,
// or from the existing context if not, and starts a span.
func NewTracingHandler(next Handler, options ...func(t *TracingHandlerOpts)) HandlerFunc {
t := &TracingHandlerOpts{
spanNameFormat: func(defaultSpanName string, _ *azservicebus.ReceivedMessage) string {
return defaultSpanName
},
}
for _, opt := range options {
opt(t)
}
return func(ctx context.Context, settler MessageSettler, message *azservicebus.ReceivedMessage) {
defaultStartOptions := []trace.SpanStartOption{trace.WithAttributes(shuttleotel.MessageAttributes(message)...)}
startOptions := append(defaultStartOptions, t.spanStartOptions...)
ctx, span := t.tracer().Start(
shuttleotel.Extract(ctx, message),
t.spanNameFormat(defaultReceiverHandleSpanName, message),
startOptions...)
defer span.End()
next.Handle(ctx, settler, message)
}
}
// WithTraceProvider allows setting a custom trace provider for the tracing handler in NewTracingHandler.
func WithTraceProvider(tp trace.TracerProvider) func(t *TracingHandlerOpts) {
return func(t *TracingHandlerOpts) {
t.traceProvider = tp
}
}
// WithReceiverSpanNameFormatter allows formatting name of the span started by the tracing handler in NewTracingHandler.
func WithReceiverSpanNameFormatter(format func(defaultSpanName string, message *azservicebus.ReceivedMessage) string) func(t *TracingHandlerOpts) {
return func(t *TracingHandlerOpts) {
t.spanNameFormat = format
}
}
// WithSpanStartOptions allows setting custom span start options for the tracing handler in NewTracingHandler.
func WithSpanStartOptions(options []trace.SpanStartOption) func(t *TracingHandlerOpts) {
return func(t *TracingHandlerOpts) {
t.spanStartOptions = options
}
}
// WithTracePropagation is a sender option to inject the trace context into the message
func WithTracePropagation(ctx context.Context) func(msg *azservicebus.Message) error {
return func(message *azservicebus.Message) error {
shuttleotel.Inject(ctx, message)
return nil
}
}