-
Notifications
You must be signed in to change notification settings - Fork 4
/
netbug.go
141 lines (133 loc) · 4.31 KB
/
netbug.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package netbug
import (
"fmt"
"log"
"net/http"
nhpprof "net/http/pprof"
"net/url"
"runtime/pprof"
"strings"
"text/template"
)
func handler(token string) http.Handler {
info := struct {
Profiles []*pprof.Profile
Token string
}{
Profiles: pprof.Profiles(),
Token: url.QueryEscape(token),
}
h := func(w http.ResponseWriter, r *http.Request) {
name := strings.TrimPrefix(r.URL.Path, "/")
switch name {
case "":
// Index page.
if err := indexTmpl.Execute(w, info); err != nil {
log.Println(err)
return
}
case "cmdline":
nhpprof.Cmdline(w, r)
case "profile":
nhpprof.Profile(w, r)
case "trace":
nhpprof.Trace(w, r)
case "symbol":
nhpprof.Symbol(w, r)
default:
// Provides access to all profiles under runtime/pprof
nhpprof.Handler(name).ServeHTTP(w, r)
}
}
return http.HandlerFunc(h)
}
// Handler returns an http.Handler that provides access to the various
// profiler and debug tools in the /net/http/pprof and /runtime/pprof
// packages.
//
// The returned handler assumed it is registered on "/" so if you wish
// to register on any other route, you should strip the route prefix
// before passing a request on to the handler.
//
// This is best done with:
//
// h := http.StripPrefix("/myroute/", netbug.Handler())
//
// Unless you need to wrap or chain the handler you probably want to use
// netbug.RegisterHandler.
func Handler() http.Handler {
return handler("")
}
// RegisterHandler registers the netbug handler on the provided
// http.ServeMux, using the provided prefix to form the route.
//
// The provided prefix needs to have a trailing slash. The full list of
// routes registered for available profiles and debug information can
// be examined by visiting prefix.
//
func RegisterHandler(prefix string, mux *http.ServeMux) {
mux.Handle(prefix, http.StripPrefix(prefix, Handler()))
}
// AuthHandler returns an http.Handler that provides authenticated
// access to the various profiler and debug tools in the
// /net/http/pprof and /runtime/pprof packages.
//
// The token provided is required as a URL parameter called token for
// all requests. The netbug package takes care of injecting the token
// into links in the index page.
//
// The returned handler assumed it is registered on "/" so if you wish
// to register on any other route, you should strip the route prefix
// before passing a request on to the handler.
//
// This is best done with:
//
// h := http.StripPrefix("/myroute/", netbug.AuthHandler("secret"))
//
// Unless you need to wrap or chain the handler you probably want to use
// netbug.RegisterAuthHandler.
func AuthHandler(token string) http.Handler {
h := handler(token)
ah := func(w http.ResponseWriter, r *http.Request) {
if r.FormValue("token") == token {
h.ServeHTTP(w, r)
} else {
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprintln(w, "Unauthorized.")
}
}
return http.HandlerFunc(ah)
}
// RegisterAuthHandler registers a handler requiring authentication on
// the provided http.ServeMux, using the provided prefix to form the
// route.
//
// The provided prefix needs to have a trailing slash. The full list of
// routes registered can be examined by visiting the root page.
func RegisterAuthHandler(token, prefix string, mux *http.ServeMux) {
mux.Handle(prefix, http.StripPrefix(prefix, AuthHandler(token)))
}
var indexTmpl = template.Must(template.New("index").Parse(`<html>
<head>
<title>Debug Information</title>
</head>
<br>
<body>
profiles:<br>
<table>
{{range .Profiles}}
<tr><td align=right>{{.Count}}<td><a href="{{.Name}}?debug=1{{if $.Token}}&token={{$.Token}}{{end}}">{{.Name}}</a>
{{end}}
<tr><td align=right><td><a href="profile{{if .Token}}?token={{.Token}}{{end}}">CPU</a>
<tr><td align=right><td><a href="trace?seconds=5{{if .Token}}&token={{.Token}}{{end}}">5-second trace</a>
<tr><td align=right><td><a href="trace?seconds=30{{if .Token}}&token={{.Token}}{{end}}">30-second trace</a>
</table>
<br>
debug information:<br>
<table>
<tr><td align=right><td><a href="cmdline{{if .Token}}?token={{.Token}}{{end}}">cmdline</a>
<tr><td align=right><td><a href="symbol{{if .Token}}?token={{.Token}}{{end}}">symbol</a>
<tr><td align=right><td><a href="goroutine?debug=2{{if .Token}}&token={{.Token}}{{end}}">full goroutine stack dump</a><br>
<table>
</body>
</html>`))