Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cosmovisor): enable logger configuration with env variable #16573

Merged
merged 1 commit into from
Jun 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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