ello-golang-otel

module
v1.5.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 2, 2026 License: Apache-2.0

README

Ello Go OpenTelemetry

Common packages for integrating OpenTelemetry distributed tracing and metrics.

Configuration

Configuration is read from environment variables using config.NewFromEnv().

Variable Description Default
OTEL_ENABLED Enable OTEL tracing and metrics false
OTEL_EXPORTER_OTLP_ENDPOINT OTLP HTTP exporter base URL (e.g. http://jaeger:4318)
OTEL_SERVICE_NAME Service name reported to the OTEL backend unknown-service
OTEL_SERVICE_VERSION Service version (e.g. a semver or git SHA)
ENVIRONMENT Deployment environment (e.g. production) unknown
OTEL_SAMPLE_RATE Fraction of traces to sample, 0.01.0 1.0

When OTEL_ENABLED is false, all providers return no-op implementations with zero overhead.

OTEL_EXPORTER_OTLP_ENDPOINT is normally left path-less — the trace and metric exporters append /v1/traces and /v1/metrics respectively. To target the literal root instead, add a trailing / (e.g. http://jaeger:4318/).

Provider

Tracer

NewTracerProvider accepts functional options to configure export and propagation behaviour:

Option Effect
WithLambda() Synchronous export via SimpleSpanProcessor — spans are delivered before the Lambda container is frozen
WithXRay() X-Ray ID generator (timestamp-prefixed trace IDs required by ADOT) + X-Ray propagator for X-Amzn-Trace-Id headers

WithLambda and WithXRay are independent: a Lambda may send to a non-X-Ray backend, and a non-Lambda service could use X-Ray.

cfg := config.NewFromEnv()

// Long-running service, no options needed
tracer, shutdown, err := provider.NewTracerProvider(ctx, cfg)

// Lambda sending to a non-X-Ray backend
tracer, shutdown, err := provider.NewTracerProvider(ctx, cfg, provider.WithLambda())

// Lambda with ADOT/X-Ray (convenience wrapper for the common Ello case)
tracer, shutdown, err := provider.NewLambdaTracerProvider(ctx, cfg)
// equivalent to: provider.NewTracerProvider(ctx, cfg, provider.WithLambda(), provider.WithXRay())

if err != nil {
    // handle error
}
defer shutdown(ctx)

W3C TraceContext and Baggage propagators are always registered globally; WithXRay additionally registers the X-Ray propagator. All propagators are registered even when OTEL_ENABLED=false so context extraction works in the disabled case.

Sampling uses a parent-based strategy: if an upstream service sampled the trace, the decision is inherited. The local rate is controlled by OTEL_SAMPLE_RATE.

Meter

Creates and globally registers a MeterProvider. Returns a metric.Meter scoped to the service and a shutdown function to flush pending metrics on Lambda shutdown.

cfg := config.NewFromEnv()
meter, shutdown, err := provider.NewMeterProvider(ctx, cfg)
if err != nil {
    // handle error
}
defer shutdown(ctx)

Lambda

Middleware

OTEL middleware wraps Lambda handlers in a root span and records invocation metrics.

For API Gateway v1 handlers, use NewAPIGatewayV1. Prepend it to the middleware slice so the span covers the full request lifecycle:

allMiddlewares := append(
    middleware.APIGatewayV1{otelmiddleware.NewAPIGatewayV1(tracer, meter)},
    commonMiddlewares...,
)

The middleware extracts incoming W3C traceparent / tracestate headers to continue an upstream trace, and sets the span status to Error on 5xx responses or returned errors.

For event-driven handlers (SQS, SNS, scheduled events) that do not return a response, use NewNoResponse:

allMiddlewares := append(
    []awsmiddleware.NoResponse[events.SQSEvent]{otelmiddleware.NewNoResponse[events.SQSEvent](tracer, meter, "process-sqs")},
    commonMiddlewares...,
)

Both middlewares record the following metrics on every invocation:

Metric Type Unit Attributes
faas.invocations Counter faas.coldstart (bool), http.response.status_code (API Gateway only), faas.error (NoResponse only)
faas.duration Histogram ms same as above

faas.coldstart is true only on the first invocation of each Lambda execution environment, making cold starts distinguishable from warm invocations in your metrics backend.

AWS

Middleware

Instruments all AWS SDK v2 calls with OpenTelemetry client spans. Each SDK call records aws.service, aws.operation, aws.region, and aws.request_id attributes, and propagates W3C trace context into outgoing HTTP request headers.

Call AppendToConfig once after building your aws.Config:

cfg, err := awsconfig.LoadDefaultConfig(ctx)
if err != nil {
    // handle error
}
awsmiddleware.AppendToConfig(&cfg)

The global TracerProvider (set by provider.NewTracerProvider) is used automatically. When OTEL is disabled the global provider is a no-op so spans are zero-overhead.

Do not also wrap the AWS HTTP transport with http/transport.Newotelaws handles trace propagation at the SDK middleware layer; double-wrapping creates duplicate spans.

slog

Handler

Wraps any slog.Handler to inject trace_id and span_id from the active OpenTelemetry span into every log record. When no span is active (or OTEL is disabled), no extra attributes are added.

inner := slog.NewJSONHandler(os.Stdout, nil)
logger := slog.New(handler.New(inner))

Pass a context carrying an active span when logging and the fields are added automatically:

logger.InfoContext(ctx, "order processed", slog.String("order_id", id))
// {"time":"...","level":"INFO","msg":"order processed","order_id":"...","trace_id":"...","span_id":"..."}

HTTP

Transport

Wraps an http.RoundTripper with OpenTelemetry instrumentation. Creates a child client span for each outgoing request and injects W3C traceparent / tracestate headers so downstream services can continue the trace.

client := &http.Client{
    Transport: transport.New(http.DefaultTransport),
}

The global TracerProvider (set by provider.NewTracerProvider) is used automatically. When OTEL is disabled the transport is safe to use with zero overhead.

Development

AI-agent context

This repository carries shared AI-agent context and tooling used across Ello repositories:

  • AGENTS.md — repository-specific agent context (read this first).
  • .ai-context/ — a git submodule of shared, cross-repo standards, conventions, and skills.
  • CLAUDE.md — a thin Claude Code-specific pointer into the two files above.

.ai-context/ is auto-initialised by make build when missing (skipped in CI, which does not need AI-agent context to build or test). To pull the latest shared standards and regenerate Claude Code skill wrappers:

make sync-ai-context   # updates the .ai-context submodule pointer, then runs sync-skills
make init-memory       # seeds .agents/memory/{progress,decisions,notes,techdebt}.md (idempotent)
Commands

Docker-based (matches CI exactly — requires Docker):

make build            # build Docker image, go mod tidy, ensure .ai-context is initialised
make format            # gofmt, go fix, goimports (local prefix github.com/ellogroup)
make test              # static-tests + unit-tests
make static-tests      # golangci-lint (config verify + run), gosec, govulncheck
make unit-tests        # go test -v -cover ./...
make build-format-test # build + format + test

Local (no Docker):

go test -v -cover ./...
go vet ./...
go mod tidy

Directories

Path Synopsis
aws
middleware
Package middleware provides AWS SDK v2 OpenTelemetry instrumentation.
Package middleware provides AWS SDK v2 OpenTelemetry instrumentation.
http
transport
Package transport provides an OpenTelemetry-instrumented HTTP transport.
Package transport provides an OpenTelemetry-instrumented HTTP transport.
internal
lambda
middleware
Package middleware provides OpenTelemetry Lambda middleware that wraps each invocation in a root trace span and records invocation metrics.
Package middleware provides OpenTelemetry Lambda middleware that wraps each invocation in a root trace span and records invocation metrics.
slog
handler
Package handler provides an slog.Handler that injects trace_id and span_id from the active OpenTelemetry span into every log record.
Package handler provides an slog.Handler that injects trace_id and span_id from the active OpenTelemetry span into every log record.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL