Skip to content

Commit

Permalink
chore(examples): update Go pprof migration example (#3768)
Browse files Browse the repository at this point in the history
  • Loading branch information
kolesnikovae authored Dec 12, 2024
1 parent 3c176a3 commit 8264c00
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 24 deletions.
18 changes: 18 additions & 0 deletions docs/sources/configure-client/language-sdks/go_push.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
@@ -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)
<img width="1426" alt="image" src="https://github.com/grafana/pyroscope/assets/23323466/f094399a-4a4d-4b47-9f03-5a15b4085fab">

## Changes made
Expand All @@ -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

Expand All @@ -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.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package main

import (
"fmt"
"net/http"
"log"
"os"
"runtime"
"sync"
Expand Down Expand Up @@ -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: "<User>", // 900009
BasicAuthPassword: "<Password>", // glc_SAMPLEAPIKEY0000000000==
Logger: pyroscope.StandardLogger,
Tags: map[string]string{"hostname": os.Getenv("HOSTNAME")},
// BasicAuthUser: "<User>", // 900009
// BasicAuthPassword: "<Password>", // glc_SAMPLEAPIKEY0000000000==
Logger: pyroscope.StandardLogger,
Tags: map[string]string{"hostname": os.Getenv("HOSTNAME")},
ProfileTypes: []pyroscope.ProfileType{
pyroscope.ProfileCPU,
pyroscope.ProfileAllocObjects,
Expand All @@ -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)
Expand Down

0 comments on commit 8264c00

Please sign in to comment.