mirror of
https://github.com/google/gops.git
synced 2024-11-24 08:22:25 +02:00
80 lines
1.6 KiB
Go
80 lines
1.6 KiB
Go
// Copyright 2013 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 agent provides hooks programs can register to retrieve
|
|
// diagnostics data by using gops.
|
|
package agent
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net"
|
|
"os"
|
|
"runtime"
|
|
"runtime/debug"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
// Stack represents a command to print stack trace.
|
|
Stack = byte(0x1)
|
|
|
|
// GC runs the garbage collector.
|
|
GC = byte(0x2)
|
|
|
|
// GCStats prints GC stats.
|
|
GCStats = byte(0x3)
|
|
)
|
|
|
|
func init() {
|
|
sock := fmt.Sprintf("/tmp/gops%d.sock", os.Getpid())
|
|
l, err := net.Listen("unix", sock)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
// TODO(jbd): cleanup the socket on shutdown.
|
|
go func() {
|
|
buf := make([]byte, 1)
|
|
for {
|
|
fd, err := l.Accept()
|
|
if err != nil {
|
|
log.Println(err)
|
|
continue
|
|
}
|
|
if _, err := fd.Read(buf); err != nil {
|
|
log.Println(err)
|
|
continue
|
|
}
|
|
if err := handle(fd, buf); err != nil {
|
|
log.Println(err)
|
|
continue
|
|
}
|
|
fd.Close()
|
|
}
|
|
}()
|
|
}
|
|
|
|
func handle(conn net.Conn, msg []byte) error {
|
|
switch msg[0] {
|
|
case Stack:
|
|
buf := make([]byte, 1<<16)
|
|
n := runtime.Stack(buf, true)
|
|
_, err := conn.Write(buf[:n])
|
|
return err
|
|
case GC:
|
|
runtime.GC()
|
|
_, err := conn.Write([]byte("ok"))
|
|
return err
|
|
case GCStats:
|
|
var stats debug.GCStats
|
|
debug.ReadGCStats(&stats)
|
|
fmt.Fprintf(conn, "Num GC: %v\n", stats.NumGC)
|
|
if stats.NumGC > 0 {
|
|
fmt.Fprintf(conn, "Last GC: %v ago\n", time.Now().Sub(stats.LastGC))
|
|
fmt.Fprintf(conn, "Total pause: %v\n", stats.PauseTotal)
|
|
}
|
|
}
|
|
return nil
|
|
}
|