diff --git a/CHANGELOG.md b/CHANGELOG.md index 136e4555548..24a72762e36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -90,6 +90,8 @@ v1.12.0 - 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) + - OpenTelemetry Collector dependencies upgraded from v0.134.0 to v0.139.0. (@dehaansa) - All `otelcol.receiver.*` components leveraging an HTTP server can configure HTTP keep alive behavior with `keep_alives_enabled`. - All `otelcol.exporter.*` components providing the `sending_queue` > `batch` block have default `batch` values. 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 33ccb0a2c6d..49fea0c1b55 100644 --- a/internal/component/pyroscope/ebpf/ebpf_linux.go +++ b/internal/component/pyroscope/ebpf/ebpf_linux.go @@ -122,6 +122,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 @@ -156,16 +164,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 { @@ -244,6 +270,7 @@ func NewDefaultArguments() Arguments { LoadProbe: false, UProbeLinks: []string{}, VerboseMode: false, + LazyMode: false, // undocumented PyroscopeDynamicProfilingPolicy: true,