Files
weave-scope/probe/process/walker_darwin.go
Peter Bourgon b585a362ac Naïve process walker for Darwin
This fixes the regression where process names weren't appearing for
Darwin probes. Makes testing easier.

Also, changes the process walker to operate on value types. There's no
performance advantage to using reference types for something of this
size, and there appeared to be a data race in the Darwin port that
caused nodes to gain and lose process names over time.

Also, restructures how to enable docker scraping. Default false when run
manually, and enabled via --probe.docker true in the scope script.
2015-07-16 12:33:59 +02:00

94 lines
1.8 KiB
Go

package process
import (
"fmt"
"os/exec"
"strconv"
"strings"
)
// NewWalker returns a Darwin (lsof-based) walker.
func NewWalker(_ string) Walker {
return &walker{}
}
type walker struct{}
const (
lsofBinary = "lsof"
lsofFields = "cn" // parseLSOF() depends on the order
)
// These functions copied from procspy.
func (walker) Walk(f func(Process)) error {
output, err := exec.Command(
lsofBinary,
"-i", // only Internet files
"-n", "-P", // no number resolving
"-w", // no warnings
"-F", lsofFields, // \n based output of only the fields we want.
).CombinedOutput()
if err != nil {
return err
}
processes, err := parseLSOF(string(output))
if err != nil {
return err
}
for _, process := range processes {
f(process)
}
return nil
}
func parseLSOF(output string) (map[string]Process, error) {
var (
processes = map[string]Process{} // Local addr -> Proc
process Process
)
for _, line := range strings.Split(output, "\n") {
if len(line) <= 1 {
continue
}
var (
field = line[0]
value = line[1:]
)
switch field {
case 'p':
pid, err := strconv.Atoi(value)
if err != nil {
return nil, fmt.Errorf("invalid 'p' field in lsof output: %#v", value)
}
process.PID = pid
case 'c':
process.Comm = value
case 'n':
// 'n' is the last field, with '-F cn'
// format examples:
// "192.168.2.111:44013->54.229.241.196:80"
// "[2003:45:2b57:8900:1869:2947:f942:aba7]:55711->[2a00:1450:4008:c01::11]:443"
// "*:111" <- a listen
addresses := strings.SplitN(value, "->", 2)
if len(addresses) != 2 {
// That's a listen entry.
continue
}
processes[addresses[0]] = Process{
PID: process.PID,
Comm: process.Comm,
}
default:
return nil, fmt.Errorf("unexpected lsof field: %c in %#v", field, value)
}
}
return processes, nil
}