2022-06-28 18:14:59 +02:00
|
|
|
// Copyright 2022 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package cmd
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"sort"
|
|
|
|
"strconv"
|
|
|
|
|
|
|
|
"github.com/google/gops/goprocess"
|
2022-06-28 18:18:41 +02:00
|
|
|
"github.com/spf13/cobra"
|
2022-06-28 18:14:59 +02:00
|
|
|
"github.com/xlab/treeprint"
|
|
|
|
)
|
|
|
|
|
2022-06-28 18:18:41 +02:00
|
|
|
// TreeCommand displays a process tree.
|
|
|
|
func TreeCommand() *cobra.Command {
|
|
|
|
return &cobra.Command{
|
|
|
|
Use: "tree",
|
|
|
|
Short: "Display parent-child tree for Go processes.",
|
|
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
|
|
displayProcessTree()
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-28 18:14:59 +02:00
|
|
|
// displayProcessTree displays a tree of all the running Go processes.
|
|
|
|
func displayProcessTree() {
|
|
|
|
ps := goprocess.FindAll()
|
|
|
|
sort.Slice(ps, func(i, j int) bool {
|
|
|
|
return ps[i].PPID < ps[j].PPID
|
|
|
|
})
|
|
|
|
pstree := make(map[int][]goprocess.P, len(ps))
|
|
|
|
for _, p := range ps {
|
|
|
|
pstree[p.PPID] = append(pstree[p.PPID], p)
|
|
|
|
}
|
|
|
|
tree := treeprint.New()
|
|
|
|
tree.SetValue("...")
|
|
|
|
seen := map[int]bool{}
|
|
|
|
for _, p := range ps {
|
|
|
|
constructProcessTree(p.PPID, p, pstree, seen, tree)
|
|
|
|
}
|
|
|
|
fmt.Println(tree.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
// constructProcessTree constructs the process tree in a depth-first fashion.
|
|
|
|
func constructProcessTree(ppid int, process goprocess.P, pstree map[int][]goprocess.P, seen map[int]bool, tree treeprint.Tree) {
|
|
|
|
|
|
|
|
if seen[ppid] {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
seen[ppid] = true
|
|
|
|
if ppid != process.PPID {
|
|
|
|
output := strconv.Itoa(ppid) + " (" + process.Exec + ")" + " {" + process.BuildVersion + "}"
|
|
|
|
if process.Agent {
|
|
|
|
tree = tree.AddMetaBranch("*", output)
|
|
|
|
} else {
|
|
|
|
tree = tree.AddBranch(output)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
tree = tree.AddBranch(ppid)
|
|
|
|
}
|
|
|
|
for index := range pstree[ppid] {
|
|
|
|
process := pstree[ppid][index]
|
|
|
|
constructProcessTree(process.PID, process, pstree, seen, tree)
|
|
|
|
}
|
|
|
|
}
|