Task · SKT-0007.07

Emit beyla_agent and envoy_gateway OTel-native

Description

Two small self-contained kinds, each a single documented config switch in the real product.

Beyla internal metrics reporter takes exporter: disabled|prometheus|otel; the construct models only the prometheus branch today, and otel ships the same internal metrics over OTLP. Envoy Gateway accepts an OpenTelemetry metrics sink on both the EnvoyProxy data plane and the EnvoyGateway control plane, and disabling the Prometheus endpoint entirely is a supported deployment rather than a hypothetical.

Both are blocked on capture: cantfind SK-86 and SK-87. Do not derive an OTLP name by un-mangling its Prometheus spelling — that is a guess wearing the costume of a translation, and it is the specific failure mode this epic exists to avoid.

Acceptance Criteria

Definition of Done

Implementation Plan

2026-09-06 execution: resolve SK-86/SK-87 only from current vendor evidence or captures, then model the real beyla_agent and envoy_gateway OTel-native discriminators without name un-mangling; leave any unconfirmed family unemitted.

2026-09-05 captured-contract run: implement only owned captured or documented contracts under frozen switches; preserve defaults; root integrates shared changes, verifies safe inventory and exact-SHA CI, and records unconfirmed shapes as capture boundaries.

Implementation Notes

2026-09-06 evidence: current vendor documentation confirms the Beyla otel internal-metrics exporter and Envoy Gateway OpenTelemetry sink switches, but does not enumerate emitted OTLP metric names, instruments, units, scopes, or attributes. Focused beylaagent, envoygateway, cwinfra, cw, and construct-metadata tests passed. No source changed, no name was reverse-derived from Prometheus, and no family was emitted. SK-86 and SK-87 remain the exact capture gaps. Resume with captures retaining names, instruments, units, scopes, resource attributes, and datapoint attributes for Beyla internal OTLP metrics plus EnvoyGateway and EnvoyProxy metric sinks.

2026-09-04 capture wave. SK-87 DATA PLANE RESOLVED, SK-86 boundary sharpened to a hard chart blocker. Both captured on the live EKS lab through a disposable in-cluster otelcol-contrib debug receiver, reverted and deleted after; cluster verified clean.

SK-87: an OpenTelemetry stats sink was added to the EnvoyProxy CR alongside its Prometheus one. Envoy Gateway’s data plane ships an OTel-shaped set in dotted Envoy stat spelling (cluster.circuit_breakers.cx_open, http., listener., server., sds.) with ZERO envoy_/xds_/watchable_/controller_runtime_ names, so it shares no name with the Prometheus scrape surface and neither spelling derives from the other. 162 names, 78 Sum / 69 Gauge / 15 Histogram. Unit is EMPTY on all 162, InstrumentationScope is EMPTY, and resource attributes carry only telemetry.sdk.* with no service.name and no k8s.. Datapoint attributes are dotted envoy. plus bare socket_match_name and priority. Recorded in e2e/lab/captures/envoy-gateway-otlp-fc9ca6cd2ec0eba6.md and signals/k8s-addons.md [slug: k8s-envoy-gateway]. The EnvoyGateway CONTROL PLANE half is NOT covered - telemetry.metrics.sinks is an EnvoyProxy field, and the controller has its own telemetry config.

SK-86: NOT capturable through k8s-monitoring at all. chart 4.5.0 _beyla-config.tpl:17 builds internal_metrics.prometheus.port from the service target port and merges it as an override over user config, so no values file can remove it; nulling the block and the key were both tried and the port returns. Beyla then exits with ‘you can’t enable both OTEL and Prometheus internal metrics’. Verified the expensive way first: the attempt crashlooped 2 of 4 DaemonSet pods on the live lab for roughly 25 minutes before revert. Resume requires a STANDALONE Beyla with a hand-written config in k3d, never the chart-managed one.

Also recorded because it cost real time: adding an unknown field to an EnvoyProxy CR is a strict-decoding rejection that ArgoCD reports as Synced. The sink silently never reached the CR. Validate CR changes with kubectl apply –dry-run=server, not sync status.

