sotel

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 6, 2026 License: MIT Imports: 31 Imported by: 0

README

sotel

The OpenTelemetry bootstrap for Go services: the whole SDK wired with one call — resource, OTLP exporters for traces, metrics and logs, an optional Prometheus scrape endpoint fed by the same MeterProvider, sampling and W3C trace-context + baggage propagation — plus an instrumented HTTP client and a baggage correlation middleware.

go get github.com/dvislobokov/sotel
tel, err := sotel.Setup(ctx, "orders",
	sotel.WithOTLP("localhost:4317"), // empty endpoint = no-op
	sotel.WithLogs(),                 // global LoggerProvider (srogotel reuses it)
	sotel.WithPrometheus(),           // pull endpoint next to OTLP push
	sotel.WithRuntimeMetrics(),
	sotel.WithEnv(),                  // OTEL_* variables win
)
if err != nil { return err }
defer tel.Shutdown(context.Background())

// serve /metrics and /prometheus (e.g. with shost/httpsvc):
if h := tel.MetricsHandler(); h != nil {
	mux := sotel.MetricsMux(h)
	...
}

Options

Group Options
Transport WithOTLP (plaintext gRPC by default) · WithOTLPHTTP (http/protobuf) · WithOTLPTLS · WithOTLPHeaders · per-signal WithTracesEndpoint / WithMetricsEndpoint / WithLogsEndpoint
Environment WithEnv — OTEL_SERVICE_NAME, OTEL_EXPORTER_OTLP_ENDPOINT (https ⇒ TLS), ..._PROTOCOL, ..._HEADERS, OTEL_RESOURCE_ATTRIBUTES
Logs WithLogs — OTLP log exporter + global LoggerProvider
Sampling WithTraceRatio · WithSampler
Resource WithResourceAttributes · WithServiceVersion · WithDeploymentEnvironment · WithResourceOptions (detectors)
Metrics WithPrometheus · WithPrometheusRegistry · WithMetricInterval · WithMetricViews · WithRuntimeMetrics
Behavior WithPropagators · WithErrorHandler · WithSpanProcessor · WithoutGlobals + Telemetry.TracerProvider/MeterProvider/LoggerProvider()

Outgoing HTTP

client := sotel.HTTPClient(sotel.WithHTTPTimeout(5 * time.Second))

// or instrument the process-global default transport once at startup:
sotel.InstrumentDefaultClient()

Custom correlation over baggage

Carry an external correlation header (MsgId, a tenant id) through every transport without per-transport plumbing:

handler = sotel.BaggageMiddleware("MsgId", "msg.id")(handler) // at the HTTP edge
srogotel.InstallBaggage(map[string]string{"msg.id": "MsgId"}) // on every log line

Instrumented clients (otelhttp, otelgrpc, otelsmsg) propagate baggage automatically.

Family

Library-specific instrumentation lives with its library and picks up the global providers sotel installs: otelsorm (SQL), otelsmsg (messaging), srogotel (logs), shost/otel (host lifecycle observer). A complete system built on the stack: s-example.

License

MIT

Documentation

Overview

Package sotel is the OpenTelemetry bootstrap for Go services: the whole SDK — resource, OTLP exporters for traces, metrics and logs, an optional Prometheus scrape endpoint, sampling and W3C propagation — wired with one Setup call, plus an instrumented HTTP client and baggage helpers.

tel, err := sotel.Setup(ctx, "orders",
    sotel.WithOTLP("localhost:4317"),
    sotel.WithLogs(),
    sotel.WithPrometheus(),
    sotel.WithEnv(), // OTEL_* variables win
)
defer tel.Shutdown(context.Background())

