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

147 lines
2.9 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 (
"bytes"
2016-11-03 14:01:55 -07:00
"fmt"
"log"
2016-11-03 22:32:46 -07:00
"os"
2017-01-01 19:54:15 -08:00
"strconv"
"sync"
2016-11-03 14:01:55 -07:00
"github.com/google/gops/internal"
"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
2017-01-01 19:54:15 -08:00
gops Lists all Go processes currently running.
gops cmd <pid> See the commands below.
2016-11-03 22:32:46 -07:00
2016-11-13 21:59:09 -08: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.
2017-01-03 01:15:13 -08:00
stats Prints the vital runtime stats.
2016-11-13 21:59:09 -08:00
pprof-heap Reads the heap profile and launches "go tool pprof".
2016-11-21 04:16:04 +07:00
pprof-cpu Reads the CPU profile and launches "go tool pprof".
2016-11-13 21:59:09 -08:00
help Prints this help text.
2016-11-03 23:05:56 -07:00
2016-11-07 17:29:14 -08:00
All commands require the agent running on the Go process.
Symbol "*" indicates the process runs the agent.`
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 14:01:55 -07:00
func main() {
2016-11-03 22:32:46 -07:00
if len(os.Args) < 2 {
2016-11-07 17:29:14 -08:00
processes()
2016-11-03 22:32:46 -07:00
return
}
2016-11-07 17:29:14 -08:00
cmd := os.Args[1]
2016-11-11 19:55:16 -08:00
if cmd == "help" {
usage("")
}
2017-01-01 19:54:15 -08:00
if len(os.Args) < 3 {
usage("missing PID")
}
pid, err := strconv.Atoi(os.Args[2])
if err != nil {
usage("PID should be numeric")
}
2016-11-07 17:29:14 -08:00
fn, ok := cmds[cmd]
if !ok {
usage("unknown subcommand")
2016-11-03 22:32:46 -07:00
}
2016-11-07 18:04:21 -08:00
if err := fn(pid); err != nil {
2016-11-07 17:29:14 -08:00
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
2016-11-03 22:32:46 -07:00
}
}
2016-11-07 17:29:14 -08:00
func processes() {
2016-11-03 14:01:55 -07:00
pss, err := ps.Processes()
if err != nil {
log.Fatal(err)
}
var wg sync.WaitGroup
wg.Add(len(pss))
2016-11-03 14:01:55 -07:00
for _, pr := range pss {
pr := pr
go func() {
defer wg.Done()
printIfGo(pr)
}()
2016-11-03 16:56:19 -07:00
}
wg.Wait()
2016-11-03 14:01:55 -07:00
}
2017-01-19 18:43:31 -08:00
// printIfGo looks up the runtime.buildVersion symbol
// in the process' binary and determines if the process
// if a Go process or not. If the process is a Go process,
// it reports PID, binary name and full path of the binary.
func printIfGo(pr ps.Process) {
if pr.Pid() == 0 {
// ignore system process
return
}
path, err := pr.Path()
if err != nil {
return
}
obj, err := objfile.Open(path)
2016-11-03 14:01:55 -07:00
if err != nil {
return
2016-11-03 14:01:55 -07:00
}
defer obj.Close()
symbols, err := obj.Symbols()
if err != nil {
return
2016-11-03 14:01:55 -07:00
}
var ok bool
2016-11-03 14:01:55 -07:00
for _, s := range symbols {
if s.Name == "runtime.buildVersion" {
ok = true
}
2016-11-03 14:01:55 -07:00
}
var agent bool
pidfile, err := internal.PIDFile(pr.Pid())
if err == nil {
_, err := os.Stat(pidfile)
agent = err == nil
}
if ok {
buf := bytes.NewBuffer(nil)
fmt.Fprintf(buf, "%d", pr.Pid())
if agent {
fmt.Fprint(buf, "*")
}
fmt.Fprintf(buf, "\t%v\t(%v)\n", pr.Executable(), path)
buf.WriteTo(os.Stdout)
}
2016-11-03 14:01:55 -07:00
}
2016-11-03 22:32:46 -07:00
2016-11-07 17:29:14 -08:00
func usage(msg string) {
if msg != "" {
fmt.Printf("gops: %v\n", msg)
2016-11-03 22:32:46 -07:00
}
2016-11-07 17:29:14 -08:00
fmt.Fprintf(os.Stderr, "%v\n", helpText)
2016-11-04 00:55:16 -07:00
os.Exit(1)
2016-11-03 22:32:46 -07:00
}