From 6946a50beec49d1dd9311ff899c1e6fb651b25b1 Mon Sep 17 00:00:00 2001 From: luweglarz Date: Wed, 12 Nov 2025 15:19:03 +0100 Subject: [PATCH] feat: Add lazy mode argument to pyroscope.ebpf --- CHANGELOG.md | 2 ++ .../components/pyroscope/pyroscope.ebpf.md | 1 + internal/component/pyroscope/ebpf/args.go | 1 + .../component/pyroscope/ebpf/ebpf_linux.go | 35 ++++++++++++++++--- 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d41adde6805..413caf6844f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,8 @@ Main (unreleased) - Add a `regex` argument to the `structured_metadata` stage in `loki.process` to extract labels matching a regular expression. (@timonegk) +- Add `lazy_mode` argument to the `pyroscope.ebpf` to defer eBPF profiler startup until there are targets to profile. (@luweglarz) + ### Enhancements - Add per-application rate limiting with the `strategy` attribute in the `faro.receiver` component, to prevent one application from consuming the rate limit quota of others. (@hhertout) diff --git a/docs/sources/reference/components/pyroscope/pyroscope.ebpf.md b/docs/sources/reference/components/pyroscope/pyroscope.ebpf.md index 30d0aa9fc89..d0d7bbe284f 100644 --- a/docs/sources/reference/components/pyroscope/pyroscope.ebpf.md +++ b/docs/sources/reference/components/pyroscope/pyroscope.ebpf.md @@ -78,6 +78,7 @@ You can use the following arguments with `pyroscope.ebpf`: | `v8_enabled` | `bool` | A flag to enable/disable V8 profiling. | `true` | no | | `off_cpu_threshold` | `float` | A flag to adjust the off-cpu profiling threshold between 0 and 1 as float. | `0` | no | | `verbose_mode` | `bool` | Enable verbose logging for the eBPF profiler. | `false` | no | +| `lazy_mode` | `bool` | Enable lazy mode to defer eBPF profiler startup until targets are discovered. | `false` | no | Only the `forward_to` and `targets` fields are required. Omitted fields take their default values. diff --git a/internal/component/pyroscope/ebpf/args.go b/internal/component/pyroscope/ebpf/args.go index ba074ba2101..2ca0ee4b465 100644 --- a/internal/component/pyroscope/ebpf/args.go +++ b/internal/component/pyroscope/ebpf/args.go @@ -25,6 +25,7 @@ type Arguments struct { LoadProbe bool `alloy:"load_probe,attr,optional"` UProbeLinks []string `alloy:"u_probe_links,attr,optional"` VerboseMode bool `alloy:"verbose_mode,attr,optional"` + LazyMode bool `alloy:"lazy_mode,attr,optional"` DeprecatedArguments DeprecatedArguments `alloy:",squash"` // undocumented diff --git a/internal/component/pyroscope/ebpf/ebpf_linux.go b/internal/component/pyroscope/ebpf/ebpf_linux.go index e3e15b4a60d..edf177d8d72 100644 --- a/internal/component/pyroscope/ebpf/ebpf_linux.go +++ b/internal/component/pyroscope/ebpf/ebpf_linux.go @@ -118,6 +118,14 @@ type Component struct { func (c *Component) Run(ctx context.Context) error { c.checkTraceFS() + + if c.args.LazyMode && len(c.args.Targets) == 0 { + _ = level.Info(c.logger).Log("msg", "lazy mode enabled, waiting for targets to profile") + if err := c.waitForTargets(ctx); err != nil { + return err + } + } + ctlr := controller.New(c.cfg) const sessionMaxErrors = 3 var err error @@ -150,16 +158,34 @@ func (c *Component) Run(ctx context.Context) error { case <-ctx.Done(): return nil case newArgs := <-c.argsUpdate: - c.args = newArgs - c.targetFinder.Update(c.args.targetsOptions(c.dynamicProfilingPolicy)) - c.appendable.UpdateChildren(newArgs.ForwardTo) - c.metrics.targetsActive.Set(float64(len(c.args.Targets))) + c.updateArgs(newArgs) } } }, func(error) {}) return g.Run() } +func (c *Component) updateArgs(newArgs Arguments) { + c.args = newArgs + c.targetFinder.Update(c.args.targetsOptions(c.dynamicProfilingPolicy)) + c.appendable.UpdateChildren(newArgs.ForwardTo) + c.metrics.targetsActive.Set(float64(len(c.args.Targets))) +} + +func (c *Component) waitForTargets(ctx context.Context) error { + for { + select { + case <-ctx.Done(): + return ctx.Err() + case newArgs := <-c.argsUpdate: + c.updateArgs(newArgs) + if len(c.args.Targets) > 0 { + return nil + } + } + } +} + func (c *Component) Update(args component.Arguments) error { newArgs := args.(Arguments) select { @@ -238,6 +264,7 @@ func NewDefaultArguments() Arguments { LoadProbe: false, UProbeLinks: []string{}, VerboseMode: false, + LazyMode: false, // undocumented PyroscopeDynamicProfilingPolicy: true,