164 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			164 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package main
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"os"
 | 
						|
	"path/filepath"
 | 
						|
	"sync"
 | 
						|
	"time"
 | 
						|
 | 
						|
	log "github.com/sirupsen/logrus"
 | 
						|
	prefixed "github.com/x-cray/logrus-prefixed-formatter"
 | 
						|
)
 | 
						|
 | 
						|
var Log *log.Logger
 | 
						|
var logFile *os.File
 | 
						|
var logWriter *syncWriter
 | 
						|
var logCtx context.Context
 | 
						|
var logCancel context.CancelFunc
 | 
						|
 | 
						|
// syncWriter écrit de manière synchrone (pas de buffer)
 | 
						|
type syncWriter struct {
 | 
						|
	file  *os.File
 | 
						|
	mutex sync.Mutex
 | 
						|
}
 | 
						|
 | 
						|
func (w *syncWriter) Write(p []byte) (n int, err error) {
 | 
						|
	w.mutex.Lock()
 | 
						|
	defer w.mutex.Unlock()
 | 
						|
 | 
						|
	n, err = w.file.Write(p)
 | 
						|
	if err == nil {
 | 
						|
		w.file.Sync() // Force l'écriture immédiate sur disque
 | 
						|
	}
 | 
						|
	return n, err
 | 
						|
}
 | 
						|
 | 
						|
func NewLog() *log.Logger {
 | 
						|
 | 
						|
	// ✅ Vérifier que Cfg existe
 | 
						|
	if Cfg == nil {
 | 
						|
		panic("Config not initialized! Call NewConfig() before NewLog()")
 | 
						|
	}
 | 
						|
 | 
						|
	// ✅ Chemin du log à côté de l'exe
 | 
						|
	exe, _ := os.Executable()
 | 
						|
	exePath := filepath.Dir(exe)
 | 
						|
	logPath := filepath.Join(exePath, "flexradio.log")
 | 
						|
 | 
						|
	if Cfg.General.DeleteLogFileAtStart {
 | 
						|
		if _, err := os.Stat(logPath); err == nil {
 | 
						|
			os.Remove(logPath)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	logCtx, logCancel = context.WithCancel(context.Background())
 | 
						|
 | 
						|
	var w io.Writer
 | 
						|
 | 
						|
	if Cfg.General.LogToFile {
 | 
						|
		f, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
 | 
						|
		if err != nil {
 | 
						|
			panic(fmt.Sprintf("Cannot open log file %s: %v", logPath, err))
 | 
						|
		}
 | 
						|
 | 
						|
		logFile = f
 | 
						|
		logWriter = &syncWriter{file: f}
 | 
						|
 | 
						|
		// ✅ IMPORTANT: Vérifier si Stdout est disponible (mode console vs GUI)
 | 
						|
		if isConsoleAvailable() {
 | 
						|
			// Mode console : log vers fichier ET console
 | 
						|
			w = io.MultiWriter(os.Stdout, logWriter)
 | 
						|
		} else {
 | 
						|
			// Mode GUI (windowsgui) : log SEULEMENT vers fichier
 | 
						|
			w = logWriter
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		// Log uniquement vers console (si disponible)
 | 
						|
		if isConsoleAvailable() {
 | 
						|
			w = os.Stdout
 | 
						|
		} else {
 | 
						|
			// Pas de console, pas de log fichier -> log vers null
 | 
						|
			w = io.Discard
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	Log = &log.Logger{
 | 
						|
		Out: w,
 | 
						|
		Formatter: &prefixed.TextFormatter{
 | 
						|
			DisableColors:    !isConsoleAvailable(),
 | 
						|
			TimestampFormat:  "02-01-2006 15:04:05",
 | 
						|
			FullTimestamp:    true,
 | 
						|
			ForceFormatting:  true,
 | 
						|
			DisableSorting:   true, // ✅ Ajoute
 | 
						|
			QuoteEmptyFields: true, // ✅ Ajoute
 | 
						|
			SpacePadding:     0,    // ✅ Ajoute (pas d'espace)
 | 
						|
		},
 | 
						|
		Hooks: make(log.LevelHooks),
 | 
						|
	}
 | 
						|
 | 
						|
	if Cfg.General.LogLevel == "DEBUG" {
 | 
						|
		Log.Level = log.DebugLevel
 | 
						|
	} else if Cfg.General.LogLevel == "INFO" {
 | 
						|
		Log.Level = log.InfoLevel
 | 
						|
	} else if Cfg.General.LogLevel == "WARN" {
 | 
						|
		Log.Level = log.WarnLevel
 | 
						|
	} else {
 | 
						|
		Log.Level = log.InfoLevel
 | 
						|
	}
 | 
						|
 | 
						|
	logBuffer = NewLogBuffer(500) // Garde les 500 derniers logs
 | 
						|
	// Log.AddHook(&LogHook{buffer: logBuffer})
 | 
						|
 | 
						|
	// ✅ Premier vrai log
 | 
						|
	Log.Infof("Logger initialized - Level: %s, ToFile: %v, LogPath: %s",
 | 
						|
		Cfg.General.LogLevel, Cfg.General.LogToFile, logPath)
 | 
						|
 | 
						|
	return Log
 | 
						|
}
 | 
						|
 | 
						|
func InitLogHook() {
 | 
						|
	if logBuffer == nil {
 | 
						|
		logBuffer = NewLogBuffer(500)
 | 
						|
	}
 | 
						|
 | 
						|
	Log.AddHook(&LogHook{buffer: logBuffer})
 | 
						|
	Log.Info("Log hook initialized and broadcasting enabled")
 | 
						|
}
 | 
						|
 | 
						|
// ✅ Détecter si on a une console (fonctionne sur Windows)
 | 
						|
func isConsoleAvailable() bool {
 | 
						|
	// Si Stdout est nil ou invalide, on n'a pas de console
 | 
						|
	stat, err := os.Stdout.Stat()
 | 
						|
	if err != nil {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
	// Si c'est un char device, on a une console
 | 
						|
	return (stat.Mode() & os.ModeCharDevice) != 0
 | 
						|
}
 | 
						|
 | 
						|
// ✅ Fonction pour fermer proprement le log
 | 
						|
func CloseLog() {
 | 
						|
	if Log != nil {
 | 
						|
		Log.Info("Closing log file...")
 | 
						|
	}
 | 
						|
 | 
						|
	if logCancel != nil {
 | 
						|
		logCancel()
 | 
						|
	}
 | 
						|
 | 
						|
	time.Sleep(200 * time.Millisecond) // Donne le temps d'écrire
 | 
						|
 | 
						|
	if logWriter != nil {
 | 
						|
		logWriter.mutex.Lock()
 | 
						|
		if logFile != nil {
 | 
						|
			logFile.Sync()
 | 
						|
			logFile.Close()
 | 
						|
			logFile = nil
 | 
						|
		}
 | 
						|
		logWriter.mutex.Unlock()
 | 
						|
	}
 | 
						|
}
 |