From e12f3b844df0311bd8110ed74afa746776a6baab Mon Sep 17 00:00:00 2001 From: nhyatt Date: Sat, 4 Nov 2023 13:10:29 -0500 Subject: [PATCH] Updates functions so they actually work :P --- internal/config/envconfig.go | 17 +++--- internal/config/initialize.go | 91 ++++++++++++++++++++++++-------- internal/config/struct-config.go | 32 ++++++----- readme.md | 2 +- 4 files changed, 96 insertions(+), 46 deletions(-) diff --git a/internal/config/envconfig.go b/internal/config/envconfig.go index 3eaf00b..befa0bb 100644 --- a/internal/config/envconfig.go +++ b/internal/config/envconfig.go @@ -203,7 +203,7 @@ func typeConversion(t, v string) (interface{}, error) { return nil, fmt.Errorf("Unable to identify type.") } -func (cfg *Config) parseFlags(cfgInfo []structInfo) { +func (cfg *Config) parseFlags(cfgInfo []structInfo) error { for _, info := range cfgInfo { switch info.Type.String() { case "string": @@ -223,21 +223,19 @@ func (cfg *Config) parseFlags(cfgInfo []structInfo) { p := reflect.ValueOf(cfg).Elem().FieldByName(info.Name).Addr().Interface().(*bool) retVal, err := getEnvBool(info.Alt, dv) if err != nil { - cfg.Log.Error("Error Encountered", "error", err) - os.Exit(1) + return err } flag.BoolVar(p, info.Name, retVal, info.Info) case "int": var dv int if info.DefaultValue != nil { - dv = info.DefaultValue.(int) + dv = int(info.DefaultValue.(int64)) } p := reflect.ValueOf(cfg).Elem().FieldByName(info.Name).Addr().Interface().(*int) retVal, err := getEnvInt(info.Alt, dv) if err != nil { - cfg.Log.Error("Error Encountered", "error", err) - os.Exit(1) + return err } flag.IntVar(p, info.Name, retVal, info.Info) case "int64": @@ -249,8 +247,7 @@ func (cfg *Config) parseFlags(cfgInfo []structInfo) { p := reflect.ValueOf(cfg).Elem().FieldByName(info.Name).Addr().Interface().(*int64) retVal, err := getEnvInt64(info.Alt, dv) if err != nil { - cfg.Log.Error("Error Encountered", "error", err) - os.Exit(1) + return err } flag.Int64Var(p, info.Name, retVal, info.Info) case "float64": @@ -262,11 +259,11 @@ func (cfg *Config) parseFlags(cfgInfo []structInfo) { p := reflect.ValueOf(cfg).Elem().FieldByName(info.Name).Addr().Interface().(*float64) retVal, err := getEnvFloat64(info.Alt, dv) if err != nil { - cfg.Log.Error("Error Encountered", "error", err) - os.Exit(1) + return err } flag.Float64Var(p, info.Name, retVal, info.Info) } } flag.Parse() + return nil } diff --git a/internal/config/initialize.go b/internal/config/initialize.go index 42ad7dd..f499a77 100644 --- a/internal/config/initialize.go +++ b/internal/config/initialize.go @@ -1,36 +1,81 @@ package config import ( + "log/slog" "os" + "reflect" + "strconv" "time" ) -func Init() *Config { - cfg := New() +type Config struct { + // time configuration + TimeFormat string `default:"2006-01-02 15:04:05" env:"time_format"` + TimeZoneLocal string `default:"America/Chicago" env:"time_zone"` + TZLocal *time.Location `ignored:"true"` + TZUTC *time.Location `ignored:"true"` - cfgInfo, err := getStructInfo(cfg) - if err != nil { - cfg.Log.Error("Unable to initialize program parameters", "error", err) - os.Exit(1) + // logging + LogLevel int `default:"50" env:"log_level"` + Log *slog.Logger `ignored:"true"` + SLogLevel *slog.LevelVar `ignored:"true"` + + // webserver + WebServerPort int `default:"8080" env:"webserver_port"` + WebServerIP string `default:"0.0.0.0" env:"webserver_ip"` + WebServerReadTimeout int `default:"5" env:"webserver_read_timeout"` + WebServerWriteTimeout int `default:"1" env:"webserver_write_timeout"` + WebServerIdleTimeout int `default:"2" env:"webserver_idle_timeout"` +} + +// New initializes the config variable for use with a prepared set of defaults. +func New() Config { + cfg := Config{ + SLogLevel: new(slog.LevelVar), } - // get command line flags - cfg.parseFlags(cfgInfo) + cfg.Log = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ + Level: cfg.SLogLevel, + })) - // set logging Level - setLogLevel(cfg) - - // set timezone & time format - cfg.TZUTC, _ = time.LoadLocation("UTC") - cfg.TZLocal, err = time.LoadLocation(cfg.TimeZoneLocal) - if err != nil { - cfg.Log.Error("Unable to parse timezone string", "error", err) - os.Exit(1) - } - - // print running config - printRunningConfig(cfg, cfgInfo) - - // return configuration return cfg } + +func setLogLevel(cfg *Config) { + switch { + // error + case cfg.LogLevel <= 20: + cfg.SLogLevel.Set(slog.LevelError) + cfg.Log.Info("Log level updated", "level", slog.LevelError) + // warning + case cfg.LogLevel > 20 && cfg.LogLevel <= 40: + cfg.SLogLevel.Set(slog.LevelWarn) + cfg.Log.Info("Log level updated", "level", slog.LevelWarn) + // info + case cfg.LogLevel > 40 && cfg.LogLevel <= 60: + cfg.SLogLevel.Set(slog.LevelInfo) + cfg.Log.Info("Log level updated", "level", slog.LevelInfo) + // debug + case cfg.LogLevel > 60: + cfg.SLogLevel.Set(slog.LevelDebug) + cfg.Log.Info("Log level updated", "level", slog.LevelDebug) + } + // set default logger + slog.SetDefault(cfg.Log) +} + +func printRunningConfig(cfg *Config, cfgInfo []structInfo) { + for _, info := range cfgInfo { + switch info.Type.String() { + case "string": + p := reflect.ValueOf(cfg).Elem().FieldByName(info.Name).Addr().Interface().(*string) + cfg.Log.Debug("Running Configuration", info.Alt, *p) + case "bool": + p := reflect.ValueOf(cfg).Elem().FieldByName(info.Name).Addr().Interface().(*bool) + cfg.Log.Debug("Running Configuration", info.Alt, strconv.FormatBool(*p)) + case "int": + p := reflect.ValueOf(cfg).Elem().FieldByName(info.Name).Addr().Interface().(*int) + cfg.Log.Debug("Running Configuration", info.Alt, strconv.FormatInt(int64(*p), 10)) + } + } +} diff --git a/internal/config/struct-config.go b/internal/config/struct-config.go index c4d4c46..f499a77 100644 --- a/internal/config/struct-config.go +++ b/internal/config/struct-config.go @@ -2,6 +2,7 @@ package config import ( "log/slog" + "os" "reflect" "strconv" "time" @@ -9,14 +10,15 @@ import ( type Config struct { // time configuration - TimeFormat string `default:"2006-01-02 15:04:05" env:"TIME_FORMAT"` - TimeZoneLocal string `default:"America/Chicago" env:"TIME_ZONE"` + TimeFormat string `default:"2006-01-02 15:04:05" env:"time_format"` + TimeZoneLocal string `default:"America/Chicago" env:"time_zone"` TZLocal *time.Location `ignored:"true"` TZUTC *time.Location `ignored:"true"` // logging - LogLevel int `default:"50" env:"log_level"` - Log *slog.Logger `ignored:"true"` + LogLevel int `default:"50" env:"log_level"` + Log *slog.Logger `ignored:"true"` + SLogLevel *slog.LevelVar `ignored:"true"` // webserver WebServerPort int `default:"8080" env:"webserver_port"` @@ -27,29 +29,35 @@ type Config struct { } // New initializes the config variable for use with a prepared set of defaults. -func New() *Config { - return &Config{} +func New() Config { + cfg := Config{ + SLogLevel: new(slog.LevelVar), + } + + cfg.Log = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ + Level: cfg.SLogLevel, + })) + + return cfg } func setLogLevel(cfg *Config) { - logLevel := &slog.LevelVar{} - switch { // error case cfg.LogLevel <= 20: - logLevel.Set(slog.LevelError) + cfg.SLogLevel.Set(slog.LevelError) cfg.Log.Info("Log level updated", "level", slog.LevelError) // warning case cfg.LogLevel > 20 && cfg.LogLevel <= 40: - logLevel.Set(slog.LevelWarn) + cfg.SLogLevel.Set(slog.LevelWarn) cfg.Log.Info("Log level updated", "level", slog.LevelWarn) // info case cfg.LogLevel > 40 && cfg.LogLevel <= 60: - logLevel.Set(slog.LevelInfo) + cfg.SLogLevel.Set(slog.LevelInfo) cfg.Log.Info("Log level updated", "level", slog.LevelInfo) // debug case cfg.LogLevel > 60: - logLevel.Set(slog.LevelDebug) + cfg.SLogLevel.Set(slog.LevelDebug) cfg.Log.Info("Log level updated", "level", slog.LevelDebug) } // set default logger diff --git a/readme.md b/readme.md index 5f00e4c..3f051ff 100644 --- a/readme.md +++ b/readme.md @@ -11,7 +11,7 @@ This is a base repository for starting a GoLang project. It includes a set of li ## Usage -Clone this repository and run the following command: +Clone this repository and update [`go.mod`](./go.mod) ```bash PRJCT="example.com/newproject"