diff --git a/build/buildx-alpine.Dockerfile b/build/buildx-alpine.Dockerfile index f78e98e..ac66221 100644 --- a/build/buildx-alpine.Dockerfile +++ b/build/buildx-alpine.Dockerfile @@ -20,11 +20,6 @@ RUN git config --global --add safe.directory '*' COPY contentserver /usr/bin/ ENTRYPOINT ["/usr/bin/contentserver"] -ENV CONTENT_SERVER_ADDRESS=0.0.0.0:8080 -ENV CONTENT_SERVER_VAR_DIR=/var/lib/contentserver -ENV LOG_JSON=1 - EXPOSE 8080 EXPOSE 9200 - -CMD ["-address=$CONTENT_SERVER_ADDRESS", "-var-dir=$CONTENT_SERVER_VAR_DIR"] +EXPOSE 9400 diff --git a/build/buildx.Dockerfile b/build/buildx.Dockerfile index 16efe7f..1744d9a 100644 --- a/build/buildx.Dockerfile +++ b/build/buildx.Dockerfile @@ -15,11 +15,6 @@ RUN git config --global --add safe.directory '*' COPY contentserver /usr/bin/ ENTRYPOINT ["/usr/bin/contentserver"] -ENV CONTENT_SERVER_ADDRESS=0.0.0.0:8080 -ENV CONTENT_SERVER_VAR_DIR=/var/lib/contentserver -ENV LOG_JSON=1 - EXPOSE 8080 EXPOSE 9200 - -CMD ["-address=$CONTENT_SERVER_ADDRESS", "-var-dir=$CONTENT_SERVER_VAR_DIR"] +EXPOSE 9400 diff --git a/cmd/flags.go b/cmd/flags.go index a5f58fa..fd79413 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -1,23 +1,65 @@ package cmd import ( + "time" + "github.com/spf13/cobra" + "github.com/spf13/pflag" "github.com/spf13/viper" ) +func logLevelFlag(v *viper.Viper) string { + return v.GetString("log.level") +} + +func addLogLevelFlag(flags *pflag.FlagSet, v *viper.Viper) { + flags.String("log-level", "info", "log level") + _ = v.BindPFlag("log.level", flags.Lookup("log-level")) + _ = v.BindEnv("log.level", "LOG_LEVEL") +} + +func logFormatFlag(v *viper.Viper) string { + return v.GetString("log.format") +} + +func addLogFormatFlag(flags *pflag.FlagSet, v *viper.Viper) { + flags.String("log-format", "json", "log format") + _ = v.BindPFlag("log.format", flags.Lookup("log-format")) + _ = v.BindEnv("log.format", "LOG_FORMAT") +} + +func addressFlag(v *viper.Viper) string { + return v.GetString("address") +} + func addAddressFlag(cmd *cobra.Command, v *viper.Viper) { - cmd.Flags().String("address", "localhost:8080", "Address to bind to (host:port)") + cmd.Flags().String("address", ":8080", "Address to bind to (host:port)") _ = v.BindPFlag("address", cmd.Flags().Lookup("address")) + _ = v.BindEnv("address", "CONTENT_SERVER_ADDRESS") +} + +func basePathFlag(v *viper.Viper) string { + return v.GetString("base_path") } func addBasePathFlag(cmd *cobra.Command, v *viper.Viper) { cmd.Flags().String("base-path", "/contentserver", "Base path to export the webserver on") _ = v.BindPFlag("base_path", cmd.Flags().Lookup("base_path")) + _ = v.BindEnv("base_path", "CONTENT_SERVER_BASE_PATH") +} + +func pollFlag(v *viper.Viper) bool { + return v.GetBool("poll") } func addPollFlag(cmd *cobra.Command, v *viper.Viper) { cmd.Flags().Bool("poll", false, "If true, the address arg will be used to periodically poll the content url") _ = v.BindPFlag("poll", cmd.Flags().Lookup("poll")) + _ = v.BindEnv("poll", "CONTENT_SERVER_POLL") +} + +func historyDirFlag(v *viper.Viper) string { + return v.GetString("history.dir") } func addHistoryDirFlag(cmd *cobra.Command, v *viper.Viper) { @@ -26,32 +68,60 @@ func addHistoryDirFlag(cmd *cobra.Command, v *viper.Viper) { _ = v.BindEnv("history.dir", "CONTENT_SERVER_HISTORY_DIR") } +func historyLimitFlag(v *viper.Viper) string { + return v.GetString("history.limit") +} + func addHistoryLimitFlag(cmd *cobra.Command, v *viper.Viper) { cmd.Flags().Int("history-limit", 2, "Number of history records to keep") _ = v.BindPFlag("history.limit", cmd.Flags().Lookup("history-limit")) + _ = v.BindEnv("history.limit", "CONTENT_SERVER_HISTORY_LIMIT") +} + +func gracefulTimeoutFlag(v *viper.Viper) time.Duration { + return v.GetDuration("graceful_timeout") } func addGracefulTimeoutFlag(cmd *cobra.Command, v *viper.Viper) { cmd.Flags().Duration("graceful-timeout", 0, "Timeout duration for graceful shutdown") - _ = v.BindPFlag("graceful.timeout", cmd.Flags().Lookup("graceful-timeout")) + _ = v.BindPFlag("graceful_timeout", cmd.Flags().Lookup("graceful-timeout")) + _ = v.BindEnv("graceful_timeout", "CONTENT_SERVER_GRACEFUL_TIMEOUT") +} + +func shutdownTimeoutFlag(v *viper.Viper) time.Duration { + return v.GetDuration("shutdown_timeout") } func addShutdownTimeoutFlag(cmd *cobra.Command, v *viper.Viper) { cmd.Flags().Duration("shutdown-timeout", 0, "Timeout duration for shutdown") - _ = v.BindPFlag("shutdown.timeout", cmd.Flags().Lookup("shutdown-timeout")) + _ = v.BindPFlag("shutdown_timeout", cmd.Flags().Lookup("shutdown-timeout")) + _ = v.BindEnv("shutdown_timeout", "CONTENT_SERVER_SHUTDOWN_TIMEOUT") +} + +func serviceHealthzEnabledFlag(v *viper.Viper) bool { + return v.GetBool("service.healthz.enabled") +} + +func addServiceHealthzEnabledFlag(cmd *cobra.Command, v *viper.Viper) { + cmd.Flags().Bool("service-healthz-enabled", false, "Enable healthz service") + _ = v.BindPFlag("service.healthz.enabled", cmd.Flags().Lookup("service-healthz-enabled")) +} + +func servicePrometheusEnabledFlag(v *viper.Viper) bool { + return v.GetBool("service.prometheus.enabled") +} + +func addServicePrometheusEnabledFlag(cmd *cobra.Command, v *viper.Viper) { + cmd.Flags().Bool("service-prometheus-enabled", false, "Enable prometheus service") + _ = v.BindPFlag("service.prometheus.enabled", cmd.Flags().Lookup("service-prometheus-enabled")) +} + +func otelEnabledFlag(v *viper.Viper) bool { + return v.GetBool("otel.enabled") } func addOtelEnabledFlag(cmd *cobra.Command, v *viper.Viper) { cmd.Flags().Bool("otel-enabled", false, "Enable otel service") _ = v.BindPFlag("otel.enabled", cmd.Flags().Lookup("otel-enabled")) -} - -func addHealthzEnabledFlag(cmd *cobra.Command, v *viper.Viper) { - cmd.Flags().Bool("healthz-enabled", false, "Enable healthz service") - _ = v.BindPFlag("healthz.enabled", cmd.Flags().Lookup("healthz-enabled")) -} - -func addPrometheusEnabledFlag(cmd *cobra.Command, v *viper.Viper) { - cmd.Flags().Bool("prometheus-enabled", false, "Enable prometheus service") - _ = v.BindPFlag("prometheus.enabled", cmd.Flags().Lookup("prometheus-enabled")) + _ = v.BindEnv("otel.enabled", "OTEL_ENABLED") } diff --git a/cmd/http.go b/cmd/http.go index ef82e81..bb6104d 100644 --- a/cmd/http.go +++ b/cmd/http.go @@ -16,7 +16,7 @@ import ( ) func NewHTTPCommand() *cobra.Command { - v := NewViper() + v := newViper() cmd := &cobra.Command{ Use: "http ", Short: "Start http server", @@ -32,11 +32,10 @@ func NewHTTPCommand() *cobra.Command { }, RunE: func(cmd *cobra.Command, args []string) error { svr := keel.NewServer( - keel.WithLogger(logger), keel.WithHTTPReadmeService(true), - keel.WithHTTPPrometheusService(v.GetBool("prometheus.enabled")), - keel.WithHTTPHealthzService(v.GetBool("healthz.enabled")), - keel.WithPrometheusMeter(v.GetBool("prometheus.enabled")), + keel.WithHTTPPrometheusService(v.GetBool("service.prometheus.enabled")), + keel.WithHTTPHealthzService(v.GetBool("service.healthz.enabled")), + keel.WithPrometheusMeter(v.GetBool("service.prometheus.enabled")), keel.WithOTLPGRPCTracer(v.GetBool("otel.enabled")), keel.WithGracefulTimeout(v.GetDuration("graceful.timeout")), keel.WithShutdownTimeout(v.GetDuration("shutdown.timeout")), @@ -44,6 +43,8 @@ func NewHTTPCommand() *cobra.Command { l := svr.Logger() + l.Error("test") + r := repo.New(l, args[0], repo.NewHistory(l, @@ -91,12 +92,8 @@ func NewHTTPCommand() *cobra.Command { addGracefulTimeoutFlag(cmd, v) addShutdownTimeoutFlag(cmd, v) addOtelEnabledFlag(cmd, v) - addHealthzEnabledFlag(cmd, v) - addPrometheusEnabledFlag(cmd, v) + addServiceHealthzEnabledFlag(cmd, v) + addServicePrometheusEnabledFlag(cmd, v) return cmd } - -func init() { - rootCmd.AddCommand(NewHTTPCommand()) -} diff --git a/cmd/init.go b/cmd/init.go deleted file mode 100644 index 83f7bdc..0000000 --- a/cmd/init.go +++ /dev/null @@ -1,27 +0,0 @@ -package cmd - -import ( - "strings" - - "github.com/spf13/viper" - "go.uber.org/zap" -) - -// initConfig reads in config file and ENV variables if set. -func initConfig() { - viper.EnvKeyReplacer(strings.NewReplacer(".", "_")) -} - -// initConfig reads in config file and ENV variables if set. -func initLogger() { - var err error - c := zap.NewProductionConfig() - c.Level, err = zap.ParseAtomicLevel(logLevel) - if err != nil { - panic(err) - } - logger, err = c.Build() - if err != nil { - panic(err) - } -} diff --git a/cmd/root.go b/cmd/root.go index e6966e4..ced7ae4 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,48 +1,56 @@ package cmd import ( - "os" + "strings" + "github.com/foomo/keel/log" "github.com/spf13/cobra" "github.com/spf13/viper" "go.uber.org/zap" ) -var ( - logger *zap.Logger - logLevel string -) +// NewRootCommand represents the base command when called without any subcommands +func NewRootCommand() *cobra.Command { + v := newViper() + cmd := &cobra.Command{ + Use: "contentserver", + Short: "Serves content tree structures very quickly", + PersistentPreRun: func(cmd *cobra.Command, args []string) { + zap.ReplaceGlobals(log.NewLogger( + logLevelFlag(v), + logFormatFlag(v), + )) + }, + } -// rootCmd represents the base command when called without any subcommands -var rootCmd = &cobra.Command{ - Use: "contentserver", - Short: "Serves content tree structures very quickly", + addLogLevelFlag(cmd.PersistentFlags(), v) + addLogFormatFlag(cmd.PersistentFlags(), v) + + cmd.AddCommand(NewHTTPCommand()) + cmd.AddCommand(NewSocketCommand()) + cmd.AddCommand(NewVersionCommand()) + + return cmd } // Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { - err := rootCmd.Execute() - if err != nil { - os.Exit(1) + if err := NewRootCommand().Execute(); err != nil { + log.Logger().Fatal("failed to run command", zap.Error(err)) } } func init() { - cobra.OnInitialize(initConfig, initLogger) - - // Here you will define your flags and configuration settings. - // Cobra supports persistent flags, which, if defined here, - // will be global for your application. - - rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "log level") - - // Cobra also supports local flags, which will only run - // when this action is called directly. - // rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + cobra.OnInitialize(initConfig) } -func NewViper() *viper.Viper { +// initConfig reads in config file and ENV variables if set. +func initConfig() { + viper.EnvKeyReplacer(strings.NewReplacer(".", "_")) +} + +func newViper() *viper.Viper { v := viper.New() v.AutomaticEnv() return v diff --git a/cmd/socket.go b/cmd/socket.go index ef5fd74..669f705 100644 --- a/cmd/socket.go +++ b/cmd/socket.go @@ -6,6 +6,7 @@ import ( "github.com/foomo/contentserver/pkg/handler" "github.com/foomo/contentserver/pkg/repo" + "github.com/foomo/keel/log" keelhttp "github.com/foomo/keel/net/http" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -28,7 +29,7 @@ func NewSocketCommand() *cobra.Command { return comps, cobra.ShellCompDirectiveNoFileComp }, RunE: func(cmd *cobra.Command, args []string) error { - l := logger + l := log.Logger() r := repo.New(l, args[0], @@ -90,7 +91,3 @@ func NewSocketCommand() *cobra.Command { return cmd } - -func init() { - rootCmd.AddCommand(NewSocketCommand()) -} diff --git a/cmd/version.go b/cmd/version.go index 92815b1..f3c81ac 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -9,14 +9,13 @@ import ( // Populated by goreleaser during build var version = "latest" -var versionCmd = &cobra.Command{ - Use: "version", - Short: "Print version information", - Run: func(cmd *cobra.Command, args []string) { - fmt.Println(version) - }, -} - -func init() { - rootCmd.AddCommand(versionCmd) +func NewVersionCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "version", + Short: "Print version information", + Run: func(cmd *cobra.Command, args []string) { + fmt.Println(version) + }, + } + return cmd } diff --git a/go.mod b/go.mod index 965abbf..5258eaa 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/foomo/contentserver go 1.21 require ( - github.com/foomo/keel v0.17.4-0.20240315155218-1be83011f59e // #190 (1be8301) update otel + github.com/foomo/keel v0.17.4-0.20240322093729-5c5d32717bb4 // #190 (5c5d327) update otel github.com/google/uuid v1.6.0 github.com/json-iterator/go v1.1.12 github.com/pkg/errors v0.9.1 @@ -16,7 +16,10 @@ require ( golang.org/x/sync v0.6.0 ) -require golang.org/x/net v0.21.0 +require ( + github.com/spf13/pflag v1.0.5 + golang.org/x/net v0.21.0 +) require ( cloud.google.com/go v0.111.0 // indirect @@ -84,7 +87,6 @@ require ( github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/tinylib/msgp v1.1.9 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect diff --git a/go.sum b/go.sum index b25ce2f..8115080 100644 --- a/go.sum +++ b/go.sum @@ -60,8 +60,8 @@ github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNY github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/foomo/keel v0.17.4-0.20240315155218-1be83011f59e h1:cAUtpoQqHHhuXPMY930rG3zzBx2Dp86/3l9gp04yPHU= -github.com/foomo/keel v0.17.4-0.20240315155218-1be83011f59e/go.mod h1:+90rU3I9pErPp3n28ZaSB708n+nfPEf5cVP1lqn5Sf8= +github.com/foomo/keel v0.17.4-0.20240322093729-5c5d32717bb4 h1:lmIP24NSehzMR9928PRg78jt1BYP9eEuhr3/WZouAZg= +github.com/foomo/keel v0.17.4-0.20240322093729-5c5d32717bb4/go.mod h1:+90rU3I9pErPp3n28ZaSB708n+nfPEf5cVP1lqn5Sf8= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=