Skip to content

How to add OpenTelemetry tracing

Wrap command handlers, query handlers, event handlers, and the event store with OpenTelemetry middleware.

Prerequisites

go get github.com/terraskye/eventsourcing/otel
go get go.opentelemetry.io/otel

Wrap a command handler

import (
    "github.com/terraskye/eventsourcing/otel"
    oteltrace "go.opentelemetry.io/otel"
)

tracer := oteltrace.Tracer("my-service")

// Assuming createTaskHandler is eventsourcing.CommandHandler[CreateTask]
tracedHandler := otel.TraceCommandHandler(tracer, createTaskHandler,
    otel.WithOperation("CreateTask"),
)

Each command execution creates a span named "CreateTask" under the current trace.

Wrap a query handler

tracedQuery := otel.TraceQueryHandler(tracer, queryHandler,
    otel.WithOperation("ListTasks"),
)

Wrap the event store

tracedStore := otel.TraceEventStore(tracer, store,
    otel.WithOperation("EventStore"),
)

Pass tracedStore to your command/query handlers instead of the raw store.

Wrap an event handler

tracedEventHandler := otel.TraceEventHandler(tracer, projector.EventHandlers(),
    otel.WithOperation("TaskListProjector"),
)
bus.Subscribe(ctx, "task-list", tracedEventHandler)

Add custom attributes

Use WithAttributes for static attributes, or WithAttributeGetter for dynamic ones extracted from context:

import "go.opentelemetry.io/otel/attribute"

tracedHandler := otel.TraceCommandHandler(tracer, handler,
    otel.WithOperation("CreateTask"),
    otel.WithAttributes(attribute.String("service.version", "1.0.0")),
    otel.WithAttributeGetter(func(ctx context.Context) []attribute.KeyValue {
        if tenantID, ok := ctx.Value("tenant_id").(string); ok {
            return []attribute.KeyValue{attribute.String("tenant.id", tenantID)}
        }
        return nil
    }),
)

Dynamic operation names

Use WithOperationGetter to set the span name from context at runtime:

otel.WithOperationGetter(func(ctx context.Context, operation string) string {
    if userID, ok := ctx.Value("user_id").(string); ok {
        return operation + ":" + userID
    }
    return operation
})

Available otel wrappers

Function Wraps
otel.TraceCommandHandler CommandHandler[C]
otel.TraceQueryHandler QueryHandler[T, R]
otel.TraceEventStore EventStore
otel.TraceEventHandler EventHandler
otel.TraceEventBus EventBus