Skip to content

feat(traffic): add Grafana Beyla as a traffic source (#1205)#1217

Draft
rafaelpissolatto wants to merge 1 commit into
skyhook-io:mainfrom
rafaelpissolatto:feat/beyla-traffic-source
Draft

feat(traffic): add Grafana Beyla as a traffic source (#1205)#1217
rafaelpissolatto wants to merge 1 commit into
skyhook-io:mainfrom
rafaelpissolatto:feat/beyla-traffic-source

Conversation

@rafaelpissolatto

@rafaelpissolatto rafaelpissolatto commented Jul 19, 2026

Copy link
Copy Markdown

Description

Adds Grafana Beyla as a fourth traffic source, alongside Hubble, Istio and Caretta.

Beyla derives network flows from eBPF without requiring a service mesh or CNI-level
integration, which makes it the first traffic source that works on a plain cluster.
Radar reads its metrics from any Prometheus-compatible endpoint - Prometheus, Mimir,
or whatever Alloy remote-writes to - rather than talking to Beyla directly.

Implementation

  • BeylaSource implementing the TrafficSource interface: Connect, Detect,
    GetFlows, StreamFlows, Close
  • Detection probes beyla_network_flow_bytes_total, with a pod-label fallback that
    recognises both Alloy-embedded and standalone Beyla deployments
  • L4 flows built from beyla_network_flow_bytes_total, keyed on owner-level
    attributes (k8s_src_owner_name / k8s_dst_owner_name) so edges land on
    Deployments rather than individual pods
  • Where L7 metrics are present, each L4 flow is enriched with the busiest HTTP
    series for that source→destination pair (method, route, status)
  • Manager wiring: registration and priority ordering - Beyla is tried last, so an
    existing Hubble or Istio install still wins

Notes for reviewers

  • Namespace filtering is emitted as two OR'd selectors (sum(...{src="ns"}) or sum(...{dst="ns"})). PromQL cannot express "src OR dst namespace" inside a
    single selector - a bare matcher after and is a parse error, not just a
    stylistic issue. This matches the idiom already used in istio.go.
  • Connections is used downstream in pkg/traffic/aggregation.go as an
    aggregation weight, so it is kept explicitly non-zero. Byte and request values
    are per-second rates over the 5m window, converted back to window totals.
  • Series with an empty source or destination name are dropped rather than emitted
    as anonymous nodes the UI cannot resolve or navigate to.

Type of change

  • New feature (non-breaking change that adds functionality)

Purely additive - the source is only used when detected, and detection is
last in priority order, so existing Hubble/Istio/Caretta users see no change.

How has this been tested?

  • Tested locally with minikube/kind (and deployed Grafana-Beyla as Daemonset)
  • Added/updated unit tests
radar_with_beyla radar_with_beyla_2

Unit tests - 13 cases covering metric-probe and pod-label detection, owner-level
and extended-label flows, the L4+L7 merge, namespace filtering, kind/transport
mapping, and a regression test pinning the namespace filter as valid PromQL.

Live cluster - validated end-to-end on a 3-node kind cluster running Beyla
(DaemonSet, hostPID + hostNetwork), Alloy scraping via ServiceMonitor, and
Mimir as the query backend:

Check Result
Detect available=true, "Beyla detected via Prometheus metrics"
GetFlows 418 flows
Namespace filter demo-backend → 24, demo-frontend → 223, no cross-namespace leakage

Representative flows:

demo-frontend/frontend (Workload) -> demo-backend/backend (Workload)  port=80 tcp  bytes=1649148
demo-frontend/frontend (Workload) -> kube-system/coredns  (Workload)  port=53 udp  bytes=784348
demo-frontend/frontend (Workload) -> kube-system/kube-dns (Service)   port=53 udp  bytes=587614

A build-tagged live test (//go:build livebeyla) is included so this is
reproducible; it is excluded from normal builds and CI.

Not yet validated: the L7 path. Beyla's application-level probes failed to load
on the test kernel (WSL2) with BPF program is too large. Processed 1000001 insn,
so no HTTP metrics existed to exercise the merge against. The L7 code path is
covered by unit tests but has not run against real data, and the metric name
http_request_duration_milliseconds_count should be confirmed on a stock kernel -
recent Beyla follows OTel semconv naming, which differs. The L4 path is unaffected.

Checklist

  • My code follows the project's coding standards
  • I have performed a self-review of my code
  • I have added comments where necessary
  • My changes generate no new warnings
  • Any dependent changes have been merged

Related issues

Part-Of and Closes #1205


Note

Low Risk
Additive traffic path with lowest detection priority; existing sources unchanged. Main caveat is dependency on Prometheus metric names and optional L7 merge, which the author notes is unit-tested but not fully validated on live HTTP metrics.

Overview
Adds Grafana Beyla as a fourth Traffic view backend, reading eBPF-derived metrics from the shared Prometheus client (standalone Beyla or Alloy) instead of a mesh/CNI integration.

BeylaSource implements the usual TrafficSource surface: Prometheus-backed Connect/Detect, GetFlows (L4 from beyla_network_flow_bytes_total at workload owner labels, optional HTTP enrichment from request-duration counts, merged per src→dst pair), and a 10s polling StreamFlows. Detection probes the same Beyla/Alloy scrape jobs as the flow queries, then falls back to running Alloy/Beyla pods. Namespace filters use two OR’d PromQL sums so src-or-dst matching stays valid.

The traffic manager registers beyla, includes it in Connect, and runs it last in auto-detect priority so Hubble, Istio, and Caretta still win when present. README Traffic section documents Beyla alongside the other sources. Unit tests cover detection, flow parsing/merge, and PromQL shape; an opt-in livebeyla test exercises a real metrics backend.

Reviewed by Cursor Bugbot for commit e09d4d7. Bugbot is set up for automated code reviews on this repo. Configure here.

Add Beyla as a fourth traffic source for L7 HTTP/gRPC visibility via
eBPF auto-instrumentation. Beyla is detected through Prometheus metrics
(beyla_network_flow_bytes_total, http_request_duration_milliseconds_count)
with a pod-label fallback for Alloy and standalone Beyla deployments

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e09d4d7. Configure here.

Comment thread internal/traffic/beyla.go
existing.HTTPMethod = l7.HTTPMethod
existing.HTTPPath = l7.HTTPPath
existing.HTTPStatus = l7.HTTPStatus
existing.RequestRate = l7.RequestRate

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

L7 merge skips multi-port flows

Medium Severity

When building L4 flows, byPair keeps only one flow per source/destination pair (the last seen). L7 HTTP fields are merged through that single pointer, so additional L4 edges on other ports for the same pair never receive L7 enrichment despite the feature intent to enrich each L4 flow.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e09d4d7. Configure here.

@rafaelpissolatto
rafaelpissolatto marked this pull request as draft July 19, 2026 16:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(traffic): add Grafana Beyla as a traffic source

1 participant