montaur-trace-go

module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 31, 2026 License: Apache-2.0

README

montaur-trace-go

pixelbuf's Go tracing glue for apps that ship traces to a node-local montaur-agent (an OpenTelemetry Collector). It is pure glue around upstream go.opentelemetry.io modules — no custom protocol code — so the API surface is tiny and the dependency graph stays minimal. Think of this as montaur's analog to dd-trace-go.

Apps talk to the agent over plain HTTP on the local node; the agent holds the montaur API key and forwards traces upstream. No credentials are configured in this library or in the app.

Quickstart

import "github.com/pixelbuf/montaur-trace-go/montaurtrace"

shutdown, err := montaurtrace.Init(ctx, montaurtrace.Config{Service: "checkout"})
if err != nil {
    log.Fatal(err)
}
defer shutdown(ctx)

http.ListenAndServe(":8080", montaurtrace.HTTP(mux))

That's it: Init wires up the global OpenTelemetry TracerProvider and W3C propagators, and montaurtrace.HTTP instruments your server. Wrap outbound http.Clients with montaurtrace.Transport and gRPC servers/clients with montaurtrace.GRPCServer/montaurtrace.GRPCClient for end-to-end trace propagation.

If you name spans yourself, keep the names low-cardinality — route patterns like GET /users/:id, never raw URLs or IDs — because span.name becomes a montaur tag key, and montaur caps each tag key at 500 distinct values per tenant.

Kubernetes: you MUST set the endpoint

The default endpoint is http://localhost:4318, which suits VM/systemd co-location only (where the montaur-agent container publishes its OTLP ports on the same host). From a Kubernetes app pod it is connection-refused: the montaur-agent DaemonSet exposes no hostPort, so apps must reach the agent through its node-local ClusterIP Service. Set OTEL_EXPORTER_OTLP_ENDPOINT (or Config.Endpoint) to the montaur-agent Service URL in your application Deployment's pod spec, mirroring the montaur repo's agent/k8s/daemonset.yaml wiring:

env:
  - name: OTEL_EXPORTER_OTLP_ENDPOINT
    value: http://montaur-agent-prod.CHANGEME-namespace.svc.cluster.local:4318

(4318 = OTLP/HTTP, which is what this library exports over.)

HTTP client propagation
client := &http.Client{Transport: montaurtrace.Transport(nil)}
gRPC
srv := grpc.NewServer(grpc.StatsHandler(montaurtrace.GRPCServer()))

conn, err := grpc.NewClient(target, grpc.WithStatsHandler(montaurtrace.GRPCClient()))
Filtering

HTTP, GRPCServer, and GRPCClient accept the underlying otelhttp/otelgrpc options variadically. Two helpers cover the common case — keeping health checks out of the traces — without making the app import the contrib packages:

srv := grpc.NewServer(grpc.StatsHandler(montaurtrace.GRPCServer(
    montaurtrace.WithoutGRPCMethods("/grpc.health.v1.Health/Check"),
)))

handler := montaurtrace.HTTP(mux, montaurtrace.WithoutHTTPPaths("/health"))

Both match exactly: WithoutGRPCMethods on the full RPC method string (/package.Service/Method), WithoutHTTPPaths on r.URL.Path. Filtered requests are served normally, just without a span (and, for gRPC, without trace-context propagation).

Config

type Config struct {
    Service     string   // required; becomes resource attribute service.name
    Version     string   // optional; service.version
    Environment string   // optional; deployment.environment
    Endpoint    string   // optional; overrides OTEL_EXPORTER_OTLP_TRACES_ENDPOINT and OTEL_EXPORTER_OTLP_ENDPOINT
    SampleRatio *float64 // optional; overrides OTEL_TRACES_SAMPLER and OTEL_TRACES_SAMPLER_ARG; default 1.0
}

Service is the only required field; Init returns an error if it is empty.

Environment variable contract

Variable Effect Precedence
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT Traces-specific base URL of the OTLP/HTTP receiver. Config.Endpoint > this > OTEL_EXPORTER_OTLP_ENDPOINT > http://localhost:4318
OTEL_EXPORTER_OTLP_ENDPOINT Base URL of the OTLP/HTTP receiver, e.g. http://montaur-agent:4318. Config.Endpoint > traces env > this > http://localhost:4318
OTEL_TRACES_SAMPLER Standard SDK sampler selection (e.g. always_off, traceidratio). Honored only when Config.SampleRatio is nil: Init then installs no sampler and defers to the SDK's own env handling of the OTEL_TRACES_SAMPLER/OTEL_TRACES_SAMPLER_ARG pair.
OTEL_TRACES_SAMPLER_ARG Head sampling ratio in [0, 1] for ParentBased(TraceIDRatioBased(...)) when OTEL_TRACES_SAMPLER is unset. Config.SampleRatio > env > 1.0

Notes:

  • Config.Endpoint/the endpoint env vars are a full base URL (scheme + host + port). http:// is allowed and expected for talking to the cluster-local agent — no TLS, no auth headers.
  • Sampler rule: an explicit Config.SampleRatio always wins, over both sampler env vars. With Config.SampleRatio nil and OTEL_TRACES_SAMPLER set (even to something this library never installs itself, like always_off), the SDK's env machinery is in full control. With both unset, ParentBased(TraceIDRatioBased) is installed, driven by OTEL_TRACES_SAMPLER_ARG alone.
  • An out-of-range sample ratio (from either Config or the environment) is clamped to [0, 1]. A malformed OTEL_TRACES_SAMPLER_ARG (fails to parse as a float) is treated as unset and falls back to 1.0 (sample everything) rather than silently under-sampling.
  • No auth/API-key environment variables are read or required by this library. The app never talks to montaur directly — only to the local agent, which is where the montaur API key lives.
Endpoint semantics

These deviate slightly from stock OTel SDK env handling (we resolve the endpoint ourselves and hand a single URL to otlptracehttp.WithEndpointURL, which uses the URL's path as-is):

  1. Resolution order: Config.Endpoint > OTEL_EXPORTER_OTLP_TRACES_ENDPOINT > OTEL_EXPORTER_OTLP_ENDPOINT > http://localhost:4318.
  2. Trailing-slash normalization: a URL whose path is empty or exactly / is stripped to no path, so the exporter's own /v1/traces default applies. (http://agent:4318 and http://agent:4318/ both export to http://agent:4318/v1/traces.)
  3. Custom paths are kept verbatim and are NOT suffixed with /v1/traces — a custom path must be the complete traces endpoint path, e.g. http://proxy:8080/otlp/v1/traces. This differs from stock OTel handling of OTEL_EXPORTER_OTLP_ENDPOINT, where the generic endpoint's path gets /v1/traces appended per signal.

Calling Init more than once

Unsupported. Init sets process-global OpenTelemetry state (the TracerProvider and TextMapPropagator); a second call overwrites the first ("last write wins"). Call it once, early in process startup, and defer shutdown(ctx) at the same call site.

Dependencies

Only go.opentelemetry.io/* modules (plus google.golang.org/grpc, pulled in transitively by otelgrpc's stats handler). See go.mod for exact versions.

Directories

Path Synopsis
Package montaurtrace is pixelbuf's Go tracing glue for shipping traces to a node-local montaur-agent (an OpenTelemetry Collector).
Package montaurtrace is pixelbuf's Go tracing glue for shipping traces to a node-local montaur-agent (an OpenTelemetry Collector).

Jump to

Keyboard shortcuts

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