- Add Version field to telemetry.Setup struct - Include service.version attribute in OpenTelemetry resource - Pass version.Short() from server to telemetry initialization - Follows OpenTelemetry semantic conventions for better observability - Enables version tracking in production traces Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
103 lines
2.7 KiB
Go
103 lines
2.7 KiB
Go
// Package telemetry provides OpenTelemetry instrumentation for the DanceLessonsCoach application
|
|
package telemetry
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
|
|
"go.opentelemetry.io/otel"
|
|
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
|
|
"go.opentelemetry.io/otel/propagation"
|
|
"go.opentelemetry.io/otel/sdk/resource"
|
|
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
|
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
|
|
"go.opentelemetry.io/otel/trace"
|
|
)
|
|
|
|
// Setup initializes OpenTelemetry tracing with the given configuration
|
|
type Setup struct {
|
|
ServiceName string
|
|
OTLPEndpoint string
|
|
Insecure bool
|
|
SamplerType string
|
|
SamplerRatio float64
|
|
Version string
|
|
}
|
|
|
|
// InitializeTracing sets up OpenTelemetry tracing provider
|
|
func (s *Setup) InitializeTracing(ctx context.Context) (*sdktrace.TracerProvider, error) {
|
|
// Create OTLP gRPC exporter
|
|
exporter, err := otlptracegrpc.New(ctx,
|
|
otlptracegrpc.WithEndpoint(s.OTLPEndpoint),
|
|
otlptracegrpc.WithInsecure(),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Create resource with service name and version
|
|
res, err := resource.New(ctx,
|
|
resource.WithAttributes(
|
|
semconv.ServiceName(s.ServiceName),
|
|
semconv.ServiceVersion(s.Version),
|
|
),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Create sampler based on configuration
|
|
sampler := s.getSampler()
|
|
|
|
// Create trace provider
|
|
tp := sdktrace.NewTracerProvider(
|
|
sdktrace.WithBatcher(exporter),
|
|
sdktrace.WithResource(res),
|
|
sdktrace.WithSampler(sampler),
|
|
)
|
|
|
|
// Set global tracer provider and propagator
|
|
otel.SetTracerProvider(tp)
|
|
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
|
|
propagation.TraceContext{},
|
|
propagation.Baggage{},
|
|
))
|
|
|
|
return tp, nil
|
|
}
|
|
|
|
// Shutdown performs cleanup of the tracer provider
|
|
func Shutdown(ctx context.Context, tp *sdktrace.TracerProvider) error {
|
|
if tp == nil {
|
|
return nil
|
|
}
|
|
return tp.Shutdown(ctx)
|
|
}
|
|
|
|
// getSampler returns the appropriate sampler based on configuration
|
|
func (s *Setup) getSampler() sdktrace.Sampler {
|
|
switch s.SamplerType {
|
|
case "always_on":
|
|
return sdktrace.AlwaysSample()
|
|
case "always_off":
|
|
return sdktrace.NeverSample()
|
|
case "traceidratio":
|
|
return sdktrace.TraceIDRatioBased(s.SamplerRatio)
|
|
case "parentbased_always_on":
|
|
return sdktrace.ParentBased(sdktrace.AlwaysSample())
|
|
case "parentbased_always_off":
|
|
return sdktrace.ParentBased(sdktrace.NeverSample())
|
|
case "parentbased_traceidratio":
|
|
return sdktrace.ParentBased(sdktrace.TraceIDRatioBased(s.SamplerRatio))
|
|
default:
|
|
log.Printf("Unknown sampler type: %s, defaulting to always_on", s.SamplerType)
|
|
return sdktrace.AlwaysSample()
|
|
}
|
|
}
|
|
|
|
// GetTracer returns a named tracer from the global provider
|
|
// Returns a no-op tracer if OpenTelemetry is not initialized
|
|
func GetTracer(name string) trace.Tracer {
|
|
return otel.Tracer(name)
|
|
}
|