| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- package logger
- import (
- "fmt"
- "io"
- "log"
- "os"
- "path/filepath"
- "strings"
- "sync"
- "time"
- )
- type Level int
- const (
- LevelDebug Level = iota
- LevelInfo
- LevelWarn
- LevelError
- )
- const (
- defaultDir = "./logs"
- )
- var (
- mu sync.RWMutex
- currentLevel = LevelInfo
- debugLog = log.New(os.Stdout, "[DEBUG] ", log.Ldate|log.Ltime)
- infoLog = log.New(os.Stdout, "[INFO] ", log.Ldate|log.Ltime)
- warnLog = log.New(os.Stderr, "[WARN] ", log.Ldate|log.Ltime)
- errorLog = log.New(os.Stderr, "[ERROR] ", log.Ldate|log.Ltime)
- logFile *rotatingFileWriter
- )
- type rotatingFileWriter struct {
- mu sync.Mutex
- file *os.File
- path string
- logDate string // 当前日志日期 YYYY-MM-DD
- }
- func (w *rotatingFileWriter) Write(p []byte) (n int, err error) {
- w.mu.Lock()
- defer w.mu.Unlock()
- today := time.Now().Format("2006-01-02")
- if today != w.logDate {
- if err := w.rotate(today); err != nil {
- return 0, err
- }
- }
- return w.file.Write(p)
- }
- func (w *rotatingFileWriter) rotate(today string) error {
- if w.logDate != "" {
- w.file.Close()
- backup := w.path + "." + w.logDate
- os.Rename(w.path, backup)
- }
- f, err := os.OpenFile(w.path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
- if err != nil {
- return err
- }
- w.file = f
- w.logDate = today
- return nil
- }
- func (w *rotatingFileWriter) Close() error {
- w.mu.Lock()
- defer w.mu.Unlock()
- if w.file != nil {
- return w.file.Close()
- }
- return nil
- }
- func SetLevel(l Level) {
- mu.Lock()
- defer mu.Unlock()
- currentLevel = l
- }
- func GetLevel() Level {
- mu.RLock()
- defer mu.RUnlock()
- return currentLevel
- }
- func ParseLevel(s string) Level {
- switch strings.ToLower(s) {
- case "debug":
- return LevelDebug
- case "info":
- return LevelInfo
- case "warn", "warning":
- return LevelWarn
- case "error":
- return LevelError
- default:
- return LevelInfo
- }
- }
- // InitFileLog 初始化文件日志。logPath 为空时默认 ./logs/monitor.log。
- // 按天轮转,日志同时输出到控制台和文件。
- func InitFileLog(logPath string) error {
- mu.Lock()
- defer mu.Unlock()
- if logPath == "" {
- logPath = defaultDir
- }
- fi, err := os.Stat(logPath)
- if err != nil || fi.IsDir() {
- logPath = filepath.Join(logPath, "monitor.log")
- }
- dir := filepath.Dir(logPath)
- if err := os.MkdirAll(dir, 0755); err != nil {
- return fmt.Errorf("创建日志目录失败: %w", err)
- }
- f, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
- if err != nil {
- return fmt.Errorf("打开日志文件失败: %w", err)
- }
- logFile = &rotatingFileWriter{
- file: f,
- path: logPath,
- logDate: time.Now().Format("2006-01-02"),
- }
- debugLog.SetOutput(io.MultiWriter(os.Stdout, logFile))
- infoLog.SetOutput(io.MultiWriter(os.Stdout, logFile))
- warnLog.SetOutput(io.MultiWriter(os.Stderr, logFile))
- errorLog.SetOutput(io.MultiWriter(os.Stderr, logFile))
- return nil
- }
- func Close() {
- mu.Lock()
- defer mu.Unlock()
- if logFile != nil {
- logFile.Close()
- logFile = nil
- }
- }
- func Debug(format string, v ...interface{}) {
- mu.RLock()
- l := currentLevel
- mu.RUnlock()
- if LevelDebug >= l {
- debugLog.Output(2, fmt.Sprintf(format, v...))
- }
- }
- func Info(format string, v ...interface{}) {
- mu.RLock()
- l := currentLevel
- mu.RUnlock()
- if LevelInfo >= l {
- infoLog.Output(2, fmt.Sprintf(format, v...))
- }
- }
- func Warn(format string, v ...interface{}) {
- mu.RLock()
- l := currentLevel
- mu.RUnlock()
- if LevelWarn >= l {
- warnLog.Output(2, fmt.Sprintf(format, v...))
- }
- }
- func Error(format string, v ...interface{}) {
- mu.RLock()
- l := currentLevel
- mu.RUnlock()
- if LevelError >= l {
- errorLog.Output(2, fmt.Sprintf(format, v...))
- }
- }
|