logger.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. package fslog
  2. import (
  3. "fmt"
  4. "go.uber.org/zap"
  5. "go.uber.org/zap/zapcore"
  6. "gopkg.in/natefinch/lumberjack.v2"
  7. "io"
  8. "sync"
  9. )
  10. // Logger 是对 zap.SugaredLogger 的封装,简化其对外使用的接口,
  11. // 并且针对于 Logger 所有配置都是支持运行时动态修改,且并发安全。
  12. // Logger 也支持了针对于 zapcore.Core 的扩展,调用 Logger.AddCore 即可,
  13. //
  14. // 构建该对象请使用 New 进行创建,在该操作中会对部分必要属性进行初始化,
  15. // 直接使用结构体创建会导致结构体不可用(甚至panic)。
  16. //
  17. // 如非深度定制化扩展,非必要不建议使用 Logger.AddCore 进行扩展,该操作会
  18. // 导致客户端应用程序对zap包编译依赖,不保证fslog切换内部日志实现。
  19. type Logger struct {
  20. // 日志打印用
  21. Logger zap.SugaredLogger
  22. // 互斥量
  23. // 用于内部不可并发逻辑使用
  24. lock sync.Mutex
  25. // 当前日志打印级别
  26. // 借助zap内部级别设置机制,该机制
  27. // 内部使用乐观锁,协程安全
  28. lv zap.AtomicLevel
  29. // 所有的core
  30. cores []zapcore.Core
  31. writers []io.Writer
  32. *loggerConfig
  33. }
  34. func New(opts ...LoggerOption) *Logger {
  35. logger := new(Logger)
  36. logger.loggerConfig = new(loggerConfig)
  37. if len(opts) == 0 {
  38. opts = []LoggerOption{WithSkipCaller(1)}
  39. }
  40. for _, opt := range opts {
  41. opt(logger.loggerConfig)
  42. }
  43. logger.lv = zap.NewAtomicLevelAt(zap.DebugLevel)
  44. logger.flushLogger()
  45. return logger
  46. }
  47. // With 拼接自定义信息
  48. // 主要用于打印当前环境快照信息(变量或其他自定义信息)
  49. // 打印后,该信息会跟随日志一起打印
  50. func (l *Logger) With(k string, v any) *Logger {
  51. newL := l.clone()
  52. newL.Logger = *newL.Logger.With(zap.Any(k, v))
  53. return newL
  54. }
  55. // Debug 格式化打印调试级别日志
  56. // 不同于zap内部可变参数逻辑,该可变参数是用于,字符串格式化的
  57. func (l *Logger) Debug(msg string, vs ...any) {
  58. if len(vs) == 0 {
  59. l.Logger.Debug(msg)
  60. return
  61. }
  62. l.Logger.Debugf(msg, vs...)
  63. }
  64. // Info 格式化打印信息级别日志
  65. // 不同于zap内部可变参数逻辑,该可变参数是用于,字符串格式化的
  66. func (l *Logger) Info(msg string, vs ...any) {
  67. if len(vs) == 0 {
  68. l.Logger.Info(msg)
  69. return
  70. }
  71. l.Logger.Infof(msg, vs...)
  72. }
  73. // Warn 格式化打印警告级别日志
  74. // 不同于zap内部可变参数逻辑,该可变参数是用于,字符串格式化的
  75. func (l *Logger) Warn(msg string, vs ...any) {
  76. if len(vs) == 0 {
  77. l.Logger.Warn(msg)
  78. return
  79. }
  80. l.Logger.Warnf(msg, vs...)
  81. }
  82. // Error 打印错误级别日志
  83. // 该方法具有两种传参形式:
  84. // 1. error类型:会直接格式化打印%+v日志
  85. // 2. 信息(格式化)
  86. // 3. error+格式化信息:error会作为 With 格式存在,且依旧以%+v格式输出
  87. func (l *Logger) Error(vs ...any) {
  88. if len(vs) == 0 {
  89. return
  90. }
  91. err, ok := vs[0].(error)
  92. if ok {
  93. if len(vs) == 1 {
  94. l.Logger.Errorf("%+v", err)
  95. return
  96. }
  97. withed := l.Logger.With(zap.String("err", fmt.Sprintf("%+v", err)))
  98. msg, ok := vs[1].(string)
  99. if ok {
  100. withed.Errorf(msg, vs[2:])
  101. return
  102. }
  103. withed.Error(vs[1:])
  104. return
  105. }
  106. msg, ok := vs[0].(string)
  107. if ok {
  108. if len(vs) > 1 {
  109. l.Logger.Errorf(msg, vs[1:]...)
  110. return
  111. }
  112. if len(vs) == 1 {
  113. l.Logger.Error(vs[0])
  114. return
  115. }
  116. }
  117. }
  118. // Lv 获取当前日志打印级别
  119. func (l *Logger) Lv() Level {
  120. return Level(l.lv.Level())
  121. }
  122. // SetLv 设置当前日志打印级别
  123. func (l *Logger) SetLv(lv Level) {
  124. l.lv.SetLevel(lv.zap())
  125. }
  126. // NewFileOutput 新增日志输出文件配置
  127. func (l *Logger) NewFileOutput(opts ...FileOutputOpt) {
  128. cfg := new(outFileConfig)
  129. for _, opt := range opts {
  130. opt(cfg)
  131. }
  132. l.NewOutput(&lumberjack.Logger{
  133. Filename: cfg.filename,
  134. MaxSize: cfg.maxSize,
  135. MaxAge: cfg.maxAge,
  136. MaxBackups: cfg.maxBackups,
  137. LocalTime: cfg.localTime,
  138. Compress: cfg.Compress,
  139. })
  140. }
  141. // NewOutput 新增日志输出位置
  142. func (l *Logger) NewOutput(writer io.Writer) {
  143. cfg := zap.NewProductionEncoderConfig()
  144. cfg.EncodeTime = zapcore.TimeEncoderOfLayout("2006-01-02 15:04:05")
  145. l.writers = append(l.writers, writer)
  146. l.AddCore(zapcore.NewCore(zapcore.NewJSONEncoder(cfg), zapcore.AddSync(writer), l.lv))
  147. }
  148. // AddCore 添加Core
  149. func (l *Logger) AddCore(core ...zapcore.Core) {
  150. l.addCoreOnly(core...)
  151. l.flushLogger()
  152. }
  153. // Flush 将缓冲区日志刷新至目标
  154. func (l *Logger) Flush() {
  155. err := l.Logger.Sync()
  156. if err != nil {
  157. With("err", err.Error()).Warn("flushLogger log error")
  158. }
  159. }
  160. // 保存内部core(不负责刷新 logger)
  161. func (l *Logger) addCoreOnly(core ...zapcore.Core) {
  162. l.lock.Lock()
  163. defer l.lock.Unlock()
  164. l.cores = append(l.cores, core...)
  165. }
  166. func (l *Logger) clone() *Logger {
  167. newL := &Logger{cores: l.cores, lv: l.lv, loggerConfig: l.loggerConfig}
  168. newL.flushLogger()
  169. return newL
  170. }
  171. // 刷新内部 logger
  172. // 刷新互斥,触发刷新后,刷新完成前依旧按照旧的配置执行
  173. func (l *Logger) flushLogger() {
  174. l.lock.Lock()
  175. defer l.lock.Unlock()
  176. l.Logger = *zap.
  177. New(
  178. zapcore.NewTee(l.cores...),
  179. zap.AddCaller(),
  180. ).
  181. Sugar().
  182. WithOptions(
  183. zap.AddCallerSkip(l.SkipCaller),
  184. zap.WithCaller(true),
  185. )
  186. }