Skip to content

Commit fd04525

Browse files
authored
Merge pull request #42 from arun0009/master
adding pprof middleware
2 parents b01f7f1 + d4d1c76 commit fd04525

File tree

4 files changed

+156
-0
lines changed

4 files changed

+156
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ Name | Description | Author
1414
session | Session middleware backed by [gorilla/sessions](https://github.com/gorilla/sessions) | [vishr](https://github.com/vishr)
1515
jaegertracing | Jaeger tracer middleware | [carlosedp](https://github.com/carlosedp)
1616
prometheus | Prometheus metrics | [carlosedp](https://github.com/carlosedp)
17+
pprof | pprof middlware | [arun0009](https://github.com/arun0009)

pprof/README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
Usage
2+
3+
```code go
4+
package main
5+
6+
import (
7+
"net/http"
8+
9+
"github.com/labstack/echo/v4"
10+
"github.com/labstack/echo-contrib/pprof"
11+
12+
)
13+
14+
func main() {
15+
e := echo.New()
16+
pprof.Register(e)
17+
......
18+
e.Logger.Fatal(e.Start(":1323"))
19+
}
20+
```
21+
22+
- Then use the pprof tool to look at the heap profile:
23+
24+
`go tool pprof http://localhost:1323/debug/pprof/heap`
25+
26+
- Or to look at a 30-second CPU profile:
27+
28+
`go tool pprof http://localhost:1323/debug/pprof/profile?seconds=30`
29+
30+
- Or to look at the goroutine blocking profile, after calling runtime.SetBlockProfileRate in your program:
31+
32+
`go tool pprof http://localhost:1323/debug/pprof/block`
33+
34+
- Or to look at the holders of contended mutexes, after calling runtime.SetMutexProfileFraction in your program:
35+
36+
`go tool pprof http://localhost:1323/debug/pprof/mutex`
37+
38+

pprof/pprof.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package pprof
2+
3+
import (
4+
"net/http"
5+
"net/http/pprof"
6+
7+
"github.com/labstack/echo/v4"
8+
)
9+
10+
const (
11+
// DefaultPrefix url prefix of pprof
12+
DefaultPrefix = "/debug/pprof"
13+
)
14+
15+
func getPrefix(prefixOptions ...string) string {
16+
if len(prefixOptions) > 0 {
17+
return prefixOptions[0]
18+
}
19+
return DefaultPrefix
20+
}
21+
22+
// Register middleware for net/http/pprof
23+
func Register(e *echo.Echo, prefixOptions ...string) {
24+
prefix := getPrefix(prefixOptions...)
25+
26+
prefixRouter := e.Group(prefix)
27+
{
28+
prefixRouter.GET("/", handler(pprof.Index))
29+
prefixRouter.GET("/allocs", handler(pprof.Handler("allocs").ServeHTTP))
30+
prefixRouter.GET("/block", handler(pprof.Handler("block").ServeHTTP))
31+
prefixRouter.GET("/cmdline", handler(pprof.Cmdline))
32+
prefixRouter.GET("/goroutine", handler(pprof.Handler("goroutine").ServeHTTP))
33+
prefixRouter.GET("/heap", handler(pprof.Handler("heap").ServeHTTP))
34+
prefixRouter.GET("/mutex", handler(pprof.Handler("mutex").ServeHTTP))
35+
prefixRouter.GET("/profile", handler(pprof.Profile))
36+
prefixRouter.POST("/symbol", handler(pprof.Symbol))
37+
prefixRouter.GET("/symbol", handler(pprof.Symbol))
38+
prefixRouter.GET("/threadcreate", handler(pprof.Handler("threadcreate").ServeHTTP))
39+
prefixRouter.GET("/trace", handler(pprof.Trace))
40+
}
41+
}
42+
43+
func handler(h http.HandlerFunc) echo.HandlerFunc {
44+
return func(c echo.Context) error {
45+
h.ServeHTTP(c.Response().Writer, c.Request())
46+
return nil
47+
}
48+
}

pprof/pprof_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package pprof
2+
3+
import (
4+
"github.com/stretchr/testify/assert"
5+
"net/http"
6+
"net/http/httptest"
7+
"testing"
8+
9+
"github.com/labstack/echo/v4"
10+
)
11+
12+
func TestPProfRegisterDefaualtPrefix(t *testing.T) {
13+
var pprofPaths = []struct {
14+
path string
15+
}{
16+
{"/"},
17+
{"/allocs"},
18+
{"/block"},
19+
{"/cmdline"},
20+
{"/goroutine"},
21+
{"/heap"},
22+
{"/mutex"},
23+
{"/profile?seconds=1"},
24+
{"/symbol"},
25+
{"/symbol"},
26+
{"/threadcreate"},
27+
{"/trace"},
28+
}
29+
for _, tt := range pprofPaths {
30+
t.Run(tt.path, func(t *testing.T) {
31+
e := echo.New()
32+
Register(e)
33+
req, _ := http.NewRequest(http.MethodGet, DefaultPrefix+tt.path, nil)
34+
rec := httptest.NewRecorder()
35+
e.ServeHTTP(rec, req)
36+
assert.Equal(t, rec.Code, http.StatusOK)
37+
})
38+
}
39+
}
40+
41+
func TestPProfRegisterCustomPrefix(t *testing.T) {
42+
var pprofPaths = []struct {
43+
path string
44+
}{
45+
{"/"},
46+
{"/allocs"},
47+
{"/block"},
48+
{"/cmdline"},
49+
{"/goroutine"},
50+
{"/heap"},
51+
{"/mutex"},
52+
{"/profile?seconds=1"},
53+
{"/symbol"},
54+
{"/symbol"},
55+
{"/threadcreate"},
56+
{"/trace"},
57+
}
58+
for _, tt := range pprofPaths {
59+
t.Run(tt.path, func(t *testing.T) {
60+
e := echo.New()
61+
pprofPrefix := "/myapp/pprof"
62+
Register(e, pprofPrefix)
63+
req, _ := http.NewRequest(http.MethodGet, pprofPrefix+tt.path, nil)
64+
rec := httptest.NewRecorder()
65+
e.ServeHTTP(rec, req)
66+
assert.Equal(t, rec.Code, http.StatusOK)
67+
})
68+
}
69+
}

0 commit comments

Comments
 (0)