diff --git a/README.md b/README.md index 7be5636..1a8f87e 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 eca19f6..477dea9 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 ebb23a5..6901a64 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 138538c..3c26bd3 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/proc/base_test.go b/proc/base_test.go index 7302165..a66f12c 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 7358aa1..a325091 100644 --- a/proc/read.go +++ b/proc/read.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "strconv" + "strings" "time" "github.com/prometheus/procfs" @@ -31,6 +32,7 @@ type ( Name string Cmdline []string Cgroups []string + Cwd string ParentPid int StartTime time.Time EffectiveUID int @@ -137,6 +139,7 @@ type ( status *procfs.ProcStatus cmdline []string cgroups []procfs.Cgroup + cwd string io *procfs.ProcIO fs *FS wchan *string @@ -313,6 +316,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 && strings.Contains(err.Error(), "permission denied") { + 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 +412,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 bddda5d..198fad4 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 e09e615..fc86bf9 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, }