Skip to content

Commit

Permalink
feat: Expose pprof endpoints in debug mode (#2503)
Browse files Browse the repository at this point in the history
* feat: Expose pprof endpoints in debug mode

* Adding documentation

* fix linter issue

* Change port

---------

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
thomaspoignant and kodiakhq[bot] authored Oct 12, 2024
1 parent 5915e35 commit 2613710
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 2 deletions.
5 changes: 5 additions & 0 deletions cmd/relayproxy/api/routes_monitoring.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package api

import (
"github.com/labstack/echo-contrib/echoprometheus"
"github.com/labstack/echo-contrib/pprof"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
custommiddleware "github.com/thomaspoignant/go-feature-flag/cmd/relayproxy/api/middleware"
Expand Down Expand Up @@ -39,4 +40,8 @@ func (s *Server) initMonitoringEndpoint(echoInstance *echo.Echo) {
// health Routes
echoInstance.GET("/health", cHealth.Handler)
echoInstance.GET("/info", cInfo.Handler)

if s.config.Debug {
pprof.Register(echoInstance)
}
}
79 changes: 79 additions & 0 deletions cmd/relayproxy/api/routes_monitoring_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package api_test

import (
"fmt"
"net/http"
"testing"

"github.com/stretchr/testify/require"
"github.com/thomaspoignant/go-feature-flag/cmd/relayproxy/api"
"github.com/thomaspoignant/go-feature-flag/cmd/relayproxy/config"
"github.com/thomaspoignant/go-feature-flag/cmd/relayproxy/metric"
"github.com/thomaspoignant/go-feature-flag/cmd/relayproxy/service"
"github.com/thomaspoignant/go-feature-flag/notifier"
"go.uber.org/zap"
)

func TestPprofEndpointsStarts(t *testing.T) {
type test struct {
name string
MonitoringPort int
Debug bool
expectedStatusCode int
}
tests := []test{
{
name: "pprof available in proxy port",
Debug: true,
expectedStatusCode: http.StatusOK,
},
{
name: "pprof available in monitoring port",
Debug: true,
MonitoringPort: 1032,
expectedStatusCode: http.StatusOK,
},
{
name: "pprof not available ii debug not enabled",
Debug: false,
MonitoringPort: 1032,
expectedStatusCode: http.StatusNotFound,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
z, err := zap.NewProduction()
require.NoError(t, err)
c := &config.Config{
Retriever: &config.RetrieverConf{
Kind: "file",
Path: "../../../testdata/flag-config.yaml",
},
MonitoringPort: tt.MonitoringPort,
ListenPort: 1031,
Debug: tt.Debug,
}

goff, err := service.NewGoFeatureFlagClient(c, z, []notifier.Notifier{})
require.NoError(t, err)
apiServer := api.New(c, service.Services{
MonitoringService: service.NewMonitoring(goff),
WebsocketService: service.NewWebsocketService(),
GOFeatureFlagService: goff,
Metrics: metric.Metrics{},
}, z)

portToCheck := c.ListenPort
if tt.MonitoringPort != 0 {
portToCheck = tt.MonitoringPort
}

go apiServer.Start()
defer apiServer.Stop()
resp, err := http.Get(fmt.Sprintf("http://localhost:%d/debug/pprof/heap", portToCheck))
require.NoError(t, err)
require.Equal(t, tt.expectedStatusCode, resp.StatusCode)
})
}
}
4 changes: 3 additions & 1 deletion cmd/relayproxy/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,9 @@ type Config struct {
// HideBanner (optional) if true, we don't display the go-feature-flag relay proxy banner
HideBanner bool `mapstructure:"hideBanner" koanf:"hidebanner"`

// Debug (optional) if true, go-feature-flag relay proxy will run on debug mode, with more logs and custom responses
// Debug (optional) if true, go-feature-flag relay proxy will run on debug mode, with more logs and custom responses.
// It will also start the pprof endpoints on the same port as the monitoring.
// Default: false
Debug bool `mapstructure:"debug" koanf:"debug"`

// EnableSwagger (optional) to have access to the swagger
Expand Down
20 changes: 20 additions & 0 deletions cmd/relayproxy/docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,26 @@ const docTemplate = `{
}
}
},
"/debug/pprof/": {
"get": {
"description": "This endpoint is provided by the echo pprof middleware.\nTo know more please check this blogpost from the GO team https://go.dev/blog/pprof.\nVisit the page /debug/pprof/ to see the available endpoints, all endpoint are not in the swagger documentation because they are standard pprof endpoints.\nThis endpoint is only available in debug mode.",
"produces": [
"text/plain"
],
"tags": [
"Profiling"
],
"summary": "pprof endpoint",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
}
}
}
},
"/health": {
"get": {
"description": "Making a **GET** request to the URL path ` + "`" + `/health` + "`" + ` will tell you if the relay proxy is ready to serve\ntraffic.\n\nThis is useful especially for loadbalancer to know that they can send traffic to the service.",
Expand Down
20 changes: 20 additions & 0 deletions cmd/relayproxy/docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,26 @@
}
}
},
"/debug/pprof/": {
"get": {
"description": "This endpoint is provided by the echo pprof middleware.\nTo know more please check this blogpost from the GO team https://go.dev/blog/pprof.\nVisit the page /debug/pprof/ to see the available endpoints, all endpoint are not in the swagger documentation because they are standard pprof endpoints.\nThis endpoint is only available in debug mode.",
"produces": [
"text/plain"
],
"tags": [
"Profiling"
],
"summary": "pprof endpoint",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
}
}
}
},
"/health": {
"get": {
"description": "Making a **GET** request to the URL path `/health` will tell you if the relay proxy is ready to serve\ntraffic.\n\nThis is useful especially for loadbalancer to know that they can send traffic to the service.",
Expand Down
17 changes: 17 additions & 0 deletions cmd/relayproxy/docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,23 @@ paths:
summary: This endpoint is used to force the refresh of the flags in the cache.
tags:
- Admin API to manage GO Feature Flag
/debug/pprof/:
get:
description: |-
This endpoint is provided by the echo pprof middleware.
To know more please check this blogpost from the GO team https://go.dev/blog/pprof.
Visit the page /debug/pprof/ to see the available endpoints, all endpoint are not in the swagger documentation because they are standard pprof endpoints.
This endpoint is only available in debug mode.
produces:
- text/plain
responses:
"200":
description: OK
schema:
type: string
summary: pprof endpoint
tags:
- Profiling
/health:
get:
description: |-
Expand Down
2 changes: 1 addition & 1 deletion cmd/relayproxy/modeldocs/metricsController.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package modeldocs

import "github.com/labstack/echo/v4"

// FakeMetricsController is the entry point for the allFlags endpoint
// FakeMetricsController is a fake entry point for swagger documentation
//
// @Summary Prometheus endpoint
// @Tags Monitoring
Expand Down
19 changes: 19 additions & 0 deletions cmd/relayproxy/modeldocs/pprofController.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// nolint: lll
package modeldocs

import "github.com/labstack/echo/v4"

// FakePprofController is a fake endpoint for swagger documentation of pprof endpoint
//
// @Summary pprof endpoint
// @Tags Profiling
// @Description This endpoint is provided by the echo pprof middleware.
// @Description To know more please check this blogpost from the GO team https://go.dev/blog/pprof.
// @Description Visit the page /debug/pprof/ to see the available endpoints, all endpoint are not in the swagger documentation because they are standard pprof endpoints.
// @Description This endpoint is only available in debug mode.
// @Produce plain
// @Success 200 {object} string
// @Router /debug/pprof/ [get]
func FakePprofController(_ echo.Context) {
// This is a fake controller, the real entry point is provided by the prometheus middleware.
}
32 changes: 32 additions & 0 deletions website/docs/relay_proxy/profiling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
sidebar_position: 81
title: Profiling
description: Profiling of the relay proxy.
---

## Profiling

The **relay proxy** is able to expose profiling information.
This is useful to understand the performance of the service and solve potential issues.

The information are exposed on the `/debug/pprof` endpoint, and we are using the default `net/http/pprof` package
to expose the information.

:::warning
By default the profiling endpoints are disabled.
You have to run the relay proxy in debug mode if you want to enable them.
:::

List of endpoints exposed is available http://localhost:1031/debug/pprof/

### Enable profiling

In your relay proxy configuration file you need to set the `debug` field to `true`.

```yaml {5}
retriever:
kind: file
path: /goff/flags.yaml # Location of your feature flag files
# ...
debug: true
```

0 comments on commit 2613710

Please sign in to comment.