From dd45a99abf0d24151117412afc8a3c0464e58019 Mon Sep 17 00:00:00 2001 From: alexandreh2ag Date: Mon, 6 May 2024 14:17:30 +0200 Subject: [PATCH] Add cwd template variable Signed-off-by: alexandreh2ag --- README.md | 1 + common.go | 1 + config/config.go | 2 ++ config/config_test.go | 14 +++++++++++++- fixtures/14804/cwd | 1 + proc/base_test.go | 2 +- proc/read.go | 26 ++++++++++++++++++++++++++ proc/read_test.go | 1 + proc/tracker.go | 1 + 9 files changed, 47 insertions(+), 2 deletions(-) create mode 120000 fixtures/14804/cwd diff --git a/README.md b/README.md index 7be56369..1a8f87ec 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,7 @@ Template variables available: - `{{.Cgroups}}` contains (if supported) the cgroups of the process (`/proc/self/cgroup`). This is particularly useful for identifying to which container a process belongs. +- `{{.Cwd}}` contains the current working directory of the process (`/proc/self/cwd`). Using `PID` or `StartTime` is discouraged: this is almost never what you want, and is likely to result in high cardinality metrics which Prometheus will have diff --git a/common.go b/common.go index eca19f6a..477dea9b 100644 --- a/common.go +++ b/common.go @@ -11,6 +11,7 @@ type ( Cmdline []string Cgroups []string Username string + Cwd string PID int StartTime time.Time } diff --git a/config/config.go b/config/config.go index ebb23a5c..6901a649 100644 --- a/config/config.go +++ b/config/config.go @@ -55,6 +55,7 @@ type ( ExeBase string ExeFull string Username string + Cwd string PID int StartTime time.Time Matches map[string]string @@ -124,6 +125,7 @@ func (m *matchNamer) MatchAndName(nacl common.ProcAttributes) (bool, string) { Username: nacl.Username, PID: nacl.PID, StartTime: nacl.StartTime, + Cwd: nacl.Cwd, }) return true, buf.String() } diff --git a/config/config_test.go b/config/config_test.go index 138538c8..3c26bd31 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -64,10 +64,13 @@ process_names: - comm: - cat name: "{{.StartTime}}" + - comm: + - echo + name: "{{.Cwd}}" ` cfg, err := GetConfig(yml, false) c.Assert(err, IsNil) - c.Check(cfg.MatchNamers.matchers, HasLen, 3) + c.Check(cfg.MatchNamers.matchers, HasLen, 4) postgres := common.ProcAttributes{Name: "postmaster", Cmdline: []string{"/usr/bin/postmaster", "-D", "/data/pg"}} found, name := cfg.MatchNamers.matchers[0].MatchAndName(postgres) @@ -92,4 +95,13 @@ process_names: found, name = cfg.MatchNamers.matchers[2].MatchAndName(cat) c.Check(found, Equals, true) c.Check(name, Equals, now.String()) + + echo := common.ProcAttributes{ + Name: "echo", + Cmdline: []string{"/bin/echo"}, + Cwd: "/", + } + found, name = cfg.MatchNamers.matchers[3].MatchAndName(echo) + c.Check(found, Equals, true) + c.Check(name, Equals, "/") } diff --git a/fixtures/14804/cwd b/fixtures/14804/cwd new file mode 120000 index 00000000..cad23091 --- /dev/null +++ b/fixtures/14804/cwd @@ -0,0 +1 @@ +/tmp \ No newline at end of file diff --git a/proc/base_test.go b/proc/base_test.go index 7302165f..a66f12ca 100644 --- a/proc/base_test.go +++ b/proc/base_test.go @@ -67,7 +67,7 @@ func (n namer) MatchAndName(nacl common.ProcAttributes) (bool, string) { func newProcIDStatic(pid, ppid int, startTime uint64, name string, cmdline []string) (ID, Static) { return ID{pid, startTime}, - Static{name, cmdline, []string{}, ppid, time.Unix(int64(startTime), 0).UTC(), 1000} + Static{name, cmdline, []string{}, "/", ppid, time.Unix(int64(startTime), 0).UTC(), 1000} } func newProc(pid int, name string, m Metrics) IDInfo { diff --git a/proc/read.go b/proc/read.go index 7358aa1b..1406e746 100644 --- a/proc/read.go +++ b/proc/read.go @@ -1,7 +1,9 @@ package proc import ( + "errors" "fmt" + "io/fs" "os" "path/filepath" "strconv" @@ -31,6 +33,7 @@ type ( Name string Cmdline []string Cgroups []string + Cwd string ParentPid int StartTime time.Time EffectiveUID int @@ -137,6 +140,7 @@ type ( status *procfs.ProcStatus cmdline []string cgroups []procfs.Cgroup + cwd string io *procfs.ProcIO fs *FS wchan *string @@ -313,6 +317,21 @@ func (p *proccache) getCgroups() ([]procfs.Cgroup, error) { return p.cgroups, nil } +func (p *proccache) getCwd() (string, error) { + if p.cwd == "" { + cwd, err := p.Cwd() + + if err != nil && errors.Is(err, fs.ErrPermission) { + cwd = "-" + } else if err != nil { + return "", err + } + p.cwd = cwd + } + + return p.cwd, nil +} + // GetProcID implements Proc. func (p *proccache) GetProcID() (ID, error) { if p.procid == nil { @@ -394,10 +413,17 @@ func (p *proccache) GetStatic() (Static, error) { } } + // /proc//cwd is normally world-readable. + cwd, err := p.getCwd() + if err != nil { + return Static{}, err + } + return Static{ Name: stat.Comm, Cmdline: cmdline, Cgroups: cgroupsStr, + Cwd: cwd, ParentPid: stat.PPID, StartTime: startTime, EffectiveUID: int(status.UIDs[1]), diff --git a/proc/read_test.go b/proc/read_test.go index bddda5df..198fad4e 100644 --- a/proc/read_test.go +++ b/proc/read_test.go @@ -64,6 +64,7 @@ func TestReadFixture(t *testing.T) { Name: "process-exporte", Cmdline: []string{"./process-exporter", "-procnames", "bash"}, Cgroups: []string{"/system.slice/docker-8dde0b0d6e919baef8d635cd9399b22639ed1e400eaec1b1cb94ff3b216cf3c3.scope"}, + Cwd: "/tmp", ParentPid: 10884, StartTime: stime, EffectiveUID: 1000, diff --git a/proc/tracker.go b/proc/tracker.go index e09e6158..fc86bf9b 100644 --- a/proc/tracker.go +++ b/proc/tracker.go @@ -432,6 +432,7 @@ func (t *Tracker) Update(iter Iter) (CollectErrors, []Update, error) { Cmdline: idinfo.Cmdline, Cgroups: idinfo.Cgroups, Username: t.lookupUid(idinfo.EffectiveUID), + Cwd: idinfo.Cwd, PID: idinfo.Pid, StartTime: idinfo.StartTime, }