diff --git a/Taskfile.yml b/Taskfile.yml index b4a6c86636..e9e41e6db0 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -150,5 +150,4 @@ tasks: vars: COVERAGE_FILE: coverage.txt TEST_PATTERN: . - TEST_FLAGS: -v TEST_OPTS: -race diff --git a/cmd/flipt/main.go b/cmd/flipt/main.go index d32ee02a53..1864011685 100644 --- a/cmd/flipt/main.go +++ b/cmd/flipt/main.go @@ -80,7 +80,6 @@ var ( cfgPath string forceMigrate bool - version = devVersion commit string date string @@ -94,7 +93,7 @@ func main() { once sync.Once loggerConfig = zap.Config{ Level: zap.NewAtomicLevelAt(zap.InfoLevel), - Development: true, + Development: false, Encoding: "console", EncoderConfig: zapcore.EncoderConfig{ // Keys can be anything except the empty string. @@ -213,6 +212,13 @@ func main() { if err != nil { logger().Fatal("parsing log level", zap.String("level", cfg.Log.Level), zap.Error(err)) } + + if cfg.Log.Encoding > config.LogEncodingConsole { + loggerConfig.Encoding = cfg.Log.Encoding.String() + + // don't encode with colors if not using console log output + loggerConfig.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder + } }) rootCmd.SetVersionTemplate(banner) @@ -234,27 +240,30 @@ func main() { } func run(ctx context.Context, logger *zap.Logger) error { - color.Cyan(banner) - fmt.Println() - ctx, cancel := context.WithCancel(ctx) - defer cancel() interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM) - defer signal.Stop(interrupt) shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second) defer shutdownCancel() var ( - isRelease = isRelease() + isRelease = isRelease() + isConsole = cfg.Log.Encoding == config.LogEncodingConsole + updateAvailable bool cv, lv semver.Version ) + if isConsole { + color.Cyan("%s\n", banner) + } else { + logger.Info("flipt starting", zap.String("version", version), zap.String("commit", commit), zap.String("date", date), zap.String("go_version", goVersion)) + } + if isRelease { var err error cv, err = semver.ParseTolerant(version) @@ -639,13 +648,26 @@ func run(ctx context.Context, logger *zap.Logger) error { logger.Debug("starting http server") - color.Green("\nAPI: %s://%s:%d/api/v1", cfg.Server.Protocol, cfg.Server.Host, httpPort) + var ( + apiAddr = fmt.Sprintf("%s://%s:%d/api/v1", cfg.Server.Protocol, cfg.Server.Host, httpPort) + uiAddr = fmt.Sprintf("%s://%s:%d", cfg.Server.Protocol, cfg.Server.Host, httpPort) + ) - if cfg.UI.Enabled { - color.Green("UI: %s://%s:%d", cfg.Server.Protocol, cfg.Server.Host, httpPort) - } + if isConsole { + color.Green("\nAPI: %s", apiAddr) + + if cfg.UI.Enabled { + color.Green("UI: %s", uiAddr) + } + + fmt.Println() + } else { + logger.Info("api available", zap.String("address", apiAddr)) - fmt.Println() + if cfg.UI.Enabled { + logger.Info("ui available", zap.String("address", uiAddr)) + } + } if cfg.Server.Protocol == config.HTTPS { httpServer.TLSConfig = &tls.Config{ diff --git a/config/config.go b/config/config.go index c1284089cd..4f768bf893 100644 --- a/config/config.go +++ b/config/config.go @@ -32,10 +32,35 @@ type Config struct { } type LogConfig struct { - Level string `json:"level,omitempty"` - File string `json:"file,omitempty"` + Level string `json:"level,omitempty"` + File string `json:"file,omitempty"` + Encoding LogEncoding `json:"encoding,omitempty"` } +type LogEncoding uint8 + +func (e LogEncoding) String() string { + return logEncodingToString[e] +} + +const ( + _ LogEncoding = iota + LogEncodingConsole + LogEncodingJSON +) + +var ( + logEncodingToString = map[LogEncoding]string{ + LogEncodingConsole: "console", + LogEncodingJSON: "json", + } + + stringToLogEncoding = map[string]LogEncoding{ + "console": LogEncodingConsole, + "json": LogEncodingJSON, + } +) + type UIConfig struct { Enabled bool `json:"enabled"` } @@ -189,7 +214,8 @@ var ( func Default() *Config { return &Config{ Log: LogConfig{ - Level: "INFO", + Level: "INFO", + Encoding: LogEncodingConsole, }, UI: UIConfig{ @@ -248,8 +274,9 @@ func Default() *Config { const ( // Logging - logLevel = "log.level" - logFile = "log.file" + logLevel = "log.level" + logFile = "log.file" + logEncoding = "log.encoding" // UI uiEnabled = "ui.enabled" @@ -325,6 +352,10 @@ func Load(path string) (*Config, error) { cfg.Log.File = viper.GetString(logFile) } + if viper.IsSet(logEncoding) { + cfg.Log.Encoding = stringToLogEncoding[viper.GetString(logEncoding)] + } + // UI if viper.IsSet(uiEnabled) { cfg.UI.Enabled = viper.GetBool(uiEnabled) diff --git a/config/config_test.go b/config/config_test.go index 85ca2faa39..f30442cbf9 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -106,6 +106,36 @@ func TestDatabaseProtocol(t *testing.T) { } } +func TestLogEncoding(t *testing.T) { + tests := []struct { + name string + encoding LogEncoding + want string + }{ + { + name: "console", + encoding: LogEncodingConsole, + want: "console", + }, + { + name: "json", + encoding: LogEncodingJSON, + want: "json", + }, + } + + for _, tt := range tests { + var ( + encoding = tt.encoding + want = tt.want + ) + + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, want, encoding.String()) + }) + } +} + func TestLoad(t *testing.T) { tests := []struct { name string @@ -197,8 +227,9 @@ func TestLoad(t *testing.T) { expected: func() *Config { cfg := Default() cfg.Log = LogConfig{ - Level: "WARN", - File: "testLogFile.txt", + Level: "WARN", + File: "testLogFile.txt", + Encoding: LogEncodingJSON, } cfg.UI = UIConfig{ Enabled: false, diff --git a/config/testdata/advanced.yml b/config/testdata/advanced.yml index 933ab24eff..d2edd63b59 100644 --- a/config/testdata/advanced.yml +++ b/config/testdata/advanced.yml @@ -1,6 +1,7 @@ log: level: WARN file: "testLogFile.txt" + encoding: "json" ui: enabled: false