package config import ( "flag" "fmt" "os" "github.com/caarlos0/env/v9" "gopkg.in/yaml.v3" ) type AppConfig struct { Name string `yaml:"name" env:"APP_NAME" envDefault:"go-http-server-with-otel"` Environment string `yaml:"environment" env:"APP_ENVIRONMENT" envDefault:"development"` Version string `yaml:"version" env:"APP_VERSION"` Logging LogConfig `yaml:"logging"` HTTP HTTPConfig `yaml:"http"` OTEL OTELConfig `yaml:"otel"` } type LogConfig struct { Enabled bool `yaml:"enabled" env:"APP_LOGGING_ENABLED" envDefault:"true"` Level string `yaml:"level" env:"APP_LOGGING_LEVEL" envDefault:"info"` Format string `yaml:"format" env:"APP_LOGGING_FORMAT" envDefault:"json"` } type HTTPConfig struct { Listen string `yaml:"listen" env:"APP_HTTP_LISTEN" envDefault:"127.0.0.1:8080"` RequestTimeout int `yaml:"request_timeout" env:"APP_HTTP_REQUEST_TIMEOUT" envDefault:"30"` } type OTELConfig struct { Enabled bool `yaml:"enabled" env:"APP_OTEL_ENABLED" envDefault:"true"` PrometheusEnabled bool `yaml:"prometheus_enabled" env:"APP_OTEL_PROMETHEUS_ENABLED" envDefault:"true"` PrometheusPath string `yaml:"prometheus_path" env:"APP_OTEL_PROMETHEUS_PATH" envDefault:"/metrics"` } // Calling this will try to load from config if -config is // provided, otherwise will return *AppConfig with defaults, // performing any environment substitutions func LoadConfig() (*AppConfig, error) { configPath := flag.String("config", "", "Path to the configuration file") flag.Parse() return loadConfig(*configPath) } func loadConfig(configPath string) (*AppConfig, error) { cfg := AppConfig{} if configPath != "" { file, err := os.Open(configPath) if err != nil { return nil, fmt.Errorf("could not open config file: %w", err) } defer file.Close() decoder := yaml.NewDecoder(file) if err := decoder.Decode(&cfg); err != nil { return nil, fmt.Errorf("could not decode config file: %w", err) } } if err := env.Parse(&cfg); err != nil { return nil, fmt.Errorf("could not parse environment variables: %w", err) } return &cfg, nil }