Pull request: log-yaml-conf
Updates #4897. Squashed commit of the following: commit 8a961157c9930bf4859ce2209e5016ce94987e12 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Jul 5 10:13:24 2023 +0400 home: imp code commit 509c07eed06311d773bc3e34b3ca28d9f14186fe Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Tue Jul 4 17:33:31 2023 +0400 all: fix commit f032e28f98552f238721491c998fca2d7d4b9802 Merge: ee0113435c46516475
Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Tue Jul 4 17:31:29 2023 +0400 Merge remote-tracking branch 'origin/master' into log-yaml-conf # Conflicts: # CHANGELOG.md commit ee011343512e82d4e21cb402759d0284523ba02a Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Tue Jul 4 12:31:42 2023 +0400 all: changelog commit 07f4c4a244b1b6200d3056cde5ebced6254084a7 Merge: 2042c075397af062f7
Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Tue Jul 4 12:25:21 2023 +0400 Merge remote-tracking branch 'origin/master' into log-yaml-conf commit 2042c0753ec29de6045c3f1de6d075cb93d6ec27 Merge: a1d3a51308004b135b
Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Mon Jul 3 16:25:26 2023 +0400 Merge remote-tracking branch 'origin/master' into log-yaml-conf commit a1d3a51307e80f9e509bd6f3bee1a7b17bf1ffe6 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Fri Jun 30 11:11:32 2023 +0400 home: imp code commit 2392a3b02620b8c38e88afb4d75988be85fe1338 Merge: 4224fbed739f5c50ac
Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Thu Jun 29 16:46:47 2023 +0400 home: imp code commit 4224fbed7113e94bee44d0ab0272e8302a8086f3 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Thu Jun 29 16:39:35 2023 +0400 home: imp code commit 5ce708cc50bed83e64f062e599fc8b6143d0d44d Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Thu Jun 29 12:48:42 2023 +0400 all: docs commit 4b6d898a888818410f59b843c3ca1a685aafec82 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Thu Jun 29 12:20:54 2023 +0400 home: imp code commit 431b44eda71f488c747c3efa4da0a6c222b1cf06 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Thu Jun 29 12:03:17 2023 +0400 home: imp tests commit 53a5c31060018c37953beb27d80c46f92bbe14af Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Jun 28 17:40:49 2023 +0400 home: imp docs commit bfa57d9f21e3326baafd3a52e91d54396d8e03fa Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Jun 28 15:49:40 2023 +0400 home: log conf commit 49e06dca9dc2ceb2647b7e36dac145ccf78a6c3f Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Jun 28 15:41:02 2023 +0400 home: log conf commit 9be432dea7cec8ae0c0d3ee1f73c58c76376d07e Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Jun 28 10:45:01 2023 +0400 home: log conf
This commit is contained in:
parent
c46516475d
commit
5a195b441c
34
CHANGELOG.md
34
CHANGELOG.md
|
@ -23,6 +23,40 @@ See also the [v0.107.34 GitHub milestone][ms-v0.107.34].
|
||||||
NOTE: Add new changes BELOW THIS COMMENT.
|
NOTE: Add new changes BELOW THIS COMMENT.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
#### Configuration Changes
|
||||||
|
|
||||||
|
In this release, the schema version has changed from 23 to 24.
|
||||||
|
|
||||||
|
- Properties starting with `log_`, and `verbose` property, which used to set up
|
||||||
|
logging are now moved to the new object `log` containing new properties `file`,
|
||||||
|
`max_backups`, `max_size`, `max_age`, `compress`, `local_time`, and `verbose`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# BEFORE:
|
||||||
|
'log_file': ""
|
||||||
|
'log_max_backups': 0
|
||||||
|
'log_max_size': 100
|
||||||
|
'log_max_age': 3
|
||||||
|
'log_compress': false
|
||||||
|
'log_localtime': false
|
||||||
|
'verbose': false
|
||||||
|
|
||||||
|
# AFTER:
|
||||||
|
'log':
|
||||||
|
'file': ""
|
||||||
|
'max_backups': 0
|
||||||
|
'max_size': 100
|
||||||
|
'max_age': 3
|
||||||
|
'compress': false
|
||||||
|
'local_time': false
|
||||||
|
'verbose': false
|
||||||
|
```
|
||||||
|
|
||||||
|
To rollback this change, remove the new object `log`, set back `log_` and
|
||||||
|
`verbose` properties and change the `schema_version` back to `23`.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Excessive RAM and CPU consumption by Safe Browsing and Parental Control
|
- Excessive RAM and CPU consumption by Safe Browsing and Parental Control
|
||||||
|
|
|
@ -30,32 +30,30 @@ import (
|
||||||
const dataDir = "data"
|
const dataDir = "data"
|
||||||
|
|
||||||
// logSettings are the logging settings part of the configuration file.
|
// logSettings are the logging settings part of the configuration file.
|
||||||
//
|
|
||||||
// TODO(a.garipov): Put them into a separate object.
|
|
||||||
type logSettings struct {
|
type logSettings struct {
|
||||||
// File is the path to the log file. If empty, logs are written to stdout.
|
// File is the path to the log file. If empty, logs are written to stdout.
|
||||||
// If "syslog", logs are written to syslog.
|
// If "syslog", logs are written to syslog.
|
||||||
File string `yaml:"log_file"`
|
File string `yaml:"file"`
|
||||||
|
|
||||||
// MaxBackups is the maximum number of old log files to retain.
|
// MaxBackups is the maximum number of old log files to retain.
|
||||||
//
|
//
|
||||||
// NOTE: MaxAge may still cause them to get deleted.
|
// NOTE: MaxAge may still cause them to get deleted.
|
||||||
MaxBackups int `yaml:"log_max_backups"`
|
MaxBackups int `yaml:"max_backups"`
|
||||||
|
|
||||||
// MaxSize is the maximum size of the log file before it gets rotated, in
|
// MaxSize is the maximum size of the log file before it gets rotated, in
|
||||||
// megabytes. The default value is 100 MB.
|
// megabytes. The default value is 100 MB.
|
||||||
MaxSize int `yaml:"log_max_size"`
|
MaxSize int `yaml:"max_size"`
|
||||||
|
|
||||||
// MaxAge is the maximum duration for retaining old log files, in days.
|
// MaxAge is the maximum duration for retaining old log files, in days.
|
||||||
MaxAge int `yaml:"log_max_age"`
|
MaxAge int `yaml:"max_age"`
|
||||||
|
|
||||||
// Compress determines, if the rotated log files should be compressed using
|
// Compress determines, if the rotated log files should be compressed using
|
||||||
// gzip.
|
// gzip.
|
||||||
Compress bool `yaml:"log_compress"`
|
Compress bool `yaml:"compress"`
|
||||||
|
|
||||||
// LocalTime determines, if the time used for formatting the timestamps in
|
// LocalTime determines, if the time used for formatting the timestamps in
|
||||||
// is the computer's local time.
|
// is the computer's local time.
|
||||||
LocalTime bool `yaml:"log_localtime"`
|
LocalTime bool `yaml:"local_time"`
|
||||||
|
|
||||||
// Verbose determines, if verbose (aka debug) logging is enabled.
|
// Verbose determines, if verbose (aka debug) logging is enabled.
|
||||||
Verbose bool `yaml:"verbose"`
|
Verbose bool `yaml:"verbose"`
|
||||||
|
@ -142,7 +140,8 @@ type configuration struct {
|
||||||
// Keep this field sorted to ensure consistent ordering.
|
// Keep this field sorted to ensure consistent ordering.
|
||||||
Clients *clientsConfig `yaml:"clients"`
|
Clients *clientsConfig `yaml:"clients"`
|
||||||
|
|
||||||
logSettings `yaml:",inline"`
|
// Log is a block with log configuration settings.
|
||||||
|
Log logSettings `yaml:"log"`
|
||||||
|
|
||||||
OSConfig *osConfig `yaml:"os"`
|
OSConfig *osConfig `yaml:"os"`
|
||||||
|
|
||||||
|
@ -390,7 +389,7 @@ var config = &configuration{
|
||||||
HostsFile: true,
|
HostsFile: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
logSettings: logSettings{
|
Log: logSettings{
|
||||||
Compress: false,
|
Compress: false,
|
||||||
LocalTime: false,
|
LocalTime: false,
|
||||||
MaxBackups: 0,
|
MaxBackups: 0,
|
||||||
|
@ -421,19 +420,19 @@ func (c *configuration) getConfigFilename() string {
|
||||||
// separate method in order to configure logger before the actual configuration
|
// separate method in order to configure logger before the actual configuration
|
||||||
// is parsed and applied.
|
// is parsed and applied.
|
||||||
func readLogSettings() (ls *logSettings) {
|
func readLogSettings() (ls *logSettings) {
|
||||||
ls = &logSettings{}
|
conf := &configuration{}
|
||||||
|
|
||||||
yamlFile, err := readConfigFile()
|
yamlFile, err := readConfigFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ls
|
return &logSettings{}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = yaml.Unmarshal(yamlFile, ls)
|
err = yaml.Unmarshal(yamlFile, conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Couldn't get logging settings from the configuration: %s", err)
|
log.Error("Couldn't get logging settings from the configuration: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ls
|
return &conf.Log
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateBindHosts returns error if any of binding hosts from configuration is
|
// validateBindHosts returns error if any of binding hosts from configuration is
|
||||||
|
|
|
@ -829,20 +829,21 @@ func configureLogger(opts options) (err error) {
|
||||||
// getLogSettings returns a log settings object properly initialized from opts.
|
// getLogSettings returns a log settings object properly initialized from opts.
|
||||||
func getLogSettings(opts options) (ls *logSettings) {
|
func getLogSettings(opts options) (ls *logSettings) {
|
||||||
ls = readLogSettings()
|
ls = readLogSettings()
|
||||||
|
configLogSettings := config.Log
|
||||||
|
|
||||||
// Command-line arguments can override config settings.
|
// Command-line arguments can override config settings.
|
||||||
if opts.verbose || config.Verbose {
|
if opts.verbose || configLogSettings.Verbose {
|
||||||
ls.Verbose = true
|
ls.Verbose = true
|
||||||
}
|
}
|
||||||
|
|
||||||
ls.File = stringutil.Coalesce(opts.logFile, config.File, ls.File)
|
ls.File = stringutil.Coalesce(opts.logFile, configLogSettings.File, ls.File)
|
||||||
|
|
||||||
// Handle default log settings overrides.
|
// Handle default log settings overrides.
|
||||||
ls.Compress = config.Compress
|
ls.Compress = configLogSettings.Compress
|
||||||
ls.LocalTime = config.LocalTime
|
ls.LocalTime = configLogSettings.LocalTime
|
||||||
ls.MaxBackups = config.MaxBackups
|
ls.MaxBackups = configLogSettings.MaxBackups
|
||||||
ls.MaxSize = config.MaxSize
|
ls.MaxSize = configLogSettings.MaxSize
|
||||||
ls.MaxAge = config.MaxAge
|
ls.MaxAge = configLogSettings.MaxAge
|
||||||
|
|
||||||
if opts.runningAsService && ls.File == "" && runtime.GOOS == "windows" {
|
if opts.runningAsService && ls.File == "" && runtime.GOOS == "windows" {
|
||||||
// When running as a Windows service, use eventlog by default if
|
// When running as a Windows service, use eventlog by default if
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// currentSchemaVersion is the current schema version.
|
// currentSchemaVersion is the current schema version.
|
||||||
const currentSchemaVersion = 23
|
const currentSchemaVersion = 24
|
||||||
|
|
||||||
// These aliases are provided for convenience.
|
// These aliases are provided for convenience.
|
||||||
type (
|
type (
|
||||||
|
@ -98,6 +98,7 @@ func upgradeConfigSchema(oldVersion int, diskConf yobj) (err error) {
|
||||||
upgradeSchema20to21,
|
upgradeSchema20to21,
|
||||||
upgradeSchema21to22,
|
upgradeSchema21to22,
|
||||||
upgradeSchema22to23,
|
upgradeSchema22to23,
|
||||||
|
upgradeSchema23to24,
|
||||||
}
|
}
|
||||||
|
|
||||||
n := 0
|
n := 0
|
||||||
|
@ -1325,6 +1326,110 @@ func upgradeSchema22to23(diskConf yobj) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// upgradeSchema23to24 performs the following changes:
|
||||||
|
//
|
||||||
|
// # BEFORE:
|
||||||
|
// 'log_file': ""
|
||||||
|
// 'log_max_backups': 0
|
||||||
|
// 'log_max_size': 100
|
||||||
|
// 'log_max_age': 3
|
||||||
|
// 'log_compress': false
|
||||||
|
// 'log_localtime': false
|
||||||
|
// 'verbose': false
|
||||||
|
//
|
||||||
|
// # AFTER:
|
||||||
|
// 'log':
|
||||||
|
// 'file': ""
|
||||||
|
// 'max_backups': 0
|
||||||
|
// 'max_size': 100
|
||||||
|
// 'max_age': 3
|
||||||
|
// 'compress': false
|
||||||
|
// 'local_time': false
|
||||||
|
// 'verbose': false
|
||||||
|
func upgradeSchema23to24(diskConf yobj) (err error) {
|
||||||
|
log.Printf("Upgrade yaml: 23 to 24")
|
||||||
|
diskConf["schema_version"] = 24
|
||||||
|
|
||||||
|
logObj := yobj{}
|
||||||
|
err = coalesceError(
|
||||||
|
moveField[string](diskConf, logObj, "log_file", "file"),
|
||||||
|
moveField[int](diskConf, logObj, "log_max_backups", "max_backups"),
|
||||||
|
moveField[int](diskConf, logObj, "log_max_size", "max_size"),
|
||||||
|
moveField[int](diskConf, logObj, "log_max_age", "max_age"),
|
||||||
|
moveField[bool](diskConf, logObj, "log_compress", "compress"),
|
||||||
|
moveField[bool](diskConf, logObj, "log_localtime", "local_time"),
|
||||||
|
moveField[bool](diskConf, logObj, "verbose", "verbose"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
// Don't wrap the error, because it's informative enough as is.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(logObj) != 0 {
|
||||||
|
diskConf["log"] = logObj
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(diskConf, "log_file")
|
||||||
|
delete(diskConf, "log_max_backups")
|
||||||
|
delete(diskConf, "log_max_size")
|
||||||
|
delete(diskConf, "log_max_age")
|
||||||
|
delete(diskConf, "log_compress")
|
||||||
|
delete(diskConf, "log_localtime")
|
||||||
|
delete(diskConf, "verbose")
|
||||||
|
|
||||||
|
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) {
|
||||||
|
ok, newVal, err := fieldValue[T](diskConf, key)
|
||||||
|
if !ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := newVal.(type) {
|
||||||
|
case int, bool, string:
|
||||||
|
newConf[newKey] = v
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid type of %s: %T", key, newVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// fieldValue returns the value of type T for key in diskConf object.
|
||||||
|
func fieldValue[T any](diskConf yobj, key string) (ok bool, field any, err error) {
|
||||||
|
fieldVal, ok := diskConf[key]
|
||||||
|
if !ok {
|
||||||
|
return false, new(T), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
f, ok := fieldVal.(T)
|
||||||
|
if !ok {
|
||||||
|
return false, nil, fmt.Errorf("unexpected type of %s: %T", key, fieldVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// coalesceError returns the first non-nil error. It is named after function
|
||||||
|
// COALESCE in SQL. If all errors are nil, it returns nil.
|
||||||
|
//
|
||||||
|
// TODO(a.garipov): Consider a similar helper to group errors together to show
|
||||||
|
// as many errors as possible.
|
||||||
|
//
|
||||||
|
// TODO(a.garipov): Think of ways to merge with [aghalg.Coalesce].
|
||||||
|
func coalesceError(errors ...error) (res error) {
|
||||||
|
for _, err := range errors {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(a.garipov): Replace with log.Output when we port it to our logging
|
// TODO(a.garipov): Replace with log.Output when we port it to our logging
|
||||||
// package.
|
// package.
|
||||||
func funcName() string {
|
func funcName() string {
|
||||||
|
|
|
@ -1306,3 +1306,76 @@ func TestUpgradeSchema22to23(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpgradeSchema23to24(t *testing.T) {
|
||||||
|
const newSchemaVer = 24
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
in yobj
|
||||||
|
want yobj
|
||||||
|
name string
|
||||||
|
wantErrMsg string
|
||||||
|
}{{
|
||||||
|
name: "empty",
|
||||||
|
in: yobj{},
|
||||||
|
want: yobj{
|
||||||
|
"schema_version": newSchemaVer,
|
||||||
|
},
|
||||||
|
wantErrMsg: "",
|
||||||
|
}, {
|
||||||
|
name: "ok",
|
||||||
|
in: yobj{
|
||||||
|
"log_file": "/test/path.log",
|
||||||
|
"log_max_backups": 1,
|
||||||
|
"log_max_size": 2,
|
||||||
|
"log_max_age": 3,
|
||||||
|
"log_compress": true,
|
||||||
|
"log_localtime": true,
|
||||||
|
"verbose": true,
|
||||||
|
},
|
||||||
|
want: yobj{
|
||||||
|
"log": yobj{
|
||||||
|
"file": "/test/path.log",
|
||||||
|
"max_backups": 1,
|
||||||
|
"max_size": 2,
|
||||||
|
"max_age": 3,
|
||||||
|
"compress": true,
|
||||||
|
"local_time": true,
|
||||||
|
"verbose": true,
|
||||||
|
},
|
||||||
|
"schema_version": newSchemaVer,
|
||||||
|
},
|
||||||
|
wantErrMsg: "",
|
||||||
|
}, {
|
||||||
|
name: "invalid",
|
||||||
|
in: yobj{
|
||||||
|
"log_file": "/test/path.log",
|
||||||
|
"log_max_backups": 1,
|
||||||
|
"log_max_size": 2,
|
||||||
|
"log_max_age": 3,
|
||||||
|
"log_compress": "",
|
||||||
|
"log_localtime": true,
|
||||||
|
"verbose": true,
|
||||||
|
},
|
||||||
|
want: yobj{
|
||||||
|
"log_file": "/test/path.log",
|
||||||
|
"log_max_backups": 1,
|
||||||
|
"log_max_size": 2,
|
||||||
|
"log_max_age": 3,
|
||||||
|
"log_compress": "",
|
||||||
|
"log_localtime": true,
|
||||||
|
"verbose": true,
|
||||||
|
"schema_version": newSchemaVer,
|
||||||
|
},
|
||||||
|
wantErrMsg: "unexpected type of log_compress: string",
|
||||||
|
}}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
err := upgradeSchema23to24(tc.in)
|
||||||
|
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
|
||||||
|
|
||||||
|
assert.Equal(t, tc.want, tc.in)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue