log_plugin.go 7.8 KB

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