Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Extend process metadata; add command line.
Browse files Browse the repository at this point in the history
Tom Wilkie committed Jun 22, 2015

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent ee14eb3 commit 574379f
Showing 7 changed files with 93 additions and 72 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@ $(SCOPE_EXPORT): $(APP_EXE) $(PROBE_EXE) docker/*

$(APP_EXE): app/*.go render/*.go report/*.go xfer/*.go

$(PROBE_EXE): probe/*.go probe/tag/*.go probe/docker/*.go report/*.go xfer/*.go
$(PROBE_EXE): probe/*.go probe/tag/*.go probe/docker/*.go probe/process/*.go report/*.go xfer/*.go

$(APP_EXE) $(PROBE_EXE):
go get -tags netgo ./$(@D)
12 changes: 7 additions & 5 deletions probe/process/reporter.go
Original file line number Diff line number Diff line change
@@ -8,9 +8,10 @@ import (

// We use these keys in node metadata
const (
PID = "pid"
Comm = "comm"
PPID = "ppid"
PID = "pid"
Comm = "comm"
PPID = "ppid"
Cmdline = "cmdline"
)

// Reporter generate Reports containing the Process topology
@@ -44,8 +45,9 @@ func (r *Reporter) processTopology() (report.Topology, error) {
pidstr := strconv.Itoa(p.PID)
nodeID := report.MakeProcessNodeID(r.scope, pidstr)
t.NodeMetadatas[nodeID] = report.NodeMetadata{
PID: pidstr,
Comm: p.Comm,
PID: pidstr,
Comm: p.Comm,
Cmdline: p.Cmdline,
}
if p.PPID > 0 {
t.NodeMetadatas[nodeID][PPID] = strconv.Itoa(p.PPID)
28 changes: 16 additions & 12 deletions probe/process/reporter_test.go
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ func TestReporter(t *testing.T) {
{PID: 1, PPID: 0, Comm: "init"},
{PID: 2, PPID: 1, Comm: "bash"},
{PID: 3, PPID: 1, Comm: "apache"},
{PID: 4, PPID: 2, Comm: "ping"},
{PID: 4, PPID: 2, Comm: "ping", Cmdline: "ping foo.bar.local"},
} {
f(p)
}
@@ -32,23 +32,27 @@ func TestReporter(t *testing.T) {
EdgeMetadatas: report.EdgeMetadatas{},
NodeMetadatas: report.NodeMetadatas{
report.MakeProcessNodeID("", "1"): report.NodeMetadata{
process.PID: "1",
process.Comm: "init",
process.PID: "1",
process.Comm: "init",
process.Cmdline: "",
},
report.MakeProcessNodeID("", "2"): report.NodeMetadata{
process.PID: "2",
process.Comm: "bash",
process.PPID: "1",
process.PID: "2",
process.Comm: "bash",
process.PPID: "1",
process.Cmdline: "",
},
report.MakeProcessNodeID("", "3"): report.NodeMetadata{
process.PID: "3",
process.Comm: "apache",
process.PPID: "1",
process.PID: "3",
process.Comm: "apache",
process.PPID: "1",
process.Cmdline: "",
},
report.MakeProcessNodeID("", "4"): report.NodeMetadata{
process.PID: "4",
process.Comm: "ping",
process.PPID: "2",
process.PID: "4",
process.Comm: "ping",
process.PPID: "2",
process.Cmdline: "ping foo.bar.local",
},
},
}
16 changes: 1 addition & 15 deletions probe/process/tree.go
Original file line number Diff line number Diff line change
@@ -20,21 +20,7 @@ func NewTree(procRoot string) (Tree, error) {
pt.processes[p.PID] = p
})

if err != nil {
return nil, err
}

for _, child := range pt.processes {
parent, ok := pt.processes[child.PPID]
if !ok {
// This can happen as listing proc is not a consistent snapshot
continue
}
child.parent = parent
parent.children = append(parent.children, child)
}

return &pt, nil
return &pt, err
}

// GetParent returns the pid of the parent process for a given pid
17 changes: 12 additions & 5 deletions probe/process/walker.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package process

import (
"bytes"
"io/ioutil"
"path"
"strconv"
@@ -11,8 +12,7 @@ import (
type Process struct {
PID, PPID int
Comm string
parent *Process
children []*Process
Cmdline string
}

// Hooks exposed for mocking
@@ -45,15 +45,22 @@ var Walk = func(procRoot string, f func(*Process)) error {
return err
}

cmdline := ""
if cmdlineBuf, err := ReadFile(path.Join(procRoot, filename, "cmdline")); err == nil {
cmdlineBuf = bytes.Replace(cmdlineBuf, []byte{'\000'}, []byte{' '}, -1)
cmdline = string(cmdlineBuf)
}

comm := "(unknown)"
if commBuf, err := ReadFile(path.Join(procRoot, filename, "comm")); err == nil {
comm = string(commBuf)
}

f(&Process{
PID: pid,
PPID: ppid,
Comm: comm,
PID: pid,
PPID: ppid,
Comm: comm,
Cmdline: cmdline,
})
}

71 changes: 45 additions & 26 deletions probe/process/walker_test.go
Original file line number Diff line number Diff line change
@@ -13,16 +13,17 @@ import (
"github.com/weaveworks/scope/test"
)

type fileinfo struct {
name string
type mockProcess struct {
name string
cmdline string
}

func (f fileinfo) Name() string { return f.name }
func (f fileinfo) Size() int64 { return 0 }
func (f fileinfo) Mode() os.FileMode { return 0 }
func (f fileinfo) ModTime() time.Time { return time.Now() }
func (f fileinfo) IsDir() bool { return true }
func (f fileinfo) Sys() interface{} { return nil }
func (p mockProcess) Name() string { return p.name }
func (p mockProcess) Size() int64 { return 0 }
func (p mockProcess) Mode() os.FileMode { return 0 }
func (p mockProcess) ModTime() time.Time { return time.Now() }
func (p mockProcess) IsDir() bool { return true }
func (p mockProcess) Sys() interface{} { return nil }

func TestWalker(t *testing.T) {
oldReadDir, oldReadFile := process.ReadDir, process.ReadFile
@@ -31,36 +32,54 @@ func TestWalker(t *testing.T) {
process.ReadFile = oldReadFile
}()

processes := map[string]mockProcess{
"3": {name: "3", cmdline: "curl"},
"2": {name: "2"},
"4": {name: "4"},
"notapid": {name: "notapid"},
"1": {name: "1"},
}

process.ReadDir = func(path string) ([]os.FileInfo, error) {
return []os.FileInfo{
fileinfo{"3"}, fileinfo{"2"}, fileinfo{"4"},
fileinfo{"notapid"}, fileinfo{"1"},
}, nil
result := []os.FileInfo{}
for _, p := range processes {
result = append(result, p)
}
return result, nil
}

process.ReadFile = func(path string) ([]byte, error) {
splits := strings.Split(path, "/")
if splits[len(splits)-1] != "stat" {
return nil, fmt.Errorf("not stat")

pid := splits[len(splits)-2]
process, ok := processes[pid]
if !ok {
return nil, fmt.Errorf("not found")
}
pid, err := strconv.Atoi(splits[len(splits)-2])
if err != nil {
return nil, err

file := splits[len(splits)-1]
switch file {
case "stat":
pid, _ := strconv.Atoi(splits[len(splits)-2])
parent := pid - 1
return []byte(fmt.Sprintf("%d na R %d", pid, parent)), nil
case "cmdline":
return []byte(process.cmdline), nil
}
parent := pid - 1
return []byte(fmt.Sprintf("%d na R %d", pid, parent)), nil

return nil, fmt.Errorf("not found")
}

want := []*process.Process{
{PID: 3, PPID: 2, Comm: "(unknown)"},
{PID: 2, PPID: 1, Comm: "(unknown)"},
{PID: 4, PPID: 3, Comm: "(unknown)"},
{PID: 1, PPID: 0, Comm: "(unknown)"},
want := map[int]*process.Process{
3: {PID: 3, PPID: 2, Comm: "(unknown)", Cmdline: "curl"},
2: {PID: 2, PPID: 1, Comm: "(unknown)", Cmdline: ""},
4: {PID: 4, PPID: 3, Comm: "(unknown)", Cmdline: ""},
1: {PID: 1, PPID: 0, Comm: "(unknown)", Cmdline: ""},
}

have := []*process.Process{}
have := map[int]*process.Process{}
err := process.Walk("unused", func(p *process.Process) {
have = append(have, p)
have[p.PID] = p
})

if err != nil || !reflect.DeepEqual(want, have) {
19 changes: 11 additions & 8 deletions render/detailed_node.go
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ import (
"strconv"

"github.com/weaveworks/scope/probe/docker"
"github.com/weaveworks/scope/probe/process"
"github.com/weaveworks/scope/report"
)

@@ -139,15 +140,17 @@ func addressOriginTable(nmd report.NodeMetadata) (Table, bool) {

func processOriginTable(nmd report.NodeMetadata) (Table, bool) {
rows := []Row{}
if val, ok := nmd["comm"]; ok {
rows = append(rows, Row{"Name (comm)", val, ""})
}
if val, ok := nmd["pid"]; ok {
rows = append(rows, Row{"PID", val, ""})
}
if val, ok := nmd["ppid"]; ok {
rows = append(rows, Row{"Parent PID", val, ""})
for _, tuple := range []struct{ key, human string }{
{process.Comm, "Name (comm)"},
{process.PID, "PID"},
{process.PPID, "Parent PID"},
{process.Cmdline, "Command"},
} {
if val, ok := nmd[tuple.key]; ok {
rows = append(rows, Row{Key: tuple.human, ValueMajor: val, ValueMinor: ""})
}
}

return Table{
Title: "Origin Process",
Numeric: false,

0 comments on commit 574379f

Please sign in to comment.