generated from cloudwego/.github
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add pprof middleware for Hertz framework (#1)
* init * add adaptor * add liscense * add license * unify dir name * unify dir name * test case * add gotils * readme_cn * delete license fiber * add group test * license-gotils * Update README_CN.md * Update README_CN.md
- Loading branch information
jc666
committed
Sep 21, 2022
1 parent
b261e61
commit 2b6aea2
Showing
14 changed files
with
1,127 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
CloudWeGo | ||
Copyright 2022 CloudWeGo authors. | ||
|
||
This product includes software developed at | ||
The Apache Software Foundation (http://www.apache.org/). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,117 @@ | ||
# .github | ||
# pprof (This is a community driven project) | ||
|
||
English | [中文](README_CN.md) | ||
|
||
pprof middleware for Hertz framework, inspired by [pprof](https://github.com/gin-contrib/pprof). | ||
This project would not have been possible without the support from the CloudWeGo community and previous work done by the gin community. | ||
|
||
- Package pprof serves via its HTTP server runtime profiling data in the format expected by the pprof visualization tool. | ||
|
||
|
||
## Install | ||
```shell | ||
go get github.com/hertz-contrib/pprof | ||
``` | ||
|
||
## Usage | ||
### Example | ||
|
||
```go | ||
func main() { | ||
h := server.Default() | ||
|
||
pprof.Register(h) | ||
|
||
h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { | ||
ctx.JSON(consts.StatusOK, utils.H{"ping": "pong"}) | ||
}) | ||
|
||
h.Spin() | ||
} | ||
``` | ||
|
||
### change default path prefix | ||
|
||
```go | ||
import ( | ||
"context" | ||
"github.com/cloudwego/hertz/pkg/app" | ||
"github.com/cloudwego/hertz/pkg/app/server" | ||
"github.com/cloudwego/hertz/pkg/common/utils" | ||
"github.com/cloudwego/hertz/pkg/protocol/consts" | ||
"hertz-contrib-beiye/pprof" | ||
) | ||
|
||
func main() { | ||
h := server.Default() | ||
|
||
// default is "debug/pprof" | ||
pprof.Register(h, "dev/pprof") | ||
|
||
h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { | ||
ctx.JSON(consts.StatusOK, utils.H{"ping": "pong"}) | ||
}) | ||
|
||
h.Spin() | ||
} | ||
|
||
``` | ||
|
||
### custom router group | ||
|
||
```go | ||
import ( | ||
"context" | ||
"github.com/cloudwego/hertz/pkg/app" | ||
"github.com/cloudwego/hertz/pkg/app/server" | ||
"hertz-contrib-beiye/pprof" | ||
"net/http" | ||
) | ||
|
||
func main() { | ||
h := server.Default() | ||
|
||
pprof.Register(h) | ||
|
||
adminGroup := h.Group("/admin") | ||
adminGroup.GET("/ping", func(c context.Context, ctx *app.RequestContext) { | ||
ctx.JSON(consts.StatusOK, utils.H{"ping": "pong"}) | ||
}) | ||
|
||
pprof.RouteRegister(adminGroup, "pprof") | ||
|
||
h.Spin() | ||
} | ||
|
||
``` | ||
|
||
|
||
### Use the pprof tool | ||
|
||
Then use the pprof tool to look at the heap profile: | ||
|
||
```bash | ||
go tool pprof http://localhost:8888/debug/pprof/heap | ||
``` | ||
|
||
Or to look at a 30-second CPU profile: | ||
|
||
```bash | ||
go tool pprof http://localhost:8888/debug/pprof/profile | ||
``` | ||
|
||
Or to look at the goroutine blocking profile, after calling runtime.SetBlockProfileRate in your program: | ||
|
||
```bash | ||
go tool pprof http://localhost:8888/debug/pprof/block | ||
``` | ||
|
||
Or to collect a 5-second execution trace: | ||
|
||
```bash | ||
wget http://localhost:8888/debug/pprof/trace?seconds=5 | ||
``` | ||
|
||
|
||
## License | ||
This project is under the Apache License 2.0. See the LICENSE file for the full license text. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
# pprof (本项目由CloudWeGo社区贡献者协作开发并维护) | ||
|
||
[English](README.md) | 中文 | ||
|
||
pprof 是为 Hertz 框架开发的中间件,参考了 [Gin](https://github.com/gin-gonic/gin) 中 [pprof](https://github.com/gin-contrib/pprof) 的实现。 | ||
本项目的完成得益于 CloudWeGo 社区的工作以及 Gin 社区所做的相关前置工作。 | ||
|
||
|
||
## 安装 | ||
```shell | ||
go get github.com/hertz-contrib/pprof | ||
``` | ||
|
||
## 使用 | ||
### 代码实例1 | ||
|
||
```go | ||
func main() { | ||
h := server.Default() | ||
|
||
pprof.Register(h) | ||
|
||
h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { | ||
ctx.JSON(consts.StatusOK, utils.H{"ping": "pong"}) | ||
}) | ||
|
||
h.Spin() | ||
} | ||
``` | ||
|
||
### 代码实例2: 自定义前缀 | ||
|
||
```go | ||
import ( | ||
"context" | ||
"github.com/cloudwego/hertz/pkg/app" | ||
"github.com/cloudwego/hertz/pkg/app/server" | ||
"github.com/cloudwego/hertz/pkg/common/utils" | ||
"github.com/cloudwego/hertz/pkg/protocol/consts" | ||
"hertz-contrib-beiye/pprof" | ||
) | ||
|
||
func main() { | ||
h := server.Default() | ||
|
||
// default is "debug/pprof" | ||
pprof.Register(h, "dev/pprof") | ||
|
||
h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { | ||
ctx.JSON(consts.StatusOK, utils.H{"ping": "pong"}) | ||
}) | ||
|
||
h.Spin() | ||
} | ||
|
||
``` | ||
|
||
### 代码实例3: 自定义路由组 | ||
|
||
```go | ||
import ( | ||
"context" | ||
"github.com/cloudwego/hertz/pkg/app" | ||
"github.com/cloudwego/hertz/pkg/app/server" | ||
"hertz-contrib-beiye/pprof" | ||
"net/http" | ||
) | ||
|
||
func main() { | ||
h := server.Default() | ||
|
||
pprof.Register(h) | ||
|
||
adminGroup := h.Group("/admin") | ||
adminGroup.GET("/ping", func(c context.Context, ctx *app.RequestContext) { | ||
ctx.JSON(consts.StatusOK, utils.H{"ping": "pong"}) | ||
}) | ||
|
||
pprof.RouteRegister(adminGroup, "pprof") | ||
|
||
h.Spin() | ||
} | ||
|
||
``` | ||
|
||
|
||
### 如何使用 | ||
|
||
使用 `pprof tool` 工具查看堆栈采样信息: | ||
|
||
```bash | ||
go tool pprof http://localhost:8888/debug/pprof/heap | ||
``` | ||
|
||
使用 `pprof tool` 工具查看 30s 的 CPU 采样信息: | ||
|
||
```bash | ||
go tool pprof http://localhost:8888/debug/pprof/profile | ||
``` | ||
|
||
使用 `pprof tool` 工具查看 go 协程阻塞信息: | ||
|
||
```bash | ||
go tool pprof http://localhost:8888/debug/pprof/block | ||
``` | ||
|
||
使用 `pprof tool` 工具查看 5s 内的执行 trace: | ||
|
||
```bash | ||
wget http://localhost:8888/debug/pprof/trace?seconds=5 | ||
``` | ||
|
||
|
||
## License | ||
This project is under the Apache License 2.0. See the LICENSE file for the full license text. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/* | ||
* Copyright 2022 CloudWeGo Authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package adaptor | ||
|
||
import ( | ||
"context" | ||
"net/http" | ||
|
||
"github.com/cloudwego/hertz/pkg/app" | ||
"github.com/cloudwego/hertz/pkg/common/adaptor" | ||
"github.com/cloudwego/hertz/pkg/common/hlog" | ||
"github.com/cloudwego/hertz/pkg/protocol/consts" | ||
"github.com/savsgio/gotils/strconv" | ||
) | ||
|
||
// NewHertzHTTPHandlerFunc wraps net/http handler to hertz app.HandlerFunc, | ||
// so it can be passed to hertz server | ||
// | ||
// While this function may be used for easy switching from net/http to hertz, | ||
// it has the following drawbacks comparing to using manually written hertz | ||
// request handler: | ||
// | ||
// - A lot of useful functionality provided by hertz is missing | ||
// from net/http handler. | ||
// | ||
// - net/http -> hertz handler conversion has some overhead, | ||
// so the returned handler will be always slower than manually written | ||
// hertz handler. | ||
// | ||
// So it is advisable using this function only for net/http -> hertz switching. | ||
// Then manually convert net/http handlers to hertz handlers | ||
func NewHertzHTTPHandlerFunc(h http.HandlerFunc) app.HandlerFunc { | ||
return NewHertzHTTPHandler(h) | ||
} | ||
|
||
// NewHertzHTTPHandler wraps net/http handler to hertz app.HandlerFunc, | ||
// so it can be passed to hertz server | ||
// | ||
// While this function may be used for easy switching from net/http to hertz, | ||
// it has the following drawbacks comparing to using manually written hertz | ||
// request handler: | ||
// | ||
// - A lot of useful functionality provided by hertz is missing | ||
// from net/http handler. | ||
// | ||
// - net/http -> hertz handler conversion has some overhead, | ||
// so the returned handler will be always slower than manually written | ||
// hertz handler. | ||
// | ||
// So it is advisable using this function only for net/http -> hertz switching. | ||
// Then manually convert net/http handlers to hertz handlers | ||
func NewHertzHTTPHandler(h http.Handler) app.HandlerFunc { | ||
return func(ctx context.Context, c *app.RequestContext) { | ||
req, err := adaptor.GetCompatRequest(c.GetRequest()) | ||
if err != nil { | ||
hlog.CtxErrorf(ctx, "HERTZ: Get request error: %v", err) | ||
c.String(http.StatusInternalServerError, consts.StatusMessage(http.StatusInternalServerError)) | ||
return | ||
} | ||
req.RequestURI = strconv.B2S(c.Request.RequestURI()) | ||
rw := adaptor.GetCompatResponseWriter(&c.Response) | ||
c.ForEachKey(func(k string, v interface{}) { | ||
ctx = context.WithValue(ctx, k, v) | ||
}) | ||
h.ServeHTTP(rw, req.WithContext(ctx)) | ||
body := c.Response.Body() | ||
// From net/http.ResponseWriter.Write: | ||
// If the Header does not contain a Content-Type line, Write adds a Content-Type set | ||
// to the result of passing the initial 512 bytes of written data to DetectContentType. | ||
if len(c.GetHeader(consts.HeaderContentType)) == 0 { | ||
l := 512 | ||
if len(body) < 512 { | ||
l = len(body) | ||
} | ||
c.Response.Header.Set(consts.HeaderContentType, http.DetectContentType(body[:l])) | ||
} | ||
} | ||
} |
Oops, something went wrong.