diff --git a/charts/beyla/templates/cluster-role.yaml b/charts/beyla/templates/cluster-role.yaml index 9f8db098a..65797e043 100644 --- a/charts/beyla/templates/cluster-role.yaml +++ b/charts/beyla/templates/cluster-role.yaml @@ -15,12 +15,8 @@ rules: resources: [ "replicasets" ] verbs: [ "list", "watch" ] - apiGroups: [ "" ] - {{- if or (eq .Values.preset "network") .Values.config.data.network }} resources: [ "pods", "services", "nodes" ] - {{- else }} - resources: [ "pods" ] - {{- end }} - verbs: [ "list", "watch" ] + verbs: [ "list", "watch", "get" ] {{- with .Values.rbac.extraClusterRoleRules }} {{- toYaml . | nindent 2 }} {{- end}} diff --git a/cmd/beyla/main.go b/cmd/beyla/main.go index b6be68188..c129030aa 100644 --- a/cmd/beyla/main.go +++ b/cmd/beyla/main.go @@ -65,7 +65,10 @@ func main() { // child process isn't found. ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGINT, syscall.SIGTERM) - components.RunBeyla(ctx, config) + if err := components.RunBeyla(ctx, config); err != nil { + slog.Error("Beyla can't start", "error", err) + os.Exit(-1) + } if gc := os.Getenv("GOCOVERDIR"); gc != "" { slog.Info("Waiting 1s to collect coverage data...") diff --git a/docs/sources/configure/options.md b/docs/sources/configure/options.md index de403febc..5fe3cd396 100644 --- a/docs/sources/configure/options.md +++ b/docs/sources/configure/options.md @@ -835,7 +835,7 @@ The purpose of this value is to avoid reporting indefinitely finished applicatio | YAML | Environment variable | Type | Default | |------------|-------------------------------|-----------------|------------------------------| -| `features` | `BEYLA_OTEL_METRICS_FEATURES` | list of strings | `["application", "network"]` | +| `features` | `BEYLA_OTEL_METRICS_FEATURES` | list of strings | `["application"]` | A list of metric groups which are allowed to be exported. Each group belongs to a different feature of Beyla: application-level metrics or network metrics. @@ -853,8 +853,8 @@ of Beyla: application-level metrics or network metrics. the OpenTelemetry service names used in Beyla. In Kubernetes environments, the OpenTelemetry service name set by the service name discovery is the best choice for service graph metrics. - If the list contains `network`, the Beyla OpenTelemetry exporter exports network-level - metrics; but only if there is defined an OpenTelemetry endpoint and the - [network metrics are enabled]({{< relref "../network" >}}). + metrics; but only if there is an OpenTelemetry endpoint defined. For network-level metrics options visit the + [network metrics]({{< relref "../network" >}}) configuration documentation. Usually you do not need to change this configuration option, unless, for example, a Beyla instance instruments both network and applications, and you want to disable application-level metrics because @@ -1214,7 +1214,7 @@ The `buckets` object allows overriding the bucket boundaries of diverse histogra | YAML | Environment variable | Type | Default | |------------|-----------------------------|-----------------|------------------------------| -| `features` | `BEYLA_PROMETHEUS_FEATURES` | list of strings | `["application", "network"]` | +| `features` | `BEYLA_PROMETHEUS_FEATURES` | list of strings | `["application"]` | A list of metric groups that are allowed to be exported. Each group belongs to a different feature of Beyla: application-level metrics or network metrics. @@ -1232,8 +1232,8 @@ of Beyla: application-level metrics or network metrics. the OpenTelemetry service names used in Beyla. In Kubernetes environments, the OpenTelemetry service name set by the service name discovery is the best choice for service graph metrics. - If the list contains `network`, the Beyla Prometheus exporter exports network-level - metrics; but only if the Prometheus `port` property is defined and the - [network metrics are enabled]({{< relref "../network" >}}). + metrics; but only if the Prometheus `port` property is defined. For network-level metrics options visit the + [network metrics]({{< relref "../network" >}}) configuration documentation. Usually you do not need to change this configuration option, unless, for example, a Beyla instance instruments both network and applications, and you want to disable application-level metrics because diff --git a/docs/sources/network/asserts.md b/docs/sources/network/asserts.md new file mode 100644 index 000000000..67a6d68ab --- /dev/null +++ b/docs/sources/network/asserts.md @@ -0,0 +1,64 @@ +--- +title: Set up Beyla network metrics in Kubernetes with Helm for Asserts +menuTitle: Set up Asserts network +description: A guide to install Beyla network metrics in Kubernetes with Helm for Asserts. +weight: 1 +keywords: + - Beyla + - eBPF + - Network +--- + +# Set up Beyla network metrics in Kubernetes with Helm for Asserts + +[Asserts](/docs/grafana-cloud/monitor-applications/asserts/) works with Beyla and requires Beyla network metrics. Learn how to set up Beyla network metrics in Kubernetes with Helm to export telemetry data to Asserts. + +To learn more about Beyla network metrics, consult the [Network](/docs/beyla/latest/network/) documentation. + +## Prerequisites + +Before you install Beyla network metrics and export telemetry data to Asserts you need: + +1. A free Grafana Cloud account. +1. Access rights to a Kubernetes cluster, enough to create components with privileges. + +You can register for a [free forever Grafana Cloud account](/auth/sign-up/create-user) in minutes and start sending telemetry data and monitoring your infrastructure and applications. + +There are two configuration options to collect metrics to send to Grafana Cloud for Asserts. First, through Kubernetes monitoring or alternatively with an OpenTelemetry Collector. + +## Configuration for Kubernetes monitoring + +If you use Kubernetes monitoring and a Helm chart for scraping metrics, create a `values.yml` with the following configuration: + +```yaml +preset: network + +podAnnotations: + k8s.grafana.com/scrape: true + k8s.grafana.com/job: beyla-network + k8s.grafana.com/metrics.portName: metrics +``` + +## Configure for OpenTelemetry Collector + +If you use an OpenTelemetry Collector for metrics collection, either Grafana Alloy the upstream collector, create a `values.yml` with the following configuration: + +```sh +preset: network + +env: + OTEL_EXPORTER_OTLP_ENDPOINT: your-otlp-endpoint:4318 +``` + +## Install and run Beyla network metrics for Asserts + +Run the following `helm` commands to add the `grafana` repository and install and run `beyla` with your configuration for network metrics: + +```sh +helm repo add grafana https://grafana.github.io/helm-charts +helm install beyla --create-namespace -n beyla -f values.yaml grafana/beyla +``` + +## Observe your services in Asserts + +Finally, navigate to Asserts in [Grafana Cloud](/auth/sign-in/) and view your instrumented services. diff --git a/docs/sources/network/config.md b/docs/sources/network/config.md index 83614f369..e21b98c29 100644 --- a/docs/sources/network/config.md +++ b/docs/sources/network/config.md @@ -2,7 +2,7 @@ title: Beyla Network Metrics configuration options menuTitle: Configuration description: Learn about the configuration options available for Beyla network metrics -weight: 2 +weight: 3 keywords: - Beyla - eBPF @@ -52,11 +52,13 @@ network metrics (in the previous example, `otel_metrics_export`, but it also acc | -------- | ----------------------- | ------- | ------- | | `enable` | `BEYLA_NETWORK_METRICS` | boolean | `false` | -Enables network metrics reporting in Beyla. +Explicitly enables network metrics reporting in Beyla. You can also enable network metrics reporting +by adding `network` to the list of `features` for [otel_metrics_export]({{< relref "../configure/options.md#otel-metrics-exporter" >}})) +or [prometheus_export]({{< relref "../configure/options.md#prometheus-http-endpoint" >}})). -| YAML | Environment variable | Type | Default | -| -------------------- | ---------------------------------- | -------- | -------- | -| `source` | `BEYLA_NETWORK_SOURCE` | string | `tc` | +| YAML | Environment variable | Type | Default | +| -------------------- | ---------------------------------- | -------- | ------------------- | +| `source` | `BEYLA_NETWORK_SOURCE` | string | `socket_filter` | Specifies the Linux Kernel feature used to source the network events Beyla reports. @@ -64,7 +66,7 @@ The available options are: `tc` and `socket_filter`. When `tc` is used as an event source, Beyla uses the Linux Traffic Control ingress and egress filters to capture the network events, in a direct action mode. This event source mode assumes -that no other eBPF programs are attaching to the same Linux Traffic Control interface, in +that no other eBPF programs are attaching to the same Linux Traffic Control interface, in direct action mode. For example, the Cilium Kubernetes CNI uses the same approach, therefore if you have Cilium CNI installed in your Kubernetes cluster, configure Beyla to capture the network events with the `socket_filter` mode. diff --git a/pkg/beyla/config.go b/pkg/beyla/config.go index 3730c1438..e78519250 100644 --- a/pkg/beyla/config.go +++ b/pkg/beyla/config.go @@ -66,7 +66,7 @@ var DefaultConfig = Config{ Buckets: otel.DefaultBuckets, ReportersCacheLen: ReporterLRUSize, HistogramAggregation: otel.AggregationExplicit, - Features: []string{otel.FeatureNetwork, otel.FeatureApplication}, + Features: []string{otel.FeatureApplication}, Instrumentations: []string{ instrumentations.InstrumentationALL, }, @@ -86,7 +86,7 @@ var DefaultConfig = Config{ Prometheus: prom.PrometheusConfig{ Path: "/metrics", Buckets: otel.DefaultBuckets, - Features: []string{otel.FeatureNetwork, otel.FeatureApplication}, + Features: []string{otel.FeatureApplication}, Instrumentations: []string{ instrumentations.InstrumentationALL, }, @@ -234,11 +234,19 @@ func (c *Config) Validate() error { return nil } +func (c *Config) promNetO11yEnabled() bool { + return c.Prometheus.Enabled() && c.Prometheus.NetworkMetricsEnabled() +} + +func (c *Config) otelNetO11yEnabled() bool { + return (c.Metrics.Enabled() || c.Grafana.OTLP.MetricsEnabled()) && c.Metrics.NetworkMetricsEnabled() +} + // Enabled checks if a given Beyla feature is enabled according to the global configuration func (c *Config) Enabled(feature Feature) bool { switch feature { case FeatureNetO11y: - return c.NetworkFlows.Enable + return c.NetworkFlows.Enable || c.promNetO11yEnabled() || c.otelNetO11yEnabled() case FeatureAppO11y: return c.Port.Len() > 0 || c.Exec.IsSet() || len(c.Discovery.Services) > 0 || c.Discovery.SystemWide } diff --git a/pkg/beyla/config_test.go b/pkg/beyla/config_test.go index 1f189dc93..738e20005 100644 --- a/pkg/beyla/config_test.go +++ b/pkg/beyla/config_test.go @@ -120,7 +120,7 @@ network: DurationHistogram: []float64{0, 1, 2}, RequestSizeHistogram: otel.DefaultBuckets.RequestSizeHistogram, }, - Features: []string{"network", "application"}, + Features: []string{"application"}, Instrumentations: []string{ instrumentations.InstrumentationALL, }, @@ -140,7 +140,7 @@ network: }, Prometheus: prom.PrometheusConfig{ Path: "/metrics", - Features: []string{otel.FeatureNetwork, otel.FeatureApplication}, + Features: []string{otel.FeatureApplication}, Instrumentations: []string{ instrumentations.InstrumentationALL, }, @@ -288,6 +288,26 @@ func TestConfig_OtelGoAutoEnv(t *testing.T) { assert.True(t, cfg.Exec.IsSet()) // Exec maps to BEYLA_EXECUTABLE_NAME } +func TestConfig_NetworkImplicit(t *testing.T) { + // OTEL_GO_AUTO_TARGET_EXE is an alias to BEYLA_EXECUTABLE_NAME + // (Compatibility with OpenTelemetry) + require.NoError(t, os.Setenv("OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4318")) + require.NoError(t, os.Setenv("BEYLA_OTEL_METRIC_FEATURES", "network")) + cfg, err := LoadConfig(bytes.NewReader(nil)) + require.NoError(t, err) + assert.True(t, cfg.Enabled(FeatureNetO11y)) // Net o11y should be on +} + +func TestConfig_NetworkImplicitProm(t *testing.T) { + // OTEL_GO_AUTO_TARGET_EXE is an alias to BEYLA_EXECUTABLE_NAME + // (Compatibility with OpenTelemetry) + require.NoError(t, os.Setenv("BEYLA_PROMETHEUS_PORT", "9090")) + require.NoError(t, os.Setenv("BEYLA_PROMETHEUS_FEATURES", "network")) + cfg, err := LoadConfig(bytes.NewReader(nil)) + require.NoError(t, err) + assert.True(t, cfg.Enabled(FeatureNetO11y)) // Net o11y should be on +} + func loadConfig(t *testing.T, env map[string]string) *Config { for k, v := range env { require.NoError(t, os.Setenv(k, v)) diff --git a/pkg/beyla/network_cfg.go b/pkg/beyla/network_cfg.go index f42f4124d..b55bc699d 100644 --- a/pkg/beyla/network_cfg.go +++ b/pkg/beyla/network_cfg.go @@ -120,7 +120,7 @@ type NetworkConfig struct { } var defaultNetworkConfig = NetworkConfig{ - Source: EbpfSourceTC, + Source: EbpfSourceSock, AgentIPIface: "external", AgentIPType: "any", ExcludeInterfaces: []string{"lo"}, diff --git a/pkg/components/beyla.go b/pkg/components/beyla.go index cd24c076a..a3d8faf89 100644 --- a/pkg/components/beyla.go +++ b/pkg/components/beyla.go @@ -2,14 +2,16 @@ package components import ( "context" + "fmt" "log/slog" - "os" + "slices" "sync" "github.com/grafana/beyla/pkg/beyla" "github.com/grafana/beyla/pkg/internal/appolly" "github.com/grafana/beyla/pkg/internal/connector" "github.com/grafana/beyla/pkg/internal/export/attributes" + "github.com/grafana/beyla/pkg/internal/export/otel" "github.com/grafana/beyla/pkg/internal/imetrics" "github.com/grafana/beyla/pkg/internal/kube" "github.com/grafana/beyla/pkg/internal/netolly/agent" @@ -19,7 +21,7 @@ import ( // RunBeyla in the foreground process. This is a blocking function and won't exit // until both the AppO11y and NetO11y components end -func RunBeyla(ctx context.Context, cfg *beyla.Config) { +func RunBeyla(ctx context.Context, cfg *beyla.Config) error { ctxInfo := buildCommonContextInfo(cfg) wg := sync.WaitGroup{} @@ -32,22 +34,33 @@ func RunBeyla(ctx context.Context, cfg *beyla.Config) { wg.Add(1) } + errs := make(chan error, 2) if app { go func() { defer wg.Done() - setupAppO11y(ctx, ctxInfo, cfg) + if err := setupAppO11y(ctx, ctxInfo, cfg); err != nil { + errs <- err + } }() } if net { go func() { defer wg.Done() - setupNetO11y(ctx, ctxInfo, cfg) + if err := setupNetO11y(ctx, ctxInfo, cfg); err != nil { + errs <- err + } }() } wg.Wait() + select { + case err := <-errs: + return err + default: + return nil + } } -func setupAppO11y(ctx context.Context, ctxInfo *global.ContextInfo, config *beyla.Config) { +func setupAppO11y(ctx context.Context, ctxInfo *global.ContextInfo, config *beyla.Config) error { slog.Info("starting Beyla in Application Observability mode") // TODO: when we split Beyla in two processes with different permissions, this code can be split: // in two parts: @@ -56,26 +69,45 @@ func setupAppO11y(ctx context.Context, ctxInfo *global.ContextInfo, config *beyl instr := appolly.New(ctx, ctxInfo, config) if err := instr.FindAndInstrument(); err != nil { - slog.Error("Beyla couldn't find target process", "error", err) - os.Exit(-1) + return fmt.Errorf("can't find target process: %w", err) } if err := instr.ReadAndForward(); err != nil { - slog.Error("Beyla couldn't start read and forwarding", "error", err) - os.Exit(-1) + return fmt.Errorf("can't start read and forwarding: %w", err) } + return nil } -func setupNetO11y(ctx context.Context, ctxInfo *global.ContextInfo, cfg *beyla.Config) { +func setupNetO11y(ctx context.Context, ctxInfo *global.ContextInfo, cfg *beyla.Config) error { + if msg := mustSkip(cfg); msg != "" { + slog.Warn(msg + ". Skipping Network metrics component") + return nil + } slog.Info("starting Beyla in Network metrics mode") flowsAgent, err := agent.FlowsAgent(ctxInfo, cfg) if err != nil { - slog.Error("can't start network metrics capture", "error", err) - os.Exit(-1) + return fmt.Errorf("can't start network metrics capture: %w", err) } if err := flowsAgent.Run(ctx); err != nil { - slog.Error("can't start network metrics capture", "error", err) - os.Exit(-1) + return fmt.Errorf("can't start network metrics capture: %w", err) + } + return nil +} + +func mustSkip(cfg *beyla.Config) string { + otelEnabled := cfg.Metrics.Enabled() + otelFeature := slices.Contains(cfg.Metrics.Features, otel.FeatureNetwork) + promEnabled := cfg.Prometheus.Enabled() + promFeature := slices.Contains(cfg.Prometheus.Features, otel.FeatureNetwork) + if otelEnabled && !otelFeature && !promEnabled { + return "network not present in BEYLA_OTEL_METRICS_FEATURES" + } + if promEnabled && !promFeature && !otelEnabled { + return "network not present in BEYLA_PROMETHEUS_FEATURES" + } + if promEnabled && !promFeature && otelEnabled && !otelFeature { + return "network not present neither in BEYLA_PROMETHEUS_FEATURES nor BEYLA_OTEL_METRICS_FEATURES" } + return "" } // BuildContextInfo populates some globally shared components and properties diff --git a/pkg/components/beyla_test.go b/pkg/components/beyla_test.go new file mode 100644 index 000000000..351be37f3 --- /dev/null +++ b/pkg/components/beyla_test.go @@ -0,0 +1,73 @@ +//go:build linux + +package components + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/grafana/beyla/pkg/beyla" +) + +// Tests fix for https://github.com/grafana/beyla/issues/926 +func TestRun_DontPanic(t *testing.T) { + type testCase struct { + description string + configProvider func() beyla.Config + } + testCases := []testCase{{ + description: "otel endpoint but feature excluded", + configProvider: func() beyla.Config { + cfg := beyla.DefaultConfig + cfg.Metrics.Features = []string{"application"} + cfg.NetworkFlows.Enable = true + cfg.Metrics.CommonEndpoint = "http://localhost" + return cfg + }, + }, { + description: "prom endpoint but feature excluded", + configProvider: func() beyla.Config { + cfg := beyla.DefaultConfig + cfg.Prometheus.Features = []string{"application"} + cfg.NetworkFlows.Enable = true + cfg.Prometheus.Port = 9090 + return cfg + }, + }, { + description: "otel endpoint, otel feature excluded, but prom enabled", + configProvider: func() beyla.Config { + cfg := beyla.DefaultConfig + cfg.Metrics.Features = []string{"application"} + cfg.NetworkFlows.Enable = true + cfg.Metrics.CommonEndpoint = "http://localhost" + cfg.Prometheus.Port = 9090 + return cfg + }, + }, { + description: "all endpoints, all features excluded", + configProvider: func() beyla.Config { + cfg := beyla.DefaultConfig + cfg.NetworkFlows.Enable = true + cfg.Prometheus.Port = 9090 + cfg.Prometheus.Features = []string{"application"} + cfg.Metrics.CommonEndpoint = "http://localhost" + cfg.Metrics.Features = []string{"application"} + return cfg + }, + }} + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + cfg := tc.configProvider() + require.NoError(t, cfg.Validate()) + + require.NotPanics(t, func() { + _ = RunBeyla(ctx, &cfg) + }) + }) + } +} diff --git a/pkg/internal/ebpf/tracer_linux.go b/pkg/internal/ebpf/tracer_linux.go index 74c977a9e..ff1adaee0 100644 --- a/pkg/internal/ebpf/tracer_linux.go +++ b/pkg/internal/ebpf/tracer_linux.go @@ -11,6 +11,7 @@ import ( "sync" "github.com/cilium/ebpf" + "github.com/cilium/ebpf/btf" common "github.com/grafana/beyla/pkg/internal/ebpf/common" "github.com/grafana/beyla/pkg/internal/request" @@ -135,6 +136,8 @@ func (pt *ProcessTracer) tracers() ([]Tracer, error) { tracers = append(tracers, p) } + btf.FlushKernelSpec() + return tracers, nil } @@ -174,5 +177,7 @@ func RunUtilityTracer(p UtilityTracer, pinPath string) error { go p.Run(context.Background()) + btf.FlushKernelSpec() + return nil } diff --git a/pkg/internal/export/otel/metrics.go b/pkg/internal/export/otel/metrics.go index 82084b36e..17c27b487 100644 --- a/pkg/internal/export/otel/metrics.go +++ b/pkg/internal/export/otel/metrics.go @@ -152,8 +152,12 @@ func (m *MetricsConfig) OTelMetricsEnabled() bool { return slices.Contains(m.Features, FeatureApplication) } +func (m *MetricsConfig) NetworkMetricsEnabled() bool { + return slices.Contains(m.Features, FeatureNetwork) +} + func (m *MetricsConfig) Enabled() bool { - return m.EndpointEnabled() && (m.OTelMetricsEnabled() || m.SpanMetricsEnabled() || m.ServiceGraphMetricsEnabled()) + return m.EndpointEnabled() && (m.OTelMetricsEnabled() || m.SpanMetricsEnabled() || m.ServiceGraphMetricsEnabled() || m.NetworkMetricsEnabled()) } // MetricsReporter implements the graph node that receives request.Span diff --git a/pkg/internal/export/otel/metrics_net.go b/pkg/internal/export/otel/metrics_net.go index e7ee62a5d..5bddd3f6a 100644 --- a/pkg/internal/export/otel/metrics_net.go +++ b/pkg/internal/export/otel/metrics_net.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "log/slog" - "slices" "time" "github.com/google/uuid" @@ -25,10 +24,11 @@ import ( type NetMetricsConfig struct { Metrics *MetricsConfig AttributeSelectors attributes.Selection + GloballyEnabled bool } func (mc NetMetricsConfig) Enabled() bool { - return mc.Metrics != nil && mc.Metrics.EndpointEnabled() && slices.Contains(mc.Metrics.Features, FeatureNetwork) + return mc.Metrics != nil && mc.Metrics.EndpointEnabled() && (mc.Metrics.NetworkMetricsEnabled() || mc.GloballyEnabled) } func nmlog() *slog.Logger { diff --git a/pkg/internal/export/otel/metrics_test.go b/pkg/internal/export/otel/metrics_test.go index cbdec655b..786b9309b 100644 --- a/pkg/internal/export/otel/metrics_test.go +++ b/pkg/internal/export/otel/metrics_test.go @@ -528,6 +528,7 @@ func TestMetricsConfig_Enabled(t *testing.T) { assert.True(t, (&MetricsConfig{Features: []string{FeatureApplication, FeatureNetwork}, CommonEndpoint: "foo"}).Enabled()) assert.True(t, (&MetricsConfig{Features: []string{FeatureApplication}, MetricsEndpoint: "foo"}).Enabled()) assert.True(t, (&MetricsConfig{Features: []string{FeatureNetwork, FeatureApplication}, Grafana: &GrafanaOTLP{Submit: []string{"traces", "metrics"}, InstanceID: "33221"}}).Enabled()) + assert.True(t, (&MetricsConfig{MetricsEndpoint: "foo", Features: []string{FeatureNetwork}}).Enabled()) } func TestMetricsConfig_Disabled(t *testing.T) { @@ -536,7 +537,6 @@ func TestMetricsConfig_Disabled(t *testing.T) { assert.False(t, (&MetricsConfig{Features: []string{FeatureApplication}, Grafana: &GrafanaOTLP{Submit: []string{"metrics"}}}).Enabled()) // application feature is not enabled assert.False(t, (&MetricsConfig{CommonEndpoint: "foo"}).Enabled()) - assert.False(t, (&MetricsConfig{MetricsEndpoint: "foo", Features: []string{FeatureNetwork}}).Enabled()) assert.False(t, (&MetricsConfig{Grafana: &GrafanaOTLP{Submit: []string{"traces", "metrics"}, InstanceID: "33221"}}).Enabled()) } diff --git a/pkg/internal/export/prom/prom.go b/pkg/internal/export/prom/prom.go index e1158a958..97763b9a8 100644 --- a/pkg/internal/export/prom/prom.go +++ b/pkg/internal/export/prom/prom.go @@ -128,13 +128,17 @@ func (p *PrometheusConfig) ServiceGraphMetricsEnabled() bool { return slices.Contains(p.Features, otel.FeatureGraph) } +func (p *PrometheusConfig) NetworkMetricsEnabled() bool { + return slices.Contains(p.Features, otel.FeatureNetwork) +} + func (p *PrometheusConfig) EndpointEnabled() bool { return p.Port != 0 || p.Registry != nil } // nolint:gocritic func (p *PrometheusConfig) Enabled() bool { - return p.EndpointEnabled() && (p.OTelMetricsEnabled() || p.SpanMetricsEnabled() || p.ServiceGraphMetricsEnabled()) + return p.EndpointEnabled() && (p.OTelMetricsEnabled() || p.SpanMetricsEnabled() || p.ServiceGraphMetricsEnabled() || p.NetworkMetricsEnabled()) } type metricsReporter struct { diff --git a/pkg/internal/export/prom/prom_net.go b/pkg/internal/export/prom/prom_net.go index b72838f3f..1adc2a4b1 100644 --- a/pkg/internal/export/prom/prom_net.go +++ b/pkg/internal/export/prom/prom_net.go @@ -3,7 +3,6 @@ package prom import ( "context" "fmt" - "slices" "github.com/mariomac/pipes/pipe" "github.com/prometheus/client_golang/prometheus" @@ -11,7 +10,6 @@ import ( "github.com/grafana/beyla/pkg/internal/connector" "github.com/grafana/beyla/pkg/internal/export/attributes" "github.com/grafana/beyla/pkg/internal/export/expire" - "github.com/grafana/beyla/pkg/internal/export/otel" "github.com/grafana/beyla/pkg/internal/netolly/ebpf" "github.com/grafana/beyla/pkg/internal/pipe/global" ) @@ -22,11 +20,12 @@ import ( type NetPrometheusConfig struct { Config *PrometheusConfig AttributeSelectors attributes.Selection + GloballyEnabled bool } // nolint:gocritic func (p NetPrometheusConfig) Enabled() bool { - return p.Config != nil && p.Config.Port != 0 && slices.Contains(p.Config.Features, otel.FeatureNetwork) + return p.Config != nil && p.Config.Port != 0 && (p.Config.NetworkMetricsEnabled() || p.GloballyEnabled) } type netMetricsReporter struct { diff --git a/pkg/internal/goexec/offsets.json b/pkg/internal/goexec/offsets.json index f48f8b2b5..f773f641c 100755 --- a/pkg/internal/goexec/offsets.json +++ b/pkg/internal/goexec/offsets.json @@ -152,7 +152,7 @@ "bw": { "versions": { "oldest": "9.0.0", - "newest": "9.5.3" + "newest": "9.5.4" }, "offsets": [ { diff --git a/pkg/internal/netolly/agent/pipeline.go b/pkg/internal/netolly/agent/pipeline.go index 2db546fc0..e8cdb293d 100644 --- a/pkg/internal/netolly/agent/pipeline.go +++ b/pkg/internal/netolly/agent/pipeline.go @@ -136,12 +136,14 @@ func (f *Flows) pipelineBuilder(ctx context.Context) (*pipe.Builder[*FlowsPipeli return otel.NetMetricsExporterProvider(ctx, f.ctxInfo, &otel.NetMetricsConfig{ Metrics: &f.cfg.Metrics, AttributeSelectors: f.cfg.Attributes.Select, + GloballyEnabled: f.cfg.NetworkFlows.Enable, }) }) pipe.AddFinalProvider(pb, promExport, func() (pipe.FinalFunc[[]*ebpf.Record], error) { return prom.NetPrometheusEndpoint(ctx, f.ctxInfo, &prom.NetPrometheusConfig{ Config: &f.cfg.Prometheus, AttributeSelectors: f.cfg.Attributes.Select, + GloballyEnabled: f.cfg.NetworkFlows.Enable, }) }) pipe.AddFinalProvider(pb, printer, func() (pipe.FinalFunc[[]*ebpf.Record], error) { diff --git a/test/integration/docker-compose-netolly-direction.yml b/test/integration/docker-compose-netolly-direction.yml index f99303361..057777252 100644 --- a/test/integration/docker-compose-netolly-direction.yml +++ b/test/integration/docker-compose-netolly-direction.yml @@ -41,7 +41,7 @@ services: BEYLA_CONFIG_PATH: /configs/instrumenter-config-netolly${BEYLA_CONFIG_SUFFIX}.yml GOCOVERDIR: "/coverage" BEYLA_NETWORK_SOURCE: ${BEYLA_NETWORK_SOURCE} - BEYLA_NETWORK_METRICS: "true" + BEYLA_OTEL_METRICS_FEATURES: "network" # implicitly enabling network metrics without a global enable BEYLA_NETWORK_PRINT_FLOWS: "true" BEYLA_NETWORK_DEDUPER: ${BEYLA_NETWORK_DEDUPER} OTEL_EXPORTER_OTLP_ENDPOINT: http://otelcol:4318 diff --git a/test/integration/docker-compose-netolly.yml b/test/integration/docker-compose-netolly.yml index 9044e7f32..da906d60b 100644 --- a/test/integration/docker-compose-netolly.yml +++ b/test/integration/docker-compose-netolly.yml @@ -32,7 +32,7 @@ services: BEYLA_CONFIG_PATH: /configs/instrumenter-config-netolly${BEYLA_CONFIG_SUFFIX}.yml GOCOVERDIR: "/coverage" BEYLA_NETWORK_SOURCE: ${BEYLA_NETWORK_SOURCE} - BEYLA_NETWORK_METRICS: "true" + BEYLA_NETWORK_METRICS: "true" # explicitly enabling network metrics BEYLA_NETWORK_PRINT_FLOWS: "true" BEYLA_NETWORK_DEDUPER: ${BEYLA_NETWORK_DEDUPER} OTEL_EXPORTER_OTLP_ENDPOINT: http://otelcol:4318 diff --git a/test/integration/k8s/manifests/06-beyla-netolly-promexport.yml b/test/integration/k8s/manifests/06-beyla-netolly-promexport.yml index caff494f5..6e46d9849 100644 --- a/test/integration/k8s/manifests/06-beyla-netolly-promexport.yml +++ b/test/integration/k8s/manifests/06-beyla-netolly-promexport.yml @@ -86,8 +86,8 @@ spec: value: "/testoutput" - name: BEYLA_CONFIG_PATH value: /config/beyla-config.yml - - name: BEYLA_NETWORK_METRICS - value: "true" + - name: BEYLA_PROMETHEUS_FEATURES # implicitly enabling network metrics for Prometheus scrape + value: "network" - name: BEYLA_NETWORK_CACHE_ACTIVE_TIMEOUT value: "100ms" - name: BEYLA_NETWORK_CACHE_MAX_FLOWS