191 lines
4.4 KiB
Go
191 lines
4.4 KiB
Go
package global
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"runtime"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
var Log *logrus.Logger
|
|
|
|
const (
|
|
red = 31
|
|
yellow = 33
|
|
blue = 36
|
|
gray = 37
|
|
)
|
|
|
|
// LogFormatter 控制台日志格式化器(带颜色)
|
|
type LogFormatter struct{}
|
|
|
|
func (f *LogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
|
var levelColor int
|
|
switch entry.Level {
|
|
case logrus.DebugLevel, logrus.TraceLevel:
|
|
levelColor = gray
|
|
case logrus.WarnLevel:
|
|
levelColor = yellow
|
|
case logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel:
|
|
levelColor = red
|
|
default:
|
|
levelColor = blue
|
|
}
|
|
|
|
var b *bytes.Buffer
|
|
if entry.Buffer != nil {
|
|
b = entry.Buffer
|
|
} else {
|
|
b = &bytes.Buffer{}
|
|
}
|
|
|
|
timestamp := entry.Time.Format("2006/01/02 15:04:05")
|
|
levelStr := strings.ToUpper(entry.Level.String())
|
|
|
|
if IsDebug && entry.HasCaller() {
|
|
funcVal := entry.Caller.Function
|
|
fileVal := fmt.Sprintf("%s:%d", path.Base(entry.Caller.File), entry.Caller.Line)
|
|
fmt.Fprintf(b, "\033[%dm[%s]\033[0m [%s] \033[%dm[%s]\033[0m %s %s: %s\n",
|
|
colorGreen, processName, timestamp, levelColor, levelStr, funcVal, fileVal, entry.Message)
|
|
} else {
|
|
fmt.Fprintf(b, "\033[%dm[%s]\033[0m [%s] \033[%dm[%s]\033[0m %s\n",
|
|
colorGreen, processName, timestamp, levelColor, levelStr, entry.Message)
|
|
}
|
|
return b.Bytes(), nil
|
|
}
|
|
|
|
// FileFormatter 文件日志格式化器(不包含 ANSI 颜色代码)
|
|
type FileFormatter struct{}
|
|
|
|
func (f *FileFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
|
var b *bytes.Buffer
|
|
if entry.Buffer != nil {
|
|
b = entry.Buffer
|
|
} else {
|
|
b = &bytes.Buffer{}
|
|
}
|
|
|
|
timestamp := entry.Time.Format("2006/01/02 15:04:05")
|
|
levelStr := strings.ToUpper(entry.Level.String())
|
|
|
|
if IsDebug && entry.HasCaller() {
|
|
funcVal := entry.Caller.Function
|
|
fileVal := fmt.Sprintf("%s:%d", path.Base(entry.Caller.File), entry.Caller.Line)
|
|
fmt.Fprintf(b, "[%s] [%s] [%s] %s %s: %s\n",
|
|
processName, timestamp, levelStr, funcVal, fileVal, entry.Message)
|
|
} else {
|
|
fmt.Fprintf(b, "[%s] [%s] [%s] %s\n",
|
|
processName, timestamp, levelStr, entry.Message)
|
|
}
|
|
return b.Bytes(), nil
|
|
}
|
|
|
|
var processName string
|
|
|
|
func init() {
|
|
processName = filepath.Base(os.Args[0])
|
|
processName = strings.TrimSuffix(processName, filepath.Ext(processName))
|
|
}
|
|
|
|
func GetProcessName() string {
|
|
return processName
|
|
}
|
|
|
|
// SetLogLevel 动态设置日志等级
|
|
func SetLogLevel(level logrus.Level) {
|
|
if Log != nil {
|
|
Log.SetLevel(level)
|
|
}
|
|
}
|
|
|
|
// InitLogger 初始化日志系统,每次运行时按启动时间保存日志文件,自动清理旧日志
|
|
func InitLogger() {
|
|
Log = logrus.New()
|
|
Log.SetFormatter(&LogFormatter{})
|
|
Log.SetLevel(logrus.InfoLevel)
|
|
|
|
if IsDebug {
|
|
Log.SetReportCaller(true)
|
|
} else {
|
|
Log.SetReportCaller(false)
|
|
}
|
|
|
|
logDir := GlobalConfig.LogDir
|
|
if err := os.MkdirAll(logDir, 0755); err != nil {
|
|
Log.Warnf("无法创建日志目录: %v", err)
|
|
}
|
|
|
|
cleanOldLogs(logDir, 10)
|
|
|
|
startTime := time.Now().Format("2006-01-02_15-04-05")
|
|
logFile := filepath.Join(logDir, startTime+".log")
|
|
file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
|
if err != nil {
|
|
Log.Warnf("无法打开日志文件: %v", err)
|
|
} else {
|
|
Log.SetOutput(os.Stdout)
|
|
Log.AddHook(&FileHook{file: file})
|
|
}
|
|
}
|
|
|
|
const colorGreen = 32
|
|
|
|
// FileHook 将日志同时写入文件的 Hook
|
|
type FileHook struct {
|
|
file *os.File
|
|
}
|
|
|
|
func (h *FileHook) Levels() []logrus.Level {
|
|
return logrus.AllLevels
|
|
}
|
|
|
|
func (h *FileHook) Fire(entry *logrus.Entry) error {
|
|
formatter := &FileFormatter{}
|
|
line, err := formatter.Format(entry)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = h.file.Write(line)
|
|
return err
|
|
}
|
|
|
|
// cleanOldLogs 清理旧日志文件,保留最新的 maxKeep 个日志
|
|
func cleanOldLogs(logDir string, maxKeep int) {
|
|
entries, err := os.ReadDir(logDir)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
var logFiles []os.DirEntry
|
|
for _, entry := range entries {
|
|
if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".log") {
|
|
logFiles = append(logFiles, entry)
|
|
}
|
|
}
|
|
|
|
if len(logFiles) <= maxKeep {
|
|
return
|
|
}
|
|
|
|
// 文件名包含时间戳,按文件名排序即按时间排序
|
|
sort.Slice(logFiles, func(i, j int) bool {
|
|
return logFiles[i].Name() < logFiles[j].Name()
|
|
})
|
|
|
|
filesToDelete := logFiles[:len(logFiles)-maxKeep]
|
|
for _, file := range filesToDelete {
|
|
os.Remove(filepath.Join(logDir, file.Name()))
|
|
}
|
|
}
|
|
|
|
func GetRuntimeInfo() string {
|
|
return fmt.Sprintf("Go %s, OS %s, Arch %s", runtime.Version(), runtime.GOOS, runtime.GOARCH)
|
|
}
|