Files
jiggablend/internal/logger/logger.go

128 lines
2.8 KiB
Go

package logger
import (
"io"
"log"
"os"
"path/filepath"
"sync"
"gopkg.in/natefinch/lumberjack.v2"
)
var (
defaultLogger *Logger
once sync.Once
)
// Logger wraps the standard log.Logger with file and stdout output
type Logger struct {
*log.Logger
fileWriter io.WriteCloser
}
// Init initializes the default logger with both file and stdout output
func Init(logDir, logFileName string, maxSizeMB int, maxBackups int, maxAgeDays int) error {
var err error
once.Do(func() {
defaultLogger, err = New(logDir, logFileName, maxSizeMB, maxBackups, maxAgeDays)
if err != nil {
return
}
// Replace standard log output with the multi-writer
multiWriter := io.MultiWriter(os.Stdout, defaultLogger.fileWriter)
log.SetOutput(multiWriter)
log.SetFlags(log.LstdFlags | log.Lshortfile)
})
return err
}
// New creates a new logger that writes to both stdout and a log file
func New(logDir, logFileName string, maxSizeMB int, maxBackups int, maxAgeDays int) (*Logger, error) {
// Ensure log directory exists
if err := os.MkdirAll(logDir, 0755); err != nil {
return nil, err
}
logPath := filepath.Join(logDir, logFileName)
// Create file writer with rotation
fileWriter := &lumberjack.Logger{
Filename: logPath,
MaxSize: maxSizeMB, // megabytes
MaxBackups: maxBackups, // number of backup files
MaxAge: maxAgeDays, // days
Compress: true, // compress old log files
}
// Create multi-writer that writes to both stdout and file
multiWriter := io.MultiWriter(os.Stdout, fileWriter)
// Create logger with standard flags
logger := log.New(multiWriter, "", log.LstdFlags|log.Lshortfile)
return &Logger{
Logger: logger,
fileWriter: fileWriter,
}, nil
}
// Close closes the file writer
func (l *Logger) Close() error {
if l.fileWriter != nil {
return l.fileWriter.Close()
}
return nil
}
// GetDefault returns the default logger instance
func GetDefault() *Logger {
return defaultLogger
}
// Printf logs a formatted message
func Printf(format string, v ...interface{}) {
if defaultLogger != nil {
defaultLogger.Printf(format, v...)
} else {
log.Printf(format, v...)
}
}
// Print logs a message
func Print(v ...interface{}) {
if defaultLogger != nil {
defaultLogger.Print(v...)
} else {
log.Print(v...)
}
}
// Println logs a message with newline
func Println(v ...interface{}) {
if defaultLogger != nil {
defaultLogger.Println(v...)
} else {
log.Println(v...)
}
}
// Fatal logs a message and exits
func Fatal(v ...interface{}) {
if defaultLogger != nil {
defaultLogger.Fatal(v...)
} else {
log.Fatal(v...)
}
}
// Fatalf logs a formatted message and exits
func Fatalf(format string, v ...interface{}) {
if defaultLogger != nil {
defaultLogger.Fatalf(format, v...)
} else {
log.Fatalf(format, v...)
}
}