Skip to content

Commit 26b910a

Browse files
authored
add pprof memory analysis and make it configurable (#1787)
* add pprof configurable * fix build
1 parent 5f4873a commit 26b910a

File tree

4 files changed

+78
-7
lines changed

4 files changed

+78
-7
lines changed

backend/bootstrap/main.go

+73
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,19 @@ package bootstrap
22

33
import (
44
"embed"
5+
"fmt"
56
"github.com/diggerhq/digger/backend/config"
67
"github.com/diggerhq/digger/backend/segment"
8+
pprof_gin "github.com/gin-contrib/pprof"
79
"html/template"
810
"io/fs"
911
"log"
1012
"net/http"
1113
"os"
14+
"path/filepath"
15+
"runtime"
16+
"runtime/pprof"
17+
1218
"time"
1319

1420
"github.com/diggerhq/digger/backend/controllers"
@@ -24,6 +30,68 @@ import (
2430
// based on https://www.digitalocean.com/community/tutorials/using-ldflags-to-set-version-information-for-go-applications
2531
var Version = "dev"
2632

33+
func setupProfiler(r *gin.Engine) {
34+
// Enable pprof endpoints
35+
pprof_gin.Register(r)
36+
37+
// Create profiles directory if it doesn't exist
38+
if err := os.MkdirAll("/tmp/profiles", 0755); err != nil {
39+
log.Fatalf("Failed to create profiles directory: %v", err)
40+
}
41+
42+
// Start periodic profiling goroutine
43+
go periodicProfiling()
44+
}
45+
46+
func periodicProfiling() {
47+
ticker := time.NewTicker(1 * time.Hour)
48+
defer ticker.Stop()
49+
50+
for {
51+
select {
52+
case <-ticker.C:
53+
// Trigger GC before taking memory profile
54+
runtime.GC()
55+
56+
// Create memory profile
57+
timestamp := time.Now().Format("2006-01-02-15-04-05")
58+
memProfilePath := filepath.Join("/tmp/profiles", fmt.Sprintf("memory-%s.pprof", timestamp))
59+
f, err := os.Create(memProfilePath)
60+
if err != nil {
61+
log.Printf("Failed to create memory profile: %v", err)
62+
continue
63+
}
64+
65+
if err := pprof.WriteHeapProfile(f); err != nil {
66+
log.Printf("Failed to write memory profile: %v", err)
67+
}
68+
f.Close()
69+
70+
// Cleanup old profiles (keep last 24)
71+
cleanupOldProfiles("/tmp/profiles", 168)
72+
}
73+
}
74+
}
75+
76+
func cleanupOldProfiles(dir string, keep int) {
77+
files, err := filepath.Glob(filepath.Join(dir, "memory-*.pprof"))
78+
if err != nil {
79+
log.Printf("Failed to list profile files: %v", err)
80+
return
81+
}
82+
83+
if len(files) <= keep {
84+
return
85+
}
86+
87+
// Sort files by name (which includes timestamp)
88+
for i := 0; i < len(files)-keep; i++ {
89+
if err := os.Remove(files[i]); err != nil {
90+
log.Printf("Failed to remove old profile %s: %v", files[i], err)
91+
}
92+
}
93+
}
94+
2795
func Bootstrap(templates embed.FS, diggerController controllers.DiggerController) *gin.Engine {
2896
defer segment.CloseClient()
2997
initLogging()
@@ -46,6 +114,11 @@ func Bootstrap(templates embed.FS, diggerController controllers.DiggerController
46114
models.ConnectDatabase()
47115

48116
r := gin.Default()
117+
118+
if _, exists := os.LookupEnv("DIGGER_PPROF_DEBUG_ENABLED"); exists {
119+
setupProfiler(r)
120+
}
121+
49122
// TODO: check "secret"
50123
store := gormsessions.NewStore(models.DB.GormDB, true, []byte("secret"))
51124

backend/go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ require (
1414
github.com/diggerhq/digger/libs v0.4.15
1515
github.com/dominikbraun/graph v0.23.0
1616
github.com/getsentry/sentry-go v0.28.0
17+
github.com/gin-contrib/pprof v1.5.0
1718
github.com/gin-contrib/sessions v1.0.1
1819
github.com/gin-gonic/gin v1.10.0
1920
github.com/go-git/go-git/v5 v5.12.0
@@ -113,7 +114,6 @@ require (
113114
github.com/creack/pty v1.1.17 // indirect
114115
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
115116
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
116-
github.com/diggerhq/digger/cli v0.0.0-20240705091808-75187a7aae8e // indirect
117117
github.com/dimchansky/utfbom v1.1.1 // indirect
118118
github.com/dineshba/tf-summarize v0.3.10 // indirect
119119
github.com/emirpasic/gods v1.18.1 // indirect

backend/go.sum

+2-4
Original file line numberDiff line numberDiff line change
@@ -297,8 +297,6 @@ github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7l
297297
github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
298298
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
299299
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
300-
github.com/alecthomas/kong v0.7.1 h1:azoTh0IOfwlAX3qN9sHWTxACE2oV8Bg2gAwBsMwDQY4=
301-
github.com/alecthomas/kong v0.7.1/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U=
302300
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
303301
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
304302
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -486,8 +484,6 @@ github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkz
486484
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
487485
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g=
488486
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
489-
github.com/diggerhq/digger/cli v0.0.0-20240705091808-75187a7aae8e h1:aRBJ92ZbJc6VQXx6zPihHuQoDotstDTwUi3C8gdbdgw=
490-
github.com/diggerhq/digger/cli v0.0.0-20240705091808-75187a7aae8e/go.mod h1:+UUif/7rqA5ElbNiYXyu6adjpXcafe5nSrY+IvFoJVA=
491487
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
492488
github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
493489
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
@@ -553,6 +549,8 @@ github.com/getsentry/sentry-go v0.28.0 h1:7Rqx9M3ythTKy2J6uZLHmc8Sz9OGgIlseuO1iB
553549
github.com/getsentry/sentry-go v0.28.0/go.mod h1:1fQZ+7l7eeJ3wYi82q5Hg8GqAPgefRq+FP/QhafYVgg=
554550
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
555551
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
552+
github.com/gin-contrib/pprof v1.5.0 h1:E/Oy7g+kNw94KfdCy3bZxQFtyDnAX2V7axRS7sNYVrU=
553+
github.com/gin-contrib/pprof v1.5.0/go.mod h1:GqFL6LerKoCQ/RSWnkYczkTJ+tOAUVN/8sbnEtaqOKs=
556554
github.com/gin-contrib/sessions v1.0.1 h1:3hsJyNs7v7N8OtelFmYXFrulAf6zSR7nW/putcPEHxI=
557555
github.com/gin-contrib/sessions v1.0.1/go.mod h1:ouxSFM24/OgIud5MJYQJLpy6AwxQ5EYO9yLhbtObGkM=
558556
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=

go.work.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,8 @@ github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbf
512512
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
513513
github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY=
514514
github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
515+
github.com/alecthomas/kong v0.7.1 h1:azoTh0IOfwlAX3qN9sHWTxACE2oV8Bg2gAwBsMwDQY4=
516+
github.com/alecthomas/kong v0.7.1/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U=
515517
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
516518
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
517519
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
@@ -1120,8 +1122,6 @@ github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXY
11201122
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
11211123
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
11221124
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
1123-
github.com/slack-go/slack v0.10.3 h1:kKYwlKY73AfSrtAk9UHWCXXfitudkDztNI9GYBviLxw=
1124-
github.com/slack-go/slack v0.10.3/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw=
11251125
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
11261126
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a h1:JSvGDIbmil4Ui/dDdFBExb7/cmkNjyX5F97oglmvCDo=
11271127
github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=

0 commit comments

Comments
 (0)