Help us shape the future of Go! Take the 2026 Go Developer Survey

route

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 6, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package route fans exported payloads out to multiple destinations/tenants by Kubernetes namespace: each route matches `k8s.namespace.name` globs and forwards to its own OTLP client (different endpoint and/or extra headers, e.g. X-Scope-OrgID); unmatched resources go to the default exporter.

It sits between the transforms and the default delivery chain (producers → transform → router → {default buffered chain | route clients}), splitting each payload per destination. First-matching route wins. A payload whose every resource goes to ONE destination, and carries no script marker, forwards untouched (no copy) — to the default chain, or to that route; a split COPIES resources into per-destination payloads and never mutates the caller's. Producers re-send the SAME object: the tailer's exportWithRetry reaches the router below the transform layer (transform.Wrapper.Inner) and retries its batch in place, the tail sampler's drain re-offers a decided payload, and the spanmetrics tap Consumes the forwarded payload after the export — so an in-place split would lose a retried batch and blind the tap. The uncopied forward relies on the same contract the default fast path always has: a destination only READS what it is handed. Delivery is at-least-once per destination: a failed destination fails the whole export, and the producer's retry re-splits the (untouched) payload deterministically — destinations that already succeeded receive duplicates, which OTLP consumers must tolerate anyway.

With -buffer-dir the default destination "succeeds" by being ENQUEUED, which it does while the collector is down, so during a route outage every retry of a producer that re-offers its batch until it lands would spool ANOTHER copy of the default share. Withholding the default share while a route fails is safe only for such a producer — a single-shot one (promscrape) never re-sends and would lose the default tenant's data to spare a duplicate — so it is per-payload and opt-in, riding the context like otlpexport.Own: a payload marked Reoffer(ctx) has its route shares sent FIRST, and a transient route failure withholds its default share (reoffer.go, which also rosters who marks). An unmarked payload keeps sending every share every attempt.

The DEFAULT destination keeps whatever durability the chain has (disk buffer); per-route destinations are direct clients — a route outage surfaces to the producer as back-pressure/retry, not spooling. Routes are for tenancy/fan-out, not for doubling the durability machinery.

Index

Constants

View Source
const ScriptMarker = "kubescrape.route"

ScriptMarker is the reserved resource attribute a transform script's route("name") verb stamps: the router honors it BEFORE the namespace globs and strips it from the outgoing copy, so kubescrape plumbing never reaches a collector. It exists as a sanctioned verb because scripts could already steer routing by rewriting k8s.namespace.name — an accidental contract worth replacing with an explicit one. A name matching no configured route falls to the default chain, warned (throttled) rather than dropped: a typo must degrade to the safe destination, not to loss.

Variables

This section is empty.

Functions

func Reoffer

func Reoffer(ctx context.Context) context.Context

Reoffer marks ctx as carrying a payload whose producer re-offers the records of a failed export until they are delivered or permanently rejected. The router may then hold a split payload's default share back while a route share fails transiently (see reoffer.go's doc for who may mark, and why).

The marker is a context VALUE, so it survives context.WithoutCancel and deadline wrappers — the same contract otlpexport.Own rides on.

func Reoffered

func Reoffered(ctx context.Context) bool

Reoffered reports whether ctx carries the Reoffer marker.

Types

type Config

type Config struct {
	Routes []Route `json:"routes"`
}

Config is the agent config's routing section.

type Destination

type Destination struct {
	Name       string
	Namespaces []string
	Exporter   Exporter
}

Destination pairs a compiled route with its exporter.

type Exporter

type Exporter interface {
	ExportLogs(ctx context.Context, ld plog.Logs) error
	ExportMetrics(ctx context.Context, md pmetric.Metrics) error
}

Exporter is a full destination (logs+metrics; traces optional via TracesExporter).

type Route

