telemetry

package
v0.9.2 Latest Latest
Warning

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

Go to latest
Published: Jun 22, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package telemetry bootstraps the OTEL SDK for outpost and exposes the small set of helpers wire callers need (gin tracing middleware, reverse-proxy traceparent preservation, slog ↔ OTEL log bridge).

Shape is intentionally mirrored in cloudbox/hub/internal/telemetry/ so a reader of either codebase finds the same four files (provider.go / middleware.go / proxy.go / slog_bridge.go) with the same function signatures. Cloudbox is proprietary and outpost is OSS, so a shared Go module would force one repo's choices on the other — convention keeps them aligned without coupling.

Configuration is pure-env-var, honoring the standard OTEL spec:

OTEL_EXPORTER_OTLP_ENDPOINT     gRPC collector, e.g. 127.0.0.1:4317
OTEL_SERVICE_NAME               defaults to "outpost"
OTEL_RESOURCE_ATTRIBUTES        e.g. service.namespace=dhnt,host.name=<host>
OTEL_TRACES_SAMPLER             parentbased_traceidratio (default)
OTEL_TRACES_SAMPLER_ARG         e.g. "1.0" or "0.1"

When OTEL_EXPORTER_OTLP_ENDPOINT is unset, the provider runs in "no-op" mode: the global TextMapPropagator is still installed so inbound `traceparent` headers from cloudbox are parsed and outbound app-proxy hops preserve them — the trace fabric still works end-to-end, just without persistence on this hop. This keeps the runtime footprint near-zero for home hosts that haven't enrolled in a centralized collector.

Index

Constants

View Source
const DefaultServiceName = "outpost"

DefaultServiceName is the service.name used when OTEL_SERVICE_NAME is unset.

Variables

This section is empty.

Functions

func PreserveTraceContext

func PreserveTraceContext(out *http.Request, in *http.Request)

PreserveTraceContext stamps the W3C `traceparent` (+ `tracestate`) from the inbound request's context onto the outbound proxy request so a cooperative app (or any downstream hop) can attach its spans to the same trace.

Call this from inside an httputil.ReverseProxy.Rewrite callback — outpost's apps.go uses Rewrite (not Director), so the inbound and outbound requests are two distinct *http.Request values via pr.In and pr.Out. The function takes them in that order:

telemetry.PreserveTraceContext(pr.Out, pr.In)

Safe to call unconditionally: when no span is active in the inbound context (no traceparent from cloudbox and no local span), the propagator injects nothing and pr.Out is left unchanged.

func Tracing

func Tracing(serviceName string) gin.HandlerFunc

Tracing returns a gin middleware that:

  • Parses incoming `traceparent` + `tracestate` from the matrix-tunnel envelope (cloudbox stamps these when its own tracing middleware ran) and installs them as the parent context on the gin Request so every downstream span / log / outbound app-proxy hop inherits the trace_id.
  • Starts a server span named after the matched gin route with standard semconv HTTP attributes.
  • Emits one slog line per /app/<name>/* request with the parsed trace_id + span_id so the outpost journal can be grep'd for a given trace_id without a running OTLP collector — load-bearing for end-to-end validation when neither cloudbox nor outpost has an exporter wired up.

Mount this generically on the main matrix-tunnel ingress engine so every /app/<name>/* proxy hop, every built-in route (/shell, /ssh, /apps, etc.), and every health check is observable.

No-op when the global TracerProvider hasn't been swapped from the default (i.e. telemetry.Init ran in no-op mode) — otelgin reads from the global TracerProvider, so the noop provider yields noop spans with near-zero overhead.

Types

type Provider

type Provider struct {
	TracerProvider *sdktrace.TracerProvider // nil in no-op mode
	LoggerProvider *sdklog.LoggerProvider   // nil in no-op mode
	// contains filtered or unexported fields
}

Provider holds the OTEL SDK lifetime for this process.

func Init

func Init(ctx context.Context) (*Provider, error)

Init bootstraps the global OTEL providers for outpost. Safe to call multiple times — only the first call boots; subsequent calls return the same Provider so any in-process supervisor restart doesn't double-install exporters.

Even when OTEL_EXPORTER_OTLP_ENDPOINT is unset, Init installs the global TextMapPropagator so the cloudbox→outpost→app chain still preserves W3C trace context across the proxy hop. Cooperative apps that implement the three-rule observability contract get a well-formed parent span even when outpost itself isn't exporting.

func (*Provider) Shutdown

func (p *Provider) Shutdown(ctx context.Context) error

Shutdown flushes pending spans/logs and tears down exporters. Safe to call multiple times; subsequent calls are no-ops.

func (*Provider) SlogHandler

func (p *Provider) SlogHandler() slog.Handler

SlogHandler returns an slog.Handler that forwards records into the OTEL LoggerProvider so log entries emitted with a span in their context automatically carry the matching trace_id + span_id.

Outpost mostly uses slog throughout, so callers can wrap their existing handler chain with this one to get trace correlation without changing log emission sites.

Returns nil when no LoggerProvider is configured (no-op mode); callers should keep their stderr handler in that case.

Jump to

Keyboard shortcuts

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