1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
| package telemetry
import ( "context"
"github.com/samber/lo" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" "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.4.0" "go.opentelemetry.io/otel/trace"
"{{{ .Package }}}/app/util" )
var ( Enabled = true initialized = false tracerProvider *sdktrace.TracerProvider )
func InitializeIfNeeded(enabled bool, version string, logger util.Logger) bool { if initialized { return false } if enabled { Initialize(version, logger) } return true }
func Initialize(_ string, logger util.Logger) { if initialized { logger.Warn("double telemetry initialization") return } otel.SetErrorHandler(&ErrHandler{logger: logger}) initialized = true
endpoint := "localhost:4318" if env := util.GetEnv("telemetry_endpoint"); env != "" { endpoint = env } logger.Debugf("initializing OpenTelemetry tracing using endpoint [%s]", endpoint) tp, err := buildTP(endpoint) if err != nil { logger.Errorf("unable to create tracing provider: %+v", err) return } tracerProvider = tp p := propagation.NewCompositeTextMapPropagator(propagation.Baggage{}, propagation.TraceContext{}) otel.SetTextMapPropagator(p) }
func buildTP(endpoint string) (*sdktrace.TracerProvider, error) { exporter, err := otlptracehttp.New(context.Background(), otlptracehttp.WithEndpoint(endpoint), otlptracehttp.WithInsecure()) if err != nil { return nil, err }
batcher := sdktrace.NewBatchSpanProcessor(exporter)
tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithSpanProcessor(batcher), sdktrace.WithResource(resource.NewWithAttributes(semconv.SchemaURL, semconv.ServiceNameKey.String(util.AppKey))), ) otel.SetTracerProvider(tp) return tp, nil }
func Close(ctx context.Context) error { return tracerProvider.Shutdown(ctx) }
func StartSpan(ctx context.Context, spanName string, logger util.Logger, opts ...any) (context.Context, *Span, util.Logger) { return spanCreate(ctx, spanName, logger, opts...) }
func StartAsyncSpan(ctx context.Context, spanName string, logger util.Logger, opts ...any) (context.Context, *Span, util.Logger) { parentSpan := trace.SpanFromContext(ctx) asyncChildCtx := trace.ContextWithSpan(context.Background(), parentSpan) return spanCreate(asyncChildCtx, spanName, logger, opts...) }
func spanCreate(ctx context.Context, spanName string, logger util.Logger, opts ...any) (context.Context, *Span, util.Logger) { tr := otel.GetTracerProvider().Tracer(util.AppKey) ssos := []trace.SpanStartOption{trace.WithSpanKind(trace.SpanKindServer)} lo.ForEach(opts, func(opt any, _ int) { o, ok := opt.(trace.SpanStartOption) if ok { ssos = append(ssos, o) } }) ctx, ot := tr.Start(ctx, spanName, ssos...) sp := &Span{OT: ot} if logger != nil { logger = LoggerFor(logger, sp) } return ctx, sp, logger }
|