Pull request 1947: AG-24320 home: pprof conf

Squashed commit of the following:

commit bc0facffe41e140fab00edeeeca3b69306cf2ceb
Merge: 71e0806ba c0691cab6
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Aug 2 17:34:15 2023 +0300

    Merge branch 'master' into pprof-conf

commit 71e0806bac52412cae7cad2748216ece7fbed36f
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Wed Aug 2 08:37:51 2023 +0300

    all: docs

commit 6ebb6f9a5f4dbeb753dd470879f2e5ff556ee5f1
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Aug 1 15:56:45 2023 +0300

    home: imp code

commit ca084011cddc20f5c0b770ee38f9ac55d62bff24
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Aug 1 13:57:53 2023 +0300

    all: docs

commit 1b498a84d6cb8207d350fceb4db64d45dc2aa46d
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Aug 1 13:46:13 2023 +0300

    all: docs

commit 0cd76c057e0f3e9e62e5bf38f95080afa830f4ff
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Aug 1 13:00:43 2023 +0300

    home: pprof conf
This commit is contained in:
Dimitry Kolyshev 2023-08-02 17:39:33 +03:00 committed by Ainar Garipov
parent c0691cab6a
commit 5eb3cd0f92
6 changed files with 186 additions and 9 deletions

View file

@ -23,6 +23,36 @@ See also the [v0.107.37 GitHub milestone][ms-v0.107.37].
NOTE: Add new changes BELOW THIS COMMENT.
-->
### Added
- The ability to set the port for the `pprof` debug API, see configuration
changes below.
### Changed
#### Configuration Changes
In this release, the schema version has changed from 24 to 25.
- Property `debug_pprof` which used to setup profiling HTTP handler, is now
moved to the new `pprof` object under `http` section. The new object contains
properties `enabled` and `port`:
```yaml
# BEFORE:
'debug_pprof': true
# AFTER:
'http':
'pprof':
'enabled': true
'port': 6060
```
Note that the new default `6060` is used as default. To rollback this change,
remove the new object `pprof`, set back `debug_pprof`, and change the
`schema_version` back to `24`.
<!--
NOTE: Add new changes ABOVE THIS COMMENT.
-->

View file

