From d64a13c08ea1fd49eb06d623c1809f8625493cb5 Mon Sep 17 00:00:00 2001 From: dmathieu <42@dmathieu.com> Date: Fri, 8 Nov 2024 10:00:37 +0100 Subject: [PATCH 1/3] extract lookupcgroupv2 out of the otlp reporter --- reporter/cgroupv2.go | 55 +++++++++++++++++++++++++++++++++++++++ reporter/otlp_reporter.go | 46 +------------------------------- 2 files changed, 56 insertions(+), 45 deletions(-) create mode 100644 reporter/cgroupv2.go diff --git a/reporter/cgroupv2.go b/reporter/cgroupv2.go new file mode 100644 index 00000000..48dfbd99 --- /dev/null +++ b/reporter/cgroupv2.go @@ -0,0 +1,55 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package reporter // import "go.opentelemetry.io/ebpf-profiler/reporter" + +import ( + "bufio" + "fmt" + "os" + + lru "github.com/elastic/go-freelru" + log "github.com/sirupsen/logrus" + "go.opentelemetry.io/ebpf-profiler/libpf" +) + +// lookupCgroupv2 returns the cgroupv2 ID for pid. +func lookupCgroupv2(cgrouplru *lru.SyncedLRU[libpf.PID, string], pid libpf.PID) (string, error) { + id, ok := cgrouplru.Get(pid) + if ok { + return id, nil + } + + // Slow path + f, err := os.Open(fmt.Sprintf("/proc/%d/cgroup", pid)) + if err != nil { + return "", err + } + defer f.Close() + + var genericCgroupv2 string + scanner := bufio.NewScanner(f) + buf := make([]byte, 512) + // Providing a predefined buffer overrides the internal buffer that Scanner uses (4096 bytes). + // We can do that and also set a maximum allocation size on the following call. + // With a maximum of 4096 characters path in the kernel, 8192 should be fine here. We don't + // expect lines in /proc//cgroup to be longer than that. + scanner.Buffer(buf, 8192) + var pathParts []string + for scanner.Scan() { + line := scanner.Text() + pathParts = cgroupv2PathPattern.FindStringSubmatch(line) + if pathParts == nil { + log.Debugf("Could not extract cgroupv2 path from line: %s", line) + continue + } + genericCgroupv2 = pathParts[1] + break + } + + // Cache the cgroupv2 information. + // To avoid busy lookups, also empty cgroupv2 information is cached. + cgrouplru.Add(pid, genericCgroupv2) + + return genericCgroupv2, nil +} diff --git a/reporter/otlp_reporter.go b/reporter/otlp_reporter.go index 1cf6201c..754a664e 100644 --- a/reporter/otlp_reporter.go +++ b/reporter/otlp_reporter.go @@ -4,13 +4,10 @@ package reporter // import "go.opentelemetry.io/ebpf-profiler/reporter" import ( - "bufio" "context" "crypto/rand" "crypto/tls" - "fmt" "maps" - "os" "regexp" "slices" "strconv" @@ -214,7 +211,7 @@ func (r *OTLPReporter) ReportTraceEvent(trace *libpf.Trace, meta *TraceEventMeta traceEventsMap := r.traceEvents.WLock() defer r.traceEvents.WUnlock(&traceEventsMap) - containerID, err := r.lookupCgroupv2(meta.PID) + containerID, err := lookupCgroupv2(r.cgroupv2ID, meta.PID) if err != nil { log.Debugf("Failed to get a cgroupv2 ID as container ID for PID %d: %v", meta.PID, err) @@ -867,44 +864,3 @@ func setupGrpcConnection(parent context.Context, cfg *Config, //nolint:staticcheck return grpc.DialContext(ctx, cfg.CollAgentAddr, opts...) } - -// lookupCgroupv2 returns the cgroupv2 ID for pid. -func (r *OTLPReporter) lookupCgroupv2(pid libpf.PID) (string, error) { - id, ok := r.cgroupv2ID.Get(pid) - if ok { - return id, nil - } - - // Slow path - f, err := os.Open(fmt.Sprintf("/proc/%d/cgroup", pid)) - if err != nil { - return "", err - } - defer f.Close() - - var genericCgroupv2 string - scanner := bufio.NewScanner(f) - buf := make([]byte, 512) - // Providing a predefined buffer overrides the internal buffer that Scanner uses (4096 bytes). - // We can do that and also set a maximum allocation size on the following call. - // With a maximum of 4096 characters path in the kernel, 8192 should be fine here. We don't - // expect lines in /proc//cgroup to be longer than that. - scanner.Buffer(buf, 8192) - var pathParts []string - for scanner.Scan() { - line := scanner.Text() - pathParts = cgroupv2PathPattern.FindStringSubmatch(line) - if pathParts == nil { - log.Debugf("Could not extract cgroupv2 path from line: %s", line) - continue - } - genericCgroupv2 = pathParts[1] - break - } - - // Cache the cgroupv2 information. - // To avoid busy lookups, also empty cgroupv2 information is cached. - r.cgroupv2ID.Add(pid, genericCgroupv2) - - return genericCgroupv2, nil -} From d9ea671d36ced657d778a62bd45de53b4a48c405 Mon Sep 17 00:00:00 2001 From: dmathieu <42@dmathieu.com> Date: Tue, 19 Nov 2024 09:41:43 +0100 Subject: [PATCH 2/3] move lookupcgroupv2 to util --- reporter/otlp_reporter.go | 8 ++------ {reporter => util/cgroup}/cgroupv2.go | 11 ++++++++--- 2 files changed, 10 insertions(+), 9 deletions(-) rename {reporter => util/cgroup}/cgroupv2.go (83%) diff --git a/reporter/otlp_reporter.go b/reporter/otlp_reporter.go index 754a664e..6c80824e 100644 --- a/reporter/otlp_reporter.go +++ b/reporter/otlp_reporter.go @@ -8,7 +8,6 @@ import ( "crypto/rand" "crypto/tls" "maps" - "regexp" "slices" "strconv" "time" @@ -28,10 +27,7 @@ import ( "go.opentelemetry.io/ebpf-profiler/libpf" "go.opentelemetry.io/ebpf-profiler/libpf/xsync" -) - -var ( - cgroupv2PathPattern = regexp.MustCompile(`0:.*?:(.*)`) + "go.opentelemetry.io/ebpf-profiler/util/cgroup" ) // Assert that we implement the full Reporter interface. @@ -211,7 +207,7 @@ func (r *OTLPReporter) ReportTraceEvent(trace *libpf.Trace, meta *TraceEventMeta traceEventsMap := r.traceEvents.WLock() defer r.traceEvents.WUnlock(&traceEventsMap) - containerID, err := lookupCgroupv2(r.cgroupv2ID, meta.PID) + containerID, err := cgroup.LookupCgroupv2(r.cgroupv2ID, meta.PID) if err != nil { log.Debugf("Failed to get a cgroupv2 ID as container ID for PID %d: %v", meta.PID, err) diff --git a/reporter/cgroupv2.go b/util/cgroup/cgroupv2.go similarity index 83% rename from reporter/cgroupv2.go rename to util/cgroup/cgroupv2.go index 48dfbd99..5026ec87 100644 --- a/reporter/cgroupv2.go +++ b/util/cgroup/cgroupv2.go @@ -1,20 +1,25 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package reporter // import "go.opentelemetry.io/ebpf-profiler/reporter" +package cgroup // import "go.opentelemetry.io/ebpf-profiler/util/cgroup" import ( "bufio" "fmt" "os" + "regexp" lru "github.com/elastic/go-freelru" log "github.com/sirupsen/logrus" "go.opentelemetry.io/ebpf-profiler/libpf" ) -// lookupCgroupv2 returns the cgroupv2 ID for pid. -func lookupCgroupv2(cgrouplru *lru.SyncedLRU[libpf.PID, string], pid libpf.PID) (string, error) { +var ( + cgroupv2PathPattern = regexp.MustCompile(`0:.*?:(.*)`) +) + +// LookupCgroupv2 returns the cgroupv2 ID for pid. +func LookupCgroupv2(cgrouplru *lru.SyncedLRU[libpf.PID, string], pid libpf.PID) (string, error) { id, ok := cgrouplru.Get(pid) if ok { return id, nil From 400b2fdd3f1eeeb90061275df9b47ff1d4abe380 Mon Sep 17 00:00:00 2001 From: dmathieu <42@dmathieu.com> Date: Wed, 20 Nov 2024 14:59:37 +0100 Subject: [PATCH 3/3] move lookupcgroupv2 to libpf --- {util/cgroup => libpf}/cgroupv2.go | 5 ++--- reporter/otlp_reporter.go | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) rename {util/cgroup => libpf}/cgroupv2.go (86%) diff --git a/util/cgroup/cgroupv2.go b/libpf/cgroupv2.go similarity index 86% rename from util/cgroup/cgroupv2.go rename to libpf/cgroupv2.go index 5026ec87..aa5d952f 100644 --- a/util/cgroup/cgroupv2.go +++ b/libpf/cgroupv2.go @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package cgroup // import "go.opentelemetry.io/ebpf-profiler/util/cgroup" +package libpf // import "go.opentelemetry.io/ebpf-profiler/libpf" import ( "bufio" @@ -11,7 +11,6 @@ import ( lru "github.com/elastic/go-freelru" log "github.com/sirupsen/logrus" - "go.opentelemetry.io/ebpf-profiler/libpf" ) var ( @@ -19,7 +18,7 @@ var ( ) // LookupCgroupv2 returns the cgroupv2 ID for pid. -func LookupCgroupv2(cgrouplru *lru.SyncedLRU[libpf.PID, string], pid libpf.PID) (string, error) { +func LookupCgroupv2(cgrouplru *lru.SyncedLRU[PID, string], pid PID) (string, error) { id, ok := cgrouplru.Get(pid) if ok { return id, nil diff --git a/reporter/otlp_reporter.go b/reporter/otlp_reporter.go index 57f01658..ec92eca7 100644 --- a/reporter/otlp_reporter.go +++ b/reporter/otlp_reporter.go @@ -27,7 +27,6 @@ import ( "go.opentelemetry.io/ebpf-profiler/libpf" "go.opentelemetry.io/ebpf-profiler/libpf/xsync" - "go.opentelemetry.io/ebpf-profiler/util/cgroup" ) // Assert that we implement the full Reporter interface. @@ -209,7 +208,7 @@ func (r *OTLPReporter) ReportTraceEvent(trace *libpf.Trace, meta *TraceEventMeta traceEventsMap := r.traceEvents.WLock() defer r.traceEvents.WUnlock(&traceEventsMap) - containerID, err := cgroup.LookupCgroupv2(r.cgroupv2ID, meta.PID) + containerID, err := libpf.LookupCgroupv2(r.cgroupv2ID, meta.PID) if err != nil { log.Debugf("Failed to get a cgroupv2 ID as container ID for PID %d: %v", meta.PID, err)