log.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. package logs
  2. import (
  3. "fmt"
  4. "github.com/natefinch/lumberjack"
  5. "github.com/sirupsen/logrus"
  6. "log"
  7. "os"
  8. "path"
  9. "path/filepath"
  10. "strings"
  11. "time"
  12. )
  13. const (
  14. defaultTimestamp = "2006-01-02 15:04:05.999"
  15. defaultLogDelimeter = "|"
  16. defaultLogLevel = logrus.ErrorLevel
  17. defaultLogFileSize = 50
  18. // 日志保存天数
  19. defaultMaxAge = 3
  20. // 每天最多保存的日志数量
  21. defaultMaxBackups = 3
  22. )
  23. type LogConfig struct {
  24. Path string
  25. AppInfo string
  26. MaxSize int // 日志文件最大尺寸,单位MB
  27. MaxBackups int // 最多保留的旧日志文件数
  28. MaxAge int // 日志文件保留的最长时间,单位天
  29. // 控制台输出
  30. Console bool
  31. }
  32. // 定义Hook结构体
  33. type FileHook struct {
  34. level logrus.Level
  35. formatter logrus.Formatter
  36. logger *log.Logger
  37. }
  38. func InitLog(level string, config LogConfig) error {
  39. FormatterInit()
  40. if config.Console {
  41. logrus.SetOutput(os.Stdout)
  42. } else {
  43. logrus.SetOutput(&NoOut{})
  44. }
  45. if level == "" {
  46. level = "error"
  47. }
  48. logrusLevel, err := logrus.ParseLevel(level)
  49. if err == nil {
  50. logrus.SetLevel(logrusLevel)
  51. } else {
  52. logrus.SetLevel(defaultLogLevel)
  53. logrus.WithError(err).Error("log level parse error, use default log level error")
  54. }
  55. logrus.SetFormatter(NewFormatter())
  56. logrus.SetReportCaller(true)
  57. if config.Path == "" {
  58. config.Path = log_config.Path
  59. }
  60. if config.Path == "" {
  61. return fmt.Errorf("config.Path is nil")
  62. }
  63. log_config = config
  64. RegisterLogHook(config)
  65. return nil
  66. }
  67. // 实现Hook接口
  68. func (hook *FileHook) Levels() []logrus.Level {
  69. return logrus.AllLevels[:hook.level+1]
  70. }
  71. func (hook *FileHook) Fire(entry *logrus.Entry) error {
  72. // 将日志消息格式化为字符串
  73. bytes, err := hook.formatter.Format(entry)
  74. hook.logger.Print(string(bytes))
  75. if err != nil {
  76. return fmt.Errorf("failed to format log entry: %v", err)
  77. }
  78. if err != nil {
  79. return fmt.Errorf("failed to write log entry: %v", err)
  80. }
  81. return nil
  82. }
  83. type NoOut struct {
  84. }
  85. func (no *NoOut) Write(p []byte) (n int, err error) {
  86. return 0, nil
  87. }
  88. func RegisterLogHook(logConf LogConfig) {
  89. hooks := make(logrus.LevelHooks)
  90. logrus.StandardLogger().ReplaceHooks(hooks)
  91. // 日志文件最大尺寸,不超过100MB
  92. if logConf.MaxSize > defaultLogFileSize || logConf.MaxSize < 1 {
  93. logConf.MaxSize = defaultLogFileSize
  94. }
  95. // 最多保留的旧日志文件数
  96. if logConf.MaxBackups > defaultMaxBackups || logConf.MaxBackups == 0 {
  97. logConf.MaxBackups = defaultMaxBackups
  98. }
  99. // 日志文件保留的最长时间,单位天
  100. if logConf.MaxAge > defaultMaxAge || logConf.MaxAge == 0 {
  101. logConf.MaxAge = defaultMaxAge
  102. }
  103. for _, val := range logrus.AllLevels {
  104. if val <= logrus.GetLevel() {
  105. fileName := filepath.Join(logConf.Path, logConf.AppInfo+"."+val.String()+".log")
  106. archive := &lumberjack.Logger{
  107. Filename: fileName,
  108. MaxSize: logConf.MaxSize, // 日志文件最大尺寸,单位MB
  109. MaxBackups: logConf.MaxBackups, // 最多保留的旧日志文件数
  110. MaxAge: logConf.MaxAge, // 日志文件保留的最长时间,单位天
  111. LocalTime: true, // 使用本地时间
  112. Compress: true,
  113. }
  114. sysLogger := &log.Logger{}
  115. sysLogger.SetOutput(archive)
  116. hooker := &FileHook{
  117. level: val,
  118. formatter: NewFormatter(),
  119. logger: sysLogger,
  120. }
  121. hooks.Add(hooker)
  122. }
  123. }
  124. }
  125. func FormatterInit() {
  126. logrus.SetFormatter(NewFormatter())
  127. logrus.SetReportCaller(true)
  128. }
  129. func NewFormatter() *MyFormatter {
  130. return &MyFormatter{
  131. Pid: os.Getpid(),
  132. TimestampFormat: defaultTimestamp,
  133. }
  134. }
  135. // Custom log format definition
  136. type MyFormatter struct {
  137. Pid int
  138. TimestampFormat string
  139. }
  140. func (s *MyFormatter) Format(entry *logrus.Entry) ([]byte, error) {
  141. //var callerFun string
  142. var fileInfo string
  143. var entryDataInfo string
  144. for key, val := range entry.Data {
  145. entryDataInfo += fmt.Sprintf(" %s=\"%v\"", key, val)
  146. }
  147. if entry.HasCaller() {
  148. //callerFun = entry.Caller.Function
  149. fileInfo = fmt.Sprintf("%s:%d", path.Base(entry.Caller.File), entry.Caller.Line)
  150. }
  151. timestamp := time.Now().Local().Format(s.TimestampFormat)
  152. msg := fmt.Sprintf("%s|%s|%d|%s] %s%s\n",
  153. timestamp, strings.ToUpper(entry.Level.String()), s.Pid, fileInfo, entry.Message, entryDataInfo)
  154. return []byte(msg), nil
  155. }
  156. var log_config LogConfig
  157. func GetLogConf() LogConfig {
  158. return log_config
  159. }