mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2026-01-09 04:54:25 +00:00
Code sanity fixes, added middlewares
This commit is contained in:
146
pkg/tracing/tracing.go
Normal file
146
pkg/tracing/tracing.go
Normal file
@@ -0,0 +1,146 @@
|
||||
package tracing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"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/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"
|
||||
)
|
||||
|
||||
var tracer trace.Tracer
|
||||
|
||||
// Config holds tracing configuration
|
||||
type Config struct {
|
||||
ServiceName string
|
||||
ServiceVersion string
|
||||
Endpoint string // OTLP endpoint (e.g., "localhost:4317")
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
// InitTracer initializes the OpenTelemetry tracer
|
||||
func InitTracer(config Config) (func(context.Context) error, error) {
|
||||
if !config.Enabled {
|
||||
// Return no-op shutdown function
|
||||
return func(context.Context) error { return nil }, nil
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Create OTLP exporter
|
||||
client := otlptracegrpc.NewClient(
|
||||
otlptracegrpc.WithEndpoint(config.Endpoint),
|
||||
otlptracegrpc.WithInsecure(), // Use WithTLSCredentials in production
|
||||
)
|
||||
|
||||
exporter, err := otlptrace.New(ctx, client)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create OTLP exporter: %w", err)
|
||||
}
|
||||
|
||||
// Create resource
|
||||
res, err := resource.New(ctx,
|
||||
resource.WithAttributes(
|
||||
semconv.ServiceNameKey.String(config.ServiceName),
|
||||
semconv.ServiceVersionKey.String(config.ServiceVersion),
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create resource: %w", err)
|
||||
}
|
||||
|
||||
// Create trace provider
|
||||
tp := sdktrace.NewTracerProvider(
|
||||
sdktrace.WithBatcher(exporter),
|
||||
sdktrace.WithResource(res),
|
||||
sdktrace.WithSampler(sdktrace.AlwaysSample()),
|
||||
)
|
||||
|
||||
// Set global trace provider
|
||||
otel.SetTracerProvider(tp)
|
||||
|
||||
// Set global propagator
|
||||
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
|
||||
propagation.TraceContext{},
|
||||
propagation.Baggage{},
|
||||
))
|
||||
|
||||
// Get tracer
|
||||
tracer = tp.Tracer(config.ServiceName)
|
||||
|
||||
// Return shutdown function
|
||||
return tp.Shutdown, nil
|
||||
}
|
||||
|
||||
// Middleware returns an HTTP middleware that creates spans for requests
|
||||
func Middleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if tracer == nil {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// Extract context from request headers
|
||||
ctx := otel.GetTextMapPropagator().Extract(r.Context(), propagation.HeaderCarrier(r.Header))
|
||||
|
||||
// Start span
|
||||
ctx, span := tracer.Start(ctx, r.Method+" "+r.URL.Path,
|
||||
trace.WithSpanKind(trace.SpanKindServer),
|
||||
trace.WithAttributes(
|
||||
semconv.HTTPMethodKey.String(r.Method),
|
||||
semconv.HTTPURLKey.String(r.URL.String()),
|
||||
semconv.HTTPTargetKey.String(r.URL.Path),
|
||||
semconv.HTTPSchemeKey.String(r.URL.Scheme),
|
||||
semconv.NetHostNameKey.String(r.Host),
|
||||
),
|
||||
)
|
||||
defer span.End()
|
||||
|
||||
// Create new request with updated context
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// StartSpan starts a new span with the given name
|
||||
func StartSpan(ctx context.Context, name string, attrs ...attribute.KeyValue) (context.Context, trace.Span) {
|
||||
if tracer == nil {
|
||||
return ctx, trace.SpanFromContext(ctx)
|
||||
}
|
||||
return tracer.Start(ctx, name, trace.WithAttributes(attrs...))
|
||||
}
|
||||
|
||||
// SpanFromContext returns the current span from the context
|
||||
func SpanFromContext(ctx context.Context) trace.Span {
|
||||
return trace.SpanFromContext(ctx)
|
||||
}
|
||||
|
||||
// AddEvent adds an event to the current span
|
||||
func AddEvent(ctx context.Context, name string, attrs ...attribute.KeyValue) {
|
||||
span := trace.SpanFromContext(ctx)
|
||||
span.AddEvent(name, trace.WithAttributes(attrs...))
|
||||
}
|
||||
|
||||
// SetAttributes sets attributes on the current span
|
||||
func SetAttributes(ctx context.Context, attrs ...attribute.KeyValue) {
|
||||
span := trace.SpanFromContext(ctx)
|
||||
span.SetAttributes(attrs...)
|
||||
}
|
||||
|
||||
// RecordError records an error on the current span
|
||||
func RecordError(ctx context.Context, err error) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
span := trace.SpanFromContext(ctx)
|
||||
span.RecordError(err)
|
||||
}
|
||||
Reference in New Issue
Block a user