gitee.com/quant1x/gox@v1.21.2/logger/logger.go (about)

     1  package logger
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"gitee.com/quant1x/gox/api"
     8  	"gitee.com/quant1x/gox/cache"
     9  	"gitee.com/quant1x/gox/mdc"
    10  	"gitee.com/quant1x/gox/signal"
    11  	"os"
    12  	"path/filepath"
    13  	"reflect"
    14  	"runtime"
    15  	"sync"
    16  	"time"
    17  )
    18  
    19  const (
    20  	DEBUG LogLevel = iota
    21  	INFO
    22  	WARN
    23  	ERROR
    24  	OFF
    25  	FATAL
    26  )
    27  
    28  const (
    29  	loggerRollerDays int = 7 // 保持7天
    30  	loggerLocalSkip      = 2
    31  	timeFmtTimestamp     = "2006-01-02T15:04:05.000"
    32  	timeFmtHour          = "2006010215"
    33  	timeFmtDay           = "20060102"
    34  	loggerTraceId        = mdc.APP_TRACEID
    35  )
    36  
    37  var (
    38  	loggerPath   string
    39  	logLevel     = DEBUG
    40  	logQueue     = make(chan *logValue, 10000)
    41  	loggerMap    sync.Map
    42  	logMutex     sync.RWMutex
    43  	currUnixTime int64
    44  	currDateHour string
    45  	currDateDay  string
    46  	finished     chan struct{}
    47  	pool         cache.Pool[logValue]
    48  )
    49  
    50  type Logger struct {
    51  	name   string
    52  	writer LogWriter
    53  }
    54  type LogLevel uint8
    55  
    56  type logValue struct {
    57  	level  LogLevel
    58  	value  []byte
    59  	fileNo string
    60  	writer LogWriter
    61  	fatal  bool
    62  }
    63  
    64  func init() {
    65  	now := time.Now()
    66  	currUnixTime = now.Unix()
    67  	currDateHour = now.Format(timeFmtHour)
    68  	currDateDay = now.Format(timeFmtDay)
    69  	finished = make(chan struct{})
    70  	go func() {
    71  		tm := time.NewTimer(time.Millisecond)
    72  		for {
    73  			now := time.Now()
    74  			d := time.Second - time.Duration(now.Nanosecond())
    75  			tm.Reset(d)
    76  			<-tm.C
    77  			now = time.Now()
    78  			logMutex.Lock()
    79  			currUnixTime = now.Unix()
    80  			currDateHour = now.Format(timeFmtHour)
    81  			currDateDay = now.Format(timeFmtDay)
    82  			logMutex.Unlock()
    83  		}
    84  	}()
    85  	go flushLog(true)
    86  
    87  	// 创建监听退出chan
    88  	sigs := signal.Notify()
    89  
    90  	_, cancel := context.WithCancel(context.Background())
    91  
    92  	go func() {
    93  		s := <-sigs
    94  		Infof("exit sign, [%+v]", s)
    95  		FlushLogger()
    96  		fmt.Println("exit", s)
    97  		cancel()
    98  		os.Exit(0)
    99  	}()
   100  
   101  }
   102  
   103  func (lv *LogLevel) String() string {
   104  	switch *lv {
   105  	case DEBUG:
   106  		return "DEBUG"
   107  	case INFO:
   108  		return "INFO"
   109  	case WARN:
   110  		return "WARN"
   111  	case ERROR:
   112  		return "ERROR"
   113  	case FATAL:
   114  		return "FATAL"
   115  	default:
   116  		return "UNKNOWN"
   117  	}
   118  }
   119  
   120  // SetLogPath 设置日志路径, 默认是INFO级别日志
   121  //
   122  //	Deprecated: 推荐使用 InitLogger
   123  func SetLogPath(path string) {
   124  	InitLogger(path, INFO)
   125  }
   126  
   127  // InitLogger 初始化
   128  func InitLogger(path string, level ...LogLevel) {
   129  	// 日志路径非空, 赋值
   130  	if !api.IsEmpty(path) {
   131  		loggerPath = path
   132  	}
   133  	name := ApplicationName()
   134  	loggerPath = filepath.Join(loggerPath, name)
   135  
   136  	// 日志级别默认是INFO
   137  	optLevel := INFO
   138  	if len(level) > 0 {
   139  		optLevel = level[0]
   140  	}
   141  	SetLevel(optLevel)
   142  }
   143  
   144  // GetLogger return an logger instance
   145  func GetLogger(name string) *Logger {
   146  	v, found := loggerMap.Load(name)
   147  	if found {
   148  		return v.(*Logger)
   149  	}
   150  	lg := &Logger{
   151  		name:   name,
   152  		writer: &ConsoleWriter{},
   153  	}
   154  	_ = lg.SetDayRoller(loggerPath, loggerRollerDays)
   155  	loggerMap.Store(name, lg)
   156  	return lg
   157  }
   158  
   159  func SetLevel(level LogLevel) {
   160  	logLevel = level
   161  }
   162  
   163  // IsDebug 是否DEBUG模式
   164  func IsDebug() bool {
   165  	if DEBUG < logLevel {
   166  		return false
   167  	}
   168  	return true
   169  }
   170  
   171  func StringToLevel(level string) LogLevel {
   172  	switch level {
   173  	case "DEBUG":
   174  		return DEBUG
   175  	case "INFO":
   176  		return INFO
   177  	case "WARN":
   178  		return WARN
   179  	case "ERROR":
   180  		return ERROR
   181  	case "FATAL":
   182  		return FATAL
   183  	default:
   184  		return DEBUG
   185  	}
   186  }
   187  
   188  func (l *Logger) SetLogName(name string) {
   189  	l.name = name
   190  }
   191  
   192  func (l *Logger) SetFileRoller(logpath string, num int, sizeMB int) error {
   193  	if err := os.MkdirAll(logpath, 0755); err != nil {
   194  		panic(err)
   195  	}
   196  	w := NewRollFileWriter(logpath, l.name, num, sizeMB)
   197  	l.writer = w
   198  	return nil
   199  }
   200  
   201  func (l *Logger) IsConsoleWriter() bool {
   202  	if reflect.TypeOf(l.writer) == reflect.TypeOf(&ConsoleWriter{}) {
   203  		return true
   204  	}
   205  	return false
   206  }
   207  
   208  func (l *Logger) SetWriter(w LogWriter) {
   209  	l.writer = w
   210  }
   211  
   212  func (l *Logger) SetDayRoller(logpath string, num int) error {
   213  	if err := os.MkdirAll(logpath, 0755); err != nil {
   214  		return err
   215  	}
   216  	w := NewDateWriter(logpath, l.name, DAY, num)
   217  	l.writer = w
   218  	return nil
   219  }
   220  
   221  func (l *Logger) SetHourRoller(logpath string, num int) error {
   222  	if err := os.MkdirAll(logpath, 0755); err != nil {
   223  		return err
   224  	}
   225  	w := NewDateWriter(logpath, l.name, HOUR, num)
   226  	l.writer = w
   227  	return nil
   228  }
   229  
   230  func (l *Logger) SetConsole() {
   231  	l.writer = &ConsoleWriter{}
   232  }
   233  
   234  func (l *Logger) Debug(v ...any) {
   235  	l.writef(loggerLocalSkip, DEBUG, "", v)
   236  }
   237  
   238  func (l *Logger) Info(v ...any) {
   239  	l.writef(loggerLocalSkip, INFO, "", v)
   240  }
   241  
   242  func (l *Logger) Warn(v ...any) {
   243  	l.writef(loggerLocalSkip, WARN, "", v)
   244  }
   245  
   246  func (l *Logger) Error(v ...any) {
   247  	l.writef(loggerLocalSkip, ERROR, "", v)
   248  }
   249  
   250  func (l *Logger) Debugf(format string, v ...any) {
   251  	l.writef(loggerLocalSkip, DEBUG, format, v)
   252  }
   253  
   254  func (l *Logger) Infof(format string, v ...any) {
   255  	l.writef(loggerLocalSkip, INFO, format, v)
   256  }
   257  
   258  func (l *Logger) Warnf(format string, v ...any) {
   259  	l.writef(loggerLocalSkip, WARN, format, v)
   260  }
   261  
   262  func (l *Logger) Errorf(format string, v ...any) {
   263  	l.writef(loggerLocalSkip, ERROR, format, v)
   264  }
   265  
   266  func (l *Logger) Fatal(v ...any) {
   267  	l.writef(loggerLocalSkip, FATAL, "", v)
   268  	waitForExit()
   269  }
   270  
   271  func (l *Logger) Fatalf(format string, v ...any) {
   272  	l.writef(loggerLocalSkip, FATAL, format, v)
   273  	waitForExit()
   274  }
   275  
   276  func getTraceId() string {
   277  	traceId := mdc.Get(loggerTraceId)
   278  	t := reflect.ValueOf(traceId)
   279  	if t.Kind() == reflect.String {
   280  		return t.String()
   281  	}
   282  	return ""
   283  }
   284  
   285  func (l *Logger) writef(skip int, level LogLevel, format string, v []any) {
   286  	if level < logLevel {
   287  		return
   288  	}
   289  
   290  	t := time.Now()
   291  	buf := bytes.NewBuffer(nil)
   292  	if l.writer.NeedPrefix() {
   293  		traceId := getTraceId()
   294  		_, _ = fmt.Fprintf(buf, "%s|%s|", t.Format(timeFmtTimestamp), traceId)
   295  		if logLevel == DEBUG {
   296  			_, file, line, ok := runtime.Caller(skip)
   297  			if !ok {
   298  				file = "???"
   299  				line = 0
   300  			} else {
   301  				file = filepath.Base(file)
   302  			}
   303  			_, _ = fmt.Fprintf(buf, "%s:%d|", file, line)
   304  		}
   305  	}
   306  	buf.WriteString(level.String())
   307  	buf.WriteByte('|')
   308  
   309  	if format == "" {
   310  		_, _ = fmt.Fprint(buf, v...)
   311  	} else {
   312  		_, _ = fmt.Fprintf(buf, format, v...)
   313  	}
   314  	if l.writer.NeedPrefix() {
   315  		buf.WriteByte('\n')
   316  	}
   317  	lv := pool.Acquire()
   318  	lv.value = buf.Bytes()
   319  	lv.writer = l.writer
   320  	lv.fatal = level == FATAL
   321  	logQueue <- lv
   322  }
   323  
   324  func FlushLogger() {
   325  	flushLog(false)
   326  }
   327  
   328  // 等待结束信号并退出
   329  func waitForExit() {
   330  	<-finished
   331  	os.Exit(-1)
   332  }
   333  
   334  func refreshLogFile(v *logValue) {
   335  	if v == nil {
   336  		return
   337  	}
   338  	v.writer.Write(v.value)
   339  	defer pool.Release(v)
   340  	if v == nil || !v.fatal {
   341  		return
   342  	}
   343  	// 致命的日志, 同时输出到控制台
   344  	fmt.Println(api.Bytes2String(v.value))
   345  	// 发送结束信号
   346  	finished <- struct{}{}
   347  }
   348  
   349  func flushLog(sync bool) {
   350  	if sync {
   351  		for v := range logQueue {
   352  			refreshLogFile(v)
   353  		}
   354  	} else {
   355  		for {
   356  			select {
   357  			case v := <-logQueue:
   358  				refreshLogFile(v)
   359  				continue
   360  			default:
   361  				return
   362  			}
   363  		}
   364  	}
   365  }
   366  
   367  func Info(v ...any) {
   368  	logger := GetLogger("runtime")
   369  	logger.writef(loggerLocalSkip, INFO, "", v)
   370  }
   371  
   372  func Infof(format string, v ...any) {
   373  	logger := GetLogger("runtime")
   374  	logger.writef(loggerLocalSkip, INFO, format, v)
   375  }
   376  
   377  func Debug(v ...any) {
   378  	logger := GetLogger("debug")
   379  	logger.writef(loggerLocalSkip, DEBUG, "", v)
   380  }
   381  
   382  func Debugf(format string, v ...any) {
   383  	logger := GetLogger("debug")
   384  	logger.writef(loggerLocalSkip, DEBUG, format, v)
   385  }
   386  
   387  func Warn(v ...any) {
   388  	logger := GetLogger("warn")
   389  	logger.writef(loggerLocalSkip, WARN, "", v)
   390  }
   391  
   392  func Warnf(format string, v ...any) {
   393  	logger := GetLogger("warn")
   394  	logger.writef(loggerLocalSkip, WARN, format, v)
   395  }
   396  
   397  func Error(v ...any) {
   398  	logger := GetLogger("error")
   399  	logger.writef(loggerLocalSkip, ERROR, "", v)
   400  }
   401  
   402  func Errorf(format string, v ...any) {
   403  	logger := GetLogger("error")
   404  	logger.writef(loggerLocalSkip, ERROR, format, v)
   405  }
   406  
   407  func Fatal(v ...any) {
   408  	logger := GetLogger("error")
   409  	logger.writef(loggerLocalSkip, FATAL, "", v)
   410  	waitForExit()
   411  }
   412  
   413  func Fatalf(format string, v ...any) {
   414  	logger := GetLogger("error")
   415  	logger.writef(loggerLocalSkip, FATAL, format, v)
   416  	waitForExit()
   417  }