@ -114,8 +114,6 @@ type configuration struct {
Language string `yaml:"language"`
// Theme is a UI theme for current user.
Theme Theme `yaml:"theme"`
// DebugPProf defines if the profiling HTTP handler will listen on :6060.
DebugPProf bool `yaml:"debug_pprof"`
DNS dnsConfig `yaml:"dns"`
TLS tlsConfigSettings `yaml:"tls"`
@ -155,6 +153,9 @@ type configuration struct {
// Field ordering is important, YAML fields better not to be reordered, if it's
// not absolutely necessary.
type httpConfig struct {
// Pprof defines the profiling HTTP handler.
Pprof *httpPprofConfig `yaml:"pprof"`
// Address is the address to serve the web UI on.
Address netip.AddrPort
@ -163,6 +164,15 @@ type httpConfig struct {
SessionTTL timeutil.Duration `yaml:"session_ttl"`
}
// httpPprofConfig is the block with pprof HTTP configuration.
type httpPprofConfig struct {
// Port for the profiling handler.
Port uint16 `yaml:"port"`
// Enabled defines if the profiling handler is enabled.
Enabled bool `yaml:"enabled"`
}
// dnsConfig is a block with DNS configuration params.
//
// Field ordering is important, YAML fields better not to be reordered, if it's
@ -277,6 +287,10 @@ var config = &configuration{
HTTPConfig: httpConfig{
Address: netip.AddrPortFrom(netip.IPv4Unspecified(), 3000),
SessionTTL: timeutil.Duration{Duration: 30 * timeutil.Day},
Pprof: &httpPprofConfig{
Enabled: false,
Port: 6060,
},
},
DNS: dnsConfig{
BindHosts: []netip.Addr{netip.IPv4Unspecified()},

View file

@ -567,9 +567,8 @@ func run(opts options, clientBuildFS fs.FS) {
err = config.write()
fatalOnError(err)
if config.DebugPProf {
// TODO(a.garipov): Make the address configurable.
startPprof("localhost:6060")
if config.HTTPConfig.Pprof.Enabled {
startPprof(config.HTTPConfig.Pprof.Port)
}
}

View file

@ -23,7 +23,7 @@ import (
)
// currentSchemaVersion is the current schema version.
const currentSchemaVersion = 24
const currentSchemaVersion = 25
// These aliases are provided for convenience.
type (
@ -99,6 +99,7 @@ func upgradeConfigSchema(oldVersion int, diskConf yobj) (err error) {
upgradeSchema21to22,
upgradeSchema22to23,
upgradeSchema23to24,
upgradeSchema24to25,
}
n := 0
@ -1380,6 +1381,50 @@ func upgradeSchema23to24(diskConf yobj) (err error) {
return nil
}
// upgradeSchema24to25 performs the following changes:
//
// # BEFORE:
// 'debug_pprof': true
//
// # AFTER:
// 'http':
// 'pprof':
// 'enabled': true
// 'port': 6060
func upgradeSchema24to25(diskConf yobj) (err error) {
log.Printf("Upgrade yaml: 24 to 25")
diskConf["schema_version"] = 25
debugPprofVal, ok := diskConf["debug_pprof"]
if !ok {
return nil
}
debugPprofEnabled, ok := debugPprofVal.(bool)
if !ok {
return fmt.Errorf("unexpected type of debug_pprof: %T", debugPprofVal)
}
httpVal, ok := diskConf["http"]
if !ok {
return nil
}
httpObj, ok := httpVal.(yobj)
if !ok {
return fmt.Errorf("unexpected type of dns: %T", httpVal)
}
httpObj["pprof"] = yobj{
"enabled": debugPprofEnabled,
"port": 6060,
}
delete(diskConf, "debug_pprof")
return nil
}
// moveField gets field value for key from diskConf, and then set this value
// in newConf for newKey.
func moveField[T any](diskConf, newConf yobj, key, newKey string) (err error) {

View file

@ -1379,3 +1379,90 @@ func TestUpgradeSchema23to24(t *testing.T) {
})
}
}
func TestUpgradeSchema24to25(t *testing.T) {
const newSchemaVer = 25
testCases := []struct {
in yobj
want yobj
name string
wantErrMsg string
}{{
name: "empty",
in: yobj{},
want: yobj{
"schema_version": newSchemaVer,
},
wantErrMsg: "",
}, {
name: "ok",
in: yobj{
"http": yobj{
"address": "0.0.0.0:3000",
"session_ttl": "720h",
},
"debug_pprof": true,
},
want: yobj{
"http": yobj{
"address": "0.0.0.0:3000",
"session_ttl": "720h",
"pprof": yobj{
"enabled": true,
"port": 6060,
},
},
"schema_version": newSchemaVer,
},
wantErrMsg: "",
}, {
name: "ok_disabled",
in: yobj{
"http": yobj{
"address": "0.0.0.0:3000",
"session_ttl": "720h",
},
"debug_pprof": false,
},
want: yobj{
"http": yobj{
"address": "0.0.0.0:3000",
"session_ttl": "720h",
"pprof": yobj{
"enabled": false,
"port": 6060,
},
},
"schema_version": newSchemaVer,
},
wantErrMsg: "",
}, {
name: "invalid",
in: yobj{
"http": yobj{
"address": "0.0.0.0:3000",
"session_ttl": "720h",
},
"debug_pprof": 1,
},
want: yobj{
"http": yobj{
"address": "0.0.0.0:3000",
"session_ttl": "720h",
},
"debug_pprof": 1,
"schema_version": newSchemaVer,
},
wantErrMsg: "unexpected type of debug_pprof: int",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema24to25(tc.in)
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
assert.Equal(t, tc.want, tc.in)
})
}
}

View file

@ -312,8 +312,10 @@ func (web *webAPI) mustStartHTTP3(address string) {
}
}
// startPprof launches the debug and profiling server on addr.
func startPprof(addr string) {
// startPprof launches the debug and profiling server on the provided port.
func startPprof(port uint16) {
addr := netip.AddrPortFrom(netutil.IPv4Localhost(), port)
runtime.SetBlockProfileRate(1)
runtime.SetMutexProfileFraction(1)
@ -324,7 +326,7 @@ func startPprof(addr string) {
defer log.OnPanic("pprof server")
log.Info("pprof: listening on %q", addr)
err := http.ListenAndServe(addr, mux)
err := http.ListenAndServe(addr.String(), mux)
if !errors.Is(err, http.ErrServerClosed) {
log.Error("pprof: shutting down: %s", err)
}