1
0
mirror of https://github.com/google/gops.git synced 2025-07-06 23:55:43 +02:00
Files
gops/cmd.go

116 lines
2.2 KiB
Go
Raw Normal View History

2016-11-07 17:29:14 -08:00
package main
import (
2016-11-13 20:38:17 -08:00
"errors"
2016-11-07 17:29:14 -08:00
"fmt"
"io/ioutil"
"net"
2016-11-13 20:04:40 -08:00
"os"
2016-11-13 20:38:17 -08:00
"os/exec"
2016-11-13 20:04:40 -08:00
2016-11-14 23:07:31 -08:00
"github.com/google/gops/internal"
2016-11-07 17:29:14 -08:00
"github.com/google/gops/signal"
2016-11-13 21:46:10 -08:00
ps "github.com/keybase/go-ps"
2016-11-07 17:29:14 -08:00
)
var cmds = map[string](func(pid int) error){
2016-11-13 21:50:30 -08:00
"stack": stackTrace,
"gc": gc,
"memstats": memStats,
"version": version,
"pprof-heap": pprofHeap,
"pprof-cpu": pprofCPU,
2016-11-14 11:07:06 -08:00
"vitals": vitals,
2016-11-07 17:29:14 -08:00
}
func stackTrace(pid int) error {
2016-11-28 19:45:02 +01:00
return cmdWithPrint(pid, signal.StackTrace)
2016-11-07 17:29:14 -08:00
}
func gc(pid int) error {
_, err := cmd(pid, signal.GC)
return err
}
func memStats(pid int) error {
2016-11-28 19:45:02 +01:00
return cmdWithPrint(pid, signal.MemStats)
2016-11-07 17:29:14 -08:00
}
func version(pid int) error {
2016-11-28 19:45:02 +01:00
return cmdWithPrint(pid, signal.Version)
2016-11-07 17:29:14 -08:00
}
2016-11-13 21:50:30 -08:00
func pprofHeap(pid int) error {
return pprof(pid, signal.HeapProfile)
}
func pprofCPU(pid int) error {
fmt.Println("Profiling CPU now, will take 30 secs...")
return pprof(pid, signal.CPUProfile)
}
func pprof(pid int, p byte) error {
out, err := cmd(pid, p)
2016-11-13 20:04:40 -08:00
if err != nil {
return err
}
2016-11-13 20:38:17 -08:00
if out == "" {
return errors.New("failed to read the profile")
}
2016-11-13 20:04:40 -08:00
tmpfile, err := ioutil.TempFile("", "heap-profile")
if err != nil {
return err
}
2016-11-13 20:38:17 -08:00
defer os.Remove(tmpfile.Name())
2016-11-13 20:04:40 -08:00
if err := ioutil.WriteFile(tmpfile.Name(), []byte(out), 0); err != nil {
return err
}
2016-11-13 21:46:10 -08:00
process, err := ps.FindProcess(pid)
if err != nil {
// TODO(jbd): add context to the error
return err
}
binary, err := process.Path()
if err != nil {
2016-11-26 18:43:04 -08:00
return fmt.Errorf("cannot the binary for the PID: %v", err)
2016-11-13 21:46:10 -08:00
}
cmd := exec.Command("go", "tool", "pprof", binary, tmpfile.Name())
2016-11-13 20:04:40 -08:00
cmd.Env = os.Environ()
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
2016-11-14 11:07:06 -08:00
func vitals(pid int) error {
2016-11-28 19:45:02 +01:00
return cmdWithPrint(pid, signal.Vitals)
}
func cmdWithPrint(pid int, c byte) error {
out, err := cmd(pid, c)
2016-11-14 11:07:06 -08:00
if err != nil {
return err
}
fmt.Printf(out)
return nil
}
2016-11-07 17:29:14 -08:00
func cmd(pid int, c byte) (string, error) {
2016-11-14 23:07:31 -08:00
port, err := internal.GetPort(pid)
2016-11-15 08:59:09 +02:00
if err != nil {
return "", err
}
conn, err := net.Dial("tcp", "127.0.0.1:"+port)
2016-11-07 17:29:14 -08:00
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
}