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"
@ -34,7 +35,6 @@ var (
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
@ -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

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) {