Log the config after loading

This commit is contained in:
2024-12-18 22:16:20 +01:00
parent 7ccd36f0e4
commit f6de4fb839
4 changed files with 34 additions and 40 deletions

View File

@@ -5,6 +5,7 @@ import (
"log"
"novamd/internal/app"
"novamd/internal/logging"
)
// @title NovaMD API
@@ -23,6 +24,10 @@ func main() {
log.Fatal("Failed to load configuration:", err)
}
// Setup logging
logging.Setup(cfg.LogLevel)
logging.Debug("Configuration loaded", "config", logging.Redact(cfg))
// Initialize and start server
options, err := app.DefaultOptions(cfg)
if err != nil {
@@ -32,7 +37,7 @@ func main() {
server := app.NewServer(options)
defer func() {
if err := server.Close(); err != nil {
log.Println("Error closing server:", err)
logging.Error("Failed to close server:", err)
}
}()

View File

@@ -19,10 +19,10 @@ type Config struct {
RootURL string
Domain string
CORSOrigins []string
AdminEmail string
AdminPassword string
EncryptionKey string
JWTSigningKey string
AdminEmail string `log:"redact"`
AdminPassword string `log:"redact"`
EncryptionKey string `log:"redact"`
JWTSigningKey string `log:"redact"`
RateLimitRequests int
RateLimitWindow time.Duration
IsDevelopment bool
@@ -58,46 +58,37 @@ func (c *Config) validate() error {
// LoadConfig creates a new Config instance with values from environment variables
func LoadConfig() (*Config, error) {
logging.Info("loading configuration from environment variables")
config := DefaultConfig()
if env := os.Getenv("NOVAMD_ENV"); env != "" {
logging.Debug("loading config for environment", "env", env)
config.IsDevelopment = env == "development"
}
if dbPath := os.Getenv("NOVAMD_DB_PATH"); dbPath != "" {
logging.Debug("loading config for database path", "path", dbPath)
config.DBPath = dbPath
}
if workDir := os.Getenv("NOVAMD_WORKDIR"); workDir != "" {
logging.Debug("loading config for work directory", "dir", workDir)
config.WorkDir = workDir
}
if staticPath := os.Getenv("NOVAMD_STATIC_PATH"); staticPath != "" {
logging.Debug("loading config for static path", "path", staticPath)
config.StaticPath = staticPath
}
if port := os.Getenv("NOVAMD_PORT"); port != "" {
logging.Debug("loading config for port", "port", port)
config.Port = port
}
if rootURL := os.Getenv("NOVAMD_ROOT_URL"); rootURL != "" {
logging.Debug("loading config for root URL", "url", rootURL)
config.RootURL = rootURL
}
if domain := os.Getenv("NOVAMD_DOMAIN"); domain != "" {
logging.Debug("loading config for domain", "domain", domain)
config.Domain = domain
}
if corsOrigins := os.Getenv("NOVAMD_CORS_ORIGINS"); corsOrigins != "" {
logging.Debug("loading config for CORS origins", "origins", corsOrigins)
config.CORSOrigins = strings.Split(corsOrigins, ",")
}
@@ -106,35 +97,17 @@ func LoadConfig() (*Config, error) {
config.EncryptionKey = os.Getenv("NOVAMD_ENCRYPTION_KEY")
config.JWTSigningKey = os.Getenv("NOVAMD_JWT_SIGNING_KEY")
logging.Debug("sensitive configuration loaded",
"adminEmailSet", config.AdminEmail != "",
"adminPasswordSet", config.AdminPassword != "",
"encryptionKeySet", config.EncryptionKey != "",
"jwtSigningKeySet", config.JWTSigningKey != "")
// Configure rate limiting
if reqStr := os.Getenv("NOVAMD_RATE_LIMIT_REQUESTS"); reqStr != "" {
parsed, err := strconv.Atoi(reqStr)
if err != nil {
logging.Warn("invalid rate limit requests value, using default",
"value", reqStr,
"default", config.RateLimitRequests,
"error", err)
} else {
logging.Debug("loading config for rate limit requests", "requests", parsed)
if err == nil {
config.RateLimitRequests = parsed
}
}
if windowStr := os.Getenv("NOVAMD_RATE_LIMIT_WINDOW"); windowStr != "" {
parsed, err := time.ParseDuration(windowStr)
if err != nil {
logging.Warn("invalid rate limit window value, using default",
"value", windowStr,
"default", config.RateLimitWindow,
"error", err)
} else {
logging.Debug("loading config for rate limit window", "window", parsed)
if err == nil {
config.RateLimitWindow = parsed
}
}
@@ -142,13 +115,10 @@ func LoadConfig() (*Config, error) {
// Configure log level, if isDevelopment is set, default to debug
if logLevel := os.Getenv("NOVAMD_LOG_LEVEL"); logLevel != "" {
parsed := logging.ParseLogLevel(logLevel)
logging.Debug("loading config for log level", "level", parsed)
config.LogLevel = parsed
} else if config.IsDevelopment {
logging.Debug("setting log level to debug for development")
config.LogLevel = logging.DEBUG
} else {
logging.Debug("setting log level to info for production")
config.LogLevel = logging.INFO
}
@@ -157,6 +127,5 @@ func LoadConfig() (*Config, error) {
return nil, err
}
logging.Info("configuration loaded successfully")
return config, nil
}

View File

@@ -4,6 +4,7 @@ package logging
import (
"log/slog"
"os"
"reflect"
)
// Logger represents the interface for logging operations
@@ -60,6 +61,27 @@ func ParseLogLevel(level string) LogLevel {
}
}
// Redact redacts sensitive fields from a struct based on the `log` struct tag
// if the tag is set to "redact" the field value is replaced with "[REDACTED]"
func Redact(v any) map[string]any {
result := make(map[string]any)
val := reflect.ValueOf(v)
typ := val.Type()
for i := 0; i < val.NumField(); i++ {
field := typ.Field(i)
if tag := field.Tag.Get("log"); tag != "" {
switch tag {
case "redact":
result[field.Name] = "[REDACTED]"
default:
result[field.Name] = val.Field(i).Interface()
}
}
}
return result
}
// Implementation of Logger interface methods
func (l *logger) Debug(msg string, args ...any) {
l.logger.Debug(msg, args...)

View File

@@ -33,8 +33,6 @@ func getLogger() logging.Logger {
// ValidateKey checks if the provided base64-encoded key is suitable for AES-256
func ValidateKey(key string) error {
log := getLogger()
log.Debug("validating encryption key")
_, err := decodeAndValidateKey(key)
return err
}