From 6ec883a7fd40a14f2882076bd1a377bbbd0438ad Mon Sep 17 00:00:00 2001 From: Martin Kagamino Lehoux Date: Thu, 27 Aug 2026 13:06:20 +0200 Subject: Add local Pyroscope server and Go continuous profiling Add a docker-compose service running the Grafana Pyroscope backend on port 4040 with a persistent data volume, and instrument the Go app via github.com/grafana/pyroscope-go. The app pushes CPU, memory, and goroutine profiles every 10s when pyroscope.enabled is set in config.yaml. Config is extended with application_name and server_address (defaults to http://localhost:4040). Document usage in the README. --- main.go | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'main.go') diff --git a/main.go b/main.go index 4404acf..8971433 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,9 @@ package main import ( "database/sql" "flag" + "log/slog" + "github.com/grafana/pyroscope-go" "github.com/martinlehoux/biking_home/cli" "github.com/martinlehoux/biking_home/config" "github.com/martinlehoux/kagamigo/kcore" @@ -18,8 +20,42 @@ func main() { flag.Parse() appConfig, err := config.Load(*configFile) kcore.Expect(err, "failed to load configuration") + stopProfiler, err := startPyroscope(appConfig.Pyroscope) + if err != nil { + kcore.Expect(err, "failed to start pyroscope") + } + if stopProfiler != nil { + defer stopProfiler() + } db, err := sql.Open("sqlite3", appConfig.Database.Path) kcore.Expect(err, "failed to open database") defer db.Close() cli.Run(db, *configFile, appConfig) } + +// startPyroscope starts the continuous profiler when enabled in the config and +// returns a stop function to flush and detach the profiler on shutdown, or nil +// when pyroscope is disabled. +func startPyroscope(appConfig config.PyroscopeConfig) (func(), error) { + if !appConfig.Enabled { + return nil, nil + } + profiler, err := pyroscope.Start(pyroscope.Config{ + ApplicationName: appConfig.ApplicationName, + ServerAddress: appConfig.ServerAddress, + Logger: pyroscope.StandardLogger, + ProfileTypes: []pyroscope.ProfileType{ + pyroscope.ProfileCPU, + pyroscope.ProfileAllocSpace, + pyroscope.ProfileAllocObjects, + pyroscope.ProfileInuseSpace, + pyroscope.ProfileInuseObjects, + pyroscope.ProfileGoroutines, + }, + }) + if err != nil { + return nil, err + } + slog.Info("pyroscope enabled", "server", appConfig.ServerAddress, "application", appConfig.ApplicationName) + return func() { _ = profiler.Stop() }, nil +} -- cgit v1.3