log_plugin.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. package logger
  2. import (
  3. "encoding/json"
  4. stringUtils "eta/eta_mini_ht_api/common/utils/string"
  5. "fmt"
  6. "github.com/beego/beego/v2/core/logs"
  7. "log"
  8. "os"
  9. "path"
  10. "strings"
  11. "sync"
  12. )
  13. const (
  14. DefalutLogFilePath = "./etalogs"
  15. LogChannelLen = 10000
  16. )
  17. var (
  18. loggerHandler *CustomLogger
  19. logMutex = &sync.Mutex{}
  20. )
  21. type logger struct {
  22. *logs.BeeLogger
  23. filter Filter
  24. }
  25. type CustomLogger struct {
  26. logs []*logger
  27. }
  28. // Logger interface
  29. type Logger interface {
  30. Info(msg string, v ...interface{})
  31. Warn(msg string, v ...interface{})
  32. Error(msg string, v ...interface{})
  33. }
  34. func Info(msg string, v ...interface{}) {
  35. logMutex.Lock()
  36. defer logMutex.Unlock()
  37. loggerHandler.Info(msg, v...)
  38. }
  39. func Error(msg string, v ...interface{}) {
  40. logMutex.Lock()
  41. defer logMutex.Unlock()
  42. loggerHandler.Error(msg, v...)
  43. }
  44. func Warn(msg string, v ...interface{}) {
  45. logMutex.Lock()
  46. defer logMutex.Unlock()
  47. loggerHandler.Warn(msg, v...)
  48. }
  49. func Debug(msg string, v ...interface{}) {
  50. loggerHandler.Debug(msg, v...)
  51. }
  52. func (c *CustomLogger) Debug(msg string, v ...interface{}) {
  53. for _, logger := range c.logs {
  54. if logger.GetLevel() >= logs.LevelInfo && logger.filter.ShouldLog(msg) {
  55. logger.Debug(msg, v...)
  56. }
  57. }
  58. }
  59. func (c *CustomLogger) Info(msg string, v ...interface{}) {
  60. for _, logger := range c.logs {
  61. if logger.GetLevel() >= logs.LevelInfo && logger.filter.ShouldLog(msg) {
  62. logger.Info(msg, v...)
  63. }
  64. }
  65. }
  66. func (c *CustomLogger) Error(msg string, v ...interface{}) {
  67. for _, logger := range c.logs {
  68. if logger.GetLevel() >= logs.LevelError && logger.filter.ShouldLog(msg) {
  69. logger.Error(msg, v...)
  70. }
  71. }
  72. }
  73. func (c *CustomLogger) Warn(msg string, v ...interface{}) {
  74. for _, logger := range c.logs {
  75. if logger.GetLevel() >= logs.LevelWarning && logger.filter.ShouldLog(msg) {
  76. logger.Warn(msg, v...)
  77. }
  78. }
  79. }
  80. func init() {
  81. var logCfg logConfig
  82. configFile, err := os.ReadFile("conf/log/log_config.json")
  83. if err != nil {
  84. log.Fatalf("Failed to read log config: %v", err)
  85. }
  86. err = json.Unmarshal(configFile, &logCfg)
  87. if err != nil {
  88. log.Fatalf("Failed to parse log config: %v", err)
  89. }
  90. initLogger(logCfg)
  91. }
  92. var levelTrans = map[string]int{
  93. "emergency": logs.LevelEmergency,
  94. "alert": logs.LevelAlert,
  95. "critical": logs.LevelCritical,
  96. "error": logs.LevelError,
  97. "warn": logs.LevelWarning,
  98. "notice": logs.LevelNotice,
  99. "info": logs.LevelInformational,
  100. "debug": logs.LevelDebug,
  101. }
  102. var terminalType = map[string]string{
  103. "console": logs.AdapterConsole,
  104. "file": logs.AdapterFile,
  105. }
  106. func GetInstance() Logger {
  107. return loggerHandler
  108. }
  109. func initLogger(logCfg logConfig) {
  110. if loggerHandler == nil {
  111. loggerHandler = new(CustomLogger)
  112. }
  113. if stringUtils.IsEmptyOrNil(logCfg.FilePath) {
  114. logCfg.FilePath = DefalutLogFilePath
  115. }
  116. for _, appender := range logCfg.Appenders {
  117. terminalType, ok := terminalType[appender.Type]
  118. if !ok {
  119. fmt.Println("初始化日志执行器失败:{%s},终端类型不支持{type:%s}", appender.FileName, appender.Type)
  120. continue
  121. }
  122. var beeLogger *logs.BeeLogger
  123. if terminalType == logs.AdapterConsole {
  124. beeLogger = logs.NewLogger(LogChannelLen)
  125. err := beeLogger.SetLogger(logs.AdapterConsole)
  126. if err != nil {
  127. fmt.Println("创建日志执行器失败:{%s} %v", appender.FileName, err)
  128. continue
  129. }
  130. } else {
  131. logFile := appender.FileName
  132. os.MkdirAll(logCfg.FilePath, os.ModePerm)
  133. // 打开文件
  134. appender.FileName = path.Join(logCfg.FilePath, logFile)
  135. logProps, err := convertAppenderToLog(&appender)
  136. if err != nil {
  137. fmt.Println("初始化日志执行器失败:{%s} %v", appender.FileName, err)
  138. continue
  139. }
  140. b, _ := json.Marshal(logProps)
  141. beeLogger = logs.NewLogger(LogChannelLen)
  142. err = beeLogger.SetLogger(logs.AdapterFile, string(b))
  143. if err != nil {
  144. fmt.Println("设置日志执行器失败:{%s} %v", appender.FileName, err)
  145. continue
  146. }
  147. beeLogger.EnableFuncCallDepth(true)
  148. }
  149. loggerHandler.logs = append(loggerHandler.logs, &logger{BeeLogger: beeLogger,
  150. filter: NewLevelFilter(appender.Filter)})
  151. }
  152. }
  153. // ConvertAppenderToLog 将 appender 结构体转换为 log 结构体
  154. func convertAppenderToLog(a *appender) (*logProps, error) {
  155. lvl, ok := levelTrans[a.Level]
  156. if !ok {
  157. return nil, fmt.Errorf("unknown log level: %s", a.Level)
  158. }
  159. return &logProps{
  160. Prefix: a.Prefix,
  161. FileName: a.FileName,
  162. MaxLines: a.MaxLines,
  163. MaxSize: a.MaxSize,
  164. Daily: a.Daily,
  165. MaxDays: a.MaxDays,
  166. Rotate: a.Rotate,
  167. Level: lvl,
  168. Color: a.Color,
  169. }, nil
  170. }
  171. // Filter 接口定义
  172. type Filter interface {
  173. ShouldLog(message string) bool
  174. }
  175. // LevelFilter 实现 Filter 接口,根据日志级别过滤日志
  176. type ContentFilter struct {
  177. filterStr string
  178. }
  179. // NewLevelFilter 创建一个新的 LevelFilter 实例
  180. func NewLevelFilter(filterStr string) *ContentFilter {
  181. return &ContentFilter{filterStr: filterStr}
  182. }
  183. // ShouldLog 根据日志级别决定是否记录日志
  184. func (lf *ContentFilter) ShouldLog(message string) bool {
  185. return strings.Contains(message, lf.filterStr)
  186. }
  187. // logConfig 日志配置
  188. type logConfig struct {
  189. FilePath string `json:"filepath" description:"日志路径"`
  190. Appenders []appender `json:"appenders" description:"日志记录"`
  191. }
  192. // appender beeLogger JSON配置
  193. type appender struct {
  194. Filter string `json:"filter"`
  195. Prefix string `json:"perfix" description:"日志前缀"`
  196. Type string `json:"type" description:"终端类型"`
  197. FileName string `json:"filename" description:"保存的文件名"`
  198. MaxLines int `json:"maxlines" description:"每个文件保存的最大行数,默认值 1000000"`
  199. MaxSize int `json:"maxsize" description:"每个文件保存的最大尺寸,默认值是 1 << 28, //256 MB"`
  200. Daily bool `json:"daily" description:"是否按照每天 logrotate,默认是 true"`
  201. MaxDays int `json:"maxdays" description:"文件最多保存多少天,默认保存 7 天"`
  202. Rotate bool `json:"rotate" description:"是否开启 logrotate,默认是 true"`
  203. Level string `json:"level" description:"日志保存的时候的级别,默认是 Trace 级别"`
  204. Color bool `json:"color" description:"日志是否输出颜色"`
  205. }
  206. // logProps beeLogger 配置
  207. type logProps struct {
  208. Prefix string `json:"perfix" description:"日志前缀"`
  209. FileName string `json:"filename" description:"保存的文件名"`
  210. MaxLines int `json:"maxlines" description:"每个文件保存的最大行数,默认值 1000000"`
  211. MaxSize int `json:"maxsize" description:"每个文件保存的最大尺寸,默认值是 1 << 28, //256 MB"`
  212. Daily bool `json:"daily" description:"是否按照每天 logrotate,默认是 true"`
  213. MaxDays int `json:"maxdays" description:"文件最多保存多少天,默认保存 7 天"`
  214. Rotate bool `json:"rotate" description:"是否开启 logrotate,默认是 true"`
  215. Level int `json:"level" description:"日志保存的时候的级别,默认是 Trace 级别"`
  216. Color bool `json:"color" description:"日志是否输出颜色"`
  217. }