Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/common-go/pprof/pprof.go
2500 views
1
// Copyright (c) 2020 Gitpod GmbH. All rights reserved.
2
// Licensed under the GNU Affero General Public License (AGPL).
3
// See License.AGPL.txt in the project root for license information.
4
5
package pprof
6
7
import (
8
"math/rand"
9
"net/http"
10
"net/http/pprof"
11
"runtime"
12
"strconv"
13
"strings"
14
15
"github.com/gitpod-io/gitpod/common-go/log"
16
)
17
18
// http handler path which MUST be used as a prefix to route pprof endpoint
19
// since it is hardcoded inside pprof
20
const Path = "/debug/pprof/"
21
22
// Serve starts a new HTTP server serving pprof endpoints on the given addr
23
func Serve(addr string) {
24
mux := Handler()
25
26
log.WithField("addr", addr).Info("serving pprof service")
27
err := http.ListenAndServe(addr, mux)
28
if err != nil {
29
log.WithField("addr", addr).WithError(err).Warn("cannot serve pprof service")
30
}
31
}
32
33
// Handler produces the pprof endpoint handler
34
func Handler() *http.ServeMux {
35
mux := http.NewServeMux()
36
mux.HandleFunc(Path, index)
37
mux.HandleFunc(Path+"cmdline", pprof.Cmdline)
38
mux.HandleFunc(Path+"profile", pprof.Profile)
39
mux.HandleFunc(Path+"symbol", pprof.Symbol)
40
mux.HandleFunc(Path+"trace", pprof.Trace)
41
42
mux.HandleFunc("/debug/logging", log.LevelHandler)
43
44
return mux
45
}
46
47
func index(w http.ResponseWriter, r *http.Request) {
48
if strings.HasPrefix(r.URL.Path, Path) {
49
// according to Ian Lance Taylor it's ok to turn on mutex and block profiling
50
// when asking for the actual profile [1]. This handler implements this idea, as
51
// discussed in [2]
52
//
53
// [1] https://groups.google.com/forum/#!topic/golang-nuts/qiHa97XzeCw
54
// [2] https://github.com/golang/go/issues/23401
55
56
var (
57
name = strings.TrimPrefix(r.URL.Path, Path)
58
seconds, serr = strconv.ParseInt(r.URL.Query().Get("seconds"), 10, 64)
59
)
60
if name == "mutex" {
61
frac, ferr := strconv.ParseInt(r.URL.Query().Get("frac"), 10, 64)
62
if serr == nil && ferr == nil && seconds > 0 && frac > 0 {
63
//nolint:gosec
64
id := rand.Uint32()
65
log.WithField("id", id).WithField("frac", frac).WithField("seconds", seconds).Debug("enabled mutex profiling")
66
67
runtime.SetMutexProfileFraction(int(frac))
68
defer func() {
69
runtime.SetMutexProfileFraction(0)
70
log.WithField("id", id).WithField("frac", frac).WithField("seconds", seconds).Debug("disabled mutex profiling")
71
}()
72
}
73
} else if name == "block" {
74
rate, rerr := strconv.ParseInt(r.URL.Query().Get("rate"), 10, 64)
75
if rerr == nil && rate > 0 && serr == nil && seconds > 0 {
76
//nolint:gosec
77
id := rand.Uint32()
78
log.WithField("id", id).WithField("rate", rate).WithField("seconds", seconds).Debug("enabled mutex block sampling")
79
runtime.SetBlockProfileRate(int(rate))
80
81
defer func() {
82
runtime.SetBlockProfileRate(0)
83
log.WithField("id", id).WithField("rate", rate).WithField("seconds", seconds).Debug("disabled mutex block sampling")
84
}()
85
}
86
}
87
}
88
89
pprof.Index(w, r)
90
}
91
92