1
0
mirror of https://github.com/google/gops.git synced 2025-02-19 19:59:55 +02:00
gops/gops.go

157 lines
3.1 KiB
Go
Raw Normal View History

2016-11-03 22:43:04 -07:00
// Copyright 2016 The Go Authors. All rights reserved.
2016-11-03 16:56:19 -07:00
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Program gops is a tool to list currently running Go processes.
2016-11-03 14:01:55 -07:00
package main
import (
2016-11-03 22:32:46 -07:00
"flag"
2016-11-03 14:01:55 -07:00
"fmt"
2016-11-03 22:32:46 -07:00
"io/ioutil"
2016-11-03 14:01:55 -07:00
"log"
2016-11-03 22:32:46 -07:00
"net"
"os"
2016-11-03 14:01:55 -07:00
"github.com/google/gops/signal"
"github.com/google/gops/internal/objfile"
2016-11-03 14:01:55 -07:00
ps "github.com/keybase/go-ps"
)
2016-11-03 22:32:46 -07:00
const helpText = `Usage: gops is a tool to list and diagnose Go processes.
2016-11-03 23:05:56 -07:00
2016-11-03 22:48:44 -07:00
gops Lists all Go processes currently running.
gops [options...] See the section below.
2016-11-03 22:32:46 -07:00
2016-11-03 23:05:56 -07:00
Options:
2016-11-03 22:48:44 -07:00
-stack Prints the stack trace.
-gc Runs the garbage collector and blocks until successful.
-gcstats Prints the garbage collection stats.
2016-11-03 22:53:07 -07:00
-version Prints the Go version used to build the program.
2016-11-03 23:05:56 -07:00
All options require the agent and the -p=<pid> flag.
2016-11-03 22:32:46 -07:00
`
2016-11-03 23:05:56 -07:00
// TODO(jbd): add link that explains the use of agent.
2016-11-03 22:32:46 -07:00
var (
2016-11-03 23:28:51 -07:00
pid = flag.Int("p", -1, "")
stack = flag.Bool("stack", false, "")
gc = flag.Bool("gc", false, "")
memstats = flag.Bool("memstats", false, "")
version = flag.Bool("version", false, "")
help = flag.Bool("help", false, "")
2016-11-03 22:32:46 -07:00
)
2016-11-03 14:01:55 -07:00
func main() {
2016-11-03 22:32:46 -07:00
flag.Usage = usage
flag.Parse()
if len(os.Args) < 2 {
2016-11-03 23:01:30 -07:00
goProcesses()
2016-11-03 22:32:46 -07:00
return
}
2016-11-03 23:01:30 -07:00
if *pid == -1 || *help {
2016-11-03 22:32:46 -07:00
usage()
}
if *stack {
2016-11-05 23:46:11 -07:00
out, err := cmd(signal.StackTrace)
2016-11-04 00:55:16 -07:00
exitIfError(err)
2016-11-03 22:32:46 -07:00
fmt.Println(out)
}
if *gc {
_, err := cmd(signal.GC)
2016-11-04 00:55:16 -07:00
exitIfError(err)
2016-11-03 22:32:46 -07:00
}
2016-11-03 23:28:51 -07:00
if *memstats {
out, err := cmd(signal.MemStats)
2016-11-04 00:55:16 -07:00
exitIfError(err)
2016-11-03 22:40:49 -07:00
fmt.Printf(out)
2016-11-03 22:32:46 -07:00
}
2016-11-03 22:53:07 -07:00
if *version {
out, err := cmd(signal.Version)
2016-11-04 00:55:16 -07:00
exitIfError(err)
2016-11-03 22:53:07 -07:00
fmt.Printf(out)
}
2016-11-05 15:23:50 -07:00
// TODO(jbd): kill by name?
2016-11-03 22:32:46 -07:00
}
func cmd(c byte) (string, error) {
sock := fmt.Sprintf("/tmp/gops%d.sock", *pid)
conn, err := net.Dial("unix", sock)
if err != nil {
return "", err
}
if _, err := conn.Write([]byte{c}); err != nil {
return "", err
}
all, err := ioutil.ReadAll(conn)
if err != nil {
return "", err
}
return string(all), nil
}
2016-11-03 23:01:30 -07:00
func goProcesses() {
2016-11-03 14:01:55 -07:00
pss, err := ps.Processes()
if err != nil {
log.Fatal(err)
}
var undetermined int
for _, pr := range pss {
name, err := pr.Path()
if err != nil {
undetermined++
continue
}
ok, err := isGo(name)
if err != nil {
2016-11-03 19:33:43 -07:00
// TODO(jbd): worth to report the number?
2016-11-03 14:01:55 -07:00
continue
}
if ok {
2016-11-05 15:23:50 -07:00
// TODO(jbd): List if the program is running the agent.
2016-11-03 19:33:43 -07:00
fmt.Printf("%d\t%v\t(%v)\n", pr.Pid(), pr.Executable(), name)
2016-11-03 14:01:55 -07:00
}
}
2016-11-03 16:56:19 -07:00
if undetermined > 0 {
2016-11-03 17:52:29 -07:00
fmt.Printf("\n%d processes left undetermined\n", undetermined)
2016-11-03 16:56:19 -07:00
}
2016-11-03 14:01:55 -07:00
}
func isGo(filename string) (ok bool, err error) {
obj, err := objfile.Open(filename)
if err != nil {
return false, err
}
defer obj.Close()
symbols, err := obj.Symbols()
if err != nil {
return false, err
}
2016-11-04 18:37:04 -07:00
// TODO(jbd): find a faster way to determine Go programs.
2016-11-03 14:01:55 -07:00
for _, s := range symbols {
if s.Name == "runtime.buildVersion" {
return true, nil
}
}
return false, nil
}
2016-11-03 22:32:46 -07:00
func usage() {
fmt.Fprintf(os.Stderr, "%v\n", helpText)
os.Exit(1)
}
2016-11-04 00:55:16 -07:00
func exitIfError(err error) {
if err == nil {
return
2016-11-03 22:32:46 -07:00
}
2016-11-04 00:55:16 -07:00
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
2016-11-03 22:32:46 -07:00
}