-
Notifications
You must be signed in to change notification settings - Fork 399
ProcessManager: Extract containerID with the rest of process metadata #577
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
49426af
7d0c039
aa21cdb
877544e
daa9dc6
55426a6
7d42302
3b0a7a2
4535523
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,13 +4,24 @@ | |||||||||||||
| package processmanager // import "go.opentelemetry.io/ebpf-profiler/processmanager" | ||||||||||||||
|
|
||||||||||||||
| import ( | ||||||||||||||
| "bufio" | ||||||||||||||
| "fmt" | ||||||||||||||
| "io" | ||||||||||||||
| "os" | ||||||||||||||
| "regexp" | ||||||||||||||
|
|
||||||||||||||
| lru "github.com/elastic/go-freelru" | ||||||||||||||
| log "github.com/sirupsen/logrus" | ||||||||||||||
|
|
||||||||||||||
| "go.opentelemetry.io/ebpf-profiler/host" | ||||||||||||||
| "go.opentelemetry.io/ebpf-profiler/libpf" | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| //nolint:lll | ||||||||||||||
| var ( | ||||||||||||||
| cgroupv2ContainerIDPattern = regexp.MustCompile(`0:.*?:.*?([0-9a-fA-F]{64})(?:\.scope)?(?:/[a-z]+)?$`) | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| type lruFileIDMapper struct { | ||||||||||||||
| cache *lru.SyncedLRU[host.FileID, libpf.FileID] | ||||||||||||||
| } | ||||||||||||||
|
|
@@ -79,3 +90,36 @@ type FileIDMapper interface { | |||||||||||||
| // Set adds a mapping from the 64-bit file ID to the 128-bit file ID. | ||||||||||||||
| Set(pre host.FileID, post libpf.FileID) | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| func parseContainerID(cgroupFile io.Reader) string { | ||||||||||||||
| scanner := bufio.NewScanner(cgroupFile) | ||||||||||||||
| 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/<PID>/cgroup to be longer than that. | ||||||||||||||
| scanner.Buffer(buf, 8192) | ||||||||||||||
| var pathParts []string | ||||||||||||||
| for scanner.Scan() { | ||||||||||||||
| line := scanner.Text() | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Skip regex processing and heap allocations for the very common case of "0::/".
Suggested change
|
||||||||||||||
| pathParts = cgroupv2ContainerIDPattern.FindStringSubmatch(line) | ||||||||||||||
| if pathParts == nil { | ||||||||||||||
| log.Debugf("Could not extract cgroupv2 path from line: %s", line) | ||||||||||||||
| continue | ||||||||||||||
| } | ||||||||||||||
| return pathParts[1] | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| // No containerID could be extracted | ||||||||||||||
| return "" | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| // extractContainerID returns the containerID for pid if cgroup v2 is used. | ||||||||||||||
| func extractContainerID(pid libpf.PID) (string, error) { | ||||||||||||||
| cgroupFile, err := os.Open(fmt.Sprintf("/proc/%d/cgroup", pid)) | ||||||||||||||
| if err != nil { | ||||||||||||||
| return "", err | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| return parseContainerID(cgroupFile), nil | ||||||||||||||
| } | ||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,56 @@ | ||||||
| // Copyright The OpenTelemetry Authors | ||||||
| // SPDX-License-Identifier: Apache-2.0 | ||||||
|
|
||||||
| package processmanager // import "go.opentelemetry.io/ebpf-profiler/processmanager" | ||||||
|
|
||||||
| import ( | ||||||
| "bytes" | ||||||
| "testing" | ||||||
|
|
||||||
| "github.com/stretchr/testify/assert" | ||||||
| ) | ||||||
|
|
||||||
| //nolint:lll | ||||||
| func TestExtractContainerID(t *testing.T) { | ||||||
| tests := []struct { | ||||||
| line string | ||||||
| expectedContainerID string | ||||||
| }{ | ||||||
| { | ||||||
| line: "0::/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podf6f2d169_f2ae_4afa-95ed_06ff2ed6b288.slice/cri-containerd-b4d6d161c62525d726fa394b27df30e14f8ea5646313ada576b390de70cfc8cc.scope", | ||||||
| expectedContainerID: "b4d6d161c62525d726fa394b27df30e14f8ea5646313ada576b390de70cfc8cc", | ||||||
| }, | ||||||
| { | ||||||
| line: "0::/kubepods/besteffort/pod05e102bf-8744-4942-a241-9b6f07983a53/f52a212505a606972cf8614c3cb856539e71b77ecae33436c5ac442232fbacf8", | ||||||
| expectedContainerID: "f52a212505a606972cf8614c3cb856539e71b77ecae33436c5ac442232fbacf8", | ||||||
| }, | ||||||
| { | ||||||
| line: "0::/kubepods/besteffort/pod897277d4-5e6f-4999-a976-b8340e8d075e/crio-a4d6b686848a610472a2eed3ae20d4d64b6b4819feb9fdfc7fd7854deaf59ef3", | ||||||
| expectedContainerID: "a4d6b686848a610472a2eed3ae20d4d64b6b4819feb9fdfc7fd7854deaf59ef3", | ||||||
| }, | ||||||
| { | ||||||
| line: "0::/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod4c9f1974_5c46_44c2_b42f_3bbf0e98eef9.slice/cri-containerd-bacb920470900725e0aa7d914fee5eb0854315448b024b6b8420ad8429c607ba.scope", | ||||||
| expectedContainerID: "bacb920470900725e0aa7d914fee5eb0854315448b024b6b8420ad8429c607ba", | ||||||
| }, | ||||||
| { | ||||||
| line: "0::/user.slice/user-1000.slice/user@1000.service/app.slice/app-org.gnome.Terminal.slice/vte-spawn-868f9513-eee8-457d-8e36-1b37ae8ae622.scope", | ||||||
| }, | ||||||
| { | ||||||
| line: "0::/../../user.slice/user-501.slice/session-3.scope", | ||||||
| }, | ||||||
| { | ||||||
| line: "0::/system.slice/docker-b1eba9dfaeba29d8b80532a574a03ea3cac29384327f339c26da13649e2120df.scope/init", | ||||||
| expectedContainerID: "b1eba9dfaeba29d8b80532a574a03ea3cac29384327f339c26da13649e2120df", | ||||||
| }, | ||||||
| } | ||||||
|
|
||||||
| for _, tc := range tests { | ||||||
| tc := tc | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| t.Run(tc.expectedContainerID, func(t *testing.T) { | ||||||
| reader := bytes.NewReader([]byte(tc.line)) | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| gotContainerID := parseContainerID(reader) | ||||||
| assert.Equal(t, tc.expectedContainerID, gotContainerID) | ||||||
| }) | ||||||
| } | ||||||
| } | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the tests only contain cgroupV2 strings, should we document this function to support cgroupV2 only? Otherwise, we should add cgroupV1 test cases.
IMO, we don't need to support for v1.