Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion cli_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/peterbourgon/ff/v3"

"go.opentelemetry.io/ebpf-profiler/collector/config"
"go.opentelemetry.io/ebpf-profiler/internal/controller"
"go.opentelemetry.io/ebpf-profiler/tracer"
)
Expand Down Expand Up @@ -42,7 +43,7 @@ var (
mapScaleFactorHelp = fmt.Sprintf("Scaling factor for eBPF map sizes. "+
"Every increase by 1 doubles the map size. Increase if you see eBPF map size errors. "+
"Default is %d corresponding to 4GB of executable address space, max is %d.",
defaultArgMapScaleFactor, controller.MaxArgMapScaleFactor)
defaultArgMapScaleFactor, config.MaxArgMapScaleFactor)
disableTLSHelp = "Disable encryption for data in transit."
bpfVerifierLogLevelHelp = "Log level of the eBPF verifier output (0,1,2). Default is 0."
versionHelp = "Show version."
Expand Down
81 changes: 80 additions & 1 deletion collector/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,19 @@

package config // import "go.opentelemetry.io/ebpf-profiler/collector/config"

import "time"
import (
"errors"
"fmt"
"runtime"
"time"

"go.opentelemetry.io/ebpf-profiler/tracer"
)

const (
// 1TB of executable address space
MaxArgMapScaleFactor = 8
)

