123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- package logger
- import (
- "encoding/json"
- stringUtils "eta/eta_mini_ht_api/common/utils/string"
- "fmt"
- "github.com/beego/beego/v2/core/logs"
- "github.com/beego/beego/v2/server/web/context"
- "log"
- "os"
- "path"
- "strings"
- "sync"
- )
- const (
- DefalutLogFilePath = "./etalogs"
- LogChannelLen = 10000
- )
- var (
- loggerHandler *CustomLogger
- logMutex = &sync.Mutex{}
- )
- type logger struct {
- *logs.BeeLogger
- filter Filter
- }
- type CustomLogger struct {
- logs []*logger
- }
- // Logger interface
- type Logger interface {
- Info(msg string, v ...interface{})
- Warn(msg string, v ...interface{})
- Error(msg string, v ...interface{})
- }
- func Info(msg string, v ...interface{}) {
- logMutex.Lock()
- defer logMutex.Unlock()
- loggerHandler.Info(msg, v...)
- }
- func Error(msg string, v ...interface{}) {
- logMutex.Lock()
- defer logMutex.Unlock()
- loggerHandler.Error(msg, v...)
- }
- func Warn(msg string, v ...interface{}) {
- logMutex.Lock()
- defer logMutex.Unlock()
- loggerHandler.Warn(msg, v...)
- }
- func Debug(msg string, v ...interface{}) {
- loggerHandler.Debug(msg, v...)
- }
- func InfoWithTraceId(ctx *context.Context, msg string, v ...interface{}) {
- if traceId := ctx.Input.GetData("traceId"); traceId != "" {
- msg = fmt.Sprintf("[traceId:%v,%v]", traceId, msg)
- }
- Info(msg, v...)
- }
- func ErrorWithTraceId(ctx *context.Context, msg string, v ...interface{}) {
- if traceId := ctx.Input.GetData("traceId"); traceId != "" {
- msg = fmt.Sprintf("[traceId:%v,%v]", traceId, msg)
- }
- Error(msg, v...)
- }
- func WarnWithTraceId(ctx *context.Context, msg string, v ...interface{}) {
- if traceId := ctx.Input.GetData("traceId"); traceId != "" {
- msg = fmt.Sprintf("[traceId:%v,%v]", traceId, msg)
- }
- Warn(msg, v...)
- }
- func DebugWithTraceId(ctx *context.Context, msg string, v ...interface{}) {
- if traceId := ctx.Input.GetData("traceId"); traceId != "" {
- msg = fmt.Sprintf("[traceId:%v,%v]", traceId, msg)
- }
- Debug(msg, v...)
- }
- func (c *CustomLogger) Debug(msg string, v ...interface{}) {
- for _, cusLogger := range c.logs {
- if cusLogger.GetLevel() >= logs.LevelDebug && cusLogger.filter.ShouldLog(msg) {
- cusLogger.Debug(msg, v...)
- }
- }
- }
- func (c *CustomLogger) Info(msg string, v ...interface{}) {
- for _, cusLogger := range c.logs {
- if cusLogger.GetLevel() >= logs.LevelInfo && cusLogger.filter.ShouldLog(msg) {
- cusLogger.Info(msg, v...)
- }
- }
- }
- func (c *CustomLogger) Error(msg string, v ...interface{}) {
- for _, cusLogger := range c.logs {
- if cusLogger.GetLevel() >= logs.LevelError && cusLogger.filter.ShouldLog(msg) {
- cusLogger.Error(msg, v...)
- }
- }
- }
- func (c *CustomLogger) Warn(msg string, v ...interface{}) {
- for _, cusLogger := range c.logs {
- if cusLogger.GetLevel() >= logs.LevelWarning && cusLogger.filter.ShouldLog(msg) {
- cusLogger.Warn(msg, v...)
- }
- }
- }
- 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 GetInstance() Logger {
- return loggerHandler
- }
- func initLogger(logCfg logConfig) {
- if loggerHandler == nil {
- loggerHandler = new(CustomLogger)
- }
- if stringUtils.IsEmptyOrNil(logCfg.FilePath) {
- logCfg.FilePath = DefalutLogFilePath
- }
- for _, appenderItem := range logCfg.Appenders {
- terminal, ok := terminalType[appenderItem.Type]
- if !ok {
- fmt.Println("初始化日志执行器失败:{%s},终端类型不支持{type:%s}", appenderItem.FileName, appenderItem.Type)
- continue
- }
- var beeLogger *logs.BeeLogger
- if terminal == logs.AdapterConsole {
- beeLogger = logs.NewLogger(LogChannelLen)
- err := beeLogger.SetLogger(logs.AdapterConsole)
- if err != nil {
- fmt.Println("创建日志执行器失败:{%s} %v", appenderItem.FileName, err)
- continue
- }
- } else {
- logFile := appenderItem.FileName
- os.MkdirAll(logCfg.FilePath, os.ModePerm)
- // 打开文件
- appenderItem.FileName = path.Join(logCfg.FilePath, logFile)
- props, err := convertAppenderToLog(&appenderItem)
- if err != nil {
- fmt.Println("初始化日志执行器失败:{%s} %v", appenderItem.FileName, err)
- continue
- }
- b, _ := json.Marshal(props)
- beeLogger = logs.NewLogger(LogChannelLen)
- err = beeLogger.SetLogger(logs.AdapterFile, string(b))
- if err != nil {
- fmt.Println("设置日志执行器失败:{%s} %v", appenderItem.FileName, err)
- continue
- }
- beeLogger.EnableFuncCallDepth(true)
- }
- loggerHandler.logs = append(loggerHandler.logs, &logger{BeeLogger: beeLogger,
- filter: NewLevelFilter(appenderItem.Filter)})
- }
- }
- // 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,
- }, nil
- }
- // Filter 接口定义
- type Filter interface {
- ShouldLog(message string) bool
- }
- // LevelFilter 实现 Filter 接口,根据日志级别过滤日志
- type ContentFilter struct {
- filterStr string
- }
- // NewLevelFilter 创建一个新的 LevelFilter 实例
- func NewLevelFilter(filterStr string) *ContentFilter {
- return &ContentFilter{filterStr: filterStr}
- }
- // ShouldLog 根据日志级别决定是否记录日志
- func (lf *ContentFilter) ShouldLog(message string) bool {
- return strings.Contains(message, lf.filterStr)
- }
- // logConfig 日志配置
- type logConfig struct {
- FilePath string `json:"filepath" description:"日志路径"`
- Appenders []appender `json:"appenders" description:"日志记录"`
- }
- // appender beeLogger JSON配置
- 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:"日志是否输出颜色"`
- }
- // logProps beeLogger 配置
- 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:"日志是否输出颜色"`
- }
|