feat: allow disabling cosmovisor logs (#15362)

This commit is contained in:
Sergey 2023-03-12 16:48:30 +03:00 committed by GitHub
parent 90c9c9a9eb
commit 8f8afd1704
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 90 additions and 67 deletions

View File

@ -44,6 +44,8 @@ Ref: https://keepachangelog.com/en/1.0.0/
* [#14881](https://github.com/cosmos/cosmos-sdk/pull/14881) Refactor Cosmovisor to use `x/upgrade` validation logic.
* [#14881](https://github.com/cosmos/cosmos-sdk/pull/14881) Refactor Cosmovisor to depend only on the `x/upgrade` module.
* [#15362](https://github.com/cosmos/cosmos-sdk/pull/15362) Allow disabling Cosmovisor logs
## v1.4.0 2022-10-23

View File

@ -99,7 +99,8 @@ All arguments passed to `cosmovisor run` will be passed to the application binar
* `DAEMON_POLL_INTERVAL` (*optional*, default 300 milliseconds), is the interval length for polling the upgrade plan file. The value must be a duration (e.g. `1s`).
* `DAEMON_DATA_BACKUP_DIR` option to set a custom backup directory. If not set, `DAEMON_HOME` is used.
* `UNSAFE_SKIP_BACKUP` (defaults to `false`), if set to `true`, upgrades directly without performing a backup. Otherwise (`false`, default) backs up the data before trying the upgrade. The default value of false is useful and recommended in case of failures and when a backup needed to rollback. We recommend using the default backup option `UNSAFE_SKIP_BACKUP=false`.
* `DAEMON_PREUPGRADE_MAX_RETRIES` (defaults to `0`). The maximum number of times to call `pre-upgrade` in the application after exit status of `31`. After the maximum number of retries, cosmovisor fails the upgrade.
* `DAEMON_PREUPGRADE_MAX_RETRIES` (defaults to `0`). The maximum number of times to call `pre-upgrade` in the application after exit status of `31`. After the maximum number of retries, Cosmovisor fails the upgrade.
* `COSMOVISOR_DISABLE_LOGS` (defaults to `false`). If set to true, this will disable Cosmovisor logs (but not the underlying process) completely. This may be useful, for example, when a Cosmovisor subcommand you are executing returns a valid JSON you are then parsing, as logs added by Cosmovisor make this output not a valid JSON.
### Folder Layout

View File

@ -28,6 +28,7 @@ const (
EnvDataBackupPath = "DAEMON_DATA_BACKUP_DIR"
EnvInterval = "DAEMON_POLL_INTERVAL"
EnvPreupgradeMaxRetries = "DAEMON_PREUPGRADE_MAX_RETRIES"
EnvDisableLogs = "COSMOVISOR_DISABLE_LOGS"
)
const (
@ -51,6 +52,7 @@ type Config struct {
UnsafeSkipBackup bool
DataBackupPath string
PreupgradeMaxRetries int
DisableLogs bool
// currently running upgrade
currentUpgrade upgradetypes.Plan
@ -158,6 +160,9 @@ func GetConfigFromEnv() (*Config, error) {
if cfg.UnsafeSkipBackup, err = booleanOption(EnvSkipBackup, false); err != nil {
errs = append(errs, err)
}
if cfg.DisableLogs, err = booleanOption(EnvDisableLogs, false); err != nil {
errs = append(errs, err)
}
interval := os.Getenv(EnvInterval)
if interval != "" {
@ -369,6 +374,7 @@ func (cfg Config) DetailString() string {
{EnvSkipBackup, fmt.Sprintf("%t", cfg.UnsafeSkipBackup)},
{EnvDataBackupPath, cfg.DataBackupPath},
{EnvPreupgradeMaxRetries, fmt.Sprintf("%d", cfg.PreupgradeMaxRetries)},
{EnvDisableLogs, fmt.Sprintf("%t", cfg.DisableLogs)},
}
derivedEntries := []struct{ name, value string }{

View File

@ -38,6 +38,7 @@ type cosmovisorEnv struct {
DataBackupPath string
Interval string
PreupgradeMaxRetries string
DisableLogs string
}
// ToMap creates a map of the cosmovisorEnv where the keys are the env var names.
@ -52,6 +53,7 @@ func (c cosmovisorEnv) ToMap() map[string]string {
EnvDataBackupPath: c.DataBackupPath,
EnvInterval: c.Interval,
EnvPreupgradeMaxRetries: c.PreupgradeMaxRetries,
EnvDisableLogs: c.DisableLogs,
}
}
@ -76,6 +78,8 @@ func (c *cosmovisorEnv) Set(envVar, envVal string) {
c.Interval = envVal
case EnvPreupgradeMaxRetries:
c.PreupgradeMaxRetries = envVal
case EnvDisableLogs:
c.DisableLogs = envVal
default:
panic(fmt.Errorf("Unknown environment variable [%s]. Ccannot set field to [%s]. ", envVar, envVal))
}
@ -367,7 +371,7 @@ func (s *argsTestSuite) TestGetConfigFromEnv() {
absPath, perr := filepath.Abs(relPath)
s.Require().NoError(perr)
newConfig := func(home, name string, downloadBin, restartUpgrade bool, restartDelay int, skipBackup bool, dataBackupPath string, interval int, preupgradeMaxRetries int) *Config {
newConfig := func(home, name string, downloadBin, restartUpgrade bool, restartDelay int, skipBackup bool, dataBackupPath string, interval int, preupgradeMaxRetries int, disableLogs bool) *Config {
return &Config{
Home: home,
Name: name,
@ -378,6 +382,7 @@ func (s *argsTestSuite) TestGetConfigFromEnv() {
UnsafeSkipBackup: skipBackup,
DataBackupPath: dataBackupPath,
PreupgradeMaxRetries: preupgradeMaxRetries,
DisableLogs: disableLogs,
}
}
@ -405,183 +410,195 @@ func (s *argsTestSuite) TestGetConfigFromEnv() {
},
{
name: "all good",
envVals: cosmovisorEnv{absPath, "testname", "true", "false", "600ms", "true", "", "303ms", "1"},
expectedCfg: newConfig(absPath, "testname", true, false, 600, true, absPath, 303, 1),
envVals: cosmovisorEnv{absPath, "testname", "true", "false", "600ms", "true", "", "303ms", "1", "false"},
expectedCfg: newConfig(absPath, "testname", true, false, 600, true, absPath, 303, 1, false),
expectedErrCount: 0,
},
{
name: "nothing set",
envVals: cosmovisorEnv{"", "", "", "", "", "", "", "", ""},
envVals: cosmovisorEnv{"", "", "", "", "", "", "", "", "", "false"},
expectedCfg: nil,
expectedErrCount: 3,
},
// Note: Home and Name tests are done in TestValidate
{
name: "download bin bad",
envVals: cosmovisorEnv{absPath, "testname", "bad", "false", "600ms", "true", "", "303ms", "1"},
envVals: cosmovisorEnv{absPath, "testname", "bad", "false", "600ms", "true", "", "303ms", "1", "false"},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "download bin not set",
envVals: cosmovisorEnv{absPath, "testname", "", "false", "600ms", "true", "", "303ms", "1"},
expectedCfg: newConfig(absPath, "testname", false, false, 600, true, absPath, 303, 1),
envVals: cosmovisorEnv{absPath, "testname", "", "false", "600ms", "true", "", "303ms", "1", "false"},
expectedCfg: newConfig(absPath, "testname", false, false, 600, true, absPath, 303, 1, false),
expectedErrCount: 0,
},
{
name: "download bin true",
envVals: cosmovisorEnv{absPath, "testname", "true", "false", "600ms", "true", "", "303ms", "1"},
expectedCfg: newConfig(absPath, "testname", true, false, 600, true, absPath, 303, 1),
envVals: cosmovisorEnv{absPath, "testname", "true", "false", "600ms", "true", "", "303ms", "1", "false"},
expectedCfg: newConfig(absPath, "testname", true, false, 600, true, absPath, 303, 1, false),
expectedErrCount: 0,
},
{
name: "download bin false",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "true", "", "303ms", "1"},
expectedCfg: newConfig(absPath, "testname", false, false, 600, true, absPath, 303, 1),
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "true", "", "303ms", "1", "false"},
expectedCfg: newConfig(absPath, "testname", false, false, 600, true, absPath, 303, 1, false),
expectedErrCount: 0,
},
{
name: "restart upgrade bad",
envVals: cosmovisorEnv{absPath, "testname", "true", "bad", "600ms", "true", "", "303ms", "1"},
envVals: cosmovisorEnv{absPath, "testname", "true", "bad", "600ms", "true", "", "303ms", "1", "false"},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "restart upgrade not set",
envVals: cosmovisorEnv{absPath, "testname", "true", "", "600ms", "true", "", "303ms", "1"},
expectedCfg: newConfig(absPath, "testname", true, true, 600, true, absPath, 303, 1),
envVals: cosmovisorEnv{absPath, "testname", "true", "", "600ms", "true", "", "303ms", "1", "false"},
expectedCfg: newConfig(absPath, "testname", true, true, 600, true, absPath, 303, 1, false),
expectedErrCount: 0,
},
{
name: "restart upgrade true",
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "600ms", "true", "", "303ms", "1"},
expectedCfg: newConfig(absPath, "testname", true, true, 600, true, absPath, 303, 1),
envVals: cosmovisorEnv{absPath, "testname", "true", "true", "600ms", "true", "", "303ms", "1", "false"},
expectedCfg: newConfig(absPath, "testname", true, true, 600, true, absPath, 303, 1, false),
expectedErrCount: 0,
},
{
name: "restart upgrade true",
envVals: cosmovisorEnv{absPath, "testname", "true", "false", "600ms", "true", "", "303ms", "1"},
expectedCfg: newConfig(absPath, "testname", true, false, 600, true, absPath, 303, 1),
envVals: cosmovisorEnv{absPath, "testname", "true", "false", "600ms", "true", "", "303ms", "1", "false"},
expectedCfg: newConfig(absPath, "testname", true, false, 600, true, absPath, 303, 1, false),
expectedErrCount: 0,
},
{
name: "skip unsafe backups bad",
envVals: cosmovisorEnv{absPath, "testname", "true", "false", "600ms", "bad", "", "303ms", "1"},
envVals: cosmovisorEnv{absPath, "testname", "true", "false", "600ms", "bad", "", "303ms", "1", "false"},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "skip unsafe backups not set",
envVals: cosmovisorEnv{absPath, "testname", "true", "false", "600ms", "", "", "303ms", "1"},
expectedCfg: newConfig(absPath, "testname", true, false, 600, false, absPath, 303, 1),
envVals: cosmovisorEnv{absPath, "testname", "true", "false", "600ms", "", "", "303ms", "1", "false"},
expectedCfg: newConfig(absPath, "testname", true, false, 600, false, absPath, 303, 1, false),
expectedErrCount: 0,
},
{
name: "skip unsafe backups true",
envVals: cosmovisorEnv{absPath, "testname", "true", "false", "600ms", "true", "", "303ms", "1"},
expectedCfg: newConfig(absPath, "testname", true, false, 600, true, absPath, 303, 1),
envVals: cosmovisorEnv{absPath, "testname", "true", "false", "600ms", "true", "", "303ms", "1", "false"},
expectedCfg: newConfig(absPath, "testname", true, false, 600, true, absPath, 303, 1, false),
expectedErrCount: 0,
},
{
name: "skip unsafe backups false",
envVals: cosmovisorEnv{absPath, "testname", "true", "false", "600ms", "false", "", "303ms", "1"},
expectedCfg: newConfig(absPath, "testname", true, false, 600, false, absPath, 303, 1),
envVals: cosmovisorEnv{absPath, "testname", "true", "false", "600ms", "false", "", "303ms", "1", "false"},
expectedCfg: newConfig(absPath, "testname", true, false, 600, false, absPath, 303, 1, false),
expectedErrCount: 0,
},
{
name: "poll interval bad",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "bad", "1"},
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "bad", "1", "false"},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "poll interval 0",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "0", "1"},
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "0", "1", "false"},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "poll interval not set",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "", "1"},
expectedCfg: newConfig(absPath, "testname", false, false, 600, false, absPath, 300, 1),
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "", "1", "false"},
expectedCfg: newConfig(absPath, "testname", false, false, 600, false, absPath, 300, 1, false),
expectedErrCount: 0,
},
{
name: "poll interval 600",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "600", "1"},
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "600", "1", "false"},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "poll interval 1s",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "1s", "1"},
expectedCfg: newConfig(absPath, "testname", false, false, 600, false, absPath, 1000, 1),
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "1s", "1", "false"},
expectedCfg: newConfig(absPath, "testname", false, false, 600, false, absPath, 1000, 1, false),
expectedErrCount: 0,
},
{
name: "poll interval -3m",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "-3m", "1"},
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "-3m", "1", "false"},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "restart delay bad",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "bad", "false", "", "303ms", "1"},
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "bad", "false", "", "303ms", "1", "false"},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "restart delay 0",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "0", "false", "", "303ms", "1"},
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "0", "false", "", "303ms", "1", "false"},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "restart delay not set",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "", "false", "", "303ms", "1"},
expectedCfg: newConfig(absPath, "testname", false, false, 0, false, absPath, 303, 1),
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "", "false", "", "303ms", "1", "false"},
expectedCfg: newConfig(absPath, "testname", false, false, 0, false, absPath, 303, 1, false),
expectedErrCount: 0,
},
{
name: "restart delay 600",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600", "false", "", "300ms", "1"},
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600", "false", "", "300ms", "1", "false"},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "restart delay 1s",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "1s", "false", "", "303ms", "1"},
expectedCfg: newConfig(absPath, "testname", false, false, 1000, false, absPath, 303, 1),
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "1s", "false", "", "303ms", "1", "false"},
expectedCfg: newConfig(absPath, "testname", false, false, 1000, false, absPath, 303, 1, false),
expectedErrCount: 0,
},
{
name: "restart delay -3m",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "-3m", "false", "", "303ms", "1"},
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "-3m", "false", "", "303ms", "1", "false"},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "prepupgrade max retries bad",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "406ms", "bad"},
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "406ms", "bad", "false"},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "prepupgrade max retries 0",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "406ms", "0"},
expectedCfg: newConfig(absPath, "testname", false, false, 600, false, absPath, 406, 0),
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "406ms", "0", "false"},
expectedCfg: newConfig(absPath, "testname", false, false, 600, false, absPath, 406, 0, false),
expectedErrCount: 0,
},
{
name: "prepupgrade max retries not set",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "406ms", ""},
expectedCfg: newConfig(absPath, "testname", false, false, 600, false, absPath, 406, 0),
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "406ms", "", "false"},
expectedCfg: newConfig(absPath, "testname", false, false, 600, false, absPath, 406, 0, false),
expectedErrCount: 0,
},
{
name: "prepupgrade max retries 5",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "406ms", "5"},
expectedCfg: newConfig(absPath, "testname", false, false, 600, false, absPath, 406, 5),
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "406ms", "5", "false"},
expectedCfg: newConfig(absPath, "testname", false, false, 600, false, absPath, 406, 5, false),
expectedErrCount: 0,
},
{
name: "disable logs bad",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "406ms", "5", "bad"},
expectedCfg: nil,
expectedErrCount: 1,
},
{
name: "disable logs good",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "600ms", "false", "", "406ms", "", "true"},
expectedCfg: newConfig(absPath, "testname", false, false, 600, false, absPath, 406, 0, true),
expectedErrCount: 0,
},
}