// Config is the configuration for the collector.
type Config struct {
Expand All @@ -27,3 +39,70 @@ type Config struct {
MaxGRPCRetries uint32 `mapstructure:"max_grpc_retries"`
MaxRPCMsgSize int `mapstructure:"max_rpc_msg_size"`
}

// Validate validates the config.
// This is automatically called by the config parser as it implements the xconfmap.Validator interface.
func (cfg *Config) Validate() error {
if cfg.SamplesPerSecond < 1 {
return fmt.Errorf("invalid sampling frequency: %d", cfg.SamplesPerSecond)
}

if cfg.MapScaleFactor > MaxArgMapScaleFactor {
return fmt.Errorf(
"eBPF map scaling factor %d exceeds limit (max: %d)",
cfg.MapScaleFactor, MaxArgMapScaleFactor,
)
}

if cfg.BPFVerifierLogLevel > 2 {
return fmt.Errorf("invalid eBPF verifier log level: %d", cfg.BPFVerifierLogLevel)
}

if cfg.ProbabilisticInterval < 1*time.Minute || cfg.ProbabilisticInterval > 5*time.Minute {
return errors.New(
"invalid argument for probabilistic-interval: use " +
"a duration between 1 and 5 minutes",
)
}

if cfg.ProbabilisticThreshold < 1 ||
cfg.ProbabilisticThreshold > tracer.ProbabilisticThresholdMax {
return fmt.Errorf(
"invalid argument for probabilistic-threshold. Value "+
"should be between 1 and %d",
tracer.ProbabilisticThresholdMax,
)
}

if cfg.OffCPUThreshold < 0.0 || cfg.OffCPUThreshold > 1.0 {
return errors.New(
"invalid argument for off-cpu-threshold. The value " +
"should be in the range [0..1]. 0 disables off-cpu profiling")
}

if !cfg.NoKernelVersionCheck {
major, minor, patch, err := tracer.GetCurrentKernelVersion()
if err != nil {
return fmt.Errorf("failed to get kernel version: %v", err)
}

var minMajor, minMinor uint32
switch runtime.GOARCH {
case "amd64":
minMajor, minMinor = 5, 2
case "arm64":
// Older ARM64 kernel versions have broken bpf_probe_read.
// https://github.com/torvalds/linux/commit/6ae08ae3dea2cfa03dd3665a3c8475c2d429ef47
minMajor, minMinor = 5, 5
default:
return fmt.Errorf("unsupported architecture: %s", runtime.GOARCH)
}

if major < minMajor || (major == minMajor && minor < minMinor) {
return fmt.Errorf("host Agent requires kernel version "+
"%d.%d or newer but got %d.%d.%d", minMajor, minMinor, major, minor, patch)
}
}

return nil
}
20 changes: 20 additions & 0 deletions collector/config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package config // import "go.opentelemetry.io/ebpf-profiler/collector/config"

import (
"testing"

"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/confmap/xconfmap"
)

func TestValidate(t *testing.T) {
cfg := &Config{
SamplesPerSecond: 0,
}
err := xconfmap.Validate(cfg)
require.Error(t, err)
require.Equal(t, "invalid sampling frequency: 0", err.Error())
}
10 changes: 10 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ require (
github.com/stretchr/testify v1.11.1
github.com/zeebo/xxh3 v1.0.2
go.opentelemetry.io/collector/component v1.45.0
go.opentelemetry.io/collector/confmap/xconfmap v0.138.0
go.opentelemetry.io/collector/consumer/consumertest v0.139.0
go.opentelemetry.io/collector/consumer/xconsumer v0.139.0
go.opentelemetry.io/collector/pdata v1.45.0
Expand Down Expand Up @@ -62,19 +63,27 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/josharian/native v1.1.0 // indirect
github.com/jsimonetti/rtnetlink/v2 v2.0.3 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/knadh/koanf/maps v0.1.2 // indirect
github.com/knadh/koanf/providers/confmap v1.0.0 // indirect
github.com/knadh/koanf/v2 v2.3.0 // indirect
github.com/mdlayher/netlink v1.7.2 // indirect
github.com/mdlayher/socket v0.4.1 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/collector/component/componenttest v0.139.0 // indirect
go.opentelemetry.io/collector/confmap v1.44.0 // indirect
go.opentelemetry.io/collector/consumer v1.45.0 // indirect
go.opentelemetry.io/collector/consumer/consumererror v0.139.0 // indirect
go.opentelemetry.io/collector/featuregate v1.45.0 // indirect
Expand All @@ -84,6 +93,7 @@ require (
go.opentelemetry.io/otel/trace v1.38.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/net v0.46.0 // indirect
golang.org/x/text v0.30.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect
Expand Down
20 changes: 20 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-quicktest/qt v1.101.1-0.20240301121107-c6c8733fa1e6 h1:teYtXy9B7y5lHTp8V9KPxpYRAVA7dozigQcMiBust1s=
github.com/go-quicktest/qt v1.101.1-0.20240301121107-c6c8733fa1e6/go.mod h1:p4lGIVX+8Wa6ZPNDvqcxq36XpUDLh42FLetFU7odllI=
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
Expand All @@ -75,6 +79,12 @@ github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3J
github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0=
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo=
github.com/knadh/koanf/maps v0.1.2/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
github.com/knadh/koanf/providers/confmap v1.0.0 h1:mHKLJTE7iXEys6deO5p6olAiZdG5zwp8Aebir+/EaRE=
github.com/knadh/koanf/providers/confmap v1.0.0/go.mod h1:txHYHiI2hAtF0/0sCmcuol4IDcuQbKTybiB1nOcUo1A=
github.com/knadh/koanf/v2 v2.3.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM=
github.com/knadh/koanf/v2 v2.3.0/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
Expand All @@ -90,6 +100,10 @@ github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
Expand All @@ -116,6 +130,10 @@ go.opentelemetry.io/collector/component v1.45.0 h1:gGFfVdbQ+1YuyUkJjWo85I7euu3H/
go.opentelemetry.io/collector/component v1.45.0/go.mod h1:xoNFnRKE8Iv6gmlqAKgjayWraRnDcYLLgrPt9VgyO2g=
go.opentelemetry.io/collector/component/componenttest v0.139.0 h1:x9Yu2eYhrHxdZ7sFXWtAWVjQ3UIraje557LgNurDC2I=
go.opentelemetry.io/collector/component/componenttest v0.139.0/go.mod h1:S9cj+qkf9FgHMzjvlYsLwQKd9BiS7B7oLZvxvlENM/c=
go.opentelemetry.io/collector/confmap v1.44.0 h1:CIK4jAk6H3KTKza4nvWQkqLqrudLkYGz3evu5163uxg=
go.opentelemetry.io/collector/confmap v1.44.0/go.mod h1:w37Xiu/PK3nTdqKb7YEvQECHYkuW7QnmdS7b9iRjOGo=
go.opentelemetry.io/collector/confmap/xconfmap v0.138.0 h1:0b/h3LXBAcHFKPE9eVjZ4KRTaj9ImdOBK2z9hBlmoyA=
go.opentelemetry.io/collector/confmap/xconfmap v0.138.0/go.mod h1:rk8hjMqoHX2KYUjGUPaiWo3qapj4o8UpQWWsdEqvorg=
go.opentelemetry.io/collector/consumer v1.45.0 h1:TtqXxgW+1GSCwdoohq0fzqnfqrZBKbfo++1XRj8mrEA=
go.opentelemetry.io/collector/consumer v1.45.0/go.mod h1:pJzqTWBubwLt8mVou+G4/Hs23b3m425rVmld3LqOYpY=
go.opentelemetry.io/collector/consumer/consumererror v0.139.0 h1:vp4MQ6pKpnS242hE+tuvp0e2OEKhY1Enb0Dpk0fYLkY=
Expand Down Expand Up @@ -164,6 +182,8 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U=
go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI=
golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
Expand Down
76 changes: 1 addition & 75 deletions internal/controller/config.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
package controller // import "go.opentelemetry.io/ebpf-profiler/internal/controller"

import (
"errors"
"flag"
"fmt"
"runtime"
"time"

"go.opentelemetry.io/ebpf-profiler/internal/log"

"go.opentelemetry.io/collector/consumer/xconsumer"
"go.opentelemetry.io/ebpf-profiler/collector/config"
"go.opentelemetry.io/ebpf-profiler/reporter"
"go.opentelemetry.io/ebpf-profiler/tracer"
)

type Config struct {
Expand All @@ -34,11 +30,6 @@ type Config struct {
Fs *flag.FlagSet
}

const (
// 1TB of executable address space
MaxArgMapScaleFactor = 8
)

// Dump visits all flag sets, and dumps them all to debug
// Used for verbose mode logging.
func (cfg *Config) Dump() {
Expand All @@ -51,70 +42,5 @@ func (cfg *Config) Dump() {
// Validate runs validations on the provided configuration, and returns errors
// if invalid values were provided.
func (cfg *Config) Validate() error {
if cfg.SamplesPerSecond < 1 {
return fmt.Errorf("invalid sampling frequency: %d", cfg.SamplesPerSecond)
}

if cfg.MapScaleFactor > MaxArgMapScaleFactor {
return fmt.Errorf(
"eBPF map scaling factor %d exceeds limit (max: %d)",
cfg.MapScaleFactor, MaxArgMapScaleFactor,
)
}

if cfg.BPFVerifierLogLevel > 2 {
return fmt.Errorf("invalid eBPF verifier log level: %d", cfg.BPFVerifierLogLevel)
}

if cfg.ProbabilisticInterval < 1*time.Minute || cfg.ProbabilisticInterval > 5*time.Minute {
return errors.New(
"invalid argument for probabilistic-interval: use " +
"a duration between 1 and 5 minutes",
)
}

if cfg.ProbabilisticThreshold < 1 ||
cfg.ProbabilisticThreshold > tracer.ProbabilisticThresholdMax {
return fmt.Errorf(
"invalid argument for probabilistic-threshold. Value "+
"should be between 1 and %d",
tracer.ProbabilisticThresholdMax,
)
}

if cfg.OffCPUThreshold < 0.0 || cfg.OffCPUThreshold > 1.0 {
return errors.New(
"invalid argument for off-cpu-threshold. The value " +
"should be in the range [0..1]. 0 disables off-cpu profiling")
}

if !cfg.NoKernelVersionCheck {
major, minor, patch, err := tracer.GetCurrentKernelVersion()
if err != nil {
return fmt.Errorf("failed to get kernel version: %v", err)
}

var minMajor, minMinor uint32
switch runtime.GOARCH {
case "amd64":
if cfg.VerboseMode {
minMajor, minMinor = 5, 2
} else {
minMajor, minMinor = 4, 19
}
case "arm64":
// Older ARM64 kernel versions have broken bpf_probe_read.
// https://github.com/torvalds/linux/commit/6ae08ae3dea2cfa03dd3665a3c8475c2d429ef47
minMajor, minMinor = 5, 5
default:
return fmt.Errorf("unsupported architecture: %s", runtime.GOARCH)
}

if major < minMajor || (major == minMajor && minor < minMinor) {
return fmt.Errorf("host Agent requires kernel version "+
"%d.%d or newer but got %d.%d.%d", minMajor, minMinor, major, minor, patch)
}
}

return nil
return cfg.Config.Validate()
}