fix(pprof): settings rates can be nil

This commit is contained in:
Quentin McGaw
2023-04-12 10:14:05 +00:00
parent d4f8eea7bf
commit fa7fd5f076
6 changed files with 63 additions and 52 deletions

View File

@@ -12,12 +12,12 @@ func readPprof() (settings pprof.Settings, err error) {
return settings, fmt.Errorf("environment variable PPROF_ENABLED: %w", err) return settings, fmt.Errorf("environment variable PPROF_ENABLED: %w", err)
} }
settings.BlockProfileRate, err = envToInt("PPROF_BLOCK_PROFILE_RATE") settings.BlockProfileRate, err = envToIntPtr("PPROF_BLOCK_PROFILE_RATE")
if err != nil { if err != nil {
return settings, fmt.Errorf("environment variable PPROF_BLOCK_PROFILE_RATE: %w", err) return settings, fmt.Errorf("environment variable PPROF_BLOCK_PROFILE_RATE: %w", err)
} }
settings.MutexProfileRate, err = envToInt("PPROF_MUTEX_PROFILE_RATE") settings.MutexProfileRate, err = envToIntPtr("PPROF_MUTEX_PROFILE_RATE")
if err != nil { if err != nil {
return settings, fmt.Errorf("environment variable PPROF_MUTEX_PROFILE_RATE: %w", err) return settings, fmt.Errorf("environment variable PPROF_MUTEX_PROFILE_RATE: %w", err)
} }

View File

