Skip to content

Commit

Permalink
feat(tools/cosmovisor): extend cosmovisor variables
Browse files Browse the repository at this point in the history
add COSMOVISOR_COLOR_OUTPUT as an option to enable/disable colored logs
add COSMOVISOR_TIMEFORMAT_LOGS as an option to configure/disable
timestamp prefix in the logs

Signed-off-by: Artur Troian <[email protected]>
  • Loading branch information
troian committed Jun 15, 2023
1 parent 7b26ff5 commit 201f435
Show file tree
Hide file tree
Showing 11 changed files with 325 additions and 124 deletions.
3 changes: 2 additions & 1 deletion tools/cosmovisor/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ Ref: https://keepachangelog.com/en/1.0.0/

## Features

* [#12457](https://github.com/cosmos/cosmos-sdk/issues/12457) Add `cosmovisor pre-upgrade` command to manually add an upgrade to cosmovisor.
* [#16573](https://github.com/cosmos/cosmos-sdk/pull/16573) Extend `cosmovisor` configuration with new log format options
* [#15361](https://github.com/cosmos/cosmos-sdk/pull/15361) Add `cosmovisor config` command to display the configuration used by cosmovisor.
* [#12457](https://github.com/cosmos/cosmos-sdk/issues/12457) Add `cosmovisor pre-upgrade` command to manually add an upgrade to cosmovisor.

## Improvements

Expand Down
2 changes: 2 additions & 0 deletions tools/cosmovisor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ Use of `cosmovisor` without one of the action arguments is deprecated. For backw
* `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`](https://docs.cosmos.network/main/building-apps/app-upgrade#pre-upgrade-handling) 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.
* `COSMOVISOR_COLOR_LOGS` (defaults to `true`). If set to true, this will colorise Cosmovisor logs (but not the underlying process).
* `COSMOVISOR_TIMEFORMAT_LOGS` (defaults to `kitchen`). If set to a value (`layout|ansic|unixdate|rubydate|rfc822|rfc822z|rfc850|rfc1123|rfc1123z|rfc3339|rfc3339nano|kitchen`), this will add timestamp prefix to Cosmovisor logs (but not the underlying process).

### Folder Layout

Expand Down
79 changes: 72 additions & 7 deletions tools/cosmovisor/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"net/url"
"os"
"path/filepath"
"strconv"
"strings"
"time"

"cosmossdk.io/log"
"cosmossdk.io/x/upgrade/plan"
upgradetypes "cosmossdk.io/x/upgrade/types"
"github.com/rs/zerolog"
)

// environment variable names
Expand All @@ -28,6 +31,8 @@ const (
EnvInterval = "DAEMON_POLL_INTERVAL"
EnvPreupgradeMaxRetries = "DAEMON_PREUPGRADE_MAX_RETRIES"
EnvDisableLogs = "COSMOVISOR_DISABLE_LOGS"
EnvColorLogs = "COSMOVISOR_COLOR_LOGS"
EnvTimeFormatLogs = "COSMOVISOR_TIMEFORMAT_LOGS"
)

const (
Expand All @@ -53,7 +58,8 @@ type Config struct {
DataBackupPath string
PreupgradeMaxRetries int
DisableLogs bool

ColorLogs bool
TimeFormatLogs string
// currently running upgrade
currentUpgrade upgradetypes.Plan
}
Expand Down Expand Up @@ -151,19 +157,25 @@ func GetConfigFromEnv() (*Config, error) {
}

var err error
if cfg.AllowDownloadBinaries, err = booleanOption(EnvDownloadBin, false); err != nil {
if cfg.AllowDownloadBinaries, err = BooleanOption(EnvDownloadBin, false); err != nil {
errs = append(errs, err)
}
if cfg.DownloadMustHaveChecksum, err = BooleanOption(EnvDownloadMustHaveChecksum, false); err != nil {
errs = append(errs, err)
}
if cfg.RestartAfterUpgrade, err = BooleanOption(EnvRestartUpgrade, true); err != nil {
errs = append(errs, err)
}
if cfg.DownloadMustHaveChecksum, err = booleanOption(EnvDownloadMustHaveChecksum, false); err != nil {
if cfg.UnsafeSkipBackup, err = BooleanOption(EnvSkipBackup, false); err != nil {
errs = append(errs, err)
}
if cfg.RestartAfterUpgrade, err = booleanOption(EnvRestartUpgrade, true); err != nil {
if cfg.DisableLogs, err = BooleanOption(EnvDisableLogs, false); err != nil {
errs = append(errs, err)
}
if cfg.UnsafeSkipBackup, err = booleanOption(EnvSkipBackup, false); err != nil {
if cfg.ColorLogs, err = BooleanOption(EnvColorLogs, true); err != nil {
errs = append(errs, err)
}
if cfg.DisableLogs, err = booleanOption(EnvDisableLogs, false); err != nil {
if cfg.TimeFormatLogs, err = TimeFormatOptionFromEnv(EnvTimeFormatLogs, time.Kitchen); err != nil {
errs = append(errs, err)
}

Expand Down Expand Up @@ -203,6 +215,20 @@ func GetConfigFromEnv() (*Config, error) {
return cfg, nil
}

func (cfg *Config) Logger(dst io.Writer) log.Logger {
var logger log.Logger

if cfg.DisableLogs {
logger = log.NewCustomLogger(zerolog.Nop())
} else {
logger = log.NewLogger(dst,
log.ColorOption(cfg.ColorLogs),
log.TimeFormatOption(cfg.TimeFormatLogs)).With(log.ModuleKey, "cosmovisor")
}

return logger
}

func parseEnvDuration(input string) (time.Duration, error) {
duration, err := time.ParseDuration(input)
if err != nil {
Expand Down Expand Up @@ -338,7 +364,7 @@ returnError:
}

// checks and validates env option
func booleanOption(name string, defaultVal bool) (bool, error) {
func BooleanOption(name string, defaultVal bool) (bool, error) {
p := strings.ToLower(os.Getenv(name))
switch p {
case "":
Expand All @@ -351,6 +377,43 @@ func booleanOption(name string, defaultVal bool) (bool, error) {
return false, fmt.Errorf("env variable %q must have a boolean value (\"true\" or \"false\"), got %q", name, p)
}

// checks and validates env option
func TimeFormatOptionFromEnv(env, defaultVal string) (string, error) {
val, set := os.LookupEnv(env)
if !set {
return defaultVal, nil
}
switch val {
case "layout":
return time.Layout, nil
case "ansic":
return time.ANSIC, nil
case "unixdate":
return time.UnixDate, nil
case "rubydate":
return time.RubyDate, nil
case "rfc822":
return time.RFC822, nil
case "rfc822z":
return time.RFC822Z, nil
case "rfc850":
return time.RFC850, nil
case "rfc1123":
return time.RFC1123, nil
case "rfc1123z":
return time.RFC1123Z, nil
case "rfc3339":
return time.RFC3339, nil
case "rfc3339nano":
return time.RFC3339Nano, nil
case "kitchen":
return time.Kitchen, nil
case "":
return "", nil
}
return "", fmt.Errorf("env variable %q must have a timeformat value (\"layout|ansic|unixdate|rubydate|rfc822|rfc822z|rfc850|rfc1123|rfc1123z|rfc3339|rfc3339nano|kitchen\"), got %q", EnvTimeFormatLogs, val)
}

// DetailString returns a multi-line string with details about this config.
func (cfg Config) DetailString() string {
configEntries := []struct{ name, value string }{
Expand All @@ -365,6 +428,8 @@ func (cfg Config) DetailString() string {
{EnvDataBackupPath, cfg.DataBackupPath},
{EnvPreupgradeMaxRetries, fmt.Sprintf("%d", cfg.PreupgradeMaxRetries)},
{EnvDisableLogs, fmt.Sprintf("%t", cfg.DisableLogs)},
{EnvColorLogs, fmt.Sprintf("%t", cfg.ColorLogs)},
{EnvTimeFormatLogs, cfg.TimeFormatLogs},
}

derivedEntries := []struct{ name, value string }{
Expand Down
Loading

0 comments on commit 201f435

Please sign in to comment.