type Route struct {
	// Name labels the route in metrics/logs.
	Name string `json:"name"`
	// Namespaces are glob patterns matched against k8s.namespace.name
	// (path.Match syntax: "team-a-*", "prod").
	Namespaces []string `json:"namespaces"`
	// Endpoint overrides the OTLP destination (empty = the default endpoint,
	// useful for header-only tenant routing).
	Endpoint string `json:"endpoint,omitempty"`
	// Headers are extra headers for this route (e.g. X-Scope-OrgID).
	Headers map[string]string `json:"headers,omitempty"`

	// Credentials for this route's destination. They are not optional
	// decoration for a route that names its OWN endpoint: such a route does
	// NOT inherit the default chain's BearerTokenFile / CA / client
	// certificate, because those authenticate this deployment to ITS
	// collector and the route is a different destination — frequently a
	// different tenant's, sometimes a different organization's. Inheriting them
	// presented the default collector's credentials to whatever host the route
	// named, which is a credential disclosure to a third party rather than a
	// convenience.
	//
	// A route with no endpoint, or one repeating -otlp-endpoint, IS the
	// default destination (reached with extra headers — the header-only
	// tenancy case): it inherits everything, and any of these fields it sets
	// wins over the inherited value, exactly as an export.<signal> override
	// without an endpoint of its own. One derivation serves both
	// (otlpexport.ExportConfig.RouteConfig).
	BearerTokenFile string `json:"bearerTokenFile,omitempty"`
	ClientCertFile  string `json:"clientCertFile,omitempty"`
	ClientKeyFile   string `json:"clientKeyFile,omitempty"`
	CAFile          string `json:"caFile,omitempty"`
	// Insecure allows plaintext gRPC to this route (for HTTP the scheme in
	// Endpoint decides). Unset (nil) INHERITS the merged flag base's
	// -otlp-insecure — the ExportOverride pattern, and what every route
	// written before this field existed relied on: a plain bool's zero value
	// flipped those routes to TLS on upgrade, turning a working plaintext
	// destination into an endless transient export failure with no startup
	// signal. Plaintext-ness is transport to the named host, not a credential,
	// so inheriting it is not the disclosure the fields above guard against.
	Insecure *bool `json:"insecure,omitempty"`
	// InsecureSkipVerify skips verifying the route destination's TLS
	// certificate. Unlike Insecure it is NOT inherited when the route names its
	// own endpoint: -otlp-tls-insecure-skip-verify is a trust decision about
	// the deployment's OWN collector, and carrying it over sent this route's
	// bearer token and client certificate to a peer whose certificate nobody
	// checked — the carryover the export section's per-signal overrides drop
	// for the same reason. Unset = verify on an own-endpoint route, and the
	// inherited flag on a route that IS the default destination (no endpoint,
	// or -otlp-endpoint repeated), where a value set here wins like the
	// credentials above.
	InsecureSkipVerify *bool `json:"insecureSkipVerify,omitempty"`
}

Route is one destination.

func (Route) ExportOverride

func (rt Route) ExportOverride() otlpexport.ExportOverride

ExportOverride is the route's destination fields in the shape otlpexport's one destination derivation reads (ExportConfig.RouteConfig) — the same shape an export.<signal> override has, so a route and a per-signal override cannot derive a destination two different ways. A route has no protocol or compression of its own; those stay the base's.

type Router

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

Router splits payloads across destinations.

func New

func New(def Exporter, dests []Destination) *Router

New builds a Router forwarding unmatched resources to def.

func (*Router) ExportLogs

func (r *Router) ExportLogs(ctx context.Context, ld plog.Logs) error

ExportLogs splits by resource namespace and forwards each group.

func (*Router) ExportMetrics

func (r *Router) ExportMetrics(ctx context.Context, md pmetric.Metrics) error

ExportMetrics splits by resource namespace and forwards each group.

func (*Router) ExportTraces

func (r *Router) ExportTraces(ctx context.Context, td ptrace.Traces) error

ExportTraces splits by resource namespace and forwards each group. Route destinations always support traces (they are otlpexport clients); the default may not — its group then errors only if non-empty.

type TracesExporter

type TracesExporter interface {
	ExportTraces(ctx context.Context, td ptrace.Traces) error
}

TracesExporter ships traces.

Jump to

Keyboard shortcuts

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