switch to log-format flag

This commit is contained in:
nils måsén 2023-08-12 17:02:24 +02:00
parent be98119552
commit 6b0c37f3d3
4 changed files with 109 additions and 59 deletions

View file

@ -1,6 +1,7 @@
package cmd package cmd
import ( import (
"errors"
"math" "math"
"net/http" "net/http"
"os" "os"
@ -28,18 +29,17 @@ import (
) )
var ( var (
client container.Client client container.Client
scheduleSpec string scheduleSpec string
cleanup bool cleanup bool
noRestart bool noRestart bool
monitorOnly bool monitorOnly bool
enableLabel bool enableLabel bool
enableJsonFormatter bool notifier t.Notifier
notifier t.Notifier timeout time.Duration
timeout time.Duration lifecycleHooks bool
lifecycleHooks bool rollingRestart bool
rollingRestart bool scope string
scope string
) )
var rootCmd = NewRootCommand() var rootCmd = NewRootCommand()
@ -77,31 +77,11 @@ func Execute() {
// PreRun is a lifecycle hook that runs before the command is executed. // PreRun is a lifecycle hook that runs before the command is executed.
func PreRun(cmd *cobra.Command, _ []string) { func PreRun(cmd *cobra.Command, _ []string) {
f := cmd.PersistentFlags() f := cmd.PersistentFlags()
if err := flags.SetupLogging(f); err != nil {
log.Fatalf("Failed to initialize logging: %s", err.Error())
}
flags.ProcessFlagAliases(f) flags.ProcessFlagAliases(f)
if enabled, _ := f.GetBool("no-color"); enabled {
log.SetFormatter(&log.TextFormatter{
DisableColors: true,
})
} else {
// enable logrus built-in support for https://bixense.com/clicolors/
log.SetFormatter(&log.TextFormatter{
EnvironmentOverrideColors: true,
})
}
rawLogLevel, _ := f.GetString(`log-level`)
if logLevel, err := log.ParseLevel(rawLogLevel); err != nil {
log.Fatalf("Invalid log level: %s", err.Error())
} else {
log.SetLevel(logLevel)
}
enableJsonFormatter, _ = f.GetBool("json-logging")
if enableJsonFormatter {
log.SetFormatter(&log.JSONFormatter{})
}
scheduleSpec, _ = f.GetString("schedule") scheduleSpec, _ = f.GetString("schedule")
flags.GetSecretsFromFiles(cmd) flags.GetSecretsFromFiles(cmd)
@ -205,7 +185,7 @@ func Run(c *cobra.Command, names []string) {
httpAPI.RegisterHandler(metricsHandler.Path, metricsHandler.Handle) httpAPI.RegisterHandler(metricsHandler.Path, metricsHandler.Handle)
} }
if err := httpAPI.Start(enableUpdateAPI && !unblockHTTPAPI); err != nil && err != http.ErrServerClosed { if err := httpAPI.Start(enableUpdateAPI && !unblockHTTPAPI); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Error("failed to start API", err) log.Error("failed to start API", err)
} }

View file

@ -107,15 +107,15 @@ Environment Variable: WATCHTOWER_LOG_LEVEL
Default: info Default: info
``` ```
## JSON Logging ## Logging format
Enables the JSON log formatter for logging, changing the log output to JSON format. By default, the log output follows the standard text-based format. Sets what logging format to use for console output.
```text ```text
Argument: --json-logging Argument: --log-format, -l
Environment Variable: WATCHTOWER_JSON_LOGGING Environment Variable: WATCHTOWER_LOG_FORMAT
Type: Boolean Possible values: Auto, LogFmt, Pretty or JSON
Default: false Default: Auto
``` ```
## ANSI colors ## ANSI colors
@ -374,4 +374,4 @@ requests and may rate limit pull requests (mainly docker.io).
Environment Variable: WATCHTOWER_WARN_ON_HEAD_FAILURE Environment Variable: WATCHTOWER_WARN_ON_HEAD_FAILURE
Possible values: always, auto, never Possible values: always, auto, never
Default: auto Default: auto
``` ```

View file

@ -86,11 +86,11 @@ func RegisterSystemFlags(rootCmd *cobra.Command) {
viper.GetBool("WATCHTOWER_LABEL_ENABLE"), viper.GetBool("WATCHTOWER_LABEL_ENABLE"),
"Watch containers where the com.centurylinklabs.watchtower.enable label is true") "Watch containers where the com.centurylinklabs.watchtower.enable label is true")
flags.BoolP( flags.StringP(
"json-logging", "log-format",
"j", "l",
viper.GetBool("WATCHTOWER_JSON_LOGGING"), viper.GetString("WATCHTOWER_LOG_FORMAT"),
"Enables the JSON log formatter for logging") "Sets what logging format to use for console output. Possible values: Auto, LogFmt, Pretty, JSON")
flags.BoolP( flags.BoolP(
"debug", "debug",
@ -385,6 +385,7 @@ func SetDefaults() {
viper.SetDefault("WATCHTOWER_NOTIFICATION_EMAIL_SUBJECTTAG", "") viper.SetDefault("WATCHTOWER_NOTIFICATION_EMAIL_SUBJECTTAG", "")
viper.SetDefault("WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER", "watchtower") viper.SetDefault("WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER", "watchtower")
viper.SetDefault("WATCHTOWER_LOG_LEVEL", "info") viper.SetDefault("WATCHTOWER_LOG_LEVEL", "info")
viper.SetDefault("WATCHTOWER_LOG_FORMAT", "auto")
} }
// EnvConfig translates the command-line options into environment variables // EnvConfig translates the command-line options into environment variables
@ -583,6 +584,46 @@ func ProcessFlagAliases(flags *pflag.FlagSet) {
} }
// SetupLogging reads only the flags that is needed to set up logging and applies them to the global logger
func SetupLogging(f *pflag.FlagSet) error {
logFormat, _ := f.GetString(`log-format`)
noColor, _ := f.GetBool("no-color")
switch strings.ToLower(logFormat) {
case "auto":
// This will either use the "pretty" or "logfmt" format, based on whether the standard out is connected to a TTY
log.SetFormatter(&log.TextFormatter{
DisableColors: noColor,
// enable logrus built-in support for https://bixense.com/clicolors/
EnvironmentOverrideColors: true,
})
case "json":
log.SetFormatter(&log.JSONFormatter{})
case "logfmt":
log.SetFormatter(&log.TextFormatter{
DisableColors: true,
FullTimestamp: true,
})
case "pretty":
log.SetFormatter(&log.TextFormatter{
// "Pretty" format combined with `--no-color` will only change the timestamp to the time since start
ForceColors: !noColor,
FullTimestamp: false,
})
default:
return fmt.Errorf("invalid log format: %s", logFormat)
}
rawLogLevel, _ := f.GetString(`log-level`)
if logLevel, err := log.ParseLevel(rawLogLevel); err != nil {
return fmt.Errorf("invalid log level: %e", err)
} else {
log.SetLevel(logLevel)
}
return nil
}
func flagIsEnabled(flags *pflag.FlagSet, name string) bool { func flagIsEnabled(flags *pflag.FlagSet, name string) bool {
value, err := flags.GetBool(name) value, err := flags.GetBool(name)
if err != nil { if err != nil {

View file

@ -183,26 +183,55 @@ func TestProcessFlagAliasesLogLevelFromEnvironment(t *testing.T) {
assert.Equal(t, `debug`, logLevel) assert.Equal(t, `debug`, logLevel)
} }
func TestJSONLoggingFlag(t *testing.T) { func TestLogFormatFlag(t *testing.T) {
cmd := new(cobra.Command) cmd := new(cobra.Command)
SetDefaults() SetDefaults()
RegisterDockerFlags(cmd) RegisterDockerFlags(cmd)
RegisterSystemFlags(cmd) RegisterSystemFlags(cmd)
// Ensure the default value is false // Ensure the default value is Auto
enableJsonFormatter, err := cmd.PersistentFlags().GetBool("json-logging") require.NoError(t, cmd.ParseFlags([]string{}))
require.NoError(t, err) require.NoError(t, SetupLogging(cmd.Flags()))
assert.IsType(t, &logrus.TextFormatter{}, logrus.StandardLogger().Formatter)
assert.Equal(t, false, enableJsonFormatter) // Test JSON format
require.NoError(t, cmd.ParseFlags([]string{`--log-format`, `JSON`}))
require.NoError(t, SetupLogging(cmd.Flags()))
assert.IsType(t, &logrus.JSONFormatter{}, logrus.StandardLogger().Formatter)
// Test with the argument // Test Pretty format
require.NoError(t, cmd.ParseFlags([]string{`--json-logging`})) require.NoError(t, cmd.ParseFlags([]string{`--log-format`, `pretty`}))
flags := cmd.Flags() require.NoError(t, SetupLogging(cmd.Flags()))
enableJsonFormatter, _ = flags.GetBool("json-logging") assert.IsType(t, &logrus.TextFormatter{}, logrus.StandardLogger().Formatter)
require.NoError(t, err) textFormatter, ok := (logrus.StandardLogger().Formatter).(*logrus.TextFormatter)
assert.Equal(t, true, enableJsonFormatter) assert.True(t, ok)
assert.True(t, textFormatter.ForceColors)
assert.False(t, textFormatter.FullTimestamp)
// Test LogFmt format
require.NoError(t, cmd.ParseFlags([]string{`--log-format`, `logfmt`}))
require.NoError(t, SetupLogging(cmd.Flags()))
textFormatter, ok = (logrus.StandardLogger().Formatter).(*logrus.TextFormatter)
assert.True(t, ok)
assert.True(t, textFormatter.DisableColors)
assert.True(t, textFormatter.FullTimestamp)
// Test invalid format
require.NoError(t, cmd.ParseFlags([]string{`--log-format`, `cowsay`}))
require.Error(t, SetupLogging(cmd.Flags()))
}
func TestLogLevelFlag(t *testing.T) {
cmd := new(cobra.Command)
SetDefaults()
RegisterDockerFlags(cmd)
RegisterSystemFlags(cmd)
// Test invalid format
require.NoError(t, cmd.ParseFlags([]string{`--log-level`, `gossip`}))
require.Error(t, SetupLogging(cmd.Flags()))
} }
func TestProcessFlagAliasesSchedAndInterval(t *testing.T) { func TestProcessFlagAliasesSchedAndInterval(t *testing.T) {