245 lines
5.5 KiB
Go
245 lines
5.5 KiB
Go
|
|
package logger
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"io"
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"github.com/sirupsen/logrus"
|
||
|
|
"gopkg.in/natefinch/lumberjack.v2"
|
||
|
|
)
|
||
|
|
|
||
|
|
var Logger *logrus.Logger
|
||
|
|
|
||
|
|
// LogConfig 日志配置
|
||
|
|
type LogConfig struct {
|
||
|
|
Level string `json:"level"` // 日志级别
|
||
|
|
Format string `json:"format"` // 日志格式 json/text
|
||
|
|
Output string `json:"output"` // 输出方式 console/file/both
|
||
|
|
FilePath string `json:"file_path"` // 日志文件路径
|
||
|
|
MaxSize int `json:"max_size"` // 单个日志文件最大大小(MB)
|
||
|
|
MaxBackups int `json:"max_backups"` // 保留的旧日志文件数量
|
||
|
|
MaxAge int `json:"max_age"` // 日志文件保留天数
|
||
|
|
Compress bool `json:"compress"` // 是否压缩旧日志文件
|
||
|
|
}
|
||
|
|
|
||
|
|
// InitLogger 初始化日志系统
|
||
|
|
func InitLogger(config LogConfig) {
|
||
|
|
Logger = logrus.New()
|
||
|
|
|
||
|
|
// 设置日志级别
|
||
|
|
setLogLevel(config.Level)
|
||
|
|
|
||
|
|
// 设置日志格式
|
||
|
|
setLogFormat(config.Format)
|
||
|
|
|
||
|
|
// 设置日志输出
|
||
|
|
setLogOutput(config)
|
||
|
|
|
||
|
|
// 添加钩子
|
||
|
|
addHooks()
|
||
|
|
|
||
|
|
Logger.Info("Logger initialized successfully")
|
||
|
|
}
|
||
|
|
|
||
|
|
// setLogLevel 设置日志级别
|
||
|
|
func setLogLevel(level string) {
|
||
|
|
switch level {
|
||
|
|
case "debug":
|
||
|
|
Logger.SetLevel(logrus.DebugLevel)
|
||
|
|
case "info":
|
||
|
|
Logger.SetLevel(logrus.InfoLevel)
|
||
|
|
case "warn":
|
||
|
|
Logger.SetLevel(logrus.WarnLevel)
|
||
|
|
case "error":
|
||
|
|
Logger.SetLevel(logrus.ErrorLevel)
|
||
|
|
case "fatal":
|
||
|
|
Logger.SetLevel(logrus.FatalLevel)
|
||
|
|
case "panic":
|
||
|
|
Logger.SetLevel(logrus.PanicLevel)
|
||
|
|
default:
|
||
|
|
Logger.SetLevel(logrus.InfoLevel)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// setLogFormat 设置日志格式
|
||
|
|
func setLogFormat(format string) {
|
||
|
|
switch format {
|
||
|
|
case "json":
|
||
|
|
Logger.SetFormatter(&logrus.JSONFormatter{
|
||
|
|
TimestampFormat: time.RFC3339,
|
||
|
|
})
|
||
|
|
case "text":
|
||
|
|
Logger.SetFormatter(&logrus.TextFormatter{
|
||
|
|
FullTimestamp: true,
|
||
|
|
TimestampFormat: "2006-01-02 15:04:05",
|
||
|
|
})
|
||
|
|
default:
|
||
|
|
Logger.SetFormatter(&logrus.JSONFormatter{
|
||
|
|
TimestampFormat: time.RFC3339,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// setLogOutput 设置日志输出
|
||
|
|
func setLogOutput(config LogConfig) {
|
||
|
|
switch config.Output {
|
||
|
|
case "console":
|
||
|
|
Logger.SetOutput(os.Stdout)
|
||
|
|
case "file":
|
||
|
|
setFileOutput(config)
|
||
|
|
case "both":
|
||
|
|
setBothOutput(config)
|
||
|
|
default:
|
||
|
|
Logger.SetOutput(os.Stdout)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// setFileOutput 设置文件输出
|
||
|
|
func setFileOutput(config LogConfig) {
|
||
|
|
// 确保日志目录存在
|
||
|
|
logDir := filepath.Dir(config.FilePath)
|
||
|
|
if err := os.MkdirAll(logDir, 0755); err != nil {
|
||
|
|
fmt.Printf("Failed to create log directory: %v\n", err)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
// 配置日志轮转
|
||
|
|
lumberjackLogger := &lumberjack.Logger{
|
||
|
|
Filename: config.FilePath,
|
||
|
|
MaxSize: config.MaxSize,
|
||
|
|
MaxBackups: config.MaxBackups,
|
||
|
|
MaxAge: config.MaxAge,
|
||
|
|
Compress: config.Compress,
|
||
|
|
}
|
||
|
|
|
||
|
|
Logger.SetOutput(lumberjackLogger)
|
||
|
|
}
|
||
|
|
|
||
|
|
// setBothOutput 设置同时输出到控制台和文件
|
||
|
|
func setBothOutput(config LogConfig) {
|
||
|
|
// 确保日志目录存在
|
||
|
|
logDir := filepath.Dir(config.FilePath)
|
||
|
|
if err := os.MkdirAll(logDir, 0755); err != nil {
|
||
|
|
fmt.Printf("Failed to create log directory: %v\n", err)
|
||
|
|
Logger.SetOutput(os.Stdout)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
// 配置日志轮转
|
||
|
|
lumberjackLogger := &lumberjack.Logger{
|
||
|
|
Filename: config.FilePath,
|
||
|
|
MaxSize: config.MaxSize,
|
||
|
|
MaxBackups: config.MaxBackups,
|
||
|
|
MaxAge: config.MaxAge,
|
||
|
|
Compress: config.Compress,
|
||
|
|
}
|
||
|
|
|
||
|
|
// 同时输出到控制台和文件,避免嵌套/转义问题
|
||
|
|
Logger.SetOutput(io.MultiWriter(os.Stdout, lumberjackLogger))
|
||
|
|
}
|
||
|
|
|
||
|
|
// addHooks 添加日志钩子
|
||
|
|
func addHooks() {
|
||
|
|
// 添加调用者信息钩子
|
||
|
|
Logger.AddHook(&CallerHook{})
|
||
|
|
}
|
||
|
|
|
||
|
|
// FileHook 文件输出钩子
|
||
|
|
type FileHook struct {
|
||
|
|
Writer *lumberjack.Logger
|
||
|
|
}
|
||
|
|
|
||
|
|
func (hook *FileHook) Fire(entry *logrus.Entry) error {
|
||
|
|
line, err := entry.String()
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
_, err = hook.Writer.Write([]byte(line))
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
func (hook *FileHook) Levels() []logrus.Level {
|
||
|
|
return logrus.AllLevels
|
||
|
|
}
|
||
|
|
|
||
|
|
// CallerHook 调用者信息钩子
|
||
|
|
type CallerHook struct{}
|
||
|
|
|
||
|
|
func (hook *CallerHook) Fire(entry *logrus.Entry) error {
|
||
|
|
if entry.HasCaller() {
|
||
|
|
entry.Data["file"] = fmt.Sprintf("%s:%d", filepath.Base(entry.Caller.File), entry.Caller.Line)
|
||
|
|
entry.Data["function"] = entry.Caller.Function
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (hook *CallerHook) Levels() []logrus.Level {
|
||
|
|
return logrus.AllLevels
|
||
|
|
}
|
||
|
|
|
||
|
|
// 便捷方法
|
||
|
|
func Debug(args ...interface{}) {
|
||
|
|
Logger.Debug(args...)
|
||
|
|
}
|
||
|
|
|
||
|
|
func Debugf(format string, args ...interface{}) {
|
||
|
|
Logger.Debugf(format, args...)
|
||
|
|
}
|
||
|
|
|
||
|
|
func Info(args ...interface{}) {
|
||
|
|
Logger.Info(args...)
|
||
|
|
}
|
||
|
|
|
||
|
|
func Infof(format string, args ...interface{}) {
|
||
|
|
Logger.Infof(format, args...)
|
||
|
|
}
|
||
|
|
|
||
|
|
func Warn(args ...interface{}) {
|
||
|
|
Logger.Warn(args...)
|
||
|
|
}
|
||
|
|
|
||
|
|
func Warnf(format string, args ...interface{}) {
|
||
|
|
Logger.Warnf(format, args...)
|
||
|
|
}
|
||
|
|
|
||
|
|
func Error(args ...interface{}) {
|
||
|
|
Logger.Error(args...)
|
||
|
|
}
|
||
|
|
|
||
|
|
func Errorf(format string, args ...interface{}) {
|
||
|
|
Logger.Errorf(format, args...)
|
||
|
|
}
|
||
|
|
|
||
|
|
func Fatal(args ...interface{}) {
|
||
|
|
Logger.Fatal(args...)
|
||
|
|
}
|
||
|
|
|
||
|
|
func Fatalf(format string, args ...interface{}) {
|
||
|
|
Logger.Fatalf(format, args...)
|
||
|
|
}
|
||
|
|
|
||
|
|
func Panic(args ...interface{}) {
|
||
|
|
Logger.Panic(args...)
|
||
|
|
}
|
||
|
|
|
||
|
|
func Panicf(format string, args ...interface{}) {
|
||
|
|
Logger.Panicf(format, args...)
|
||
|
|
}
|
||
|
|
|
||
|
|
// WithFields 创建带字段的日志条目
|
||
|
|
func WithFields(fields logrus.Fields) *logrus.Entry {
|
||
|
|
return Logger.WithFields(fields)
|
||
|
|
}
|
||
|
|
|
||
|
|
// WithField 创建带单个字段的日志条目
|
||
|
|
func WithField(key string, value interface{}) *logrus.Entry {
|
||
|
|
return Logger.WithField(key, value)
|
||
|
|
}
|
||
|
|
|
||
|
|
// WithError 创建带错误信息的日志条目
|
||
|
|
func WithError(err error) *logrus.Entry {
|
||
|
|
return Logger.WithError(err)
|
||
|
|
}
|