3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-12-22 18:52:41 +01:00

expose various go internals as a DEBUG command

This commit is contained in:
Jeremy Latt 2014-02-23 10:04:31 -08:00
parent f482b6b82f
commit 3b56b5bf42
4 changed files with 67 additions and 0 deletions

View File

@ -22,6 +22,7 @@ var (
parseCommandFuncs = map[StringCode]parseCommandFunc{ parseCommandFuncs = map[StringCode]parseCommandFunc{
AWAY: NewAwayCommand, AWAY: NewAwayCommand,
CAP: NewCapCommand, CAP: NewCapCommand,
DEBUG: NewDebugCommand,
ISON: NewIsOnCommand, ISON: NewIsOnCommand,
JOIN: NewJoinCommand, JOIN: NewJoinCommand,
KICK: NewKickCommand, KICK: NewKickCommand,
@ -863,3 +864,18 @@ func NewNamesCommand(args []string) (editableCommand, error) {
} }
return cmd, nil return cmd, nil
} }
type DebugCommand struct {
BaseCommand
subCommand string
}
func NewDebugCommand(args []string) (editableCommand, error) {
if len(args) == 0 {
return nil, NotEnoughArgsError
}
return &DebugCommand{
subCommand: strings.ToUpper(args[0]),
}, nil
}

View File

@ -34,6 +34,7 @@ const (
// string codes // string codes
AWAY StringCode = "AWAY" AWAY StringCode = "AWAY"
CAP StringCode = "CAP" CAP StringCode = "CAP"
DEBUG StringCode = "DEBUG"
ERROR StringCode = "ERROR" ERROR StringCode = "ERROR"
INVITE StringCode = "INVITE" INVITE StringCode = "INVITE"
ISON StringCode = "ISON" ISON StringCode = "ISON"

View File

@ -9,6 +9,9 @@ import (
"log" "log"
"net" "net"
"os" "os"
"runtime"
"runtime/debug"
"runtime/pprof"
"strings" "strings"
"time" "time"
) )
@ -717,3 +720,47 @@ func (msg *NamesCommand) HandleServer(server *Server) {
channel.Names(client) channel.Names(client)
} }
} }
func (server *Server) Reply(target *Client, format string, args ...interface{}) {
target.Reply(RplPrivMsg(server, target, fmt.Sprintf(format, args...)))
}
func (msg *DebugCommand) HandleServer(server *Server) {
client := msg.Client()
if !client.flags[Operator] {
return
}
switch msg.subCommand {
case "GC":
runtime.GC()
server.Reply(client, "OK")
case "GCSTATS":
stats := &debug.GCStats{
PauseQuantiles: make([]time.Duration, 5),
}
server.Reply(client, "last GC: %s", stats.LastGC.Format(time.RFC1123))
server.Reply(client, "num GC: %d", stats.NumGC)
server.Reply(client, "pause total: %s", stats.PauseTotal)
server.Reply(client, "pause quantiles min%%: %s", stats.PauseQuantiles[0])
server.Reply(client, "pause quantiles 25%%: %s", stats.PauseQuantiles[1])
server.Reply(client, "pause quantiles 50%%: %s", stats.PauseQuantiles[2])
server.Reply(client, "pause quantiles 75%%: %s", stats.PauseQuantiles[3])
server.Reply(client, "pause quantiles max%%: %s", stats.PauseQuantiles[4])
case "NUMGOROUTINE":
count := runtime.NumGoroutine()
server.Reply(client, "num goroutines: %d", count)
case "PROFILEHEAP":
file, err := os.Create("ergonomadic.heap.prof")
if err != nil {
log.Printf("error: %s", err)
break
}
defer file.Close()
pprof.Lookup("heap").WriteTo(file, 0)
server.Reply(client, "written to ergonomadic-heap.prof")
}
}

View File

@ -74,6 +74,9 @@ func (socket *Socket) Read() <-chan string {
} }
func (socket *Socket) Write(lines ...string) (err error) { func (socket *Socket) Write(lines ...string) (err error) {
if socket.closed {
return io.EOF
}
for _, line := range lines { for _, line := range lines {
err = socket.WriteLine(line) err = socket.WriteLine(line)
if err != nil { if err != nil {