logger.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. package logger
  2. import (
  3. "fmt"
  4. "io"
  5. "log"
  6. "os"
  7. "path/filepath"
  8. "strings"
  9. "sync"
  10. "time"
  11. )
  12. type Level int
  13. const (
  14. LevelDebug Level = iota
  15. LevelInfo
  16. LevelWarn
  17. LevelError
  18. )
  19. const (
  20. defaultDir = "./logs"
  21. )
  22. var (
  23. mu sync.RWMutex
  24. currentLevel = LevelInfo
  25. debugLog = log.New(os.Stdout, "[DEBUG] ", log.Ldate|log.Ltime)
  26. infoLog = log.New(os.Stdout, "[INFO] ", log.Ldate|log.Ltime)
  27. warnLog = log.New(os.Stderr, "[WARN] ", log.Ldate|log.Ltime)
  28. errorLog = log.New(os.Stderr, "[ERROR] ", log.Ldate|log.Ltime)
  29. logFile *rotatingFileWriter
  30. )
  31. type rotatingFileWriter struct {
  32. mu sync.Mutex
  33. file *os.File
  34. path string
  35. logDate string // 当前日志日期 YYYY-MM-DD
  36. }
  37. func (w *rotatingFileWriter) Write(p []byte) (n int, err error) {
  38. w.mu.Lock()
  39. defer w.mu.Unlock()
  40. today := time.Now().Format("2006-01-02")
  41. if today != w.logDate {
  42. if err := w.rotate(today); err != nil {
  43. return 0, err
  44. }
  45. }
  46. return w.file.Write(p)
  47. }
  48. func (w *rotatingFileWriter) rotate(today string) error {
  49. if w.logDate != "" {
  50. w.file.Close()
  51. backup := w.path + "." + w.logDate
  52. os.Rename(w.path, backup)
  53. }
  54. f, err := os.OpenFile(w.path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
  55. if err != nil {
  56. return err
  57. }
  58. w.file = f
  59. w.logDate = today
  60. return nil
  61. }
  62. func (w *rotatingFileWriter) Close() error {
  63. w.mu.Lock()
  64. defer w.mu.Unlock()
  65. if w.file != nil {
  66. return w.file.Close()
  67. }
  68. return nil
  69. }
  70. func SetLevel(l Level) {
  71. mu.Lock()
  72. defer mu.Unlock()
  73. currentLevel = l
  74. }
  75. func GetLevel() Level {
  76. mu.RLock()
  77. defer mu.RUnlock()
  78. return currentLevel
  79. }
  80. func ParseLevel(s string) Level {
  81. switch strings.ToLower(s) {
  82. case "debug":
  83. return LevelDebug
  84. case "info":
  85. return LevelInfo
  86. case "warn", "warning":
  87. return LevelWarn
  88. case "error":
  89. return LevelError
  90. default:
  91. return LevelInfo
  92. }
  93. }
  94. // InitFileLog 初始化文件日志。logPath 为空时默认 ./logs/monitor.log。
  95. // 按天轮转,日志同时输出到控制台和文件。
  96. func InitFileLog(logPath string) error {
  97. mu.Lock()
  98. defer mu.Unlock()
  99. if logPath == "" {
  100. logPath = defaultDir
  101. }
  102. fi, err := os.Stat(logPath)
  103. if err != nil || fi.IsDir() {
  104. logPath = filepath.Join(logPath, "monitor.log")
  105. }
  106. dir := filepath.Dir(logPath)
  107. if err := os.MkdirAll(dir, 0755); err != nil {
  108. return fmt.Errorf("创建日志目录失败: %w", err)
  109. }
  110. f, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
  111. if err != nil {
  112. return fmt.Errorf("打开日志文件失败: %w", err)
  113. }
  114. logFile = &rotatingFileWriter{
  115. file: f,
  116. path: logPath,
  117. logDate: time.Now().Format("2006-01-02"),
  118. }
  119. debugLog.SetOutput(io.MultiWriter(os.Stdout, logFile))
  120. infoLog.SetOutput(io.MultiWriter(os.Stdout, logFile))
  121. warnLog.SetOutput(io.MultiWriter(os.Stderr, logFile))
  122. errorLog.SetOutput(io.MultiWriter(os.Stderr, logFile))
  123. return nil
  124. }
  125. func Close() {
  126. mu.Lock()
  127. defer mu.Unlock()
  128. if logFile != nil {
  129. logFile.Close()
  130. logFile = nil
  131. }
  132. }
  133. func Debug(format string, v ...interface{}) {
  134. mu.RLock()
  135. l := currentLevel
  136. mu.RUnlock()
  137. if LevelDebug >= l {
  138. debugLog.Output(2, fmt.Sprintf(format, v...))
  139. }
  140. }
  141. func Info(format string, v ...interface{}) {
  142. mu.RLock()
  143. l := currentLevel
  144. mu.RUnlock()
  145. if LevelInfo >= l {
  146. infoLog.Output(2, fmt.Sprintf(format, v...))
  147. }
  148. }
  149. func Warn(format string, v ...interface{}) {
  150. mu.RLock()
  151. l := currentLevel
  152. mu.RUnlock()
  153. if LevelWarn >= l {
  154. warnLog.Output(2, fmt.Sprintf(format, v...))
  155. }
  156. }
  157. func Error(format string, v ...interface{}) {
  158. mu.RLock()
  159. l := currentLevel
  160. mu.RUnlock()
  161. if LevelError >= l {
  162. errorLog.Output(2, fmt.Sprintf(format, v...))
  163. }
  164. }