refactor(backend): replace 40 fmt.Printf calls with zap structured logging
CLN-03: router.go, track/service.go, upload_validator.go, cors.go, playlist_handler.go, and mfa.go now use zap.L() or local logger for structured logging instead of fmt.Printf.
This commit is contained in:
parent
8e9431fe93
commit
872e42d81c
6 changed files with 54 additions and 50 deletions
|
|
@ -89,17 +89,18 @@ func getUploadConfigWithEnv() *services.UploadConfig {
|
|||
|
||||
// Lire ENABLE_CLAMAV depuis l'environnement (défaut: true pour sécurité en production)
|
||||
envValue := os.Getenv("ENABLE_CLAMAV")
|
||||
fmt.Printf("🔍 [ROUTER] ENABLE_CLAMAV depuis env: '%s'\n", envValue)
|
||||
zap.L().Debug("ENABLE_CLAMAV from env", zap.String("value", envValue))
|
||||
clamAVEnabled := getEnvBool("ENABLE_CLAMAV", true)
|
||||
fmt.Printf("🔍 [ROUTER] ENABLE_CLAMAV parsé: %v\n", clamAVEnabled)
|
||||
zap.L().Debug("ENABLE_CLAMAV parsed", zap.Bool("value", clamAVEnabled))
|
||||
uploadConfig.ClamAVEnabled = clamAVEnabled
|
||||
|
||||
// Lire CLAMAV_REQUIRED depuis l'environnement (défaut: true pour sécurité)
|
||||
clamAVRequired := getEnvBool("CLAMAV_REQUIRED", true)
|
||||
uploadConfig.ClamAVRequired = clamAVRequired
|
||||
|
||||
fmt.Printf("🔧 [ROUTER] Configuration finale - ClamAVEnabled=%v, ClamAVRequired=%v\n",
|
||||
uploadConfig.ClamAVEnabled, uploadConfig.ClamAVRequired)
|
||||
zap.L().Info("Upload config final",
|
||||
zap.Bool("clamav_enabled", uploadConfig.ClamAVEnabled),
|
||||
zap.Bool("clamav_required", uploadConfig.ClamAVRequired))
|
||||
|
||||
return uploadConfig
|
||||
}
|
||||
|
|
@ -108,17 +109,17 @@ func getUploadConfigWithEnv() *services.UploadConfig {
|
|||
func getEnvBool(key string, defaultValue bool) bool {
|
||||
value := os.Getenv(key)
|
||||
if value == "" {
|
||||
fmt.Printf("🔍 [ROUTER] Variable %s non définie, utilisation défaut: %v\n", key, defaultValue)
|
||||
zap.L().Debug("Env var undefined, using default", zap.String("key", key), zap.Bool("default", defaultValue))
|
||||
return defaultValue
|
||||
}
|
||||
// Nettoyer la valeur (trim spaces)
|
||||
value = strings.TrimSpace(value)
|
||||
fmt.Printf("🔍 [ROUTER] Variable %s='%s' (trimmed)\n", key, value)
|
||||
zap.L().Debug("Env var trimmed", zap.String("key", key), zap.String("value", value))
|
||||
if boolValue, err := strconv.ParseBool(value); err == nil {
|
||||
fmt.Printf("🔍 [ROUTER] Variable %s parsée: %v\n", key, boolValue)
|
||||
zap.L().Debug("Env var parsed", zap.String("key", key), zap.Bool("value", boolValue))
|
||||
return boolValue
|
||||
}
|
||||
fmt.Printf("⚠️ [ROUTER] Erreur parsing %s='%s', utilisation défaut: %v\n", key, value, defaultValue)
|
||||
zap.L().Warn("Env var parse error, using default", zap.String("key", key), zap.String("value", value), zap.Bool("default", defaultValue))
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -227,19 +227,19 @@ func (s *TrackService) UploadTrack(ctx context.Context, userID uuid.UUID, fileHe
|
|||
}
|
||||
|
||||
// Créer le répertoire d'upload s'il n'existe pas
|
||||
fmt.Printf("📁 [UPLOAD] Vérification dossier upload: %s\n", s.uploadDir)
|
||||
s.logger.Debug("Checking upload directory", zap.String("upload_dir", s.uploadDir))
|
||||
if err := os.MkdirAll(s.uploadDir, 0755); err != nil {
|
||||
fmt.Printf("❌ [UPLOAD] Erreur création dossier: %v\n", err)
|
||||
s.logger.Error("Failed to create upload directory", zap.String("upload_dir", s.uploadDir), zap.Error(err))
|
||||
return nil, fmt.Errorf("%w: failed to create upload directory: %w", ErrStorageError, err)
|
||||
}
|
||||
fmt.Printf("✅ [UPLOAD] Dossier upload créé/vérifié: %s\n", s.uploadDir)
|
||||
s.logger.Debug("Upload directory created/verified", zap.String("upload_dir", s.uploadDir))
|
||||
|
||||
// Générer un nom de fichier unique
|
||||
timestamp := uuid.New()
|
||||
ext := filepath.Ext(fileHeader.Filename)
|
||||
filename := fmt.Sprintf("%s_%s%s", userID.String(), timestamp.String(), ext) // Fixed format to use strings for UUID
|
||||
filePath := filepath.Join(s.uploadDir, filename)
|
||||
fmt.Printf("💾 [UPLOAD] Chemin fichier de destination: %s\n", filePath)
|
||||
s.logger.Debug("Upload destination path", zap.String("file_path", filePath))
|
||||
|
||||
// Déterminer le format depuis l'extension
|
||||
format := strings.TrimPrefix(strings.ToUpper(ext), ".")
|
||||
|
|
@ -274,14 +274,14 @@ func (s *TrackService) UploadTrack(ctx context.Context, userID uuid.UUID, fileHe
|
|||
}
|
||||
|
||||
if err := s.db.WithContext(ctx).Create(track).Error; err != nil {
|
||||
fmt.Printf("❌ [UPLOAD] Erreur création enregistrement track: %v\n", err)
|
||||
s.logger.Error("Failed to create track record", zap.Error(err))
|
||||
return nil, fmt.Errorf("failed to create track record: %w", err)
|
||||
}
|
||||
fmt.Printf("✅ [UPLOAD] Enregistrement track créé en DB (ID: %s)\n", track.ID.String())
|
||||
s.logger.Debug("Track record created in DB", zap.String("track_id", track.ID.String()))
|
||||
|
||||
// MOD-P2-008: Lancer la copie fichier en goroutine avec suivi (context + cancellation)
|
||||
// La goroutine mettra à jour le Status quand terminé
|
||||
fmt.Printf("🚀 [UPLOAD] Lancement copie fichier en asynchrone...\n")
|
||||
s.logger.Debug("Starting async file copy")
|
||||
go s.copyFileAsync(ctx, track.ID, fileHeader, filePath, userID)
|
||||
|
||||
// MOD-P2-003: Enregistrer la métrique business
|
||||
|
|
@ -305,39 +305,39 @@ func (s *TrackService) copyFileAsync(ctx context.Context, trackID uuid.UUID, fil
|
|||
defer cancel()
|
||||
|
||||
// Ouvrir le fichier source
|
||||
fmt.Printf("📂 [UPLOAD ASYNC] Ouverture fichier source...\n")
|
||||
s.logger.Debug("Opening source file for async copy")
|
||||
src, err := fileHeader.Open()
|
||||
if err != nil {
|
||||
fmt.Printf("❌ [UPLOAD ASYNC] Erreur ouverture fichier source: %v\n", err)
|
||||
s.logger.Error("Failed to open source file for async copy", zap.Error(err))
|
||||
s.updateTrackStatus(copyCtx, trackID, models.TrackStatusFailed, fmt.Sprintf("Failed to open uploaded file: %v", err))
|
||||
s.cleanupFailedUpload(filePath, trackID, "failed to open source file")
|
||||
return
|
||||
}
|
||||
defer src.Close()
|
||||
fmt.Printf("✅ [UPLOAD ASYNC] Fichier source ouvert\n")
|
||||
s.logger.Debug("Source file opened for async copy")
|
||||
|
||||
// Créer le fichier de destination
|
||||
fmt.Printf("💾 [UPLOAD ASYNC] Création fichier destination: %s\n", filePath)
|
||||
s.logger.Debug("Creating destination file", zap.String("file_path", filePath))
|
||||
dst, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ [UPLOAD ASYNC] Erreur création fichier destination: %v\n", err)
|
||||
s.logger.Error("Failed to create destination file", zap.String("file_path", filePath), zap.Error(err))
|
||||
s.updateTrackStatus(copyCtx, trackID, models.TrackStatusFailed, fmt.Sprintf("Failed to create destination file: %v", err))
|
||||
s.cleanupFailedUpload(filePath, trackID, "failed to create destination file")
|
||||
return
|
||||
}
|
||||
defer dst.Close()
|
||||
fmt.Printf("✅ [UPLOAD ASYNC] Fichier destination créé\n")
|
||||
s.logger.Debug("Destination file created")
|
||||
|
||||
// Copier le fichier avec gestion d'erreurs
|
||||
fmt.Printf("📋 [UPLOAD ASYNC] Début copie fichier...\n")
|
||||
s.logger.Debug("Starting file copy")
|
||||
bytesWritten, err := io.Copy(dst, src)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ [UPLOAD ASYNC] Erreur copie fichier: %v\n", err)
|
||||
s.logger.Error("File copy failed", zap.Error(err))
|
||||
s.updateTrackStatus(copyCtx, trackID, models.TrackStatusFailed, fmt.Sprintf("Failed to save file: %v", err))
|
||||
s.cleanupFailedUpload(filePath, trackID, fmt.Sprintf("copy failed: %v", err))
|
||||
return
|
||||
}
|
||||
fmt.Printf("✅ [UPLOAD ASYNC] Fichier copié avec succès (%d bytes écrits)\n", bytesWritten)
|
||||
s.logger.Debug("File copied successfully", zap.Int64("bytes_written", bytesWritten))
|
||||
|
||||
// Vérifier si le contexte a été annulé
|
||||
select {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package handlers
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
|
@ -163,14 +162,14 @@ func (h *PlaylistHandler) GetPlaylists(c *gin.Context) {
|
|||
// Get current user ID
|
||||
var currentUserID *uuid.UUID
|
||||
if uidInterface, exists := c.Get("user_id"); exists {
|
||||
fmt.Printf("🔍 [HANDLER] GetPlaylists: user_id found in context: %v (Type: %T)\n", uidInterface, uidInterface)
|
||||
h.commonHandler.logger.Debug("GetPlaylists: user_id found in context", zap.Any("value", uidInterface))
|
||||
if uid, ok := uidInterface.(uuid.UUID); ok {
|
||||
currentUserID = &uid
|
||||
} else {
|
||||
fmt.Printf("❌ [HANDLER] GetPlaylists: user_id type assertion failed\n")
|
||||
h.commonHandler.logger.Debug("GetPlaylists: user_id type assertion failed")
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("❌ [HANDLER] GetPlaylists: user_id NOT found in context\n")
|
||||
h.commonHandler.logger.Debug("GetPlaylists: user_id not found in context")
|
||||
}
|
||||
|
||||
// MOD-P1-004: Ajouter timeout context pour opération DB
|
||||
|
|
|
|||
|
|
@ -79,7 +79,11 @@ func ValidateCORSConfiguration(allowedOrigins []string, environment string, logg
|
|||
)
|
||||
} else {
|
||||
// Fallback si logger n'est pas disponible
|
||||
fmt.Printf("⚠️ %s\n", warningMsg)
|
||||
zap.L().Warn(warningMsg,
|
||||
zap.Strings("weak_origins", weakOrigins),
|
||||
zap.String("environment", environment),
|
||||
zap.String("recommendation", "Use specific origins instead of wildcards for production"),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/pquerna/otp/totp"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// MFAMethod représente une méthode MFA
|
||||
|
|
@ -188,7 +189,7 @@ func (mfa *MFAManager) SendSMSCode(methodID string) (string, error) {
|
|||
|
||||
// Dans un vrai système, on enverrait le SMS via un service
|
||||
// Ici on simule l'envoi
|
||||
fmt.Printf("SMS code sent to %s: %s\n", method.Phone, code)
|
||||
zap.L().Info("SMS MFA code sent", zap.String("phone", method.Phone))
|
||||
|
||||
return code, nil
|
||||
}
|
||||
|
|
@ -248,7 +249,7 @@ func (mfa *MFAManager) SendEmailCode(methodID string) (string, error) {
|
|||
|
||||
// Dans un vrai système, on enverrait l'email via un service
|
||||
// Ici on simule l'envoi
|
||||
fmt.Printf("Email code sent to %s: %s\n", method.Email, code)
|
||||
zap.L().Info("Email MFA code sent", zap.String("email", method.Email))
|
||||
|
||||
return code, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,11 +91,12 @@ func DefaultUploadConfig() *UploadConfig {
|
|||
// MOD-P1-001-REFINEMENT: Fail-secure localisé - serveur démarre même si ClamAV down,
|
||||
// mais uploads seront rejetés lors de la validation
|
||||
func NewUploadValidator(config *UploadConfig, logger *zap.Logger) (*UploadValidator, error) {
|
||||
fmt.Printf("🔧 [UPLOAD VALIDATOR] Initialisation - ClamAVEnabled=%v, ClamAVRequired=%v\n", config.ClamAVEnabled, config.ClamAVRequired)
|
||||
logger.Info("Upload validator initialization",
|
||||
zap.Bool("clamav_enabled", config.ClamAVEnabled),
|
||||
zap.Bool("clamav_required", config.ClamAVRequired))
|
||||
|
||||
// EARLY RETURN: Si ClamAV est désactivé, ne JAMAIS toucher à clamdscan
|
||||
if !config.ClamAVEnabled {
|
||||
fmt.Printf("✅ [UPLOAD VALIDATOR] ClamAV désactivé - Aucun scan antivirus\n")
|
||||
logger.Info("ClamAV is disabled - virus scanning will be skipped",
|
||||
zap.Bool("clamav_enabled", config.ClamAVEnabled),
|
||||
zap.Bool("clamav_required", config.ClamAVRequired),
|
||||
|
|
@ -114,7 +115,7 @@ func NewUploadValidator(config *UploadConfig, logger *zap.Logger) (*UploadValida
|
|||
if clamdPath == "" {
|
||||
clamdPath = "clamdscan"
|
||||
}
|
||||
fmt.Printf("🛡️ [UPLOAD VALIDATOR] ClamAV activé - Utilisation de %s (exec)\n", clamdPath)
|
||||
logger.Info("ClamAV enabled, using exec", zap.String("clamd_path", clamdPath))
|
||||
|
||||
// Config pour connexion TCP distante (ex: clamav:3310 en Docker)
|
||||
clamAVConfigPath := ""
|
||||
|
|
@ -127,7 +128,7 @@ func NewUploadValidator(config *UploadConfig, logger *zap.Logger) (*UploadValida
|
|||
_, _ = tmpFile.WriteString(configContent)
|
||||
_ = tmpFile.Close()
|
||||
clamAVConfigPath = tmpFile.Name()
|
||||
fmt.Printf("🛡️ [UPLOAD VALIDATOR] Config TCP: %s -> %s\n", config.ClamAVAddress, clamAVConfigPath)
|
||||
logger.Info("ClamAV TCP config created", zap.String("address", config.ClamAVAddress), zap.String("config_path", clamAVConfigPath))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -136,7 +137,6 @@ func NewUploadValidator(config *UploadConfig, logger *zap.Logger) (*UploadValida
|
|||
pingCtx, pingCancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer pingCancel()
|
||||
if err := exec.CommandContext(pingCtx, clamdPath, "--version").Run(); err != nil {
|
||||
fmt.Printf("⚠️ [UPLOAD VALIDATOR] clamdscan non disponible: %v\n", err)
|
||||
if config.ClamAVRequired {
|
||||
logger.Warn("ClamAV is enabled and required but clamdscan unavailable - uploads will be rejected",
|
||||
zap.Error(err),
|
||||
|
|
@ -150,7 +150,6 @@ func NewUploadValidator(config *UploadConfig, logger *zap.Logger) (*UploadValida
|
|||
)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("✅ [UPLOAD VALIDATOR] clamdscan disponible - OK\n")
|
||||
logger.Info("ClamAV (clamdscan) available for virus scanning")
|
||||
}
|
||||
|
||||
|
|
@ -177,14 +176,17 @@ type ValidationResult struct {
|
|||
// ValidateFile valide un fichier uploadé
|
||||
// MOD-P1-001: Le scan ClamAV se fait AVANT toute persistance
|
||||
func (uv *UploadValidator) ValidateFile(ctx context.Context, fileHeader *multipart.FileHeader, fileType string) (*ValidationResult, error) {
|
||||
// DEBUG: Log de début de validation
|
||||
fmt.Printf("🚀 [UPLOAD VALIDATE] Début validation fichier: %s (taille: %d bytes, type: %s)\n", fileHeader.Filename, fileHeader.Size, fileType)
|
||||
fmt.Printf("🔍 [UPLOAD VALIDATE] État ClamAV - enabled=%v, required=%v, requiredButUnavailable=%v\n",
|
||||
uv.clamdPath != "", uv.clamAVRequired, uv.clamAVRequiredButUnavailable)
|
||||
uv.logger.Debug("Validation started",
|
||||
zap.String("filename", fileHeader.Filename),
|
||||
zap.Int64("size", fileHeader.Size),
|
||||
zap.String("file_type", fileType),
|
||||
zap.Bool("clamav_enabled", uv.clamdPath != ""),
|
||||
zap.Bool("clamav_required", uv.clamAVRequired),
|
||||
zap.Bool("clamav_required_but_unavailable", uv.clamAVRequiredButUnavailable))
|
||||
|
||||
// EARLY CHECK: Si ClamAV est complètement désactivé, on skip immédiatement
|
||||
if uv.clamdPath == "" {
|
||||
fmt.Printf("⏭️ [UPLOAD VALIDATE] ClamAV désactivé - scan antivirus ignoré\n")
|
||||
uv.logger.Debug("ClamAV disabled - virus scan skipped")
|
||||
}
|
||||
|
||||
result := &ValidationResult{
|
||||
|
|
@ -194,12 +196,12 @@ func (uv *UploadValidator) ValidateFile(ctx context.Context, fileHeader *multipa
|
|||
// Ouvrir le fichier
|
||||
file, err := fileHeader.Open()
|
||||
if err != nil {
|
||||
fmt.Printf("❌ [UPLOAD] Erreur ouverture fichier: %v\n", err)
|
||||
uv.logger.Error("Failed to open file for validation", zap.String("filename", fileHeader.Filename), zap.Error(err))
|
||||
result.Error = "Failed to open file"
|
||||
return result, err
|
||||
}
|
||||
defer file.Close()
|
||||
fmt.Printf("✅ [UPLOAD] Fichier ouvert avec succès\n")
|
||||
uv.logger.Debug("File opened successfully", zap.String("filename", fileHeader.Filename))
|
||||
|
||||
// BE-SEC-010: Enhanced file validation - read magic bytes for robust type detection
|
||||
header := make([]byte, 512)
|
||||
|
|
@ -268,11 +270,10 @@ func (uv *UploadValidator) ValidateFile(ctx context.Context, fileHeader *multipa
|
|||
|
||||
// Scanner avec ClamAV si disponible (clamdscan exec)
|
||||
if uv.clamdPath != "" {
|
||||
fmt.Printf("🛡️ [UPLOAD VALIDATE] ClamAV activé - Début scan antivirus...\n")
|
||||
uv.logger.Debug("ClamAV scan starting", zap.String("filename", fileHeader.Filename))
|
||||
file.Seek(0, 0)
|
||||
infected, err := uv.scanWithClamAV(ctx, file)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ [UPLOAD] Erreur scan ClamAV: %v\n", err)
|
||||
uv.logger.Error("ClamAV scan failed",
|
||||
zap.Error(err),
|
||||
zap.String("filename", fileHeader.Filename),
|
||||
|
|
@ -284,7 +285,6 @@ func (uv *UploadValidator) ValidateFile(ctx context.Context, fileHeader *multipa
|
|||
|
||||
// MOD-P1-001: Si virus détecté, rejeter immédiatement (code 422)
|
||||
if infected {
|
||||
fmt.Printf("⚠️ [UPLOAD] Virus détecté\n")
|
||||
result.Quarantined = true
|
||||
result.Error = "Virus detected"
|
||||
uv.logger.Warn("Virus detected in uploaded file",
|
||||
|
|
@ -293,13 +293,12 @@ func (uv *UploadValidator) ValidateFile(ctx context.Context, fileHeader *multipa
|
|||
return result, fmt.Errorf("clamav_infected: virus detected")
|
||||
}
|
||||
|
||||
fmt.Printf("✅ [UPLOAD VALIDATE] Scan ClamAV réussi - fichier propre\n")
|
||||
uv.logger.Info("File scanned successfully with ClamAV",
|
||||
zap.String("filename", fileHeader.Filename),
|
||||
zap.String("status", "clean"),
|
||||
)
|
||||
} else {
|
||||
fmt.Printf("⏭️ [UPLOAD VALIDATE] ClamAV désactivé - scan ignoré, validation continue\n")
|
||||
uv.logger.Debug("ClamAV disabled - scan skipped, validation continues")
|
||||
}
|
||||
|
||||
// Valider l'extension du fichier
|
||||
|
|
@ -310,7 +309,7 @@ func (uv *UploadValidator) ValidateFile(ctx context.Context, fileHeader *multipa
|
|||
}
|
||||
|
||||
result.Valid = true
|
||||
fmt.Printf("✅ [UPLOAD VALIDATE] Validation complète - fichier accepté (Valid=true)\n")
|
||||
uv.logger.Debug("Validation complete - file accepted", zap.String("filename", fileHeader.Filename))
|
||||
return result, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue