Files
SimpleRemoter/server/go/logger/logger.go
2025-12-21 22:19:19 +01:00

205 lines
4.3 KiB
Go

package logger
import (
"io"
"os"
"path/filepath"
"time"
"github.com/rs/zerolog"
"gopkg.in/natefinch/lumberjack.v2"
)
// Level represents log level
type Level = zerolog.Level
const (
LevelDebug = zerolog.DebugLevel
LevelInfo = zerolog.InfoLevel
LevelWarn = zerolog.WarnLevel
LevelError = zerolog.ErrorLevel
LevelFatal = zerolog.FatalLevel
)
// Logger wraps zerolog.Logger
type Logger struct {
zl zerolog.Logger
}
// Config holds logger configuration
type Config struct {
// Level is the minimum log level
Level Level
// Console enables console output
Console bool
// File is the log file path (empty to disable file logging)
File string
// MaxSize is the max size in MB before rotation
MaxSize int
// MaxBackups is the max number of old log files to keep
MaxBackups int
// MaxAge is the max days to keep old log files
MaxAge int
// Compress enables gzip compression for rotated files
Compress bool
}
// DefaultConfig returns default configuration
func DefaultConfig() Config {
return Config{
Level: LevelInfo,
Console: true,
File: "",
MaxSize: 100,
MaxBackups: 3,
MaxAge: 30,
Compress: true,
}
}
// New creates a new logger with config
func New(cfg Config) *Logger {
var writers []io.Writer
// Console output with color
if cfg.Console {
consoleWriter := zerolog.ConsoleWriter{
Out: os.Stdout,
TimeFormat: "2006-01-02 15:04:05",
}
writers = append(writers, consoleWriter)
}
// File output with rotation
if cfg.File != "" {
// Ensure directory exists
dir := filepath.Dir(cfg.File)
if dir != "" && dir != "." {
_ = os.MkdirAll(dir, 0755)
}
fileWriter := &lumberjack.Logger{
Filename: cfg.File,
MaxSize: cfg.MaxSize,
MaxBackups: cfg.MaxBackups,
MaxAge: cfg.MaxAge,
Compress: cfg.Compress,
LocalTime: true,
}
writers = append(writers, fileWriter)
}
// Combine writers
var writer io.Writer
if len(writers) == 0 {
writer = os.Stdout
} else if len(writers) == 1 {
writer = writers[0]
} else {
writer = zerolog.MultiLevelWriter(writers...)
}
// Create logger
zl := zerolog.New(writer).
Level(cfg.Level).
With().
Timestamp().
Logger()
return &Logger{zl: zl}
}
// WithPrefix returns a new logger with a prefix field
func (l *Logger) WithPrefix(prefix string) *Logger {
return &Logger{
zl: l.zl.With().Str("module", prefix).Logger(),
}
}
// Debug logs a debug message
func (l *Logger) Debug(format string, args ...interface{}) {
l.zl.Debug().Msgf(format, args...)
}
// Info logs an info message
func (l *Logger) Info(format string, args ...interface{}) {
l.zl.Info().Msgf(format, args...)
}
// Warn logs a warning message
func (l *Logger) Warn(format string, args ...interface{}) {
l.zl.Warn().Msgf(format, args...)
}
// Error logs an error message
func (l *Logger) Error(format string, args ...interface{}) {
l.zl.Error().Msgf(format, args...)
}
// Fatal logs a fatal message and exits
func (l *Logger) Fatal(format string, args ...interface{}) {
l.zl.Fatal().Msgf(format, args...)
}
// SetLevel sets the log level
func (l *Logger) SetLevel(level Level) {
l.zl = l.zl.Level(level)
}
// GetLevel returns the current log level
func (l *Logger) GetLevel() Level {
return l.zl.GetLevel()
}
// ClientEvent logs client online/offline events
func (l *Logger) ClientEvent(event string, clientID uint64, ip string, extra ...string) {
e := l.zl.Info().
Str("event", event).
Uint64("client_id", clientID).
Str("ip", ip).
Time("time", time.Now())
if len(extra) >= 2 {
for i := 0; i+1 < len(extra); i += 2 {
e = e.Str(extra[i], extra[i+1])
}
}
e.Msg("")
}
// default global logger
var defaultLogger = New(DefaultConfig())
// SetDefault sets the default global logger
func SetDefault(l *Logger) {
defaultLogger = l
}
// Default returns the default global logger
func Default() *Logger {
return defaultLogger
}
// Package-level convenience functions
func Debug(format string, args ...interface{}) {
defaultLogger.Debug(format, args...)
}
func Info(format string, args ...interface{}) {
defaultLogger.Info(format, args...)
}
func Warn(format string, args ...interface{}) {
defaultLogger.Warn(format, args...)
}
func Error(format string, args ...interface{}) {
defaultLogger.Error(format, args...)
}
func Fatal(format string, args ...interface{}) {
defaultLogger.Fatal(format, args...)
}