1
0
mirror of https://github.com/google/gops.git synced 2024-11-24 08:22:25 +02:00
gops/main.go

128 lines
2.6 KiB
Go
Raw Normal View History

2016-11-04 07:43:04 +02:00
// Copyright 2016 The Go Authors. All rights reserved.
2016-11-04 01:56:19 +02: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 23:01:55 +02:00
package main
import (
2016-11-04 07:32:46 +02:00
"flag"
2016-11-03 23:01:55 +02:00
"fmt"
"log"
2016-11-04 07:32:46 +02:00
"os"
2016-11-03 23:01:55 +02:00
"github.com/google/gops/internal/objfile"
2016-11-03 23:01:55 +02:00
ps "github.com/keybase/go-ps"
)
2016-11-04 07:32:46 +02:00
const helpText = `Usage: gops is a tool to list and diagnose Go processes.
2016-11-04 08:05:56 +02:00
2016-11-08 03:29:14 +02:00
gops Lists all Go processes currently running.
gops [cmd] -p=<pid> See the section below.
2016-11-04 07:32:46 +02:00
2016-11-14 07:59:09 +02:00
Commands:
gc Runs the garbage collector and blocks until successful.
stack Prints the stack trace.
memstats Prints the garbage collection stats.
version Prints the Go version used to build the program.
pprof-heap Reads the heap profile and launches "go tool pprof".
pprof-mem Reads the CPU profile and launches "go tool pprof".
help Prints this help text.
2016-11-04 08:05:56 +02:00
2016-11-08 03:29:14 +02:00
All commands require the agent running on the Go process.
2016-11-04 07:32:46 +02:00
`
2016-11-04 08:05:56 +02:00
// TODO(jbd): add link that explains the use of agent.
2016-11-03 23:01:55 +02:00
func main() {
2016-11-04 07:32:46 +02:00
if len(os.Args) < 2 {
2016-11-08 03:29:14 +02:00
processes()
2016-11-04 07:32:46 +02:00
return
}
2016-11-08 03:29:14 +02:00
cmd := os.Args[1]
2016-11-12 05:55:16 +02:00
if cmd == "help" {
usage("")
}
2016-11-08 03:29:14 +02:00
fn, ok := cmds[cmd]
if !ok {
usage("unknown subcommand")
2016-11-04 07:32:46 +02:00
}
2016-11-08 03:29:14 +02:00
2016-11-08 04:04:21 +02:00
var pid int
flag.IntVar(&pid, "p", -1, "")
2016-11-08 03:29:14 +02:00
flag.CommandLine.Parse(os.Args[2:])
2016-11-08 04:04:21 +02:00
if pid == -1 {
2016-11-08 03:29:14 +02:00
usage("missing -p=<pid> flag")
2016-11-04 07:32:46 +02:00
}
2016-11-08 03:29:14 +02:00
2016-11-08 04:04:21 +02:00
if err := fn(pid); err != nil {
2016-11-08 03:29:14 +02:00
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
2016-11-04 07:32:46 +02:00
}
}
2016-11-08 03:29:14 +02:00
func processes() {
2016-11-03 23:01:55 +02:00
pss, err := ps.Processes()
if err != nil {
log.Fatal(err)
}
var undetermined int
for _, pr := range pss {
2016-11-12 14:26:51 +02:00
if pr.Pid() == 0 {
// ignore system process
continue
}
2016-11-03 23:01:55 +02:00
name, err := pr.Path()
if err != nil {
undetermined++
continue
}
ok, err := isGo(name)
if err != nil {
2016-11-04 04:33:43 +02:00
// TODO(jbd): worth to report the number?
2016-11-03 23:01:55 +02:00
continue
}
if ok {
2016-11-06 00:23:50 +02:00
// TODO(jbd): List if the program is running the agent.
2016-11-04 04:33:43 +02:00
fmt.Printf("%d\t%v\t(%v)\n", pr.Pid(), pr.Executable(), name)
2016-11-03 23:01:55 +02:00
}
}
2016-11-04 01:56:19 +02:00
if undetermined > 0 {
2016-11-04 02:52:29 +02:00
fmt.Printf("\n%d processes left undetermined\n", undetermined)
2016-11-04 01:56:19 +02:00
}
2016-11-03 23:01:55 +02:00
}
func isGo(executable string) (ok bool, err error) {
obj, err := objfile.Open(executable)
2016-11-03 23:01:55 +02:00
if err != nil {
return false, err
}
defer obj.Close()
symbols, err := obj.Symbols()
if err != nil {
return false, err
}
2016-11-05 03:37:04 +02:00
// TODO(jbd): find a faster way to determine Go programs.
2016-11-03 23:01:55 +02:00
for _, s := range symbols {
if s.Name == "runtime.buildVersion" {
return true, nil
}
}
return false, nil
}
2016-11-04 07:32:46 +02:00
2016-11-08 03:29:14 +02:00
func usage(msg string) {
if msg != "" {
fmt.Printf("gops: %v\n", msg)
2016-11-04 07:32:46 +02:00
}
2016-11-08 03:29:14 +02:00
fmt.Fprintf(os.Stderr, "%v\n", helpText)
2016-11-04 09:55:16 +02:00
os.Exit(1)
2016-11-04 07:32:46 +02:00
}