You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
239 lines
5.9 KiB
239 lines
5.9 KiB
package log
|
|
|
|
import (
|
|
"os"
|
|
"sync"
|
|
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
"gopkg.in/natefinch/lumberjack.v2"
|
|
)
|
|
|
|
// Level is an alias for zapcore.Level
|
|
type Level = zapcore.Level
|
|
|
|
// LogConfig holds the configuration for logging
|
|
type LogConfig struct {
|
|
// LogFile is the path to the log file. If empty, logs will be written to stdout
|
|
LogFile string
|
|
// MaxSize is the maximum size in megabytes of the log file before it gets rotated
|
|
MaxSize int
|
|
// MaxBackups is the maximum number of old log files to retain
|
|
MaxBackups int
|
|
// MaxAge is the maximum number of days to retain old log files
|
|
MaxAge int
|
|
// Compress determines if the rotated log files should be compressed
|
|
Compress bool
|
|
}
|
|
|
|
var (
|
|
// Logger is the global logger instance
|
|
Logger *zap.Logger
|
|
// Sugar is the global sugared logger instance
|
|
Sugar *zap.SugaredLogger
|
|
// atom is the atomic level for dynamic log level changes
|
|
atom zap.AtomicLevel
|
|
// once ensures initialization happens only once
|
|
once sync.Once
|
|
// defaultLevel is the default logging level if not specified
|
|
defaultLevel = zapcore.InfoLevel
|
|
)
|
|
|
|
// VerboseLogger wraps a sugared logger with verbosity level
|
|
type VerboseLogger struct {
|
|
level Level
|
|
}
|
|
|
|
// Verbose returns a VerboseLogger for the given verbosity level
|
|
func Verbose(level Level) *VerboseLogger {
|
|
return &VerboseLogger{level: level}
|
|
}
|
|
|
|
// Infof logs a formatted message at info level if the verbosity level is enabled
|
|
func (v *VerboseLogger) Infof(format string, args ...interface{}) {
|
|
if atom.Enabled(v.level) {
|
|
Sugar.Infof(format, args...)
|
|
}
|
|
}
|
|
|
|
// Info logs a message at info level if the verbosity level is enabled
|
|
func (v *VerboseLogger) Info(args ...interface{}) {
|
|
if atom.Enabled(v.level) {
|
|
Sugar.Info(args...)
|
|
}
|
|
}
|
|
|
|
// Infoln logs a message at info level with a newline if the verbosity level is enabled
|
|
func (v *VerboseLogger) Infoln(args ...interface{}) {
|
|
if atom.Enabled(v.level) {
|
|
Sugar.Infoln(args...)
|
|
}
|
|
}
|
|
|
|
// Warning logs a message at warn level if the verbosity level is enabled
|
|
func (v *VerboseLogger) Warning(args ...interface{}) {
|
|
if atom.Enabled(v.level) {
|
|
Sugar.Warn(args...)
|
|
}
|
|
}
|
|
|
|
// Warningf logs a formatted message at warn level if the verbosity level is enabled
|
|
func (v *VerboseLogger) Warningf(format string, args ...interface{}) {
|
|
if atom.Enabled(v.level) {
|
|
Sugar.Warnf(format, args...)
|
|
}
|
|
}
|
|
|
|
// Init initializes the logger with the given level and configuration
|
|
func Init(level Level, config *LogConfig) {
|
|
once.Do(func() {
|
|
// Initialize with default level if not specified
|
|
if level == 0 {
|
|
level = defaultLevel
|
|
}
|
|
|
|
atom = zap.NewAtomicLevel()
|
|
atom.SetLevel(level)
|
|
|
|
encoderConfig := zap.NewProductionEncoderConfig()
|
|
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
|
|
|
|
var writeSyncer zapcore.WriteSyncer
|
|
if config != nil && config.LogFile != "" {
|
|
// Create a lumberjack logger for log rotation
|
|
rotator := &lumberjack.Logger{
|
|
Filename: config.LogFile,
|
|
MaxSize: config.MaxSize, // megabytes
|
|
MaxBackups: config.MaxBackups,
|
|
MaxAge: config.MaxAge, // days
|
|
Compress: config.Compress,
|
|
}
|
|
writeSyncer = zapcore.AddSync(rotator)
|
|
} else {
|
|
writeSyncer = zapcore.AddSync(os.Stdout)
|
|
}
|
|
|
|
core := zapcore.NewCore(
|
|
zapcore.NewJSONEncoder(encoderConfig),
|
|
writeSyncer,
|
|
atom,
|
|
)
|
|
|
|
Logger = zap.New(core)
|
|
Sugar = Logger.Sugar()
|
|
})
|
|
}
|
|
|
|
// SetLevel changes the logging level dynamically
|
|
func SetLevel(level Level) {
|
|
if atom == (zap.AtomicLevel{}) {
|
|
Init(level, nil)
|
|
return
|
|
}
|
|
atom.SetLevel(level)
|
|
}
|
|
|
|
// V returns a VerboseLogger for the given verbosity level
|
|
func V(level Level) *VerboseLogger {
|
|
if atom == (zap.AtomicLevel{}) {
|
|
Init(defaultLevel, nil)
|
|
}
|
|
return Verbose(level)
|
|
}
|
|
|
|
// Info logs a message at info level
|
|
func Info(args ...interface{}) {
|
|
if atom == (zap.AtomicLevel{}) {
|
|
Init(defaultLevel, nil)
|
|
}
|
|
Sugar.Info(args...)
|
|
}
|
|
|
|
// Infof logs a formatted message at info level
|
|
func Infof(format string, args ...interface{}) {
|
|
if atom == (zap.AtomicLevel{}) {
|
|
Init(defaultLevel, nil)
|
|
}
|
|
Sugar.Infof(format, args...)
|
|
}
|
|
|
|
// Warning logs a message at warn level
|
|
func Warning(args ...interface{}) {
|
|
if atom == (zap.AtomicLevel{}) {
|
|
Init(defaultLevel, nil)
|
|
}
|
|
Sugar.Warn(args...)
|
|
}
|
|
|
|
// Warningf logs a formatted message at warn level
|
|
func Warningf(format string, args ...interface{}) {
|
|
if atom == (zap.AtomicLevel{}) {
|
|
Init(defaultLevel, nil)
|
|
}
|
|
Sugar.Warnf(format, args...)
|
|
}
|
|
|
|
// Error logs a message at error level
|
|
func Error(args ...interface{}) {
|
|
if atom == (zap.AtomicLevel{}) {
|
|
Init(defaultLevel, nil)
|
|
}
|
|
Sugar.Error(args...)
|
|
}
|
|
|
|
// Errorf logs a formatted message at error level
|
|
func Errorf(format string, args ...interface{}) {
|
|
if atom == (zap.AtomicLevel{}) {
|
|
Init(defaultLevel, nil)
|
|
}
|
|
Sugar.Errorf(format, args...)
|
|
}
|
|
|
|
// Fatal logs a message at fatal level and then calls os.Exit(1)
|
|
func Fatal(args ...interface{}) {
|
|
if atom == (zap.AtomicLevel{}) {
|
|
Init(defaultLevel, nil)
|
|
}
|
|
Sugar.Fatal(args...)
|
|
}
|
|
|
|
// Fatalf logs a formatted message at fatal level and then calls os.Exit(1)
|
|
func Fatalf(format string, args ...interface{}) {
|
|
if atom == (zap.AtomicLevel{}) {
|
|
Init(defaultLevel, nil)
|
|
}
|
|
Sugar.Fatalf(format, args...)
|
|
}
|
|
|
|
// Exitf logs a formatted message at fatal level and then calls os.Exit(1)
|
|
func Exitf(format string, args ...interface{}) {
|
|
if atom == (zap.AtomicLevel{}) {
|
|
Init(defaultLevel, nil)
|
|
}
|
|
Sugar.Fatalf(format, args...)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// With returns a logger with the given fields
|
|
func With(fields ...zap.Field) *zap.Logger {
|
|
if atom == (zap.AtomicLevel{}) {
|
|
Init(defaultLevel, nil)
|
|
}
|
|
return Logger.With(fields...)
|
|
}
|
|
|
|
// WithSugar returns a sugared logger with the given fields
|
|
func WithSugar(args ...interface{}) *zap.SugaredLogger {
|
|
if atom == (zap.AtomicLevel{}) {
|
|
Init(defaultLevel, nil)
|
|
}
|
|
return Sugar.With(args...)
|
|
}
|
|
|
|
// Printf logs a formatted message at info level
|
|
func Printf(format string, args ...interface{}) {
|
|
if atom == (zap.AtomicLevel{}) {
|
|
Init(defaultLevel, nil)
|
|
}
|
|
Sugar.Infof(format, args...)
|
|
}
|