Skip to content

Commit

Permalink
feat: Improve error logging when configuration load fails
Browse files Browse the repository at this point in the history
  • Loading branch information
aholstenson committed Jun 19, 2024
1 parent 03a5072 commit 1bd816a
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 29 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
73 changes: 47 additions & 26 deletions internal/config/config.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
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"
)

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
Expand All @@ -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
Expand All @@ -38,36 +44,51 @@ 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
}

return config, nil
}
}

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
Expand Down

0 comments on commit 1bd816a

Please sign in to comment.