Architecture¶
gatewayapiprocessor is a single Go component shared across the traces, logs,
and metrics pipelines. A single instance keeps one set of informer caches and
one parser chain so the Kubernetes API is watched exactly once per collector
process, regardless of how many signals are enriched.
Component layout¶
flowchart LR
subgraph Collector
direction LR
MP[memory_limiter] --> K8S[k8sattributes]
K8S --> G[gatewayapiprocessor]
G --> B[batch]
end
subgraph ProcessorInternal[gatewayapiprocessor internals]
direction TB
P[Parser chain]
L[RouteLookup]
E[Enricher]
P --> E
L --> E
end
G -.-> ProcessorInternal
subgraph K8S_API[Kubernetes API]
GW[Gateway]
GC[GatewayClass]
HR[HTTPRoute]
GR[GRPCRoute]
end
K8S_API -.-> Informers[Shared informers]
Informers --> L
memory_limiteris always first,batchis always last — collector invariants.k8sattributesruns beforegatewayapiprocessorso pod and workload metadata are already on the record when enrichment runs.
Signal flow¶
On every ConsumeTraces / ConsumeLogs / ConsumeMetrics call:
- Parser chain match. For each record, the parser chain is walked in the
configured order. Each parser receives the record's attributes and the
controller identity it knows how to match. The first parser that returns
a non-empty
(namespace, name)tuple wins. If no parser matches and the chain ends withpassthrough, the raw string is written tok8s.gatewayapi.raw_route_nameand the record passes through unmodified otherwise. - RouteLookup. The winning
(namespace, name)is looked up in the informer-backedRouteLookup. This returns the HTTPRoute (or GRPCRoute) object, its resolved parent Gateway, and the matching GatewayClass. - Enrichment. The Attribute contract is
written to the record. On the metrics pipeline, attributes listed in
enrich.exclude_from_metric_attributesare stripped right before emit. - Status conditions. When
emit_status_conditions: true,k8s.httproute.acceptedandk8s.httproute.resolved_refsare stamped from the HTTPRoute status subresource'sAcceptedandResolvedRefsconditions. The same logic applies to GRPCRoute, stampingk8s.grpcroute.acceptedandk8s.grpcroute.resolved_refsfrom the GRPCRoute status subresource.
Parser chain¶
Parsers are configured as an ordered list. The chain is an explicit contract:
envoy— parses an opaqueroute_nameattribute via a named- capture regex. Default regex handleshttproute/<ns>/<name>[/rule/<rule>][/match/<match>]. Thensandnamecapture groups are required;ruleandmatchare optional and stampk8s.httproute.rule_index/k8s.httproute.match_indexwhen present.linkerd— reads discrete Linkerd label attributes (route_name,route_kind,route_namespace,parent_name) and derives the HTTPRoute identity from them.passthrough— catch-all. Writes the raw source attribute value to a configurable key (k8s.gatewayapi.raw_route_nameby default) and returns an empty match so the record falls out of enrichment. Must be last in the chain; config validation rejects any other placement.
A parser may declare a list of controllers regex patterns. These are
matched against GatewayClass.spec.controllerName; empty list means "match
any". The processor stamps k8s.gatewayapi.parser with the name of the
parser that resolved the record, which is the fastest way to verify the
chain is routing traffic as intended.
Informers¶
When auth_type is serviceAccount or kubeConfig, the processor starts a
set of shared informers against:
gateway.networking.k8s.io/v1—Gateway,HTTPRoute,GRPCRoute,GatewayClass.
Scoping is controlled by watch.namespaces. An empty or null list means
cluster-wide; any non-empty list narrows the informer factory to the listed
namespaces. watch.resync_period sets the informer's periodic resync; the
default 5m is a compromise between responsiveness to status changes and
load on the Kubernetes API.
At startup, Start() blocks for up to informer_sync_timeout (default
30s) waiting for the informer caches to warm up. If the caches never sync
within that window, the component returns an error and the collector fails
its readiness probe.
When auth_type: none, no informers are started. Only string-only parsing
runs — Gateway and HTTPRoute lookups return empty and no status
conditions are emitted.
Metrics cardinality guard¶
The default enrich.exclude_from_metric_attributes list strips three
attributes before metrics are emitted:
k8s.httproute.uidk8s.gateway.uidk8s.gatewayapi.raw_route_name
These are the known high-cardinality fields: UIDs rotate per object lifetime, and the raw route name carries rule/match indices that blow up cardinality when combined with other dimensions. Customize this list via config when you want a tighter or looser guard; see Examples.
BackendRef fallback¶
When enabled (default), the processor applies a best-effort enrichment path
when no HTTPRoute match is resolved. It reads a configurable attribute
(default server.address, commonly set by k8sattributes) and resolves it
against the informer's backend-to-route index. The fallback only fires when
the primary lookup fails, and it is a best-effort signal — records enriched
this way do not receive k8s.httproute.accepted /
k8s.httproute.resolved_refs (or the GRPCRoute equivalents).
Failure modes¶
- Gateway API CRDs missing. Informer caches fail to sync;
informer_sync_timeoutelapses andStart()returns an error. - Partial RBAC. Missing
list/watchon any of the four resource kinds causes the corresponding informer to error; the component logs the failure via the collector's structured logger and the affected enrichment path (for example, GRPCRoute lookups) returns empty. - No parser matches. If
passthroughis not configured, the record is emitted unchanged; no Gateway API attributes are stamped. Withpassthroughconfigured, the raw string is stamped onk8s.gatewayapi.raw_route_name(excluded from metrics by default). - Regex misconfiguration. Caught at config validation time. The component
refuses to build if a
controllersentry or anenvoyformat_regexdoes not compile, or if theenvoyregex is missing thensornamenamed group.