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 ¶
const DefaultServiceName = "outpost"
DefaultServiceName is the service.name used when OTEL_SERVICE_NAME is unset.
Variables ¶
This section is empty.
Functions ¶
func PreserveTraceContext ¶
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.
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 ¶
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 ¶
Shutdown flushes pending spans/logs and tears down exporters. Safe to call multiple times; subsequent calls are no-ops.
func (*Provider) SlogHandler ¶
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.