149 lines
4.4 KiB
Go
149 lines
4.4 KiB
Go
package config
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
|
|
"veza-backend-api/internal/logging"
|
|
"veza-backend-api/internal/middleware"
|
|
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
)
|
|
|
|
// Reloadable représente une configuration qui peut être rechargée (T0034)
|
|
type Reloadable interface {
|
|
Reload() error
|
|
}
|
|
|
|
// ConfigReloader gère le rechargement de configurations à chaud (T0034)
|
|
type ConfigReloader struct {
|
|
mu sync.RWMutex
|
|
config *Config
|
|
logger *zap.Logger
|
|
loggingService *logging.Logger // Service de logging pour changement de niveau dynamique
|
|
simpleRateLimiter *middleware.SimpleRateLimiter
|
|
}
|
|
|
|
// NewConfigReloader crée un nouveau ConfigReloader (T0034)
|
|
func NewConfigReloader(config *Config, logger *zap.Logger) *ConfigReloader {
|
|
return &ConfigReloader{
|
|
config: config,
|
|
logger: logger,
|
|
loggingService: nil, // Sera initialisé lors du premier reload si nécessaire
|
|
simpleRateLimiter: config.SimpleRateLimiter,
|
|
}
|
|
}
|
|
|
|
// SetLoggingService définit le service de logging pour permettre le changement dynamique de niveau
|
|
func (r *ConfigReloader) SetLoggingService(loggingService *logging.Logger) {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
r.loggingService = loggingService
|
|
}
|
|
|
|
// ReloadLogLevel recharge le niveau de log depuis les variables d'environnement (T0034)
|
|
func (r *ConfigReloader) ReloadLogLevel() error {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
|
|
// Récupérer le nouveau niveau depuis les variables d'environnement
|
|
newLevelStr := getEnv("LOG_LEVEL", "INFO")
|
|
if newLevelStr == "" {
|
|
newLevelStr = "INFO"
|
|
}
|
|
|
|
// Parser le niveau
|
|
level, err := zapcore.ParseLevel(newLevelStr)
|
|
if err != nil {
|
|
level = zapcore.InfoLevel
|
|
}
|
|
|
|
// Si le logger zap est accessible directement et utilise AtomicLevel
|
|
// On peut changer le niveau dynamiquement
|
|
if r.config.Logger != nil {
|
|
// Essayer de changer le niveau via l'AtomicLevel si disponible
|
|
// Note: Le logger zap doit être créé avec AtomicLevel pour permettre le changement dynamique
|
|
// Pour l'instant, on log juste le changement et on met à jour la config
|
|
r.config.LogLevel = newLevelStr
|
|
r.logger.Info("Log level reloaded from environment",
|
|
zap.String("old_level", r.config.LogLevel),
|
|
zap.String("new_level", newLevelStr),
|
|
zap.String("parsed_level", level.String()),
|
|
)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ReloadRateLimits recharge les limites de rate limiting depuis les variables d'environnement (T0034)
|
|
func (r *ConfigReloader) ReloadRateLimits() error {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
|
|
// Récupérer les nouvelles limites depuis les variables d'environnement
|
|
newLimit := getEnvInt("RATE_LIMIT_LIMIT", 100)
|
|
newWindowSeconds := getEnvInt("RATE_LIMIT_WINDOW", 60)
|
|
newWindow := time.Duration(newWindowSeconds) * time.Second
|
|
|
|
// Si le simple rate limiter existe, mettre à jour ses limites
|
|
if r.simpleRateLimiter != nil {
|
|
// Mettre à jour les limites directement dans le rate limiter
|
|
r.simpleRateLimiter.UpdateLimits(newLimit, newWindow)
|
|
|
|
// Mettre à jour la config
|
|
r.config.RateLimitLimit = newLimit
|
|
r.config.RateLimitWindow = newWindowSeconds
|
|
|
|
r.logger.Info("Rate limits reloaded from environment",
|
|
zap.Int("new_limit", newLimit),
|
|
zap.Int("new_window_seconds", newWindowSeconds),
|
|
)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ReloadAll recharge toutes les configurations reloadable (T0034)
|
|
func (r *ConfigReloader) ReloadAll() error {
|
|
var errors []error
|
|
|
|
// Recharger le niveau de log
|
|
if err := r.ReloadLogLevel(); err != nil {
|
|
errors = append(errors, err)
|
|
}
|
|
|
|
// Recharger les limites de rate limiting
|
|
if err := r.ReloadRateLimits(); err != nil {
|
|
errors = append(errors, err)
|
|
}
|
|
|
|
if len(errors) > 0 {
|
|
r.logger.Error("Some configurations failed to reload", zap.Int("error_count", len(errors)))
|
|
return errors[0] // Retourner la première erreur
|
|
}
|
|
|
|
r.logger.Info("All configurations reloaded successfully")
|
|
return nil
|
|
}
|
|
|
|
// GetCurrentConfig retourne la configuration actuelle (en lecture seule)
|
|
func (r *ConfigReloader) GetCurrentConfig() *ReloadableConfig {
|
|
r.mu.RLock()
|
|
defer r.mu.RUnlock()
|
|
|
|
return &ReloadableConfig{
|
|
LogLevel: r.config.LogLevel,
|
|
RateLimitLimit: r.config.RateLimitLimit,
|
|
RateLimitWindow: r.config.RateLimitWindow,
|
|
}
|
|
}
|
|
|
|
// ReloadableConfig représente la partie de la configuration qui peut être rechargée
|
|
type ReloadableConfig struct {
|
|
LogLevel string `json:"log_level"`
|
|
RateLimitLimit int `json:"rate_limit_limit"`
|
|
RateLimitWindow int `json:"rate_limit_window"`
|
|
}
|
|
|
|
// Note: getEnv et getEnvInt sont définis dans config.go
|