Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Expose pprof endpoints in debug mode #2503

Merged
merged 6 commits into from
Oct 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
```
Loading