Skip to content

Commit 05c338e

Browse files
authored
feat: support to get pprof of an extension (#307)
Co-authored-by: rick <[email protected]>
1 parent 8e34dba commit 05c338e

File tree

21 files changed

+725
-230
lines changed

21 files changed

+725
-230
lines changed

cmd/server.go

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import (
5858
"golang.org/x/oauth2"
5959
"google.golang.org/grpc"
6060
"google.golang.org/grpc/credentials/insecure"
61+
"google.golang.org/grpc/metadata"
6162
"google.golang.org/grpc/reflection"
6263
)
6364

@@ -275,7 +276,7 @@ func (o *serverOption) runE(cmd *cobra.Command, args []string) (err error) {
275276
promhttp.HandlerFor(reg, promhttp.HandlerOpts{Registry: reg}).ServeHTTP(w, r)
276277
})
277278

278-
debugHandler(mux)
279+
debugHandler(mux, remoteServer)
279280
o.httpServer.WithHandler(mux)
280281
log.Printf("HTTP server listening at %v", httplis.Addr())
281282
log.Printf("Server is running.")
@@ -346,9 +347,32 @@ func frontEndHandlerWithLocation(consolePath string) func(w http.ResponseWriter,
346347
}
347348
}
348349

349-
func debugHandler(mux *runtime.ServeMux) {
350+
func debugHandler(mux *runtime.ServeMux, remoteServer server.RunnerServer) {
350351
mux.HandlePath(http.MethodGet, "/debug/pprof/{sub}", func(w http.ResponseWriter, r *http.Request, pathParams map[string]string) {
351-
switch sub := pathParams["sub"]; sub {
352+
sub := pathParams["sub"]
353+
extName := r.URL.Query().Get("name")
354+
if extName != "" && remoteServer != nil {
355+
log.Println("get pprof of extension:", extName)
356+
357+
ctx := metadata.NewIncomingContext(r.Context(), metadata.New(map[string]string{
358+
server.HeaderKeyStoreName: extName,
359+
}))
360+
361+
data, err := remoteServer.PProf(ctx, &server.PProfRequest{
362+
Name: sub,
363+
})
364+
if err == nil {
365+
w.Header().Set("Content-Type", "application/octet-stream")
366+
w.Write(data.Data)
367+
} else {
368+
w.WriteHeader(http.StatusBadRequest)
369+
w.Write([]byte(err.Error()))
370+
}
371+
372+
return
373+
}
374+
375+
switch sub {
352376
case "cmdline":
353377
pprof.Cmdline(w, r)
354378
case "profile":

cmd/server_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ func TestFrontEndHandlerWithLocation(t *testing.T) {
132132
"allocs", "block", "goroutine", "heap", "mutex", "threadcreate"}
133133

134134
mu := runtime.NewServeMux()
135-
debugHandler(mu)
135+
debugHandler(mu, nil)
136136

137137
ready := make(chan struct{})
138138
var err error

extensions/store-etcd/pkg/server.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"log"
3131
"time"
3232

33+
"github.com/linuxsuren/api-testing/pkg/extension"
3334
"github.com/linuxsuren/api-testing/pkg/server"
3435
"github.com/linuxsuren/api-testing/pkg/testing"
3536
"github.com/linuxsuren/api-testing/pkg/testing/remote"
@@ -263,6 +264,14 @@ func (s *remoteserver) Verify(ctx context.Context, in *server.Empty) (reply *ser
263264
}
264265
return
265266
}
267+
func (s *remoteserver) PProf(ctx context.Context, in *server.PProfRequest) (data *server.PProfData, err error) {
268+
log.Println("pprof", in.Name)
269+
270+
data = &server.PProfData{
271+
Data: extension.LoadPProf(in.Name),
272+
}
273+
return
274+
}
266275

267276
func connectTestOption() []clientv3.OpOption {
268277
return []clientv3.OpOption{clientv3.WithLimit(1), clientv3.WithPrefix(),

extensions/store-git/pkg/server.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import (
3939
"github.com/go-git/go-git/v5/plumbing"
4040
"github.com/go-git/go-git/v5/plumbing/object"
4141
"github.com/go-git/go-git/v5/plumbing/transport/http"
42+
"github.com/linuxsuren/api-testing/pkg/extension"
4243
"github.com/linuxsuren/api-testing/pkg/server"
4344
"github.com/linuxsuren/api-testing/pkg/testing"
4445
"github.com/linuxsuren/api-testing/pkg/testing/remote"
@@ -268,6 +269,14 @@ func (s *gitClient) Verify(ctx context.Context, in *server.Empty) (reply *server
268269
}
269270
return
270271
}
272+
func (s *gitClient) PProf(ctx context.Context, in *server.PProfRequest) (data *server.PProfData, err error) {
273+
log.Println("pprof", in.Name)
274+
275+
data = &server.PProfData{
276+
Data: extension.LoadPProf(in.Name),
277+
}
278+
return
279+
}
271280
func (s *gitClient) getClient(ctx context.Context) (opt *gitOptions, err error) {
272281
store := remote.GetStoreFromContext(ctx)
273282
if store == nil {

extensions/store-mongodb/pkg/server.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ package pkg
2626

2727
import (
2828
"context"
29+
"log"
2930

31+
"github.com/linuxsuren/api-testing/pkg/extension"
3032
"github.com/linuxsuren/api-testing/pkg/server"
3133
"github.com/linuxsuren/api-testing/pkg/testing"
3234
"github.com/linuxsuren/api-testing/pkg/testing/remote"
@@ -265,6 +267,14 @@ func (s *dbserver) Verify(ctx context.Context, in *server.Empty) (reply *server.
265267
}
266268
return
267269
}
270+
func (s *dbserver) PProf(ctx context.Context, in *server.PProfRequest) (data *server.PProfData, err error) {
271+
log.Println("pprof", in.Name)
272+
273+
data = &server.PProfData{
274+
Data: extension.LoadPProf(in.Name),
275+
}
276+
return
277+
}
268278

269279
type SuiteNameGetter interface {
270280
GetSuiteName() string

extensions/store-orm/pkg/server.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"log"
3232
"strings"
3333

34+
"github.com/linuxsuren/api-testing/pkg/extension"
3435
"github.com/linuxsuren/api-testing/pkg/server"
3536
"github.com/linuxsuren/api-testing/pkg/testing/remote"
3637
"github.com/linuxsuren/api-testing/pkg/util"
@@ -268,6 +269,14 @@ func (s *dbserver) Verify(ctx context.Context, in *server.Empty) (reply *server.
268269
}
269270
return
270271
}
272+
func (s *dbserver) PProf(ctx context.Context, in *server.PProfRequest) (data *server.PProfData, err error) {
273+
log.Println("pprof", in.Name)
274+
275+
data = &server.PProfData{
276+
Data: extension.LoadPProf(in.Name),
277+
}
278+
return
279+
}
271280

272281
func testCaseIdentiy(db *gorm.DB, testcase *TestCase) *gorm.DB {
273282
return db.Model(testcase).Where(fmt.Sprintf("suite_name = '%s' AND name = '%s'", testcase.SuiteName, testcase.Name))

extensions/store-s3/pkg/s3_server.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"github.com/aws/aws-sdk-go/aws/credentials"
3636
"github.com/aws/aws-sdk-go/aws/session"
3737
"github.com/aws/aws-sdk-go/service/s3"
38+
"github.com/linuxsuren/api-testing/pkg/extension"
3839
"github.com/linuxsuren/api-testing/pkg/server"
3940
"github.com/linuxsuren/api-testing/pkg/testing"
4041
"github.com/linuxsuren/api-testing/pkg/testing/remote"
@@ -205,6 +206,14 @@ func (s *s3Client) Verify(ctx context.Context, in *server.Empty) (reply *server.
205206
}
206207
return
207208
}
209+
func (s *s3Client) PProf(ctx context.Context, in *server.PProfRequest) (data *server.PProfData, err error) {
210+
log.Println("pprof", in.Name)
211+
212+
data = &server.PProfData{
213+
Data: extension.LoadPProf(in.Name),
214+
}
215+
return
216+
}
208217
func (s *s3Client) getClient(ctx context.Context) (db *s3WithBucket, err error) {
209218
store := remote.GetStoreFromContext(ctx)
210219
if store == nil {

pkg/extension/pprof.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
MIT License
3+
4+
Copyright (c) 2023 API Testing Authors.
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in all
14+
copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
SOFTWARE.
23+
*/
24+
25+
package extension
26+
27+
import (
28+
"bytes"
29+
"runtime/pprof"
30+
)
31+
32+
func LoadPProf(name string) []byte {
33+
buf := new(bytes.Buffer)
34+
if p := pprof.Lookup(name); p != nil {
35+
p.WriteTo(buf, 0)
36+
}
37+
return buf.Bytes()
38+
}

pkg/server/remote_server.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ func (s *server) getLoader(ctx context.Context) (loader testing.Writer) {
180180
if mdd, ok = metadata.FromIncomingContext(ctx); ok {
181181
storeNameMeta := mdd.Get(HeaderKeyStoreName)
182182
if len(storeNameMeta) > 0 {
183-
storeName := storeNameMeta[0]
183+
storeName := strings.TrimSpace(storeNameMeta[0])
184184
if storeName == "local" || storeName == "" {
185185
return
186186
}
@@ -813,6 +813,13 @@ func (s *server) DeleteSecret(ctx context.Context, in *Secret) (reply *CommonRes
813813
func (s *server) UpdateSecret(ctx context.Context, in *Secret) (reply *CommonResult, err error) {
814814
return s.secretServer.UpdateSecret(ctx, in)
815815
}
816+
func (s *server) PProf(ctx context.Context, in *PProfRequest) (reply *PProfData, err error) {
817+
loader := s.getLoader(ctx)
818+
reply = &PProfData{
819+
Data: loader.PProf(in.Name),
820+
}
821+
return
822+
}
816823

817824
func (s *server) getLoaderByStoreName(storeName string) (loader testing.Writer, err error) {
818825
var store *testing.Store

0 commit comments

Comments
 (0)