mirror of
https://github.com/weaveworks/scope.git
synced 2026-02-24 14:54:26 +00:00
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.
94 lines
1.8 KiB
Go
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
|
|
}
|