110 lines
2.7 KiB
Go
110 lines
2.7 KiB
Go
// Package trace setup otlp trace and unified the traceID, requestID header, rid log
|
|
package trace
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"log/slog"
|
|
|
|
"github.com/samber/lo"
|
|
"go.opentelemetry.io/otel"
|
|
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
|
|
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
|
|
"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.37.0"
|
|
|
|
"git.ifooth.com/common/pkg/version"
|
|
)
|
|
|
|
// Option trace setup opt
|
|
type Option struct {
|
|
Enabled bool `json:"enabled"`
|
|
Endpoint string `json:"endpoint"`
|
|
Token string `json:"token"`
|
|
}
|
|
|
|
// SetupTrace setup trace by opt
|
|
func SetupTrace(ctx context.Context, opt *Option) error {
|
|
var (
|
|
exporter sdktrace.SpanExporter
|
|
err error
|
|
)
|
|
|
|
if opt.Enabled && opt.Endpoint != "" {
|
|
slog.InfoContext(ctx, "trace enabled", "exporter", "otlptracehttp", "endpoint", opt.Endpoint)
|
|
|
|
// 配置http上报地址
|
|
option := []otlptracehttp.Option{
|
|
otlptracehttp.WithEndpoint(opt.Endpoint),
|
|
otlptracehttp.WithInsecure(),
|
|
}
|
|
exporter, err = otlptracehttp.New(ctx, option...)
|
|
} else {
|
|
// 日志打印rid/span等
|
|
exporter, err = stdouttrace.New(stdouttrace.WithWriter(io.Discard))
|
|
}
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
tp, err := newTraceProvider(exporter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Set as global trace provider
|
|
otel.SetTracerProvider(tp)
|
|
|
|
// 支持传递traceparent/X-Request-Id
|
|
// W3C Trace Context traceparent = <version>-<trace-id>-<parent-id>-<flags>
|
|
propagator := propagation.NewCompositeTextMapPropagator(
|
|
propagation.TraceContext{}, // 支持从外部设置 traceparent
|
|
requestIDContext{}, // 支持外部设置 X-Request-Id
|
|
propagation.Baggage{},
|
|
)
|
|
otel.SetTextMapPropagator(propagator)
|
|
return nil
|
|
}
|
|
|
|
// Shutdown graceful shutdown trace exporter
|
|
func Shutdown(ctx context.Context) error {
|
|
tp, ok := otel.GetTracerProvider().(*sdktrace.TracerProvider)
|
|
if !ok || tp == nil {
|
|
return nil
|
|
}
|
|
|
|
return tp.Shutdown(ctx)
|
|
}
|
|
|
|
// OTEL tracer provider setup
|
|
func newTraceProvider(exp sdktrace.SpanExporter) (*sdktrace.TracerProvider, error) {
|
|
r, err := resource.Merge(
|
|
resource.Default(),
|
|
resource.NewWithAttributes(
|
|
semconv.SchemaURL,
|
|
semconv.ServiceName("trace"),
|
|
semconv.ServiceVersion(version.Version),
|
|
),
|
|
)
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("merge resource: %w", err)
|
|
}
|
|
|
|
provider := sdktrace.NewTracerProvider(
|
|
sdktrace.WithSampler(sdktrace.AlwaysSample()),
|
|
sdktrace.WithBatcher(exp),
|
|
sdktrace.WithResource(r),
|
|
)
|
|
return provider, nil
|
|
}
|
|
|
|
func init() {
|
|
// 默认只做context传递, 不导出到其他输出
|
|
lo.Must0(SetupTrace(context.Background(), new(Option)))
|
|
}
|