|
@@ -0,0 +1,177 @@
|
|
|
+package logger
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/json"
|
|
|
+ "fmt"
|
|
|
+ "github.com/beego/beego/v2/core/logs"
|
|
|
+ "log"
|
|
|
+ "os"
|
|
|
+ "path"
|
|
|
+ stringUtils "wechat/common/utils"
|
|
|
+)
|
|
|
+
|
|
|
+const (
|
|
|
+ DefalutLogFilePath = "./etalogs"
|
|
|
+ LogChannelLen = 10000
|
|
|
+)
|
|
|
+
|
|
|
+var (
|
|
|
+ loggerHandler *WechatLogger
|
|
|
+)
|
|
|
+
|
|
|
+type logger struct {
|
|
|
+ *logs.BeeLogger
|
|
|
+ filter string
|
|
|
+}
|
|
|
+type WechatLogger struct {
|
|
|
+ logs []*logger
|
|
|
+}
|
|
|
+
|
|
|
+func Info(msg string) {
|
|
|
+ for _, appender := range loggerHandler.logs {
|
|
|
+ if appender.GetLevel() > logs.LevelInfo {
|
|
|
+ appender.Info(msg)
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func Error(msg string) {
|
|
|
+ for _, logger := range loggerHandler.logs {
|
|
|
+ if logger.GetLevel() > logs.LevelError {
|
|
|
+ logger.Error(msg)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func init() {
|
|
|
+ var logCfg logConfig
|
|
|
+ configFile, err := os.ReadFile("conf/log/log_config.json")
|
|
|
+ if err != nil {
|
|
|
+ log.Fatalf("Failed to read log config: %v", err)
|
|
|
+ }
|
|
|
+ err = json.Unmarshal(configFile, &logCfg)
|
|
|
+ if err != nil {
|
|
|
+ log.Fatalf("Failed to parse log config: %v", err)
|
|
|
+ }
|
|
|
+ initLogger(logCfg)
|
|
|
+}
|
|
|
+
|
|
|
+var levelTrans = map[string]int{
|
|
|
+ "emergency": logs.LevelEmergency,
|
|
|
+ "alert": logs.LevelAlert,
|
|
|
+ "critical": logs.LevelCritical,
|
|
|
+ "error": logs.LevelError,
|
|
|
+ "warn": logs.LevelWarning,
|
|
|
+ "notice": logs.LevelNotice,
|
|
|
+ "info": logs.LevelInformational,
|
|
|
+ "debug": logs.LevelDebug,
|
|
|
+}
|
|
|
+
|
|
|
+var terminalType = map[string]string{
|
|
|
+ "console": logs.AdapterConsole,
|
|
|
+ "file": logs.AdapterFile,
|
|
|
+}
|
|
|
+
|
|
|
+func initLogger(logCfg logConfig) {
|
|
|
+ if loggerHandler == nil {
|
|
|
+ loggerHandler = new(WechatLogger)
|
|
|
+ }
|
|
|
+ if stringUtils.IsEmptyOrNil(logCfg.FilePath) {
|
|
|
+ logCfg.FilePath = DefalutLogFilePath
|
|
|
+ }
|
|
|
+ for _, appender := range logCfg.Appenders {
|
|
|
+ terminalType, ok := terminalType[appender.Type]
|
|
|
+ if !ok {
|
|
|
+ fmt.Println("初始化日志执行器失败:{%s},终端类型不支持{type:%s}", appender.FileName, appender.Type)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ var beeLogger *logs.BeeLogger
|
|
|
+ if terminalType == logs.AdapterConsole {
|
|
|
+ beeLogger = logs.NewLogger(LogChannelLen)
|
|
|
+ err := beeLogger.SetLogger(logs.AdapterConsole)
|
|
|
+ if err != nil {
|
|
|
+ fmt.Println("创建日志执行器失败:{%s} %v", appender.FileName, err)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ logFile := appender.FileName
|
|
|
+ os.MkdirAll(logCfg.FilePath, os.ModePerm)
|
|
|
+ // 打开文件
|
|
|
+ appender.FileName = path.Join(logCfg.FilePath, logFile)
|
|
|
+ logProps, err := ConvertAppenderToLog(&appender)
|
|
|
+ if err != nil {
|
|
|
+ fmt.Println("初始化日志执行器失败:{%s} %v", appender.FileName, err)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ b, _ := json.Marshal(logProps)
|
|
|
+ beeLogger = logs.NewLogger(LogChannelLen)
|
|
|
+ err = beeLogger.SetLogger(logs.AdapterFile, string(b))
|
|
|
+ if err != nil {
|
|
|
+ fmt.Println("设置日志执行器失败:{%s} %v", appender.FileName, err)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ beeLogger.EnableFuncCallDepth(true)
|
|
|
+ }
|
|
|
+ loggerHandler.logs = append(loggerHandler.logs, &logger{BeeLogger: beeLogger,
|
|
|
+ filter: appender.Filter})
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func initFileLogger() {
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// ConvertAppenderToLog 将 appender 结构体转换为 log 结构体
|
|
|
+func ConvertAppenderToLog(a *appender) (*logProps, error) {
|
|
|
+ lvl, ok := levelTrans[a.Level]
|
|
|
+ if !ok {
|
|
|
+ return nil, fmt.Errorf("unknown log level: %s", a.Level)
|
|
|
+ }
|
|
|
+
|
|
|
+ return &logProps{
|
|
|
+ Prefix: a.Prefix,
|
|
|
+ FileName: a.FileName,
|
|
|
+ MaxLines: a.MaxLines,
|
|
|
+ MaxSize: a.MaxSize,
|
|
|
+ Daily: a.Daily,
|
|
|
+ MaxDays: a.MaxDays,
|
|
|
+ Rotate: a.Rotate,
|
|
|
+ Level: lvl,
|
|
|
+ Color: a.Color,
|
|
|
+ //Perm: a.Perm,
|
|
|
+ }, nil
|
|
|
+}
|
|
|
+
|
|
|
+type logConfig struct {
|
|
|
+ FilePath string `json:"filepath" description:"日志路径"`
|
|
|
+ Appenders []appender `json:"appenders" description:"日志记录"`
|
|
|
+}
|
|
|
+
|
|
|
+type appender struct {
|
|
|
+ Filter string `json:"filter"`
|
|
|
+ Prefix string `json:"perfix" description:"日志前缀"`
|
|
|
+ Type string `json:"type" description:"终端类型"`
|
|
|
+ FileName string `json:"filename" description:"保存的文件名"`
|
|
|
+ MaxLines int `json:"maxlines" description:"每个文件保存的最大行数,默认值 1000000"`
|
|
|
+ MaxSize int `json:"maxsize" description:"每个文件保存的最大尺寸,默认值是 1 << 28, //256 MB"`
|
|
|
+ Daily bool `json:"daily" description:"是否按照每天 logrotate,默认是 true"`
|
|
|
+ MaxDays int `json:"maxdays" description:"文件最多保存多少天,默认保存 7 天"`
|
|
|
+ Rotate bool `json:"rotate" description:"是否开启 logrotate,默认是 true"`
|
|
|
+ Level string `json:"level" description:"日志保存的时候的级别,默认是 Trace 级别"`
|
|
|
+ Color bool `json:"color" description:"日志是否输出颜色"`
|
|
|
+ //Perm string `json:"perm" description:"日志文件权限"`
|
|
|
+}
|
|
|
+
|
|
|
+type logProps struct {
|
|
|
+ Prefix string `json:"perfix" description:"日志前缀"`
|
|
|
+ FileName string `json:"filename" description:"保存的文件名"`
|
|
|
+ MaxLines int `json:"maxlines" description:"每个文件保存的最大行数,默认值 1000000"`
|
|
|
+ MaxSize int `json:"maxsize" description:"每个文件保存的最大尺寸,默认值是 1 << 28, //256 MB"`
|
|
|
+ Daily bool `json:"daily" description:"是否按照每天 logrotate,默认是 true"`
|
|
|
+ MaxDays int `json:"maxdays" description:"文件最多保存多少天,默认保存 7 天"`
|
|
|
+ Rotate bool `json:"rotate" description:"是否开启 logrotate,默认是 true"`
|
|
|
+ Level int `json:"level" description:"日志保存的时候的级别,默认是 Trace 级别"`
|
|
|
+ Color bool `json:"color" description:"日志是否输出颜色"`
|
|
|
+ //Perm string `json:"perm" description:"日志文件权限"`
|
|
|
+}
|