Skip to content
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

discovery.process and pyroscope.java #5858

Merged
merged 81 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from 51 commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
d2f8d79
fix
korniltsev Nov 27, 2023
c760564
process discovery draft
korniltsev Nov 27, 2023
6ecfc15
fix test
korniltsev Nov 27, 2023
79a397d
tmp
korniltsev Dec 13, 2023
a33542d
loop seem work
korniltsev Dec 14, 2023
9b2f532
fix
korniltsev Dec 15, 2023
bbd6b7a
use shirou/gopsutil
korniltsev Jan 3, 2024
16fd32f
Merge branch 'discovery_process' into pyroscope-java
korniltsev Jan 3, 2024
9faeb23
add darwin
korniltsev Jan 4, 2024
eee5677
add proper extraction
korniltsev Jan 4, 2024
3cd66ad
java loop fixes
korniltsev Jan 5, 2024
4423b73
fix
korniltsev Jan 5, 2024
2e5ad13
fix
korniltsev Jan 5, 2024
ce7ab63
fixes
korniltsev Jan 5, 2024
0857f45
lbic detection fix
korniltsev Jan 5, 2024
0ea88fb
use jfr-parser lib
korniltsev Jan 8, 2024
2b05b04
handle marshall error
korniltsev Jan 8, 2024
8d0b6eb
fix jfr parsing for asprof 3.0
korniltsev Jan 8, 2024
b11aaf3
rm darwin, use 2.9 instead of 3.0-ea
korniltsev Jan 8, 2024
57f7fcb
switch back to 3.0 ea
korniltsev Jan 9, 2024
59b86f7
fix process alive check
korniltsev Jan 9, 2024
6a91e26
tmp dir arg
korniltsev Jan 9, 2024
d9a5ab8
discover config
korniltsev Jan 9, 2024
074acc1
improve logging
korniltsev Jan 9, 2024
3c5e922
improve logging
korniltsev Jan 9, 2024
2df98d5
fix shutdodown
korniltsev Jan 9, 2024
da58272
improve extract
korniltsev Jan 9, 2024
80c719a
stub
korniltsev Jan 9, 2024
a76ab8c
fix bug
korniltsev Jan 9, 2024
5245429
Merge remote-tracking branch 'origin/main' into discovery_process
korniltsev Jan 9, 2024
1dc6796
fix arm64
korniltsev Jan 9, 2024
7d8b1b5
fix stub
korniltsev Jan 9, 2024
21ff759
fix bild
korniltsev Jan 9, 2024
33cfdf4
fixbuild
korniltsev Jan 9, 2024
ed6a795
fix lib copying
korniltsev Jan 10, 2024
8cd3ca3
Update component/discovery/process/discover.go
korniltsev Jan 11, 2024
2fe0aba
Update component/pyroscope/java/java_stub.go
korniltsev Jan 11, 2024
60d96cd
Update component/pyroscope/java/loop.go
korniltsev Jan 11, 2024
cba6d8e
Update component/pyroscope/java/asprof/asprof_test.go
korniltsev Jan 11, 2024
0e369dc
review fixes
korniltsev Jan 11, 2024
d7a0054
handle discoverConfig and refreshinterval updates in discover.process…
korniltsev Jan 11, 2024
021ea45
add discovery.process.md
korniltsev Jan 11, 2024
28ab763
doc notes
korniltsev Jan 11, 2024
09869e6
cleanup
korniltsev Jan 11, 2024
80e430e
add pyroscope.java.md
korniltsev Jan 11, 2024
09f58c1
go gen
korniltsev Jan 11, 2024
67e5dd5
Merge remote-tracking branch 'origin/main' into discovery_process
korniltsev Jan 11, 2024
026ae31
fix windows build
korniltsev Jan 11, 2024
d1823b7
Update component/pyroscope/java/loop.go
korniltsev Jan 11, 2024
46a4748
Update component/discovery/process/process.go
korniltsev Jan 11, 2024
36e567b
rm incomplete tests
korniltsev Jan 11, 2024
ea65839
update loop target and profiling config
korniltsev Jan 11, 2024
0cfb9d2
link to async-profiler
korniltsev Jan 11, 2024
1a2b02a
more docs
korniltsev Jan 11, 2024
cdeb7e7
fix
korniltsev Jan 11, 2024
682b352
lint
korniltsev Jan 11, 2024
1ba2c8f
fix stub build
korniltsev Jan 11, 2024
283c341
lint
korniltsev Jan 11, 2024
ddaa3aa
restart
korniltsev Jan 11, 2024
8b66b30
fix
korniltsev Jan 11, 2024
a0dfedf
fix
korniltsev Jan 11, 2024
e312379
fix
korniltsev Jan 11, 2024
300ce7f
Update docs/sources/flow/reference/components/discovery.process.md
korniltsev Jan 12, 2024
e888cd4
Update docs/sources/flow/reference/components/discovery.process.md
korniltsev Jan 12, 2024
68dcf16
Update docs/sources/flow/reference/components/discovery.process.md
korniltsev Jan 12, 2024
5de7ed1
Update docs/sources/flow/reference/components/discovery.process.md
korniltsev Jan 12, 2024
9df7b7c
Update docs/sources/flow/reference/components/discovery.process.md
korniltsev Jan 12, 2024
e215947
Update docs/sources/flow/reference/components/pyroscope.java.md
korniltsev Jan 12, 2024
08c5f45
Update docs/sources/flow/reference/components/pyroscope.java.md
korniltsev Jan 12, 2024
e53b0dc
Update docs/sources/flow/reference/components/pyroscope.java.md
korniltsev Jan 12, 2024
4835d23
Update docs/sources/flow/reference/components/pyroscope.java.md
korniltsev Jan 12, 2024
d022e85
Update docs/sources/flow/reference/components/discovery.process.md
korniltsev Jan 12, 2024
166a42c
Update docs/sources/flow/reference/components/pyroscope.java.md
korniltsev Jan 12, 2024
17764d3
Update docs/sources/flow/reference/components/pyroscope.java.md
korniltsev Jan 12, 2024
2186950
Update docs/sources/flow/reference/components/pyroscope.java.md
korniltsev Jan 12, 2024
fedd6dc
Update docs/sources/flow/reference/components/pyroscope.java.md
korniltsev Jan 12, 2024
c18dae0
Apply suggestions from code review
korniltsev Jan 12, 2024
2c4b03b
Merge branch 'main' into discovery_process
korniltsev Jan 12, 2024
eadcad1
Update docs/sources/flow/reference/components/pyroscope.java.md
korniltsev Jan 13, 2024
8d0def3
Update docs/sources/flow/reference/components/pyroscope.java.md
korniltsev Jan 13, 2024
887b9ed
Merge remote-tracking branch 'origin/main' into discovery_process
korniltsev Jan 16, 2024
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ Main (unreleased)
- [GO-2023-2412](https://github.com/advisories/GHSA-7ww5-4wqc-m92c)
- [CVE-2023-49568](https://github.com/advisories/GHSA-mw99-9chc-xw7r)

### Features

- A new `discovery.process` component for discovering Linux OS processes on the current host. (@korniltsev)

- A new `pyroscope.java` component for profiling Java processes using async-profiler. (@korniltsev)

### Enhancements

- Add an option to the windows static mode installer for expanding environment vars in the yaml config. (@erikbaranowski)
Expand Down
2 changes: 2 additions & 0 deletions component/all/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
_ "github.com/grafana/agent/component/discovery/nomad" // Import discovery.nomad
_ "github.com/grafana/agent/component/discovery/openstack" // Import discovery.openstack
_ "github.com/grafana/agent/component/discovery/ovhcloud" // Import discovery.ovhcloud
_ "github.com/grafana/agent/component/discovery/process" // Import discovery.process
_ "github.com/grafana/agent/component/discovery/puppetdb" // Import discovery.puppetdb
_ "github.com/grafana/agent/component/discovery/relabel" // Import discovery.relabel
_ "github.com/grafana/agent/component/discovery/scaleway" // Import discovery.scaleway
Expand Down Expand Up @@ -127,6 +128,7 @@ import (
_ "github.com/grafana/agent/component/prometheus/remotewrite" // Import prometheus.remote_write
_ "github.com/grafana/agent/component/prometheus/scrape" // Import prometheus.scrape
_ "github.com/grafana/agent/component/pyroscope/ebpf" // Import pyroscope.ebpf
_ "github.com/grafana/agent/component/pyroscope/java" // Import pyroscope.java
_ "github.com/grafana/agent/component/pyroscope/scrape" // Import pyroscope.scrape
_ "github.com/grafana/agent/component/pyroscope/write" // Import pyroscope.write
_ "github.com/grafana/agent/component/remote/http" // Import remote.http
Expand Down
37 changes: 37 additions & 0 deletions component/discovery/process/args.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package process

import (
"time"

"github.com/grafana/agent/component/discovery"
)

type Arguments struct {
Join []discovery.Target `river:"join,attr,optional"`
RefreshInterval time.Duration `river:"refresh_interval,attr,optional"`
DiscoverConfig DiscoverConfig `river:"discover_config,block,optional"`
}

type DiscoverConfig struct {
Cwd bool `river:"cwd,attr,optional"`
Exe bool `river:"exe,attr,optional"`
Commandline bool `river:"commandline,attr,optional"`
Username bool `river:"username,attr,optional"`
UID bool `river:"uid,attr,optional"`
ContainerID bool `river:"container_id,attr,optional"`
}

var DefaultConfig = Arguments{
Join: nil,
RefreshInterval: 60 * time.Second,
DiscoverConfig: DiscoverConfig{
Cwd: true,
Exe: true,
Commandline: true,
ContainerID: true,
},
}

func (args *Arguments) SetToDefault() {
*args = DefaultConfig
}
56 changes: 56 additions & 0 deletions component/discovery/process/container.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package process

import (
"bufio"
"io"
"regexp"
"strings"

"github.com/grafana/agent/component/discovery"
)

var (
// cgroupContainerIDRe matches a container ID from a /proc/{pid}}/cgroup
cgroupContainerIDRe = regexp.MustCompile(`^.*/(?:.*-)?([0-9a-f]{64})(?:\.|\s*$)`)
)

func getContainerIDFromCGroup(cgroup io.Reader) string {
scanner := bufio.NewScanner(cgroup)
for scanner.Scan() {
line := scanner.Bytes()
matches := cgroupContainerIDRe.FindSubmatch(line)
if len(matches) <= 1 {
continue
}
return string(matches[1])
}
return ""
}

var knownContainerIDPrefixes = []string{"docker://", "containerd://", "cri-o://"}

// get container id from __meta_kubernetes_pod_container_id label
func getContainerIDFromK8S(k8sContainerID string) string {
for _, p := range knownContainerIDPrefixes {
if strings.HasPrefix(k8sContainerID, p) {
return strings.TrimPrefix(k8sContainerID, p)
}
}
return ""
}

func getContainerIDFromTarget(target discovery.Target) string {
cid, ok := target[labelProcessContainerID]

Check failure on line 43 in component/discovery/process/container.go

View workflow job for this annotation

GitHub Actions / Test (macos-latest-xlarge)

undefined: labelProcessContainerID
if ok && cid != "" {
return cid
}
cid, ok = target["__meta_kubernetes_pod_container_id"]
if ok && cid != "" {
return getContainerIDFromK8S(cid)
}
cid, ok = target["__meta_docker_container_id"]
if ok && cid != "" {
return cid
}
return ""
}
64 changes: 64 additions & 0 deletions component/discovery/process/container_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package process

import (
"bytes"
"fmt"
"testing"

"github.com/stretchr/testify/require"
)

func TestCGroupMatching(t *testing.T) {
type testcase = struct {
containerID, cgroup, expectedID string
}
testcases := []testcase{
{
containerID: "containerd://a534eb629135e43beb13213976e37bb2ab95cba4c0d1d0b4e27c6bc4d8091b83",
cgroup: "12:cpuset:/kubepods.slice/kubepods-burstable.slice/" +
"kubepods-burstable-pod471203d1_984f_477e_9c35_db96487ffe5e.slice/" +
"cri-containerd-a534eb629135e43beb13213976e37bb2ab95cba4c0d1d0b4e27c6bc4d8091b83.scope",
expectedID: "a534eb629135e43beb13213976e37bb2ab95cba4c0d1d0b4e27c6bc4d8091b83",
},
{
containerID: "cri-o://0ecc7949cbaf17e883264ea1055f60b184a7cb264fd759c4a692e1155086fe2d",
cgroup: "0::/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podb57320a0_e7eb_4ac8_a791_4c4472796867.slice/" +
"crio-0ecc7949cbaf17e883264ea1055f60b184a7cb264fd759c4a692e1155086fe2d.scope",
expectedID: "0ecc7949cbaf17e883264ea1055f60b184a7cb264fd759c4a692e1155086fe2d",
},
{

containerID: "docker://656959d9ee87a0b131c601ce9d9f8f76b1dda60e8608c503b5979d849cbdc714",
cgroup: "0::/../../kubepods-besteffort-pod88f6f4e3_59c0_4ce8_9ecf_391c8b5a60ad.slice/" +
"docker-656959d9ee87a0b131c601ce9d9f8f76b1dda60e8608c503b5979d849cbdc714.scope",
expectedID: "656959d9ee87a0b131c601ce9d9f8f76b1dda60e8608c503b5979d849cbdc714",
},
{
containerID: "containerd://47e320f795efcec1ecf2001c3a09c95e3701ed87de8256837b70b10e23818251",
cgroup: "0::/kubepods.slice/kubepods-burstable.slice/" +
"kubepods-burstable-podf9a04ecc_1875_491b_926c_d2f64757704e.slice/" +
"cri-containerd-47e320f795efcec1ecf2001c3a09c95e3701ed87de8256837b70b10e23818251.scope",
expectedID: "47e320f795efcec1ecf2001c3a09c95e3701ed87de8256837b70b10e23818251",
},
{
containerID: "docker://7edda1de1e0d1d366351e478359cf5fa16bb8ab53063a99bb119e56971bfb7e2",
cgroup: "11:devices:/kubepods/besteffort/pod85adbef3-622f-4ef2-8f60-a8bdf3eb6c72/" +
"7edda1de1e0d1d366351e478359cf5fa16bb8ab53063a99bb119e56971bfb7e2",
expectedID: "7edda1de1e0d1d366351e478359cf5fa16bb8ab53063a99bb119e56971bfb7e2",
},
{
containerID: "",
cgroup: "0::/../../user.slice/user-501.slice/session-3.scope",
expectedID: "",
},
}
for i, tc := range testcases {
t.Run(fmt.Sprintf("testcase %d %s", i, tc.cgroup), func(t *testing.T) {
cid := getContainerIDFromCGroup(bytes.NewReader([]byte(tc.cgroup)))
expected := tc.expectedID
require.Equal(t, expected, cid)
cid = getContainerIDFromK8S(tc.containerID)
require.Equal(t, expected, cid)
})
}
}
169 changes: 169 additions & 0 deletions component/discovery/process/discover.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
//go:build linux

package process

import (
"errors"
"fmt"
"os"
"path"
"runtime"

"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/grafana/agent/component/discovery"
gopsutil "github.com/shirou/gopsutil/v3/process"
"golang.org/x/sys/unix"
)

const (
labelProcessID = "__process_pid__"
labelProcessExe = "__meta_process_exe"
labelProcessCwd = "__meta_process_cwd"
labelProcessCommandline = "__meta_process_commandline"
labelProcessUsername = "__meta_process_username"
labelProcessUID = "__meta_process_uid"
labelProcessContainerID = "__container_id__"
)

type process struct {
pid string
exe string
cwd string
commandline string
containerID string
username string
uid string
}

func (p process) String() string {
return fmt.Sprintf("pid=%s exe=%s cwd=%s commandline=%s containerID=%s", p.pid, p.exe, p.cwd, p.commandline, p.containerID)
}

func convertProcesses(ps []process) []discovery.Target {
var res []discovery.Target
for _, p := range ps {
t := convertProcess(p)
res = append(res, t)
}
return res
}

func convertProcess(p process) discovery.Target {
t := make(discovery.Target, 5)
t[labelProcessID] = p.pid
if p.exe != "" {
t[labelProcessExe] = p.exe
}
if p.cwd != "" {
t[labelProcessCwd] = p.cwd
}
if p.commandline != "" {
t[labelProcessCommandline] = p.commandline
}
if p.containerID != "" {
t[labelProcessContainerID] = p.containerID
}
if p.username != "" {
t[labelProcessUsername] = p.username
}
if p.uid != "" {
t[labelProcessUID] = p.uid
}
return t
}

func discover(l log.Logger, cfg *DiscoverConfig) ([]process, error) {
processes, err := gopsutil.Processes()
if err != nil {
return nil, fmt.Errorf("failed to list processes: %w", err)
}
res := make([]process, 0, len(processes))
loge := func(pid int, e error) {
if errors.Is(e, unix.ESRCH) {
return
}
if errors.Is(e, os.ErrNotExist) {
return
}
_ = level.Error(l).Log("msg", "failed to get process info", "err", e, "pid", pid)
}
for _, p := range processes {
spid := fmt.Sprintf("%d", p.Pid)
var (
exe, cwd, commandline, containerID, username, uid string
)
if cfg.Exe {
exe, err = p.Exe()
if err != nil {
loge(int(p.Pid), err)
continue
}
}
if cfg.Cwd {
cwd, err = p.Cwd()
if err != nil {
loge(int(p.Pid), err)
continue
}
}
if cfg.Commandline {
commandline, err = p.Cmdline()
if err != nil {
loge(int(p.Pid), err)
continue
}
}
if cfg.Username {
username, err = p.Username()
if err != nil {
loge(int(p.Pid), err)
continue
}
}
if cfg.UID {
uids, err := p.Uids()
if err != nil {
loge(int(p.Pid), err)
continue
}
if len(uids) > 0 {
uid = fmt.Sprintf("%d", uids[0])
}
}

if cfg.ContainerID {
containerID, err = getLinuxProcessContainerID(l, spid)
if err != nil {
loge(int(p.Pid), err)
continue
}
}
res = append(res, process{
pid: spid,
exe: exe,
cwd: cwd,
commandline: commandline,
containerID: containerID,
username: username,
uid: uid,
})
}

return res, nil
}

func getLinuxProcessContainerID(l log.Logger, pid string) (string, error) {
if runtime.GOOS == "linux" {
cgroup, err := os.Open(path.Join("/proc", pid, "cgroup"))
if err != nil {
return "", err
}
defer cgroup.Close()
cid := getContainerIDFromCGroup(cgroup)
if cid != "" {
return cid, nil
}
}
return "", nil
}
Loading
Loading