Skip to content

Commit

Permalink
Add pprof endpoints to the monitoring server if enabled (#5562)
Browse files Browse the repository at this point in the history
The documentation claims this should work, but it currently doesn't.
  • Loading branch information
swiatekm authored Sep 24, 2024
1 parent 116848c commit 8e31a5d
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 10 deletions.
32 changes: 32 additions & 0 deletions changelog/fragments/1726740792-pprof-endpoint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Kind can be one of:
# - breaking-change: a change to previously-documented behavior
# - deprecation: functionality that is being removed in a later release
# - bug-fix: fixes a problem in a previous version
# - enhancement: extends functionality but does not break or fix existing behavior
# - feature: new functionality
# - known-issue: problems that we are aware of in a given version
# - security: impacts on the security of a product or a user’s deployment.
# - upgrade: important information for someone upgrading from a prior version
# - other: does not fit into any of the other categories
kind: bug-fix

# Change summary; a 80ish characters long description of the change.
summary: Add pprof endpoints to the monitoring server if enabled

# Long description; in case the summary is not enough to describe the change
# this field accommodate a description without length limits.
# NOTE: This field will be rendered only for breaking-change and known-issue kinds at the moment.
#description:

# Affected component; usually one of "elastic-agent", "fleet-server", "filebeat", "metricbeat", "auditbeat", "all", etc.
component: elastic-agent

# PR URL; optional; the PR number that added the changeset.
# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added.
# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number.
# Please provide it if you are adding a fragment for a different PR.
#pr: https://github.com/owner/repo/1234

# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of).
# If not present is automatically filled by the tooling with the issue linked to the PR number.
#issue: https://github.com/owner/repo/1234
10 changes: 10 additions & 0 deletions internal/pkg/agent/application/monitoring/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package monitoring

import (
"net/http"
_ "net/http/pprof" //nolint:gosec // this is only conditionally exposed
"net/url"
"os"
"path/filepath"
Expand Down Expand Up @@ -76,6 +77,11 @@ func exposeMetricsEndpoint(
r.Handle("/liveness", createHandler(livenessHandler(coord)))
}

if isPprofEnabled(cfg) {
// importing net/http/pprof adds the handlers to the right paths on the default Mux, so we just defer to it here
r.PathPrefix("/debug/pprof/").Handler(http.DefaultServeMux)
}

mux := http.NewServeMux()
mux.Handle("/", r)

Expand Down Expand Up @@ -131,3 +137,7 @@ func isHttpUrl(s string) bool {
func isProcessStatsEnabled(cfg *monitoringCfg.MonitoringConfig) bool {
return cfg != nil && cfg.HTTP.Enabled
}

func isPprofEnabled(cfg *monitoringCfg.MonitoringConfig) bool {
return cfg != nil && cfg.Pprof != nil && cfg.Pprof.Enabled
}
47 changes: 37 additions & 10 deletions internal/pkg/agent/application/monitoring/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,18 +98,18 @@ func TestHTTPReloadEnableBehavior(t *testing.T) {
t.Logf("starting server...")
serverReloader.Start()
if testCase.httpOnAtInit {
waitOnReturnCode(t, http.StatusOK, "?failon=failed", serverReloader)
waitOnReturnCode(t, http.StatusOK, "liveness", "?failon=failed", serverReloader)
} else {
waitOnReturnCode(t, http.StatusNotFound, "?failon=failed", serverReloader)
waitOnReturnCode(t, http.StatusNotFound, "liveness", "?failon=failed", serverReloader)
}

err = serverReloader.Reload(testCase.secondConfig)
require.NoError(t, err)

if testCase.httpOnAfterReload {
waitOnReturnCode(t, http.StatusOK, "?failon=failed", serverReloader)
waitOnReturnCode(t, http.StatusOK, "liveness", "?failon=failed", serverReloader)
} else {
waitOnReturnCode(t, http.StatusNotFound, "?failon=failed", serverReloader)
waitOnReturnCode(t, http.StatusNotFound, "liveness", "?failon=failed", serverReloader)
}

})
Expand All @@ -132,24 +132,51 @@ func TestBasicLivenessConfig(t *testing.T) {
t.Logf("starting server...")
serverReloader.Start()

waitOnReturnCode(t, http.StatusInternalServerError, "?failon=degraded", serverReloader)
waitOnReturnCode(t, http.StatusInternalServerError, "liveness", "?failon=degraded", serverReloader)

waitOnReturnCode(t, http.StatusOK, "?failon=failed", serverReloader)
waitOnReturnCode(t, http.StatusOK, "liveness", "?failon=failed", serverReloader)

t.Logf("stopping server...")
err = serverReloader.Stop()
require.NoError(t, err)

}

func waitOnReturnCode(t *testing.T, expectedReturnCode int, formValue string, rel *reload.ServerReloader) {
func TestPprofEnabled(t *testing.T) {
_ = logp.DevelopmentSetup()
testAPIConfig := api.Config{}
testConfig := config.MonitoringConfig{
Enabled: true,
HTTP: &config.MonitoringHTTPConfig{
Enabled: true,
Port: 0,
},
Pprof: &config.PprofConfig{
Enabled: true,
},
}
serverReloader, err := NewServer(logp.L(), testAPIConfig, nil, nil, fakeCoordCfg, "linux", &testConfig)
require.NoError(t, err)

t.Logf("starting server...")
serverReloader.Start()

waitOnReturnCode(t, http.StatusOK, "debug/pprof/", "", serverReloader)

t.Logf("stopping server...")
err = serverReloader.Stop()
require.NoError(t, err)

}

func waitOnReturnCode(t *testing.T, expectedReturnCode int, path string, formValue string, rel *reload.ServerReloader) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
client := &http.Client{}
fastEventually(t, func() bool {
path := fmt.Sprintf("http://%s/liveness%s", rel.Addr().String(), formValue)
t.Logf("checking %s", path)
req, err := http.NewRequestWithContext(ctx, "GET", path, nil)
url := fmt.Sprintf("http://%s/%s%s", rel.Addr().String(), path, formValue)
t.Logf("checking %s", url)
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
require.NoError(t, err)

resp, err := client.Do(req)
Expand Down

0 comments on commit 8e31a5d

Please sign in to comment.