From d32764eff2d75ee0564451c90c4be4cba788a854 Mon Sep 17 00:00:00 2001 From: Anton Kolesnikov Date: Thu, 12 Dec 2024 16:00:46 +0800 Subject: [PATCH 1/2] chore: update Go pprof migration example --- .../migrating-from-standard-pprof/README.md | 30 +++++++++++----- .../migrating-from-standard-pprof/main.go | 34 ++++++++++--------- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/examples/language-sdk-instrumentation/golang-push/migrating-from-standard-pprof/README.md b/examples/language-sdk-instrumentation/golang-push/migrating-from-standard-pprof/README.md index 113eea39dc..f5472c70ad 100644 --- a/examples/language-sdk-instrumentation/golang-push/migrating-from-standard-pprof/README.md +++ b/examples/language-sdk-instrumentation/golang-push/migrating-from-standard-pprof/README.md @@ -1,8 +1,9 @@ # Migrating from standard pprof to Pyroscope in a Go application -This README provides a comprehensive guide on migrating from the standard pprof library to Pyroscope in a Go application. The example demonstrates the transition within a detective-themed Go application, enhancing the process of profiling with Pyroscope's advanced capabilities. The actual changes needed to migrate from standard `pprof` to using the Pyroscope SDK is very simple (it extends the standard pprof library with extra functionality and performance improvements). If you would like to use standard `pprof` _algonside_ the pyroscope go sdk simultaneously see the [example here](https://github.com/grafana/pyroscope-go/tree/main/example/http). +This README provides a comprehensive guide on migrating from the standard `pprof` library to Pyroscope in a Go application. The example demonstrates the transition within a detective-themed Go application, showcasing how to enhance the profiling process with Pyroscope's advanced capabilities. The actual changes needed to migrate from the standard `pprof` to using [the Pyroscope SDK](https://grafana.com/docs/pyroscope/latest/configure-client/language-sdks/go_push/) are very simple. See [the source PR](https://github.com/grafana/pyroscope/pull/2830). + +The Pyroscope Go SDK extends the standard `pprof` library with extra functionality and performance improvements. If you would like to use the standard `pprof` _alongside_ the Pyroscope Go SDK simultaneously, see the [example here](https://github.com/grafana/pyroscope-go/tree/main/example/http). -See link to [source PR here](https://github.com/grafana/pyroscope/pull/2830) image ## Changes made @@ -16,13 +17,27 @@ Originally in the pre-pyroscope code, the `main.go` file used the standard `net/ In the post-pyroscope code, to leverage the advanced features of Pyroscope, we made the following changes: 1. **Removed Standard pprof Import:** The `_ "net/http/pprof"` import was removed, as Pyroscope replaces its functionality. -2. **Added Pyroscope SDK:** We installed the Pyroscope module using `go get github.com/grafana/pyroscope-go` and imported it in our `main.go`. -3. **Configured Pyroscope:** Inside the `main()` function, we set up Pyroscope using the `pyroscope.Start()` method with the following configuration: + + +2. **Added Pyroscope SDK:** We installed the Pyroscope module using the following command and imported it in our `main.go`: + +> go get github.com/grafana/pyroscope-go + +3. **Enabled block and mutex profilers:** This step is only required if you're using mutex or block profiling. Inside the `main()` function, we enabled the block and mutex profilers using the runtime functions: + +```go +runtime.SetMutexProfileFraction(5) +runtime.SetBlockProfileRate(5) +``` + +4. **Configured Pyroscope:** Inside the `main()` function, we set up Pyroscope using the `pyroscope.Start()` method with the following configuration: - Application name and server address. - Logger configuration. - Tags for additional metadata. - Profile types to be captured. -4. Consider using [godeltaprof](https://pkg.go.dev/github.com/grafana/pyroscope-go/godeltaprof) -- which is an optimized way to do memory profiling more efficiently + + +5. **Consider using [godeltaprof](https://pkg.go.dev/github.com/grafana/pyroscope-go/godeltaprof):** It provides an optimized way to perform memory, mutex, and block profiling more efficiently. ## Benefits of using Pyroscope @@ -35,9 +50,8 @@ In the post-pyroscope code, to leverage the advanced features of Pyroscope, we m ## Migration guide -To view the exact changes made during the migration, refer to our [pull request](https://github.com/grafana/pyroscope/pull/2830). This PR clearly illustrates the differences and necessary steps to transition from standard pprof to Pyroscope. +To view the exact changes made during the migration, refer to our [pull request](https://github.com/grafana/pyroscope/pull/2830). This PR clearly illustrates the differences and the necessary steps to transition from the standard `pprof` library to Pyroscope. ## Conclusion -Migrating to Pyroscope SDK in a Go application is a straightforward process that significantly enhances profiling capabilities. By following the steps outlined in this guide and reviewing the provided PR, developers can easily switch from standard pprof to Pyroscope, benefiting from real-time, continuous profiling and advanced performance insights. - +Migrating to the Pyroscope SDK in a Go application is a straightforward process that significantly enhances profiling capabilities. By following the steps outlined in this guide and reviewing the provided PR, developers can easily transition from the standard `pprof` library to Pyroscope, benefiting from real-time, continuous profiling and advanced performance insights. diff --git a/examples/language-sdk-instrumentation/golang-push/migrating-from-standard-pprof/main.go b/examples/language-sdk-instrumentation/golang-push/migrating-from-standard-pprof/main.go index 1e305c163f..d584c0a9a5 100644 --- a/examples/language-sdk-instrumentation/golang-push/migrating-from-standard-pprof/main.go +++ b/examples/language-sdk-instrumentation/golang-push/migrating-from-standard-pprof/main.go @@ -2,7 +2,7 @@ package main import ( "fmt" - "net/http" + "log" "os" "runtime" "sync" @@ -49,18 +49,19 @@ func solveMystery(wg *sync.WaitGroup) { } func main() { - // Pyroscope configuration + // These 2 lines are only required if you're using mutex or block profiling runtime.SetMutexProfileFraction(5) runtime.SetBlockProfileRate(5) - pyroscope.Start(pyroscope.Config{ + // Pyroscope configuration + profiler, err := pyroscope.Start(pyroscope.Config{ ApplicationName: "detective.mystery.app", - ServerAddress: "https://profiles-prod-001.grafana.net", // if OSS then http://localhost:4040 + ServerAddress: "https://profiles-prod-001.grafana.net", // If OSS, then "http://pyroscope.local:4040" // Optional HTTP Basic authentication - BasicAuthUser: "", // 900009 - BasicAuthPassword: "", // glc_SAMPLEAPIKEY0000000000== - Logger: pyroscope.StandardLogger, - Tags: map[string]string{"hostname": os.Getenv("HOSTNAME")}, + // BasicAuthUser: "", // 900009 + // BasicAuthPassword: "", // glc_SAMPLEAPIKEY0000000000== + Logger: pyroscope.StandardLogger, + Tags: map[string]string{"hostname": os.Getenv("HOSTNAME")}, ProfileTypes: []pyroscope.ProfileType{ pyroscope.ProfileCPU, pyroscope.ProfileAllocObjects, @@ -74,16 +75,17 @@ func main() { pyroscope.ProfileBlockDuration, }, }) + if err != nil { + log.Fatalf("Error starting profiler: %v", err) + } + defer profiler.Stop() - var wg sync.WaitGroup - - // Server for pprof - go func() { - fmt.Println(http.ListenAndServe("localhost:6060", nil)) - }() - wg.Add(1) // pprof - so we won't exit prematurely + // pyroscope.Start is non-blocking: the profiler will start shortly. + // To ensure we don't miss the investigation, we wait briefly. + time.Sleep(time.Second) - wg.Add(4) // Adding 4 detective tasks + var wg sync.WaitGroup + wg.Add(5) // Adding 5 detective tasks go gatherClues(&wg) go analyzeEvidence(&wg) go interviewWitnesses(&wg) From 8df97af884860ab5d7d985d9ad8a12f93234c71b Mon Sep 17 00:00:00 2001 From: Anton Kolesnikov Date: Thu, 12 Dec 2024 17:01:57 +0800 Subject: [PATCH 2/2] document Go profiler shutdown --- .../configure-client/language-sdks/go_push.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/sources/configure-client/language-sdks/go_push.md b/docs/sources/configure-client/language-sdks/go_push.md index cf77896d19..8d5b1553c2 100644 --- a/docs/sources/configure-client/language-sdks/go_push.md +++ b/docs/sources/configure-client/language-sdks/go_push.md @@ -85,6 +85,24 @@ func main() { } ``` +Alternatively, if you want more control over the profiling process, you can manually handle the profiler initialization and termination: + +```go + profiler, err := pyroscope.Start(pyroscope.Config{ + // omitted for brevity + }) + if err != nil { + // the only reason this would fail is if the configuration is not valid + log.Fatalf("failed to start Pyroscope: %v", err) + } + defer profiler.Stop() + + // your code goes here +} +``` + +This approach may be necessary if you need to ensure that the last profile is sent before the application exits. + ### Add profiling labels to your application You can add tags (labels) to the profiling data. These tags can be used to filter the data in the UI. There is a custom API that's in line with the go-native pprof API: