Skip to content

Commit

Permalink
add pprof profiller for debugging (#114)
Browse files Browse the repository at this point in the history
* feat: add pprof profiller for debugging

* feat: load profiller on a more generic way

* fix: lint issues

* feat: adding docs

* feat: adding some extra lines about performance
  • Loading branch information
emmanuelm41 committed Apr 12, 2024
1 parent ecca9f3 commit c4ca66b
Show file tree
Hide file tree
Showing 2 changed files with 202 additions and 0 deletions.
111 changes: 111 additions & 0 deletions pkg/zprofiller/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# ZProfiller

## Overview

`zprofiller` is a Go package designed to facilitate the integration of Go's built-in `pprof` profiling into web applications using the Chi router. It offers a structured way to expose profiling endpoints to monitor and analyze the performance of Go applications in both development and production environments.

## Features

- **Easy Integration**: Seamlessly integrates with the Chi router.
- **Automatic Profiling Endpoints**: Automatically registers standard `pprof` endpoints.
- **Custom Configuration**: Allows customization of server timeouts and logging.

## Getting Started

### Installation

To use `zprofiller` in your project, ensure you have Go installed and your workspace is set up, then add `zprofiller` to your dependencies:

```
go get -u github.com/zondax/zprofiller
```

### Integration

Integrate `zprofiller` into your Go application:

1. **Import the Package**

```go
import (
"github.com/zondax/zprofiller"
)
```

2. **Create a Config Object**

```go
config := &zprofiller.Config{
ReadTimeOut: 5 * time.Second,
WriteTimeOut: 5 * time.Second,
Logger: logger.NewLogger(),
}
```

3. **Instantiate zprofiller**

```go
profiler := zprofiller.New(nil, config)
```

4. **Run the Profiler**

```go
err := profiler.Run(":9999")
if err != nil {
log.Fatalf("Failed to start profiler: %v", err)
}
```

### Usage

Access the profiling endpoints at `http://localhost:<port>/debug/pprof/`, where `<port>` is the port you specified.

## Viewing pprof Results on the Web

### Accessing pprof via Web Browser

Navigate to:

```
http://localhost:<port>/debug/pprof/
```

This index page links to profiles like Heap, Goroutine, Threadcreate, Block, and Mutex.

### Visualizing Profiles

Use tools like `Go Tool Pprof` or `Graphviz` for deeper analysis:

- **Go Tool Pprof**:

```
go tool pprof -http=:8081 http://localhost:<port>/debug/pprof/profile
```

This command downloads the CPU profile data from your application and opens it in an interactive web interface on `http://localhost:8081`.

- **Graphviz**:

```
sudo apt-get install graphviz
go tool pprof -http=:8081 --graph http://localhost:<port>/debug/pprof/profile
```

### Online Tools and Extensions

Consider using online tools or browser extensions like **pprof++** for Chrome for in-browser visualization of pprof data.

## Performance Considerations

When integrating profiling tools such as `pprof` into your application, it is essential to consider the potential impact on performance:

- **Resource Usage**: Profiling operations can consume significant CPU and memory resources, particularly when capturing and analyzing high-frequency data such as CPU profiles.
- **Production Use**: While `pprof` can be invaluable for diagnosing issues in production, it should be enabled selectively. Consider using environment variables or configuration files to control access to profiling endpoints.
- **Sampling Rate**: Adjust the sampling rate of profiles according to the performance impact and the level of detail required. Lower rates can reduce overhead but may miss critical details.
- **Security**: Exposing profiling information can introduce security risks. Ensure that profiling endpoints are protected with authentication mechanisms and are only accessible by authorized personnel.
- **Impact Measurement**: Continuously monitor the impact of enabling profiling on your system’s response times and resource usage. Disable profiling when not needed to avoid unnecessary overhead.

## Security Considerations

Ensure that access to profiling endpoints is secured, especially in production environments, to protect sensitive application data.
91 changes: 91 additions & 0 deletions pkg/zprofiller/zprofiller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package zprofiller

import (
"fmt"
"github.com/go-chi/chi/v5"
"github.com/zondax/golem/pkg/logger"
"github.com/zondax/golem/pkg/metrics"
"net/http"
"net/http/pprof"
pprofRuntime "runtime/pprof"
"time"
)

const (
defaultAddress = ":8888"
defaultTimeOut = 240000
)

type Config struct {
ReadTimeOut time.Duration
WriteTimeOut time.Duration
Logger *logger.Logger
}

type zprofiller struct {
router *chi.Mux
config *Config
}

type ZProfiller interface {
Run(addr ...string) error
}

func (c *Config) setDefaultValues() {
if c.ReadTimeOut == 0 {
c.ReadTimeOut = time.Duration(defaultTimeOut) * time.Millisecond
}

if c.WriteTimeOut == 0 {
c.WriteTimeOut = time.Duration(defaultTimeOut) * time.Millisecond
}

if c.Logger == nil {
l := logger.NewLogger()
c.Logger = l
}
}

func New(_ metrics.TaskMetrics, config *Config) ZProfiller {
if config == nil {
config = &Config{}
}

config.setDefaultValues()

router := chi.NewRouter()
router.HandleFunc("/debug/pprof/", pprof.Index)
router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
router.HandleFunc("/debug/pprof/profile", pprof.Profile)
router.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
router.HandleFunc("/debug/pprof/trace", pprof.Trace)

for _, profile := range pprofRuntime.Profiles() {
router.Handle(fmt.Sprintf("/debug/pprof/%s", profile.Name()), pprof.Handler(profile.Name()))
}

zr := &zprofiller{
router: router,
config: config,
}

return zr
}

func (r *zprofiller) Run(addr ...string) error {
address := defaultAddress
if len(addr) > 0 {
address = addr[0]
}

r.config.Logger.Infof("Start profiller server at %v", address)

server := &http.Server{
Addr: address,
Handler: r.router,
ReadTimeout: r.config.ReadTimeOut,
WriteTimeout: r.config.WriteTimeOut,
}

return server.ListenAndServe()
}

0 comments on commit c4ca66b

Please sign in to comment.