83 lines
2.5 KiB
Go
83 lines
2.5 KiB
Go
// Package middleware defines OTel tracing infrastructure and gin middlewares.
|
|
package middleware
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"eventRT/config"
|
|
"eventRT/constants"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"go.opentelemetry.io/otel"
|
|
"go.opentelemetry.io/otel/attribute"
|
|
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
|
|
"go.opentelemetry.io/otel/propagation"
|
|
sdkresource "go.opentelemetry.io/otel/sdk/resource"
|
|
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
|
oteltrace "go.opentelemetry.io/otel/trace"
|
|
)
|
|
|
|
// InitTracerProvider creates an OTLP TracerProvider and registers it as the global provider.
|
|
// It registers the W3C TraceContext propagator (traceparent header).
|
|
// The caller is responsible for calling Shutdown on the returned provider during graceful shutdown.
|
|
func InitTracerProvider(ctx context.Context, cfg config.EventRTConfig) (*sdktrace.TracerProvider, error) {
|
|
opts := []otlptracehttp.Option{
|
|
otlptracehttp.WithEndpoint(cfg.OtelConfig.Endpoint),
|
|
}
|
|
if cfg.OtelConfig.Insecure {
|
|
opts = append(opts, otlptracehttp.WithInsecure())
|
|
}
|
|
|
|
exporter, err := otlptracehttp.New(ctx, opts...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create OTLP exporter: %w", err)
|
|
}
|
|
|
|
res := sdkresource.NewSchemaless(
|
|
attribute.String("service.name", cfg.ServiceName),
|
|
attribute.String("deployment.environment", cfg.DeployEnv),
|
|
)
|
|
|
|
tp := sdktrace.NewTracerProvider(
|
|
sdktrace.WithBatcher(exporter),
|
|
sdktrace.WithResource(res),
|
|
sdktrace.WithSampler(sdktrace.AlwaysSample()),
|
|
)
|
|
|
|
otel.SetTracerProvider(tp)
|
|
otel.SetTextMapPropagator(propagation.TraceContext{})
|
|
|
|
return tp, nil
|
|
}
|
|
|
|
// StartTrace extracts upstream W3C trace context from request headers and starts a server span.
|
|
func StartTrace() gin.HandlerFunc {
|
|
tracer := otel.Tracer("eventRT/http")
|
|
return func(c *gin.Context) {
|
|
ctx := otel.GetTextMapPropagator().Extract(
|
|
c.Request.Context(),
|
|
propagation.HeaderCarrier(c.Request.Header),
|
|
)
|
|
|
|
spanName := c.FullPath()
|
|
if spanName == "" {
|
|
spanName = c.Request.URL.Path
|
|
}
|
|
ctx, span := tracer.Start(ctx, spanName,
|
|
oteltrace.WithSpanKind(oteltrace.SpanKindServer),
|
|
)
|
|
defer span.End()
|
|
|
|
spanCtx := span.SpanContext()
|
|
ctx = context.WithValue(ctx, constants.CtxKeyTraceID, spanCtx.TraceID().String())
|
|
ctx = context.WithValue(ctx, constants.CtxKeySpanID, spanCtx.SpanID().String())
|
|
|
|
c.Request = c.Request.WithContext(ctx)
|
|
c.Set(constants.HeaderTraceID, spanCtx.TraceID().String())
|
|
c.Set(constants.HeaderSpanID, spanCtx.SpanID().String())
|
|
|
|
c.Next()
|
|
}
|
|
}
|