106 lines
2.6 KiB
Go
106 lines
2.6 KiB
Go
package tracing
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"os"
|
|
"time"
|
|
|
|
"go.opentelemetry.io/otel"
|
|
"go.opentelemetry.io/otel/attribute"
|
|
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
|
|
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
|
|
"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.24.0"
|
|
"go.opentelemetry.io/otel/trace"
|
|
)
|
|
|
|
const (
|
|
AppName = "WeKnoraApp"
|
|
)
|
|
|
|
type Tracer struct {
|
|
Cleanup func(context.Context) error
|
|
}
|
|
|
|
var tracer trace.Tracer
|
|
|
|
// InitTracer initializes OpenTelemetry tracer
|
|
func InitTracer() (*Tracer, error) {
|
|
// Create resource description
|
|
labels := []attribute.KeyValue{
|
|
semconv.TelemetrySDKLanguageGo,
|
|
semconv.ServiceNameKey.String(AppName),
|
|
}
|
|
res := resource.NewWithAttributes(semconv.SchemaURL, labels...)
|
|
var err error
|
|
|
|
// First try to create OTLP exporter (can connect to Jaeger, Zipkin, etc.)
|
|
var traceExporter sdktrace.SpanExporter
|
|
if endpoint := os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT"); endpoint != "" {
|
|
// Use gRPC exporter
|
|
client := otlptracegrpc.NewClient(
|
|
otlptracegrpc.WithEndpoint(endpoint),
|
|
otlptracegrpc.WithInsecure(),
|
|
)
|
|
traceExporter, err = otlptrace.New(context.Background(), client)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
// If no OTLP endpoint is set, default to standard output
|
|
traceExporter, err = stdouttrace.New()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// Create batch SpanProcessor
|
|
bsp := sdktrace.NewBatchSpanProcessor(traceExporter)
|
|
|
|
sampler := sdktrace.AlwaysSample()
|
|
|
|
// Create and register TracerProvider
|
|
tp := sdktrace.NewTracerProvider(
|
|
sdktrace.WithSampler(sampler),
|
|
sdktrace.WithResource(res),
|
|
sdktrace.WithSpanProcessor(bsp),
|
|
)
|
|
otel.SetTracerProvider(tp)
|
|
|
|
// Set global propagator
|
|
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
|
|
propagation.TraceContext{},
|
|
propagation.Baggage{},
|
|
))
|
|
|
|
// Create Tracer for project use
|
|
tracer = tp.Tracer(AppName)
|
|
|
|
// Return cleanup function
|
|
return &Tracer{
|
|
Cleanup: func(ctx context.Context) error {
|
|
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
|
defer cancel()
|
|
if err := tp.Shutdown(ctx); err != nil {
|
|
log.Printf("Error shutting down tracer provider: %v", err)
|
|
return err
|
|
}
|
|
return nil
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
// GetTracer gets global Tracer
|
|
func GetTracer() trace.Tracer {
|
|
return tracer
|
|
}
|
|
|
|
// Create context with span
|
|
func ContextWithSpan(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
|
|
return GetTracer().Start(ctx, name, opts...)
|
|
}
|