Library-specific instrumentation stays with its library (otelsorm, otelsmsg, srogotel, shost/otel's lifecycle observer) — they all pick up the global providers this package installs.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BaggageMiddleware

func BaggageMiddleware(header, baggageKey string) func(http.Handler) http.Handler

BaggageMiddleware carries a custom correlation header (an external MsgId, a tenant id) through the whole system without per-transport plumbing: it reads the header at the HTTP edge (generating a random id when absent), stores it in the context baggage and echoes it on the response. Every instrumented client downstream — otelhttp, otelgrpc, otelsmsg — propagates baggage automatically, and srogotel.InstallBaggage stamps it on every log line:

handler = sotel.BaggageMiddleware("MsgId", "msg.id")(handler)
srogotel.InstallBaggage(map[string]string{"msg.id": "MsgId"})

func HTTPClient

func HTTPClient(opts ...HTTPClientOption) *http.Client

HTTPClient returns an *http.Client whose transport records a client span and http.client.* metrics for every request and injects the trace context (traceparent + baggage) via the global propagator — so outgoing HTTP calls keep the trace and any baggage correlation going. The default timeout is 30s; override with WithHTTPTimeout.

func InstrumentDefaultClient

func InstrumentDefaultClient(opts ...HTTPClientOption)

InstrumentDefaultClient wraps the process-global http.DefaultTransport with the same instrumentation, so http.DefaultClient, http.Get and every third-party package that quietly uses the default client propagate the trace context too. Call it once during startup (Setup does not do it for you — mutating package globals is opt-in). Calling it again is a no-op unless the default transport was replaced in between; WithHTTPTimeout additionally sets http.DefaultClient.Timeout.

func MetricsMux

func MetricsMux(h http.Handler) *http.ServeMux

MetricsMux serves h on the conventional /metrics path and on /prometheus — ready to host with httpsvc:

AddService(httpsvc.New(addr, shostotel.MetricsMux(handler), httpsvc.WithName("metrics")))

func NewPrometheusHandler

func NewPrometheusHandler() (http.Handler, *sdkmetric.MeterProvider, error)

NewPrometheusHandler creates a MeterProvider backed by a dedicated Prometheus registry and an http.Handler serving it in Prometheus text format — a ready checkpoint for httpsvc:

handler, provider, err := shostotel.NewPrometheusHandler()
obs, _ := shostotel.NewObserver(shostotel.WithMeterProvider(provider))
mux.Handle("/metrics", handler)

The caller owns the provider and should call provider.Shutdown on exit (e.g. from the host's OnStopped hook). To attach Prometheus export to an existing provider use NewPrometheusReader; for the full bootstrap use Setup.

func NewPrometheusReader

func NewPrometheusReader() (sdkmetric.Reader, http.Handler, error)

NewPrometheusReader creates a metric reader backed by a dedicated Prometheus registry and an http.Handler serving it in Prometheus text format. Unlike NewPrometheusHandler it composes with a caller-owned MeterProvider, so one provider can feed OTLP push and Prometheus pull at the same time:

reader, handler, err := shostotel.NewPrometheusReader()
mp := sdkmetric.NewMeterProvider(
    sdkmetric.WithReader(otlpReader),
    sdkmetric.WithReader(reader),
    sdkmetric.WithResource(res),
)

Types

type HTTPClientOption

type HTTPClientOption func(*httpClientConfig)

HTTPClientOption configures HTTPClient and InstrumentDefaultClient.

func WithHTTPBase

func WithHTTPBase(rt http.RoundTripper) HTTPClientOption

WithHTTPBase sets the underlying transport to instrument (connection pools, proxies, custom TLS). Defaults to http.DefaultTransport.

func WithHTTPOptions

func WithHTTPOptions(opts ...otelhttp.Option) HTTPClientOption

WithHTTPOptions passes options through to otelhttp.NewTransport (span name formatter, filters, ...).

func WithHTTPTimeout

func WithHTTPTimeout(d time.Duration) HTTPClientOption

WithHTTPTimeout sets the client timeout (HTTPClient defaults to 30s; InstrumentDefaultClient leaves the default client's timeout untouched unless this option is given).

type SetupOption

type SetupOption func(*setupConfig)

SetupOption configures Setup.

func WithBaggageSpanAttributes added in v1.1.0

func WithBaggageSpanAttributes(keys ...string) SetupOption

WithBaggageSpanAttributes copies the listed baggage members (every member when the list is empty) onto each span at start, using the member name as the attribute key — that makes correlation ids carried in baggage (an external MsgId, a tenant) searchable in the trace backend:

sotel.Setup(ctx, "orders",
    sotel.WithOTLP(endpoint),
    sotel.WithBaggageSpanAttributes("msg.id"),
)
// Tempo/Jaeger: search spans by tag msg.id=...

Keep the list explicit in most systems: baggage can carry many members and every one becomes an attribute on every span.

func WithDeploymentEnvironment

func WithDeploymentEnvironment(env string) SetupOption

WithDeploymentEnvironment stamps deployment.environment onto the resource.

func WithEnv

func WithEnv() SetupOption

WithEnv reads the standard OpenTelemetry environment variables and applies them over the programmatic configuration:

OTEL_SERVICE_NAME              overrides the service name
OTEL_EXPORTER_OTLP_ENDPOINT    endpoint; an https:// scheme implies TLS
OTEL_EXPORTER_OTLP_PROTOCOL    "grpc" (default) or "http/protobuf"
OTEL_EXPORTER_OTLP_HEADERS     "k=v,k2=v2"
OTEL_RESOURCE_ATTRIBUTES       "k=v,k2=v2"

Apply it last so the environment wins — the convention Kubernetes operators and collectors expect.

func WithErrorHandler

func WithErrorHandler(fn func(error)) SetupOption

WithErrorHandler receives asynchronous SDK errors (export failures); by default the SDK prints them to stderr.

func WithLogs

func WithLogs() SetupOption

WithLogs additionally exports logs over OTLP and installs the global LoggerProvider, which srogotel picks up with a zero Config:

tel, _ := shostotel.Setup(ctx, "orders", shostotel.WithOTLP(ep), shostotel.WithLogs())
opt, sink, _ := srogotel.WithLogs(ctx, srogotel.Config{}) // reuses the global provider

func WithLogsEndpoint

func WithLogsEndpoint(endpoint string) SetupOption

WithLogsEndpoint overrides the OTLP endpoint for logs only.

func WithMetricInterval

func WithMetricInterval(d time.Duration) SetupOption

WithMetricInterval sets the OTLP metric push interval (default 15s).

func WithMetricViews

func WithMetricViews(views ...sdkmetric.View) SetupOption

WithMetricViews customizes aggregation: rename instruments, drop attributes, set histogram buckets.

func WithMetricsEndpoint

func WithMetricsEndpoint(endpoint string) SetupOption

WithMetricsEndpoint overrides the OTLP endpoint for metrics only.

func WithOTLP

func WithOTLP(endpoint string) SetupOption

WithOTLP exports traces, metrics and (with WithLogs) logs to an OTLP endpoint — plaintext gRPC by default, e.g. an otel-collector at "localhost:4317". An empty endpoint is a no-op, so the value can come straight from optional configuration. Use WithOTLPHTTP, WithOTLPTLS and WithOTLPHeaders to change the transport, and the per-signal With*Endpoint options to split signals across backends.

func WithOTLPHTTP

func WithOTLPHTTP() SetupOption

WithOTLPHTTP switches the OTLP exporters to http/protobuf (typically port 4318) instead of gRPC.

func WithOTLPHeaders

func WithOTLPHeaders(headers map[string]string) SetupOption

WithOTLPHeaders adds headers to every OTLP request — API keys and the like ("Authorization": "Bearer ...").

func WithOTLPTLS

func WithOTLPTLS(cfg *tls.Config) SetupOption

WithOTLPTLS enables TLS on the OTLP connection. Pass &tls.Config{} for system defaults.

func WithPrometheus

func WithPrometheus() SetupOption

WithPrometheus additionally registers a Prometheus reader on the same MeterProvider and exposes it via Telemetry.MetricsHandler — push and pull export can be active at once.

func WithPrometheusRegistry

func WithPrometheusRegistry(reg *prometheus.Registry) SetupOption

WithPrometheusRegistry uses a caller-owned registry for WithPrometheus — pre-register your own collectors (Go runtime, process) and they share the scrape endpoint. Implies WithPrometheus.

func WithPropagators

func WithPropagators(ps ...propagation.TextMapPropagator) SetupOption

WithPropagators replaces the default W3C trace-context + baggage propagators — add a custom one for proprietary correlation headers.

func WithResourceAttributes

func WithResourceAttributes(attrs ...attribute.KeyValue) SetupOption

WithResourceAttributes adds attributes to the telemetry resource beside the service name (e.g. semconv.DeploymentEnvironment("staging")).

func WithResourceOptions

func WithResourceOptions(opts ...resource.Option) SetupOption

WithResourceOptions runs resource detectors (resource.WithContainer(), resource.WithHost(), custom detectors) and merges the result.

func WithRuntimeMetrics

func WithRuntimeMetrics() SetupOption

WithRuntimeMetrics starts the contrib Go runtime instrumentation (goroutines, GC, heap) on the MeterProvider Setup builds.

func WithSampler

func WithSampler(s sdktrace.Sampler) SetupOption

WithSampler sets the trace sampler (default: sample everything).

func WithServiceVersion

func WithServiceVersion(version string) SetupOption

WithServiceVersion stamps service.version onto the resource.

func WithSpanProcessor

func WithSpanProcessor(ps ...sdktrace.SpanProcessor) SetupOption

WithSpanProcessor registers additional span processors — filtering, redaction, extra exporters.

func WithTraceRatio

func WithTraceRatio(fraction float64) SetupOption

WithTraceRatio samples the given fraction of new traces (parent-based: a sampled upstream decision is always honored). 1.0 records everything.

func WithTracesEndpoint

func WithTracesEndpoint(endpoint string) SetupOption

WithTracesEndpoint overrides the OTLP endpoint for traces only.

func WithoutGlobals

func WithoutGlobals() SetupOption

WithoutGlobals skips installing the providers, propagator and error handler globally — read them from the returned Telemetry instead.

type Telemetry

type Telemetry struct {
	// contains filtered or unexported fields
}

Telemetry is the result of Setup: the handles a hosted service needs to serve and tear down its telemetry.

func Setup

func Setup(ctx context.Context, serviceName string, opts ...SetupOption) (*Telemetry, error)

Setup wires the OpenTelemetry SDK for a hosted service: resource with the service name, OTLP exporters for traces and metrics (WithOTLP) and optionally logs (WithLogs), an optional Prometheus scrape handler fed by the same MeterProvider (WithPrometheus), and W3C trace-context + baggage propagation. It installs the resulting providers globally (unless WithoutGlobals) and returns the shutdown handle.

With no effective exporter (no options, or an empty OTLP endpoint and no Prometheus) Setup is a no-op returning a zero Telemetry.

func (*Telemetry) LoggerProvider

func (t *Telemetry) LoggerProvider() *sdklog.LoggerProvider

LoggerProvider returns the provider Setup built with WithLogs, else nil.

func (*Telemetry) MeterProvider

func (t *Telemetry) MeterProvider() *sdkmetric.MeterProvider

MeterProvider returns the provider Setup built, nil when metrics are off.

func (*Telemetry) MetricsHandler

func (t *Telemetry) MetricsHandler() http.Handler

MetricsHandler serves the Prometheus text format when Setup ran with WithPrometheus, nil otherwise. Host it with httpsvc:

if h := tel.MetricsHandler(); h != nil {
    b.AddService(httpsvc.New(":9090", shostotel.MetricsMux(h), httpsvc.WithName("metrics")))
}

func (*Telemetry) Shutdown

func (t *Telemetry) Shutdown(ctx context.Context) error

Shutdown flushes and stops every exporter Setup created. Safe to call on a zero-value Telemetry.

func (*Telemetry) TracerProvider

func (t *Telemetry) TracerProvider() *sdktrace.TracerProvider

TracerProvider returns the provider Setup built, nil when tracing is off. Useful with WithoutGlobals.

Jump to

Keyboard shortcuts

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