View File

@ -3,6 +3,7 @@ package main
import (
"cosmossdk.io/log"
"cosmossdk.io/tools/cosmovisor"
"github.com/rs/zerolog"
"github.com/spf13/cobra"
)
@ -16,19 +17,23 @@ var runCmd = &cobra.Command{
SilenceUsage: true,
DisableFlagParsing: true,
RunE: func(cmd *cobra.Command, args []string) error {
logger := cmd.Context().Value(log.ContextKey).(log.Logger)
return Run(logger, args)
return Run(cmd, args)
},
}
// Run runs the configured program with the given args and monitors it for upgrades.
func Run(logger log.Logger, args []string, options ...RunOption) error {
func Run(cmd *cobra.Command, args []string, options ...RunOption) error {
cfg, err := cosmovisor.GetConfigFromEnv()
if err != nil {
return err
}
logger := cmd.Context().Value(log.ContextKey).(log.Logger)
if cfg.DisableLogs {
logger = log.NewCustomLogger(zerolog.Nop())
}
runCfg := DefaultRunConfig
for _, opt := range options {
opt(&runCfg)

View File

@ -6,8 +6,6 @@ import (
"runtime/debug"
"strings"
"cosmossdk.io/log"
"github.com/rs/zerolog"
"github.com/spf13/cobra"
)
@ -24,13 +22,11 @@ var versionCmd = &cobra.Command{
Short: "Prints the version of Cosmovisor.",
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
logger := cmd.Context().Value(log.ContextKey).(log.Logger)
if val, err := cmd.Flags().GetString(OutputFlag); val == "json" && err == nil {
return printVersionJSON(logger, args)
return printVersionJSON(cmd, args)
}
return printVersion(logger, args)
return printVersion(cmd, args)
},
}
@ -43,25 +39,21 @@ func getVersion() string {
return strings.TrimSpace(version.Main.Version)
}
func printVersion(logger log.Logger, args []string) error {
func printVersion(cmd *cobra.Command, args []string) error {
fmt.Printf("cosmovisor version: %s\n", getVersion())
if err := Run(logger, append([]string{"version"}, args...)); err != nil {
if err := Run(cmd, append([]string{"version"}, args...)); err != nil {
return fmt.Errorf("failed to run version command: %w", err)
}
return nil
}
func printVersionJSON(logger log.Logger, args []string) error {
func printVersionJSON(cmd *cobra.Command, args []string) error {
buf := new(strings.Builder)
// disable logger
zl := logger.Impl().(*zerolog.Logger)
logger = log.NewCustomLogger(zl.Level(zerolog.Disabled))
if err := Run(
logger,
cmd,
[]string{"version", "--long", "--output", "json"},
StdOutRunOption(buf),
); err != nil {