package telemetry import ( "context" "errors" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/sdk/trace" "time" ) func InitTelemetry(ctx context.Context) (shutdown func(context.Context) error, err error) { var shutdownFuncs []func(context.Context) error // shutdown 会调用通过 shutdownFuncs 注册的清理函数。 // 调用产生的错误会被合并。 // 每个注册的清理函数将被调用一次。 shutdown = func(ctx context.Context) error { var err error for _, fn := range shutdownFuncs { err = errors.Join(err, fn(ctx)) } shutdownFuncs = nil return err } // handleErr 调用 shutdown 进行清理,并确保返回所有错误信息。 handleErr := func(inErr error) { err = errors.Join(inErr, shutdown(ctx)) } // 设置传播器 prop := newPropagator() otel.SetTextMapPropagator(prop) // 设置 trace provider. tracerProvider, err := newJaegerTraceProvider(ctx) if err != nil { handleErr(err) return } shutdownFuncs = append(shutdownFuncs, tracerProvider.Shutdown) otel.SetTracerProvider(tracerProvider) return } func newPropagator() propagation.TextMapPropagator { return propagation.NewCompositeTextMapPropagator( propagation.TraceContext{}, propagation.Baggage{}, ) } func newJaegerTraceProvider(ctx context.Context) (*trace.TracerProvider, error) { // 创建一个使用 HTTP 协议连接本机Jaeger的 Exporter traceExporter, err := otlptracehttp.New(ctx, otlptracehttp.WithEndpointURL("https://oltp.jerryyan.top/v1/traces")) if err != nil { return nil, err } traceProvider := trace.NewTracerProvider( trace.WithBatcher(traceExporter, // 默认为 5s。为便于演示,设置为 1s。 trace.WithBatchTimeout(time.Second)), ) return traceProvider, nil }