// +build httpstats package go9p import ( "fmt" "io" "net/http" "sync" ) var mux sync.RWMutex var stat map[string]http.Handler var httponce sync.Once func register(s string, h http.Handler) { mux.Lock() if stat == nil { stat = make(map[string]http.Handler) } if h == nil { delete(stat, s) } else { stat[s] = h } mux.Unlock() } func (srv *Srv) statsRegister() { httponce.Do(func() { http.HandleFunc("/go9p/", StatsHandler) go http.ListenAndServe(":6060", nil) }) register("/go9p/srv/"+srv.Id, srv) } func (srv *Srv) statsUnregister() { register("/go9p/srv/"+srv.Id, nil) } func (srv *Srv) ServeHTTP(c http.ResponseWriter, r *http.Request) { io.WriteString(c, fmt.Sprintf("

Server %s

", srv.Id)) defer io.WriteString(c, "") // connections io.WriteString(c, "

Connections

") srv.Lock() defer srv.Unlock() if len(srv.conns) == 0 { io.WriteString(c, "none") return } for _, conn := range srv.conns { io.WriteString(c, fmt.Sprintf("%s
", srv.Id, conn.Id, conn.Id)) } } func (conn *Conn) statsRegister() { register("/go9p/srv/"+conn.Srv.Id+"/conn/"+conn.Id, conn) } func (conn *Conn) statsUnregister() { register("/go9p/srv/"+conn.Srv.Id+"/conn/"+conn.Id, nil) } func (conn *Conn) ServeHTTP(c http.ResponseWriter, r *http.Request) { io.WriteString(c, fmt.Sprintf("

Connection %s/%s

", conn.Srv.Id, conn.Id)) defer io.WriteString(c, "") // statistics conn.Lock() io.WriteString(c, fmt.Sprintf("

Number of processed requests: %d", conn.nreqs)) io.WriteString(c, fmt.Sprintf("
Sent %v bytes", conn.rsz)) io.WriteString(c, fmt.Sprintf("
Received %v bytes", conn.tsz)) io.WriteString(c, fmt.Sprintf("
Pending requests: %d max %d", conn.npend, conn.maxpend)) io.WriteString(c, fmt.Sprintf("
Number of reads: %d", conn.nreads)) io.WriteString(c, fmt.Sprintf("
Number of writes: %d", conn.nwrites)) conn.Unlock() // fcalls if conn.Debuglevel&DbgLogFcalls != 0 { fs := conn.Srv.Log.Filter(conn, DbgLogFcalls) io.WriteString(c, fmt.Sprintf("

Last %d 9P messages

", len(fs))) for i, l := range fs { fc := l.Data.(*Fcall) if fc.Type == 0 { continue } lbl := "" if fc.Type%2 == 0 { // try to find the response for the T message for j := i + 1; j < len(fs); j++ { rc := fs[j].Data.(*Fcall) if rc.Tag == fc.Tag { lbl = fmt.Sprintf("", j) break } } } else { // try to find the request for the R message for j := i - 1; j >= 0; j-- { tc := fs[j].Data.(*Fcall) if tc.Tag == fc.Tag { lbl = fmt.Sprintf("", j) break } } } io.WriteString(c, fmt.Sprintf("
%d: %s%s", i, i, fc, lbl)) } } } func StatsHandler(c http.ResponseWriter, r *http.Request) { mux.RLock() if v, ok := stat[r.URL.Path]; ok { v.ServeHTTP(c, r) } else if r.URL.Path == "/go9p/" { io.WriteString(c, fmt.Sprintf("

On offer:


")) for v := range stat { io.WriteString(c, fmt.Sprintf("%s
", v, v)) } io.WriteString(c, "") } mux.RUnlock() }