feat: Enhance log level configuration with flexible environment and config support
- Add `LogLevel` to `GeneralConfig` for more granular logging control - Implement log level configuration from environment variable `GORDON_LOG_LEVEL` - Add default log level fallback to "info" - Support log level configuration through YAML config file - Improve log level parsing with case-insensitive matching - Add debug logging for log level configuration changes
- commit
- b5e5ea3683f65c1373d790b77cca3edbc1578e71
- author
- bamen · · 2025-03-09 16:02 UTC
- parent
- 2445c7c
- signature
- unsigned
1 file · +71 -7
M internal/common/init_config.go +71 -7
| @@ -30,11 +30,33 @@ func init() { | |||
| 30 | 30 | log.SetReportTimestamp(true) | |
| 31 | 31 | log.SetTimeFormat("15:04:05") | |
| 32 | 32 | ||
| 33 | - | // Check for debug environment variable | |
| 34 | - | if os.Getenv("ENV") == "dev" { | |
| 35 | - | // Set logger to debug level | |
| 33 | + | // First check for GORDON_LOG_LEVEL environment variable | |
| 34 | + | if logLevelEnv := os.Getenv("GORDON_LOG_LEVEL"); logLevelEnv != "" { | |
| 35 | + | // Convert string log level to charmbracelet/log level | |
| 36 | + | var logLevel log.Level | |
| 37 | + | switch strings.ToLower(logLevelEnv) { | |
| 38 | + | case "debug": | |
| 39 | + | logLevel = log.DebugLevel | |
| 40 | + | case "info": | |
| 41 | + | logLevel = log.InfoLevel | |
| 42 | + | case "warn", "warning": | |
| 43 | + | logLevel = log.WarnLevel | |
| 44 | + | case "error": | |
| 45 | + | logLevel = log.ErrorLevel | |
| 46 | + | case "fatal": | |
| 47 | + | logLevel = log.FatalLevel | |
| 48 | + | default: | |
| 49 | + | // Default to info level for unknown values | |
| 50 | + | logLevel = log.InfoLevel | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | // Set the logger level | |
| 54 | + | logger.SetLevel(logLevel) | |
| 55 | + | logger.Debug("Log level set from environment variable", "level", logLevelEnv) | |
| 56 | + | } else if os.Getenv("ENV") == "dev" { | |
| 57 | + | // Fall back to ENV=dev behavior if GORDON_LOG_LEVEL is not set | |
| 36 | 58 | logger.SetLevel(log.DebugLevel) | |
| 37 | - | logger.Debug("Debug logging enabled") | |
| 59 | + | logger.Debug("Debug logging enabled from ENV=dev") | |
| 38 | 60 | } | |
| 39 | 61 | } | |
| 40 | 62 | ||
| @@ -62,6 +84,7 @@ type AdminConfig struct { | |||
| 62 | 84 | type GeneralConfig struct { | |
| 63 | 85 | StorageDir string `yaml:"storageDir"` | |
| 64 | 86 | Token string `yaml:"token"` | |
| 87 | + | LogLevel string `yaml:"logLevel"` | |
| 65 | 88 | } | |
| 66 | 89 | type HttpConfig struct { | |
| 67 | 90 | Port string `yaml:"port"` | |
| @@ -99,9 +122,10 @@ var ( | |||
| 99 | 122 | certDir = "/certs" | |
| 100 | 123 | letsEncryptMode = "staging" | |
| 101 | 124 | autoRenew = true | |
| 102 | - | renewBefore = 30 // days | |
| 103 | - | cacheSize = 1000 // entries | |
| 104 | - | gracePeriod = 30 // seconds | |
| 125 | + | renewBefore = 30 // days | |
| 126 | + | cacheSize = 1000 // entries | |
| 127 | + | gracePeriod = 30 // seconds | |
| 128 | + | defaultLogLevel = "info" // Default log level | |
| 105 | 129 | ) | |
| 106 | 130 | ||
| 107 | 131 | // applyDefaultsToConfig applies default values to any fields that have zero values | |
| @@ -109,6 +133,13 @@ var ( | |||
| 109 | 133 | func applyDefaultsToConfig(config *Config) bool { | |
| 110 | 134 | defaultsApplied := false | |
| 111 | 135 | ||
| 136 | + | // Apply defaults to GeneralConfig | |
| 137 | + | if config.General.LogLevel == "" { | |
| 138 | + | config.General.LogLevel = defaultLogLevel | |
| 139 | + | logger.Debug("Applied default value for General.LogLevel", "value", defaultLogLevel) | |
| 140 | + | defaultsApplied = true | |
| 141 | + | } | |
| 142 | + | ||
| 112 | 143 | // Apply defaults to ReverseProxy config | |
| 113 | 144 | if config.ReverseProxy.Port == "" { | |
| 114 | 145 | config.ReverseProxy.Port = reverseProxyPort | |
| @@ -353,6 +384,12 @@ func loadConfigFromEnv(config *Config, printLogs bool) { | |||
| 353 | 384 | logger.Info("Using environment variable GORDON_TOKEN") | |
| 354 | 385 | } | |
| 355 | 386 | } | |
| 387 | + | if val := os.Getenv("GORDON_LOG_LEVEL"); val != "" { | |
| 388 | + | config.General.LogLevel = val | |
| 389 | + | if printLogs { | |
| 390 | + | logger.Info("Using environment variable GORDON_LOG_LEVEL", "value", val) | |
| 391 | + | } | |
| 392 | + | } | |
| 356 | 393 | ||
| 357 | 394 | // HTTP Configuration | |
| 358 | 395 | if val := os.Getenv("GORDON_HTTP_PORT"); val != "" { | |
| @@ -530,6 +567,7 @@ func (config *Config) LoadConfig() (*Config, error) { | |||
| 530 | 567 | *config = Config{ | |
| 531 | 568 | General: GeneralConfig{ | |
| 532 | 569 | StorageDir: homeDir + "/.gordon", | |
| 570 | + | LogLevel: defaultLogLevel, | |
| 533 | 571 | }, | |
| 534 | 572 | Http: HttpConfig{ | |
| 535 | 573 | Port: "8080", | |
| @@ -666,6 +704,7 @@ func (config *Config) LoadConfig() (*Config, error) { | |||
| 666 | 704 | *config = Config{ | |
| 667 | 705 | General: GeneralConfig{ | |
| 668 | 706 | StorageDir: homeDir + "/.gordon", | |
| 707 | + | LogLevel: defaultLogLevel, | |
| 669 | 708 | }, | |
| 670 | 709 | Http: HttpConfig{ | |
| 671 | 710 | Port: "8080", | |
| @@ -762,6 +801,31 @@ func (config *Config) LoadConfig() (*Config, error) { | |||
| 762 | 801 | logger.Info("Loaded configuration from", "path", configFilePath) | |
| 763 | 802 | } | |
| 764 | 803 | ||
| 804 | + | // Apply the log level from configuration | |
| 805 | + | if config.General.LogLevel != "" { | |
| 806 | + | // Convert string log level to charmbracelet/log level | |
| 807 | + | var logLevel log.Level | |
| 808 | + | switch strings.ToLower(config.General.LogLevel) { | |
| 809 | + | case "debug": | |
| 810 | + | logLevel = log.DebugLevel | |
| 811 | + | case "info": | |
| 812 | + | logLevel = log.InfoLevel | |
| 813 | + | case "warn", "warning": | |
| 814 | + | logLevel = log.WarnLevel | |
| 815 | + | case "error": | |
| 816 | + | logLevel = log.ErrorLevel | |
| 817 | + | case "fatal": | |
| 818 | + | logLevel = log.FatalLevel | |
| 819 | + | default: | |
| 820 | + | logger.Warn("Unknown log level specified, using default info level", "specified", config.General.LogLevel) | |
| 821 | + | logLevel = log.InfoLevel | |
| 822 | + | } | |
| 823 | + | ||
| 824 | + | // Set the logger level | |
| 825 | + | logger.SetLevel(logLevel) | |
| 826 | + | logger.Debug("Log level set from configuration", "level", config.General.LogLevel) | |
| 827 | + | } | |
| 828 | + | ||
| 765 | 829 | logger.Debug("LoadConfig: Completed LoadConfig function") | |
| 766 | 830 | return config, nil | |
| 767 | 831 | } | |
| @@ -30,11 +30,33 @@ func init() { | |||||
| 30 | log.SetReportTimestamp(true) | 30 | log.SetReportTimestamp(true) | ||
| 31 | log.SetTimeFormat("15:04:05") | 31 | log.SetTimeFormat("15:04:05") | ||
| 32 | 32 | ||||
| 33 | - | // Check for debug environment variable | 33 | + | // First check for GORDON_LOG_LEVEL environment variable |
| 34 | - | if os.Getenv("ENV") == "dev" { | 34 | + | if logLevelEnv := os.Getenv("GORDON_LOG_LEVEL"); logLevelEnv != "" { |
| 35 | - | // Set logger to debug level | 35 | + | // Convert string log level to charmbracelet/log level |
| 36 | + | var logLevel log.Level | |||
| 37 | + | switch strings.ToLower(logLevelEnv) { | |||
| 38 | + | case "debug": | |||
| 39 | + | logLevel = log.DebugLevel | |||
| 40 | + | case "info": | |||
| 41 | + | logLevel = log.InfoLevel | |||
| 42 | + | case "warn", "warning": | |||
| 43 | + | logLevel = log.WarnLevel | |||
| 44 | + | case "error": | |||
| 45 | + | logLevel = log.ErrorLevel | |||
| 46 | + | case "fatal": | |||
| 47 | + | logLevel = log.FatalLevel | |||
| 48 | + | default: | |||
| 49 | + | // Default to info level for unknown values | |||
| 50 | + | logLevel = log.InfoLevel | |||
| 51 | + | } | |||
| 52 | + | ||||
| 53 | + | // Set the logger level | |||
| 54 | + | logger.SetLevel(logLevel) | |||
| 55 | + | logger.Debug("Log level set from environment variable", "level", logLevelEnv) | |||
| 56 | + | } else if os.Getenv("ENV") == "dev" { | |||
| 57 | + | // Fall back to ENV=dev behavior if GORDON_LOG_LEVEL is not set | |||
| 36 | logger.SetLevel(log.DebugLevel) | 58 | logger.SetLevel(log.DebugLevel) | ||
| 37 | - | logger.Debug("Debug logging enabled") | 59 | + | logger.Debug("Debug logging enabled from ENV=dev") |
| 38 | } | 60 | } | ||
| 39 | } | 61 | } | ||
| 40 | 62 | ||||
| @@ -62,6 +84,7 @@ type AdminConfig struct { | |||||
| 62 | type GeneralConfig struct { | 84 | type GeneralConfig struct { | ||
| 63 | StorageDir string `yaml:"storageDir"` | 85 | StorageDir string `yaml:"storageDir"` | ||
| 64 | Token string `yaml:"token"` | 86 | Token string `yaml:"token"` | ||
| 87 | + | LogLevel string `yaml:"logLevel"` | |||
| 65 | } | 88 | } | ||
| 66 | type HttpConfig struct { | 89 | type HttpConfig struct { | ||
| 67 | Port string `yaml:"port"` | 90 | Port string `yaml:"port"` | ||
| @@ -99,9 +122,10 @@ var ( | |||||
| 99 | certDir = "/certs" | 122 | certDir = "/certs" | ||
| 100 | letsEncryptMode = "staging" | 123 | letsEncryptMode = "staging" | ||
| 101 | autoRenew = true | 124 | autoRenew = true | ||
| 102 | - | renewBefore = 30 // days | 125 | + | renewBefore = 30 // days |
| 103 | - | cacheSize = 1000 // entries | 126 | + | cacheSize = 1000 // entries |
| 104 | - | gracePeriod = 30 // seconds | 127 | + | gracePeriod = 30 // seconds |
| 128 | + | defaultLogLevel = "info" // Default log level | |||
| 105 | ) | 129 | ) | ||
| 106 | 130 | ||||
| 107 | // applyDefaultsToConfig applies default values to any fields that have zero values | 131 | // applyDefaultsToConfig applies default values to any fields that have zero values | ||
| @@ -109,6 +133,13 @@ var ( | |||||
| 109 | func applyDefaultsToConfig(config *Config) bool { | 133 | func applyDefaultsToConfig(config *Config) bool { | ||
| 110 | defaultsApplied := false | 134 | defaultsApplied := false | ||
| 111 | 135 | ||||
| 136 | + | // Apply defaults to GeneralConfig | |||
| 137 | + | if config.General.LogLevel == "" { | |||
| 138 | + | config.General.LogLevel = defaultLogLevel | |||
| 139 | + | logger.Debug("Applied default value for General.LogLevel", "value", defaultLogLevel) | |||
| 140 | + | defaultsApplied = true | |||
| 141 | + | } | |||
| 142 | + | ||||
| 112 | // Apply defaults to ReverseProxy config | 143 | // Apply defaults to ReverseProxy config | ||
| 113 | if config.ReverseProxy.Port == "" { | 144 | if config.ReverseProxy.Port == "" { | ||
| 114 | config.ReverseProxy.Port = reverseProxyPort | 145 | config.ReverseProxy.Port = reverseProxyPort | ||
| @@ -353,6 +384,12 @@ func loadConfigFromEnv(config *Config, printLogs bool) { | |||||
| 353 | logger.Info("Using environment variable GORDON_TOKEN") | 384 | logger.Info("Using environment variable GORDON_TOKEN") | ||
| 354 | } | 385 | } | ||
| 355 | } | 386 | } | ||
| 387 | + | if val := os.Getenv("GORDON_LOG_LEVEL"); val != "" { | |||
| 388 | + | config.General.LogLevel = val | |||
| 389 | + | if printLogs { | |||
| 390 | + | logger.Info("Using environment variable GORDON_LOG_LEVEL", "value", val) | |||
| 391 | + | } | |||
| 392 | + | } | |||
| 356 | 393 | ||||
| 357 | // HTTP Configuration | 394 | // HTTP Configuration | ||
| 358 | if val := os.Getenv("GORDON_HTTP_PORT"); val != "" { | 395 | if val := os.Getenv("GORDON_HTTP_PORT"); val != "" { | ||
| @@ -530,6 +567,7 @@ func (config *Config) LoadConfig() (*Config, error) { | |||||
| 530 | *config = Config{ | 567 | *config = Config{ | ||
| 531 | General: GeneralConfig{ | 568 | General: GeneralConfig{ | ||
| 532 | StorageDir: homeDir + "/.gordon", | 569 | StorageDir: homeDir + "/.gordon", | ||
| 570 | + | LogLevel: defaultLogLevel, | |||
| 533 | }, | 571 | }, | ||
| 534 | Http: HttpConfig{ | 572 | Http: HttpConfig{ | ||
| 535 | Port: "8080", | 573 | Port: "8080", | ||
| @@ -666,6 +704,7 @@ func (config *Config) LoadConfig() (*Config, error) { | |||||
| 666 | *config = Config{ | 704 | *config = Config{ | ||
| 667 | General: GeneralConfig{ | 705 | General: GeneralConfig{ | ||
| 668 | StorageDir: homeDir + "/.gordon", | 706 | StorageDir: homeDir + "/.gordon", | ||
| 707 | + | LogLevel: defaultLogLevel, | |||
| 669 | }, | 708 | }, | ||
| 670 | Http: HttpConfig{ | 709 | Http: HttpConfig{ | ||
| 671 | Port: "8080", | 710 | Port: "8080", | ||
| @@ -762,6 +801,31 @@ func (config *Config) LoadConfig() (*Config, error) { | |||||
| 762 | logger.Info("Loaded configuration from", "path", configFilePath) | 801 | logger.Info("Loaded configuration from", "path", configFilePath) | ||
| 763 | } | 802 | } | ||
| 764 | 803 | ||||
| 804 | + | // Apply the log level from configuration | |||
| 805 | + | if config.General.LogLevel != "" { | |||
| 806 | + | // Convert string log level to charmbracelet/log level | |||
| 807 | + | var logLevel log.Level | |||
| 808 | + | switch strings.ToLower(config.General.LogLevel) { | |||
| 809 | + | case "debug": | |||
| 810 | + | logLevel = log.DebugLevel | |||
| 811 | + | case "info": | |||
| 812 | + | logLevel = log.InfoLevel | |||
| 813 | + | case "warn", "warning": | |||
| 814 | + | logLevel = log.WarnLevel | |||
| 815 | + | case "error": | |||
| 816 | + | logLevel = log.ErrorLevel | |||
| 817 | + | case "fatal": | |||
| 818 | + | logLevel = log.FatalLevel | |||
| 819 | + | default: | |||
| 820 | + | logger.Warn("Unknown log level specified, using default info level", "specified", config.General.LogLevel) | |||
| 821 | + | logLevel = log.InfoLevel | |||
| 822 | + | } | |||
| 823 | + | ||||
| 824 | + | // Set the logger level | |||
| 825 | + | logger.SetLevel(logLevel) | |||
| 826 | + | logger.Debug("Log level set from configuration", "level", config.General.LogLevel) | |||
| 827 | + | } | |||
| 828 | + | ||||
| 765 | logger.Debug("LoadConfig: Completed LoadConfig function") | 829 | logger.Debug("LoadConfig: Completed LoadConfig function") | ||
| 766 | return config, nil | 830 | return config, nil | ||
| 767 | } | 831 | } | ||