diff options
author | dakkar <dakkar@thenautilus.net> | 2024-12-19 09:42:17 +0000 |
---|---|---|
committer | dakkar <dakkar@thenautilus.net> | 2024-12-19 09:42:17 +0000 |
commit | c940ac4f72e7e55ef1a7aa35cc0fc32684716977 (patch) | |
tree | df46d71d6b0ea49a979f90fc43b6947617942b04 /config/config.go | |
download | go-example-c940ac4f72e7e55ef1a7aa35cc0fc32684716977.tar.gz go-example-c940ac4f72e7e55ef1a7aa35cc0fc32684716977.tar.bz2 go-example-c940ac4f72e7e55ef1a7aa35cc0fc32684716977.zip |
minimal example
Diffstat (limited to 'config/config.go')
-rw-r--r-- | config/config.go | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..3c93d53 --- /dev/null +++ b/config/config.go @@ -0,0 +1,126 @@ +package config + +import ( + "errors" + "fmt" + "os" + "path" + "strings" + + "github.com/mitchellh/mapstructure" + "github.com/rs/zerolog" + "github.com/spf13/pflag" + "github.com/spf13/viper" +) + +type LoggerConfig struct { + Verbose bool `mapstructure:"verbose"` + Format string `mapstructure:"format"` +} + +func (c *LoggerConfig) MarshalZerologObject(e *zerolog.Event) { + e. + Bool("verbose", c.Verbose). + Str("format", c.Format) +} + +type SomethingConfig struct { + Value int `mapstructure:"value"` +} + +func (c *SomethingConfig) MarshalZerologObject(event *zerolog.Event) { + event. + Int("value", c.Value) +} + +type MainConfig struct { + Something SomethingConfig `mapstructure:"something"` + Logger LoggerConfig `mapstructure:"logger"` + + configFile string +} + +func (c *MainConfig) MarshalZerologObject(event *zerolog.Event) { + event. + Str("config-file", c.configFile). + Object("logger", &c.Logger). + Object("something", &c.Something) +} + +func addLoggerOptions() { + pflag.Bool("verbose", false, "log at debug level") + viper.BindPFlag("logger.verbose", pflag.Lookup("verbose")) //nolint:errcheck + pflag.String("log-format", "json", "logging format (json, console)") + viper.BindPFlag("logger.format", pflag.Lookup("log-format")) //nolint:errcheck +} + +func addSomethingOptions() { + pflag.Int("something-value", 123, "value used to do something") + viper.BindPFlag("something.value", pflag.Lookup("something-value")) //nolint:errcheck + viper.BindEnv("something.value", "SOMETHING_VALUE") //nolint:errcheck +} + +func addConfigFromFile(configRelPath string) error { + mode := os.Getenv("RUN_MODE") + if mode == "" { + mode = "development" + } + + viper.SetConfigName("example." + mode) + + myName, err := os.Executable() + if err == nil && !strings.HasPrefix(configRelPath, "/") { + myDir := path.Dir(myName) + viper.AddConfigPath(path.Join(myDir, configRelPath)) + } else { + viper.AddConfigPath(configRelPath) + } + + err = viper.ReadInConfig() + if err != nil { + var notFound viper.ConfigFileNotFoundError + if !errors.As(err, ¬Found) { + return fmt.Errorf("failed to read config file at %s: %w", viper.ConfigFileUsed(), err) + } + } + + return nil +} + +func loadConfigFromFile(path string) (MainConfig, error) { + pathFromEnv := os.Getenv("EXAMPLE_CONFIG") + if pathFromEnv != "" { + path = pathFromEnv + } + + err := addConfigFromFile(path) + if err != nil { + return MainConfig{}, err + } + + var config MainConfig + + err = viper.Unmarshal(&config, viper.DecodeHook( + mapstructure.ComposeDecodeHookFunc( + mapstructure.StringToTimeDurationHookFunc(), + mapstructure.StringToIPHookFunc(), + ), + )) + if err != nil { + return MainConfig{}, fmt.Errorf("failed to parse options: %w", err) + } + + config.configFile = viper.ConfigFileUsed() + + return config, nil +} + +func GetMainConfig(path string) (MainConfig, error) { + addLoggerOptions() + addSomethingOptions() + + pflag.Parse() + viper.BindPFlags(pflag.CommandLine) //nolint:errcheck + + return loadConfigFromFile(path) +} |