logger.go 5.3 KB

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