diff --git a/go.mod b/go.mod index e410c77..73872e2 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ toolchain go1.22.2 require ( github.com/KimMachineGun/automemlimit v0.6.1 github.com/alexliesenfeld/health v0.8.0 - github.com/caarlos0/env/v9 v9.0.0 + github.com/caarlos0/env/v11 v11.1.0 github.com/go-logr/logr v1.4.2 github.com/go-logr/zapr v1.3.0 github.com/onsi/ginkgo/v2 v2.19.0 diff --git a/go.sum b/go.sum index d66587a..959724b 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ github.com/KimMachineGun/automemlimit v0.6.1 h1:ILa9j1onAAMadBsyyUJv5cack8Y1WT26 github.com/KimMachineGun/automemlimit v0.6.1/go.mod h1:T7xYht7B8r6AG/AqFcUdc7fzd2bIdBKmepfP2S1svPY= github.com/alexliesenfeld/health v0.8.0 h1:lCV0i+ZJPTbqP7LfKG7p3qZBl5VhelwUFCIVWl77fgk= github.com/alexliesenfeld/health v0.8.0/go.mod h1:TfNP0f+9WQVWMQRzvMUjlws4ceXKEL3WR+6Hp95HUFc= -github.com/caarlos0/env/v9 v9.0.0 h1:SI6JNsOA+y5gj9njpgybykATIylrRMklbs5ch6wO6pc= -github.com/caarlos0/env/v9 v9.0.0/go.mod h1:ye5mlCVMYh6tZ+vCgrs/B95sj88cg5Tlnc0XIzgZ020= +github.com/caarlos0/env/v11 v11.1.0 h1:a5qZqieE9ZfzdvbbdhTalRrHT5vu/4V1/ad1Ka6frhI= +github.com/caarlos0/env/v11 v11.1.0/go.mod h1:LwgkYk1kDvfGpHthrWWLof3Ny7PezzFwS4QrsJdHTMo= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cilium/ebpf v0.9.1 h1:64sn2K3UKw8NbP/blsixRpF3nXuyhz/VjRlRzvlBRu4= diff --git a/internal/config/config.go b/internal/config/config.go index be45a47..fd8e420 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1,10 +1,11 @@ package config import ( + "errors" "reflect" - "github.com/caarlos0/env/v9" - "github.com/go-logr/logr" + "github.com/caarlos0/env/v11" + "github.com/levelfourab/sprout-go/internal/logging" "go.uber.org/fx" "go.uber.org/zap" ) @@ -12,8 +13,7 @@ import ( type In struct { fx.In - Logger *zap.Logger `optional:"true"` - LogrLogger *logr.Logger `optional:"true"` + Logger *zap.Logger `optional:"true"` } // Config will read configuration from the environment and provide the @@ -24,11 +24,17 @@ func Config[T any](prefix string, value T) any { } return func(in In) (T, error) { - var config = value + config := value + + logger := in.Logger + if logger == nil { + // No logger provided, use the default logger + logger = logging.CreateLogger(zap.L(), []string{"config"}) + } opts := env.Options{ Prefix: prefix, - OnSet: logFunc(in), + OnSet: logFunc(logger), } var err error @@ -38,7 +44,14 @@ func Config[T any](prefix string, value T) any { err = env.ParseWithOptions(&config, opts) } - if err != nil { + var aggregateError env.AggregateError + if errors.As(err, &aggregateError) { + for _, err := range aggregateError.Errors { + logError(logger, err) + } + + return config, errors.New("failed to load configuration") + } else if err != nil { return config, err } @@ -46,28 +59,36 @@ func Config[T any](prefix string, value T) any { } } -func logFunc(in In) func(tag string, value interface{}, isDefault bool) { - if in.Logger != nil { - logger := in.Logger - return func(tag string, value interface{}, isDefault bool) { - if !isDefault { - logger.Info("Read config value", zap.String("key", tag), zap.Any("value", value)) - } else { - logger.Debug("Config value set to default", zap.String("key", tag), zap.Any("value", value)) - } - } - } else if in.LogrLogger != nil { - logger := in.LogrLogger - return func(tag string, value interface{}, isDefault bool) { - if !isDefault { - logger.Info("Read config value", "key", tag, "value", value) - } else { - logger.V(1).Info("Config value set to default", "key", tag, "value", value) - } +func logFunc(logger *zap.Logger) func(tag string, value interface{}, isDefault bool) { + return func(tag string, value interface{}, isDefault bool) { + if !isDefault { + logger.Info("Read config value", zap.String("key", tag), zap.Any("value", value)) + } else { + logger.Info("Config value set to default", zap.String("key", tag), zap.Any("value", value)) } } +} + +func logError(logger *zap.Logger, err error) { + var parseError env.ParseError + if errors.As(err, &parseError) { + logger.Error("Failed to parse configuration value", zap.String("key", parseError.Name), zap.Error(parseError.Err)) + return + } + + var envVarIsNotSetError env.EnvVarIsNotSetError + if errors.As(err, &envVarIsNotSetError) { + logger.Error("Required environment variable is not set", zap.String("key", envVarIsNotSetError.Key)) + return + } + + var emptyEnvVarError env.EmptyEnvVarError + if errors.As(err, &emptyEnvVarError) { + logger.Error("Environment variable should not be empty", zap.String("key", emptyEnvVarError.Key)) + return + } - return func(tag string, value interface{}, isDefault bool) {} + logger.Error("Failed to parse configuration", zap.Error(err)) } // BindConfig is an on-demand version of Config. It will read configuration