@@ -8,6 +8,8 @@ import (
func boolPtr(b bool) *bool { return &b } func boolPtr(b bool) *bool { return &b }
func intPtr(n int) *int { return &n }
var _ gomock.Matcher = (*regexMatcher)(nil) var _ gomock.Matcher = (*regexMatcher)(nil)
type regexMatcher struct { type regexMatcher struct {

View File

@@ -13,8 +13,8 @@ import (
// with the settings given. It returns an error // with the settings given. It returns an error
// if one of the settings is not valid. // if one of the settings is not valid.
func New(settings Settings) (server *httpserver.Server, err error) { func New(settings Settings) (server *httpserver.Server, err error) {
runtime.SetBlockProfileRate(settings.BlockProfileRate) runtime.SetBlockProfileRate(*settings.BlockProfileRate)
runtime.SetMutexProfileFraction(settings.MutexProfileRate) runtime.SetMutexProfileFraction(*settings.MutexProfileRate)
handler := http.NewServeMux() handler := http.NewServeMux()
handler.HandleFunc("/debug/pprof/", pprof.Index) handler.HandleFunc("/debug/pprof/", pprof.Index)

View File

@@ -26,6 +26,8 @@ func Test_Server(t *testing.T) {
const httpServerShutdownTimeout = 10 * time.Second // 10s in case test worker is slow const httpServerShutdownTimeout = 10 * time.Second // 10s in case test worker is slow
settings := Settings{ settings := Settings{
BlockProfileRate: intPtr(0),
MutexProfileRate: intPtr(0),
HTTPServer: httpserver.Settings{ HTTPServer: httpserver.Settings{
Address: address, Address: address,
Logger: logger, Logger: logger,
@@ -112,7 +114,8 @@ func Test_Server_BadSettings(t *testing.T) {
t.Parallel() t.Parallel()
settings := Settings{ settings := Settings{
BlockProfileRate: -1, BlockProfileRate: intPtr(-1),
MutexProfileRate: intPtr(0),
} }
server, err := New(settings) server, err := New(settings)

View File

@@ -16,10 +16,10 @@ type Settings struct {
Enabled *bool Enabled *bool
// See runtime.SetBlockProfileRate // See runtime.SetBlockProfileRate
// Set to 0 to disable profiling. // Set to 0 to disable profiling.
BlockProfileRate int BlockProfileRate *int
// See runtime.SetMutexProfileFraction // See runtime.SetMutexProfileFraction
// Set to 0 to disable profiling. // Set to 0 to disable profiling.
MutexProfileRate int MutexProfileRate *int
// HTTPServer contains settings to configure // HTTPServer contains settings to configure
// the HTTP server serving pprof data. // the HTTP server serving pprof data.
HTTPServer httpserver.Settings HTTPServer httpserver.Settings
@@ -44,15 +44,15 @@ func (s Settings) Copy() (copied Settings) {
func (s *Settings) MergeWith(other Settings) { func (s *Settings) MergeWith(other Settings) {
s.Enabled = helpers.MergeWithBool(s.Enabled, other.Enabled) s.Enabled = helpers.MergeWithBool(s.Enabled, other.Enabled)
s.BlockProfileRate = helpers.MergeWithInt(s.BlockProfileRate, other.BlockProfileRate) s.BlockProfileRate = helpers.MergeWithIntPtr(s.BlockProfileRate, other.BlockProfileRate)
s.MutexProfileRate = helpers.MergeWithInt(s.MutexProfileRate, other.MutexProfileRate) s.MutexProfileRate = helpers.MergeWithIntPtr(s.MutexProfileRate, other.MutexProfileRate)
s.HTTPServer.MergeWith(other.HTTPServer) s.HTTPServer.MergeWith(other.HTTPServer)
} }
func (s *Settings) OverrideWith(other Settings) { func (s *Settings) OverrideWith(other Settings) {
s.Enabled = helpers.OverrideWithBool(s.Enabled, other.Enabled) s.Enabled = helpers.OverrideWithBool(s.Enabled, other.Enabled)
s.BlockProfileRate = helpers.OverrideWithInt(s.BlockProfileRate, other.BlockProfileRate) s.BlockProfileRate = helpers.OverrideWithIntPtr(s.BlockProfileRate, other.BlockProfileRate)
s.MutexProfileRate = helpers.OverrideWithInt(s.MutexProfileRate, other.MutexProfileRate) s.MutexProfileRate = helpers.OverrideWithIntPtr(s.MutexProfileRate, other.MutexProfileRate)
s.HTTPServer.OverrideWith(other.HTTPServer) s.HTTPServer.OverrideWith(other.HTTPServer)
} }
@@ -62,11 +62,11 @@ var (
) )
func (s Settings) Validate() (err error) { func (s Settings) Validate() (err error) {
if s.BlockProfileRate < 0 { if *s.BlockProfileRate < 0 {
return ErrBlockProfileRateNegative return ErrBlockProfileRateNegative
} }
if s.MutexProfileRate < 0 { if *s.MutexProfileRate < 0 {
return ErrMutexProfileRateNegative return ErrMutexProfileRateNegative
} }
@@ -80,12 +80,12 @@ func (s Settings) ToLinesNode() (node *gotree.Node) {
node = gotree.New("Pprof settings:") node = gotree.New("Pprof settings:")
if s.BlockProfileRate > 0 { if *s.BlockProfileRate > 0 {
node.Appendf("Block profile rate: %d", s.BlockProfileRate) node.Appendf("Block profile rate: %d", *s.BlockProfileRate)
} }
if s.MutexProfileRate > 0 { if *s.MutexProfileRate > 0 {
node.Appendf("Mutex profile rate: %d", s.MutexProfileRate) node.Appendf("Mutex profile rate: %d", *s.MutexProfileRate)
} }
node.AppendNode(s.HTTPServer.ToLinesNode()) node.AppendNode(s.HTTPServer.ToLinesNode())

View File

@@ -31,8 +31,8 @@ func Test_Settings_SetDefaults(t *testing.T) {
"non empty settings": { "non empty settings": {
initial: Settings{ initial: Settings{
Enabled: boolPtr(true), Enabled: boolPtr(true),
BlockProfileRate: 1, BlockProfileRate: intPtr(1),
MutexProfileRate: 1, MutexProfileRate: intPtr(1),
HTTPServer: httpserver.Settings{ HTTPServer: httpserver.Settings{
Address: ":6061", Address: ":6061",
ReadHeaderTimeout: time.Second, ReadHeaderTimeout: time.Second,
@@ -42,8 +42,8 @@ func Test_Settings_SetDefaults(t *testing.T) {
}, },
expected: Settings{ expected: Settings{
Enabled: boolPtr(true), Enabled: boolPtr(true),
BlockProfileRate: 1, BlockProfileRate: intPtr(1),
MutexProfileRate: 1, MutexProfileRate: intPtr(1),
HTTPServer: httpserver.Settings{ HTTPServer: httpserver.Settings{
Address: ":6061", Address: ":6061",
ReadHeaderTimeout: time.Second, ReadHeaderTimeout: time.Second,
@@ -77,8 +77,8 @@ func Test_Settings_Copy(t *testing.T) {
"non empty settings": { "non empty settings": {
initial: Settings{ initial: Settings{
Enabled: boolPtr(true), Enabled: boolPtr(true),
BlockProfileRate: 1, BlockProfileRate: intPtr(1),
MutexProfileRate: 1, MutexProfileRate: intPtr(1),
HTTPServer: httpserver.Settings{ HTTPServer: httpserver.Settings{
Address: ":6061", Address: ":6061",
ShutdownTimeout: time.Second, ShutdownTimeout: time.Second,
@@ -86,8 +86,8 @@ func Test_Settings_Copy(t *testing.T) {
}, },
expected: Settings{ expected: Settings{
Enabled: boolPtr(true), Enabled: boolPtr(true),
BlockProfileRate: 1, BlockProfileRate: intPtr(1),
MutexProfileRate: 1, MutexProfileRate: intPtr(1),
HTTPServer: httpserver.Settings{ HTTPServer: httpserver.Settings{
Address: ":6061", Address: ":6061",
ShutdownTimeout: time.Second, ShutdownTimeout: time.Second,
@@ -120,16 +120,16 @@ func Test_Settings_MergeWith(t *testing.T) {
"merge empty with filled": { "merge empty with filled": {
other: Settings{ other: Settings{
Enabled: boolPtr(true), Enabled: boolPtr(true),
BlockProfileRate: 1, BlockProfileRate: intPtr(1),
MutexProfileRate: 1, MutexProfileRate: intPtr(1),
HTTPServer: httpserver.Settings{ HTTPServer: httpserver.Settings{
Address: ":8001", Address: ":8001",
}, },
}, },
expected: Settings{ expected: Settings{
Enabled: boolPtr(true), Enabled: boolPtr(true),
BlockProfileRate: 1, BlockProfileRate: intPtr(1),
MutexProfileRate: 1, MutexProfileRate: intPtr(1),
HTTPServer: httpserver.Settings{ HTTPServer: httpserver.Settings{
Address: ":8001", Address: ":8001",
}, },
@@ -138,16 +138,16 @@ func Test_Settings_MergeWith(t *testing.T) {
"merge filled with empty": { "merge filled with empty": {
settings: Settings{ settings: Settings{
Enabled: boolPtr(true), Enabled: boolPtr(true),
BlockProfileRate: 1, BlockProfileRate: intPtr(1),
MutexProfileRate: 1, MutexProfileRate: intPtr(1),
HTTPServer: httpserver.Settings{ HTTPServer: httpserver.Settings{
Address: ":8001", Address: ":8001",
}, },
}, },
expected: Settings{ expected: Settings{
Enabled: boolPtr(true), Enabled: boolPtr(true),
BlockProfileRate: 1, BlockProfileRate: intPtr(1),
MutexProfileRate: 1, MutexProfileRate: intPtr(1),
HTTPServer: httpserver.Settings{ HTTPServer: httpserver.Settings{
Address: ":8001", Address: ":8001",
}, },
@@ -179,16 +179,16 @@ func Test_Settings_OverrideWith(t *testing.T) {
"override empty with filled": { "override empty with filled": {
other: Settings{ other: Settings{
Enabled: boolPtr(true), Enabled: boolPtr(true),
BlockProfileRate: 1, BlockProfileRate: intPtr(1),
MutexProfileRate: 1, MutexProfileRate: intPtr(1),
HTTPServer: httpserver.Settings{ HTTPServer: httpserver.Settings{
Address: ":8001", Address: ":8001",
}, },
}, },
expected: Settings{ expected: Settings{
Enabled: boolPtr(true), Enabled: boolPtr(true),
BlockProfileRate: 1, BlockProfileRate: intPtr(1),
MutexProfileRate: 1, MutexProfileRate: intPtr(1),
HTTPServer: httpserver.Settings{ HTTPServer: httpserver.Settings{
Address: ":8001", Address: ":8001",
}, },
@@ -197,16 +197,16 @@ func Test_Settings_OverrideWith(t *testing.T) {
"override filled with empty": { "override filled with empty": {
settings: Settings{ settings: Settings{
Enabled: boolPtr(true), Enabled: boolPtr(true),
BlockProfileRate: 1, BlockProfileRate: intPtr(1),
MutexProfileRate: 1, MutexProfileRate: intPtr(1),
HTTPServer: httpserver.Settings{ HTTPServer: httpserver.Settings{
Address: ":8001", Address: ":8001",
}, },
}, },
expected: Settings{ expected: Settings{
Enabled: boolPtr(true), Enabled: boolPtr(true),
BlockProfileRate: 1, BlockProfileRate: intPtr(1),
MutexProfileRate: 1, MutexProfileRate: intPtr(1),
HTTPServer: httpserver.Settings{ HTTPServer: httpserver.Settings{
Address: ":8001", Address: ":8001",
}, },
@@ -215,24 +215,24 @@ func Test_Settings_OverrideWith(t *testing.T) {
"override filled with filled": { "override filled with filled": {
settings: Settings{ settings: Settings{
Enabled: boolPtr(false), Enabled: boolPtr(false),
BlockProfileRate: 1, BlockProfileRate: intPtr(1),
MutexProfileRate: 1, MutexProfileRate: intPtr(1),
HTTPServer: httpserver.Settings{ HTTPServer: httpserver.Settings{
Address: ":8001", Address: ":8001",
}, },
}, },
other: Settings{ other: Settings{
Enabled: boolPtr(true), Enabled: boolPtr(true),
BlockProfileRate: 2, BlockProfileRate: intPtr(2),
MutexProfileRate: 3, MutexProfileRate: intPtr(3),
HTTPServer: httpserver.Settings{ HTTPServer: httpserver.Settings{
Address: ":8002", Address: ":8002",
}, },
}, },
expected: Settings{ expected: Settings{
Enabled: boolPtr(true), Enabled: boolPtr(true),
BlockProfileRate: 2, BlockProfileRate: intPtr(2),
MutexProfileRate: 3, MutexProfileRate: intPtr(3),
HTTPServer: httpserver.Settings{ HTTPServer: httpserver.Settings{
Address: ":8002", Address: ":8002",
}, },
@@ -262,27 +262,33 @@ func Test_Settings_Validate(t *testing.T) {
}{ }{
"negative block profile rate": { "negative block profile rate": {
settings: Settings{ settings: Settings{
BlockProfileRate: -1, BlockProfileRate: intPtr(-1),
MutexProfileRate: intPtr(0),
}, },
errWrapped: ErrBlockProfileRateNegative, errWrapped: ErrBlockProfileRateNegative,
errMessage: ErrBlockProfileRateNegative.Error(), errMessage: ErrBlockProfileRateNegative.Error(),
}, },
"negative mutex profile rate": { "negative mutex profile rate": {
settings: Settings{ settings: Settings{
MutexProfileRate: -1, BlockProfileRate: intPtr(0),
MutexProfileRate: intPtr(-1),
}, },
errWrapped: ErrMutexProfileRateNegative, errWrapped: ErrMutexProfileRateNegative,
errMessage: ErrMutexProfileRateNegative.Error(), errMessage: ErrMutexProfileRateNegative.Error(),
}, },
"http server validation error": { "http server validation error": {
settings: Settings{ settings: Settings{
HTTPServer: httpserver.Settings{}, BlockProfileRate: intPtr(0),
MutexProfileRate: intPtr(0),
HTTPServer: httpserver.Settings{},
}, },
errWrapped: address.ErrValueNotValid, errWrapped: address.ErrValueNotValid,
errMessage: "value is not valid: missing port in address", errMessage: "value is not valid: missing port in address",
}, },
"valid settings": { "valid settings": {
settings: Settings{ settings: Settings{
BlockProfileRate: intPtr(0),
MutexProfileRate: intPtr(0),
HTTPServer: httpserver.Settings{ HTTPServer: httpserver.Settings{
Address: ":8000", Address: ":8000",
Handler: http.NewServeMux(), Handler: http.NewServeMux(),
@@ -325,8 +331,8 @@ func Test_Settings_String(t *testing.T) {
"all values": { "all values": {
settings: Settings{ settings: Settings{
Enabled: boolPtr(true), Enabled: boolPtr(true),
BlockProfileRate: 2, BlockProfileRate: intPtr(2),
MutexProfileRate: 1, MutexProfileRate: intPtr(1),
HTTPServer: httpserver.Settings{ HTTPServer: httpserver.Settings{
Address: ":8000", Address: ":8000",
ShutdownTimeout: time.Second, ShutdownTimeout: time.Second,