2026-09-04 second capture wave: SK-86 RESOLVED and SK-87 control plane captured. Both taken through a disposable in-cluster otelcol-contrib debug receiver on the live EKS lab; all disposables deleted and both temporary infra commits reverted, cluster verified clean.

SK-86 RESOLVED. Beyla internal_metrics.exporter otel emits DOTTED semconv spelling, not the un-mangled Prometheus form: beyla.bpf.map.entries_total (Gauge), beyla.bpf.map.max_entries_total (Gauge), beyla.bpf.probe.executions (Sum, unit {call}), beyla.bpf.probe.latency_seconds_total (Sum, unit s), beyla.internal.build.info (Gauge). Units ARE populated on the probe families, unlike the Envoy data-plane sink where every unit was empty. Captured with a STANDALONE Beyla v3.32.0 because the k8s-monitoring chart cannot express the config: _beyla-config.tpl:17 injects internal_metrics.prometheus.port as an override no values file can remove, and Beyla refuses OTEL plus Prometheus together. Beyla also refuses to start with only internal_metrics set; at least one data exporter must be present.

SK-87 control plane captured and it is the MIRROR IMAGE of the data plane. The EnvoyGateway controller ships UNDERSCORE names verbatim, identical to its Prometheus spelling, 12 names all unit 1: watchable_depth, watchable_event_total, watchable_publish_total, watchable_subscribe_total, watchable_subscribe_duration_seconds, resource_apply_total, resource_apply_duration_seconds, resource_delete_total, resource_delete_duration_seconds, status_update_total, status_update_duration_seconds, xds_snapshot_create_total. One product, two APIs, opposite spellings. The sink is NOT a replacement for the scrape: it carries none of controller_runtime_, workqueue_, rest_client_* or certwatcher_*.

Measured aside worth keeping: NO Envoy Gateway metric, control plane or data plane, was present in the reference stack at capture time or 12h earlier. prometheus.disable false exposes :19001 but nothing collects it there, so signals/k8s-addons.md describing it as scraped does not match the stack.

AC 2 and AC 4 remain unchecked: the emitters themselves are still not implemented. What changes is that the exact contracts are now known rather than guessed, so implementation no longer needs a capture first.

2026-09-06 completion evidence: the richer live capture retained both planes complete envelopes and all 19 histogram bound sets. The immutable JSON contract drives set-diff tests. The Envoy emitter now emits 16 control-plane and 206 data-plane families under the already-shipped independent product switches, using captured resource values, scope, instruments, units, datapoint attributes and bounds only. Explicit otlp-native dump contained all 222 Envoy families and zero Agent Observability kinds. just check and just e2e passed locally; hosted ci runs 33998246701 and 33998689112 passed e2e and ci-success. Disposable receiver and temporary sinks were removed and live CR read-back showed zero metric sinks.

Final Summary

2026-09-06: Parked at the non-inferable capture boundary. The product switches are documented, but the emitted OTLP contracts are not; existing behavior correctly emits neither family and no speculative translation was added.

2026-09-05 integration: Beyla native internal metrics are implemented with the five captured names, exact kinds/units, and version-pinned source evidence for scope and attributes. Unsupported host metadata is omitted at SK-109. Envoy has the frozen independent product switches, per-plane scrape disable, and capture-diffed 162+12 name/type tables, but emits no native datapoints: missing resource values, per-family attributes, scope details on the controller, and all histogram bounds are SK-110 through SK-112. The earlier statement that the complete contracts were known was too strong. AC2 remains unchecked because native Envoy behavior is incomplete; neither names nor attributes were guessed. Integrated just check and explicit safe dump passed; Beyla contributes five native names, Envoy contributes only the intentionally retained scrape surface. Both CodeRabbit batches completed; slice-only missing-field finding was checked against the real integrated tree and the assertion retained. This task stays Parked, not Done; resume at a richer Envoy wire capture retaining the missing fields.

Completed both Beyla and Envoy native metric paths from captured contracts. Envoy now emits the complete 16 control-plane and 206 data-plane family sets with capture-diffed envelopes and bounds; no name was un-mangled from Prometheus. Local full gates and exact-SHA hosted e2e passed, and the live capture infrastructure was reverted and removed.

View the source file on GitHub