logger.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. // Pacage logger provides a simple wrapper around zap logger
  2. package logger
  3. import (
  4. "encoding/json"
  5. "fmt"
  6. "os"
  7. "strings"
  8. "time"
  9. "go.uber.org/zap"
  10. "go.uber.org/zap/zapcore"
  11. "gopkg.in/natefinch/lumberjack.v2"
  12. "github.com/runningwater/gohub/pkg/app"
  13. )
  14. // Logger 全局日志对象
  15. var Logger *zap.Logger
  16. // Init 初始化日志
  17. func Init(filename string, maxSize, maxBackup, maxAge int, compress bool, logType, level string) {
  18. // 获取日志写入介质
  19. writeSyncer := getLogWriter(filename, maxSize, maxBackup, maxAge, compress, logType)
  20. // 设置日志等级, 具体见 config/log.go
  21. logLevel := new(zap.AtomicLevel)
  22. if err := logLevel.UnmarshalText([]byte(level)); err != nil {
  23. fmt.Println("日志初始化错误,日志级别设置有误。请修改 config/log.go 中的 log.level")
  24. }
  25. // 初始化 core
  26. core := zapcore.NewCore(getEncoder(), writeSyncer, logLevel)
  27. // 初始化 logger
  28. Logger = zap.New(core,
  29. zap.AddCaller(), // 调用文件和行号,内部使用 runtime.Caller
  30. zap.AddCallerSkip(1), // 调用文件和行号,内部使用 runtime.Caller
  31. // zap.Development(), // 开发模式,堆栈跟踪
  32. zap.AddStacktrace(zapcore.ErrorLevel), // 记录错误级别以上的堆栈信息
  33. )
  34. // 设置全局 logger
  35. // 将自定义的 logger 替换 zap 的全局 logger
  36. zap.ReplaceGlobals(Logger)
  37. }
  38. // getEncoder 获取编码器(如何写入日志), 输出: 日志格式
  39. func getEncoder() zapcore.Encoder {
  40. // 日志模式规则
  41. encoderConfig := zapcore.EncoderConfig{
  42. TimeKey: "time", // 时间字段名
  43. LevelKey: "level", // 日志级别字段名
  44. NameKey: "logger", // 日志名称字段名
  45. CallerKey: "caller", // 调用者字段名
  46. FunctionKey: zapcore.OmitKey, // 函数名字段名,不显示
  47. MessageKey: "msg", // 消息字段名
  48. StacktraceKey: "stacktrace", // 堆栈跟踪字段名
  49. LineEnding: zapcore.DefaultLineEnding, // 每行日志的结尾添加换行符
  50. EncodeLevel: zapcore.CapitalLevelEncoder, // 大写编码器
  51. EncodeTime: customTimeEncoder, // 自定义时间编码器
  52. EncodeDuration: zapcore.SecondsDurationEncoder, // 以秒为单位显示持续时间
  53. EncodeCaller: zapcore.ShortCallerEncoder, // 短路径编码器
  54. }
  55. if app.IsLocal() {
  56. encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder // 彩色编码器
  57. // 如果是本地环境,使用 console 编码器
  58. return zapcore.NewConsoleEncoder(encoderConfig)
  59. }
  60. // 如果不是本地环境,使用 JSON 编码器
  61. return zapcore.NewJSONEncoder(encoderConfig)
  62. }
  63. func customTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
  64. // 自定义时间格式
  65. enc.AppendString(t.Format("2006-01-02 15:04:05"))
  66. }
  67. // getLogWriter 获取日志写入介质
  68. // os.Stdout: 标准输出
  69. // 文件输出
  70. func getLogWriter(filename string, maxSize, maxBackup, maxAge int, compress bool, logType string) zapcore.WriteSyncer {
  71. // 如果配置了按日期记录日志,则使用按日期记录日志
  72. if logType == "daily" {
  73. logName := time.Now().Format("2006-01-02") + ".log"
  74. filename = strings.Replace(filename, "logs.log", logName, 1)
  75. }
  76. // 滚动日志,详见 config/log.go
  77. lumberJackLogger := &lumberjack.Logger{
  78. Filename: filename, // 日志文件名
  79. MaxSize: maxSize, // 每个日志文件保存的最大尺寸 单位:MB
  80. MaxBackups: maxBackup, // 日志文件最多保存多少个备份
  81. MaxAge: maxAge, // 文件最多保存多少天
  82. Compress: compress, // 是否压缩
  83. }
  84. if app.IsLocal() {
  85. // 如果是本地环境,使用标准输出和文件输出
  86. return zapcore.NewMultiWriteSyncer(
  87. zapcore.AddSync(os.Stdout),
  88. zapcore.AddSync(lumberJackLogger),
  89. )
  90. } else {
  91. // 生产环境只记录文件
  92. return zapcore.AddSync(lumberJackLogger)
  93. }
  94. }
  95. // Dump 调试专用, 不会中断程序,会在终端打印 warning 信息。
  96. // 第一个参数会使用 json.Marshal 进行渲染,第二个参数可选
  97. //
  98. // logger.Dump(user.User{Name: "test"})
  99. // logger.Dump(user.User{Name: "test"}, "用户信息")
  100. func Dump(v any, msg ...string) {
  101. valueStr := jsonString(v)
  102. if len(msg) > 0 {
  103. Logger.Warn("Dump", zap.String(msg[0], valueStr))
  104. } else {
  105. Logger.Warn("Dump", zap.String("data", valueStr))
  106. }
  107. }
  108. // LogIf 当 err != nill 时记录 error 等级的日志
  109. func LogIf(err error) {
  110. if err != nil {
  111. Logger.Error("Error Occurred: ", zap.Error(err))
  112. }
  113. }
  114. // LogWarnIf 当 err != nill 时记录 warning 等级的日志
  115. func LogWarnIf(err error) {
  116. if err != nil {
  117. Logger.Warn("Error Occurred: ", zap.Error(err))
  118. }
  119. }
  120. // LogInfoIf 当 err != nill 时记录 info 等级的日志
  121. func LogInfoIf(err error) {
  122. if err != nil {
  123. Logger.Info("Error Occurred: ", zap.Error(err))
  124. }
  125. }
  126. // Debug 调试专用, 不会中断程序
  127. //
  128. // logger.Debug("Database", zap.String("sql", sql))
  129. func Debug(msg string, fields ...zap.Field) {
  130. Logger.Debug(msg, fields...)
  131. }
  132. // Info 信息级别
  133. func Info(msg string, fields ...zap.Field) {
  134. Logger.Info(msg, fields...)
  135. }
  136. // Warn 警告级别
  137. func Warn(msg string, fields ...zap.Field) {
  138. Logger.Warn(msg, fields...)
  139. }
  140. // Error 错误级别
  141. func Error(msg string, fields ...zap.Field) {
  142. Logger.Error(msg, fields...)
  143. }
  144. // Fatal 致命级别
  145. func Fatal(msg string, fields ...zap.Field) {
  146. Logger.Fatal(msg, fields...)
  147. }
  148. // DebugString 记录一条字符串类型的 debug 日志
  149. //
  150. // logger.DebugString("User", "name", "John")
  151. func DebugString(moduleName, name, msg string) {
  152. Logger.Debug(moduleName, zap.String(name, msg))
  153. }
  154. func InfoString(moduleName, name, msg string) {
  155. Logger.Info(moduleName, zap.String(name, msg))
  156. }
  157. func WarnString(moduleName, name, msg string) {
  158. Logger.Warn(moduleName, zap.String(name, msg))
  159. }
  160. func ErrorString(moduleName, name, msg string) {
  161. Logger.Error(moduleName, zap.String(name, msg))
  162. }
  163. func FatalString(moduleName, name, msg string) {
  164. Logger.Fatal(moduleName, zap.String(name, msg))
  165. }
  166. // DebugJSON 记录对象类型的 debug 日志,使用 json.Marshal 进行编码。调用示例:
  167. //
  168. // logger.DebugJSON("Auth", "读取登录用户", auth.CurrentUser())
  169. func DebugJSON(moduleName, name string, value any) {
  170. Logger.Debug(moduleName, zap.String(name, jsonString(value)))
  171. }
  172. func InfoJSON(moduleName, name string, value any) {
  173. Logger.Info(moduleName, zap.String(name, jsonString(value)))
  174. }
  175. func WarnJSON(moduleName, name string, value any) {
  176. Logger.Warn(moduleName, zap.String(name, jsonString(value)))
  177. }
  178. func ErrorJSON(moduleName, name string, value any) {
  179. Logger.Error(moduleName, zap.String(name, jsonString(value)))
  180. }
  181. func FatalJSON(moduleName, name string, value any) {
  182. Logger.Fatal(moduleName, zap.String(name, jsonString(value)))
  183. }
  184. func jsonString(v any) string {
  185. b, err := json.Marshal(v)
  186. if err != nil {
  187. Logger.Error("Logger", zap.String("json.Marshal error", err.Error()))
  188. }
  189. return string(b)
  190. }