设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间10 现在时间10 缓存数据 只要你的心是晴的,人生就没有雨天。就像好事情总是发生在那些微笑着的人身上。调整心情,保持微笑。早安!

只要你的心是晴的,人生就没有雨天。就像好事情总是发生在那些微笑着的人身上。调整心情,保持微笑。早安!

查看: 960|回复: 1

golang整合日志zap的实现示例

[复制链接]

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
26
主题
20
精华
0
金钱
76
积分
46
注册时间
2023-9-30
最后登录
2025-3-14

发表于 2024-11-27 00:39:47 | 显示全部楼层 |阅读模式
目录


  • 安装
  • 基本使用
  • NewExample/NewDevelopment/NewProduction使用

    • NewExample()使用
    • NewDevelopment()使用
    • NewProduction()使用
    • 传入配置项

  • zap.Hook() 添加回调函数
  • 自定义配置项
  • SugaredLogger日志
  • logger日志
  • 输出日志到文件
  • 日志切割归档
  • 全局logger
在许多Go语言项目中,我们需要一个好的日志记录器能够提供下面这些功能:

  • 能够将事件记录到文件中,而不是应用程序控制台;
  • 日志切割-能够根据文件大小、时间或间隔等来切割日志文件;
  • 支持不同的日志级别。例如INFO,DEBUG,ERROR等;
  • 能够打印基本信息,如调用文件/函数名和行号,日志时间等;


  • 日志分级:有 Debug,Info,Warn,Error,DPanic,Panic,Fatal 等
  • 日志记录结构化:日志内容记录是结构化的,比如 json 格式输出
  • 自定义格式:用户可以自定义输出的日志格式
  • 自定义公共字段:用户可以自定义公共字段,大家输出的日志内容就共同拥有了这些字段
  • 调试:可以打印文件名、函数名、行号、日志时间等,便于调试程序
  • 自定义调用栈级别:可以根据日志级别输出它的调用栈信息
  • Namespace:日志命名空间。定义命名空间后,所有日志内容就在这个命名空间下。命名空间相当于一个文件夹
  • 支持 hook 操作

安装
  1. go get -u go.uber.org/zap
复制代码
基本使用
  1. package main

  2. import "go.uber.org/zap"

  3. var logger *zap.Logger

  4. func main() {
  5.         logger, _ = zap.NewProduction() // 使用生产环境
  6.     // logger, _ := zap.NewDevelopment() // 使用开发环境
  7.         defer logger.Sync() // 刷新缓存
  8.    
  9.    
  10.     suger := logger.Sugar() // 开启日志语法糖
  11.    
  12.     suger.Debug("我是Debug级别的日志")
  13.         suger.Debugw("我是Debug级别的日志", "key1", "value1", "key2", "value2")
  14.         suger.Debugf("我是Debug级别的日志%s", "value")

  15.         suger.Warn("我是Warn级别的日志")
  16.         suger.Warnw("我是Warn级别的日志", "key1", "value1", "key2", "value2")
  17.         suger.Warnf("我是Warn级别的日志%s", "value")

  18.         suger.Info("我是Info级别的日志")
  19.         suger.Infow("我是Info级别的日志", "key1", "value1", "key2", "value2")
  20.         suger.Infof("我是Info级别的日志 %s", "info")

  21.         suger.Error("我是Error级别的日志")
  22.         suger.Errorw("我是Error级别的日志", "key1", "value1", "key2", "value2")
  23.         suger.Errorf("我是Error级别的日志 %s", "value")

  24.         suger.Panic("我是Panic级别的日志")
  25.         suger.Panicw("我是Panic级别的日志", "key1", "value1", "key2", "value2")
  26.         suger.Panicf("我是Panic级别的日志 %s", "value")
  27.    
  28.     // 使用不带语法糖的日志
  29.     logger.Debug("我是Debug级别的日志", zap.String("key", "value"), zap.Int("num", 10))
  30.         logger.Warn("我是Warn级别的日志", zap.String("key", "value"), zap.Int("num", 10))
  31.         logger.Info("我是Info级别的日志", zap.String("key", "value"), zap.Int("num", 10))
  32.         logger.Error("我是Error级别的日志", zap.String("key", "value"), zap.Int("num", 10))
  33.         logger.Panic("我是Panic级别的日志", zap.String("key", "value"), zap.Int("num", 10))
  34. }
复制代码
NewExample/NewDevelopment/NewProduction使用

zap 为我们提供了三种快速创建 logger 的方法:
  1. zap.NewProduction()
复制代码
  1. zap.NewDevelopment()
复制代码
  1. zap.NewExample()
复制代码
Example 一般用在测试代码中,Development 用在开发环境中,Production 用在生成环境中

NewExample()使用

NewExample 构建一个 logger,专门为在 zap 的测试示例使用。它将 DebugLevel 及以上日志用 JSON 格式标准输出,但它省略了时间戳和调用函数,以保持示例输出的简短和确定性
因为在这个方法里,zap 已经定义好了日志配置项部分默认值
  1. // https://github.com/uber-go/zap/blob/v1.24.0/logger.go#L127
  2. func NewExample(options ...Option) *Logger {
  3.         encoderCfg := zapcore.EncoderConfig{
  4.         MessageKey:     "msg",  // 日志内容key:val, 前面的key设为msg
  5.                 LevelKey:       "level", // 日志级别的key设为level
  6.                 NameKey:        "logger", // 日志名
  7.                 EncodeLevel:    zapcore.LowercaseLevelEncoder, //日志级别,默认小写
  8.                 EncodeTime:     zapcore.ISO8601TimeEncoder, // 日志时间
  9.                 EncodeDuration: zapcore.StringDurationEncoder,
  10.         }
  11.         core := zapcore.NewCore(zapcore.NewJSONEncoder(encoderCfg), os.Stdout, DebugLevel)
  12.         return New(core).WithOptions(options...)
  13. }
复制代码
使用例子
  1. package main
  2. import (
  3.         "go.uber.org/zap"
  4. )
  5. func main() {
  6.         logger := zap.NewExample()
  7.         logger.Debug("this is debug message")
  8. }
复制代码
NewDevelopment()使用

NewDevelopment() 构建一个开发使用的 Logger
使用例子
  1. package main

  2. import (
  3.         "time"

  4.         "go.uber.org/zap"
  5. )
  6. func main() {
  7.         logger, _ := zap.NewDevelopment()
  8.         defer logger.Sync()

  9.         logger.Info("failed to fetch url",
  10.                 // 强类型字段
  11.                 zap.String("url", "http://example.com"),
  12.                 zap.Int("attempt", 3),
  13.                 zap.Duration("duration", time.Second),
  14.         )

  15.         logger.With(
  16.                 // 强类型字段
  17.                 zap.String("url", "http://development.com"),
  18.                 zap.Int("attempt", 4),
  19.                 zap.Duration("duration", time.Second*5),
  20.         ).Info("[With] failed to fetch url")
  21. }
复制代码
NewProduction()使用

NewProduction() 构建了一个合理的 Prouction 日志记录器,它将 info 及以上的日志内容以 JSON 格式记写入标准错误里
使用例子
  1. package main

  2. import (
  3.         "time"

  4.         "go.uber.org/zap"
  5. )

  6. func main() {
  7.         logger, _ := zap.NewProduction()
  8.         defer logger.Sync()

  9.         url := "http://zap.uber.io"
  10.         sugar := logger.Sugar()
  11.         sugar.Infow("failed to fetch URL",
  12.                 "url", url,
  13.                 "attempt", 3,
  14.                 "time", time.Second,
  15.         )

  16.         sugar.Infof("Failed to fetch URL: %s", url)

  17.         // 或更简洁 Sugar() 使用
  18.         // sugar := zap.NewProduction().Sugar()
  19.         // defer sugar.Sync()
  20. }
复制代码
传入配置项

在这 3 个函数中,可以传入一些配置项。
func NewExample(options …Option) *Logger
  1. package main

  2. import (
  3.         "os"

  4.         "go.uber.org/zap"
  5.         "go.uber.org/zap/zapcore"
  6. )

  7. func main() {

  8.         encoder := zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())

  9.         file, _ := os.OpenFile("./log.txt", os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm)
  10.         syncFile := zapcore.AddSync(file)
  11.         syncConsole := zapcore.AddSync(os.Stderr)
  12.         sync := zapcore.NewMultiWriteSyncer(syncConsole, syncFile)

  13.         core := zapcore.NewCore(encoder, sync, zapcore.InfoLevel)
  14.         logger := zap.New(core)
  15.         logger.Info("info 日志", zap.Int("line", 1))
  16. }
复制代码
zap.Hook() 添加回调函数

Hook (钩子函数)回调函数为用户提供一种简单方法,在每次日志内容记录后运行这个回调函数,执行用户需要的操作。也就是说记录完日志后你还想做其它事情就可以调用这个函数
  1. package main

  2. import (
  3.         "fmt"

  4.         "go.uber.org/zap"
  5.         "go.uber.org/zap/zapcore"
  6. )

  7. func main() {
  8.         logger := zap.NewExample(zap.Hooks(func(entry zapcore.Entry) error {
  9.                 fmt.Println("[zap.Hooks]test Hooks")
  10.                 return nil
  11.         }))
  12.         defer logger.Sync()

  13.         logger.Info("test output")

  14.         logger.Warn("warn info")
  15. }
复制代码
自定义配置项

快速构建 logger 日志记录器最简单的方法就是用 zap 预定义了配置的方法:
  1. NewExample(), NewProduction()
复制代码
  1. NewDevelopment()
复制代码
,这 3 个方法通过单个函数调用就可以构建一个日志计记录器,也可以简单配置
Config 配置项源码
  1. // zap v1.24.0
  2. type Config struct {
  3.     // 动态改变日志级别,在运行时你可以安全改变日志级别
  4.         Level AtomicLevel `json:"level" yaml:"level"`
  5.     // 将日志记录器设置为开发模式,在 WarnLevel 及以上级别日志会包含堆栈跟踪信息
  6.         Development bool `json:"development" yaml:"development"`
  7.     // 在日志中停止调用函数所在文件名、行数
  8.         DisableCaller bool `json:"disableCaller" yaml:"disableCaller"`
  9.     // 完全禁止自动堆栈跟踪。默认情况下,在 development 中,warnlevel及以上日志级别会自动捕获堆栈跟踪信息
  10.     // 在 production 中,ErrorLevel 及以上也会自动捕获堆栈信息
  11.         DisableStacktrace bool `json:"disableStacktrace" yaml:"disableStacktrace"`
  12.     // 设置采样策略。没有 SamplingConfing 将禁止采样
  13.         Sampling *SamplingConfig `json:"sampling" yaml:"sampling"`
  14.     // 设置日志编码。可以设置为 console 和 json。也可以通过 RegisterEncoder 设置第三方编码格式
  15.         Encoding string `json:"encoding" yaml:"encoding"`
  16.     // 为encoder编码器设置选项。详细设置信息在 zapcore.zapcore.EncoderConfig
  17.         EncoderConfig zapcore.EncoderConfig `json:"encoderConfig" yaml:"encoderConfig"`
  18.     // 日志输出地址可以是一个 URLs 地址或文件路径,可以设置多个
  19.         OutputPaths []string `json:"outputPaths" yaml:"outputPaths"`
  20.     // 错误日志输出地址。默认输出标准错误信息
  21.         ErrorOutputPaths []string `json:"errorOutputPaths" yaml:"errorOutputPaths"`
  22.     // 可以添加自定义的字段信息到 root logger 中。也就是每条日志都会携带这些字段信息,公共字段
  23.         InitialFields map[string]interface{} `json:"initialFields" yaml:"initialFields"`
  24. }
复制代码
EncoderConfig 结构源码,它里面也有很多配置选项
  1. // zapcore@v1.24.0
  2. type EncoderConfig struct {
  3.     // 为log entry设置key。如果 key 为空,那么在日志中的这部分信息也会省略
  4.         MessageKey     string `json:"messageKey" yaml:"messageKey"`//日志信息的健名,默认为msg
  5.         LevelKey       string `json:"levelKey" yaml:"levelKey"`//日志级别的健名,默认为level
  6.         TimeKey        string `json:"timeKey" yaml:"timeKey"`//记录日志时间的健名,默认为time
  7.         NameKey        string `json:"nameKey" yaml:"nameKey"`
  8.         CallerKey      string `json:"callerKey" yaml:"callerKey"`
  9.         FunctionKey    string `json:"functionKey" yaml:"functionKey"`
  10.         StacktraceKey  string `json:"stacktraceKey" yaml:"stacktraceKey"`
  11.         SkipLineEnding bool   `json:"skipLineEnding" yaml:"skipLineEnding"`
  12.         LineEnding     string `json:"lineEnding" yaml:"lineEnding"`
  13.     // 日志编码的一些设置项
  14.         EncodeLevel    LevelEncoder    `json:"levelEncoder" yaml:"levelEncoder"`
  15.         EncodeTime     TimeEncoder     `json:"timeEncoder" yaml:"timeEncoder"`
  16.         EncodeDuration DurationEncoder `json:"durationEncoder" yaml:"durationEncoder"`
  17.         EncodeCaller   CallerEncoder   `json:"callerEncoder" yaml:"callerEncoder"`
  18.     // 与其它编码器不同, 这个编码器可选
  19.         EncodeName NameEncoder `json:"nameEncoder" yaml:"nameEncoder"`
  20.     // 配置 interface{} 类型编码器。如果没设置,将用 json.Encoder 进行编码
  21.         NewReflectedEncoder func(io.Writer) ReflectedEncoder `json:"-" yaml:"-"`
  22.     // 配置 console 中字段分隔符。默认使用 tab
  23.         ConsoleSeparator string `json:"consoleSeparator" yaml:"consoleSeparator"`
  24. }
  25. type Entry struct {
  26.         Level      Level
  27.         Time       time.Time
  28.         LoggerName string
  29.         Message    string
  30.         Caller     EntryCaller
  31.         Stack      string
  32. }zap 提供了 2 种日志记录器:`SugaredLogger` 和 `Logger`
复制代码
SugaredLogger日志

在需要性能但不是很重要的情况下,使用 SugaredLogger 较合适。它比其它结构化日志包快 4-10 倍,包括 结构化日志和 printf 风格的 API
使用: suger.[日志级别]x
w 支持键值对方式传入日志
f 支持%s 方式插值
  1. suger := logger.Sugar() // 开启日志语法糖
  2.    
  3. suger.Debug("我是Debug级别的日志")
  4. suger.Debugw("我是Debug级别的日志", "key1", "value1", "key2", "value2")
  5. suger.Debugf("我是Debug级别的日志%s", "value")

  6. suger.Warn("我是Warn级别的日志")
  7. suger.Warnw("我是Warn级别的日志", "key1", "value1", "key2", "value2")
  8. suger.Warnf("我是Warn级别的日志%s", "value")

  9. suger.Info("我是Info级别的日志")
  10. suger.Infow("我是Info级别的日志", "key1", "value1", "key2", "value2")
  11. suger.Infof("我是Info级别的日志 %s", "info")

  12. suger.Error("我是Error级别的日志")
  13. suger.Errorw("我是Error级别的日志", "key1", "value1", "key2", "value2")
  14. suger.Errorf("我是Error级别的日志 %s", "value")

  15. suger.Panic("我是Panic级别的日志")
  16. suger.Panicw("我是Panic级别的日志", "key1", "value1", "key2", "value2")
  17. suger.Panicf("我是Panic级别的日志 %s", "value")
复制代码
logger日志

当性能和类型安全很重要时,请使用 Logger。它比 SugaredLogger 更快,分配的资源更少,但它只支持结构化日志和强类型字段
第一个参数打印日志名,后边支持传入可变参, …zapcore.Field类型
zap.String(“key”, “value”) 表示打印key为字符串 value为字符串的 map
  1. logger.Debug("我是Debug级别的日志", zap.String("key", "value"), zap.Int("num", 10))
  2. logger.Warn("我是Warn级别的日志", zap.String("key", "value"), zap.Int("num", 10))
  3. logger.Info("我是Info级别的日志", zap.String("key", "value"), zap.Int("num", 10))
  4. logger.Error("我是Error级别的日志", zap.String("key", "value"), zap.Int("num", 10))
  5. logger.Panic("我是Panic级别的日志", zap.String("key", "value"), zap.Int("num", 10))
复制代码
输出日志到文件
  1. cfg := zap.NewProductionConfig()
  2. cfg.OutputPaths = []string{
  3.    "./OUTPUT.log", "stderr", "stdout",
  4. }
  5. logger, _ = cfg.Build()

  6. logger.Debug("打印日志到文件")
复制代码
日志切割归档

lumberjack 这个库是按照日志大小切割日志文件。
  1. go get -u github.com/natefinch/lumberjack@v2
复制代码
  1. log.SetOutput(&lumberjack.Logger{
  2.     Filename:   "/var/log/myapp/foo.log", // 文件位置
  3.     MaxSize:    500,  // megabytes,M 为单位,达到这个设置数后就进行日志切割
  4.     MaxBackups: 3,    // 保留旧文件最大份数
  5.     MaxAge:     28,   //days , 旧文件最大保存天数
  6.     Compress:   true, // disabled by default,是否压缩日志归档,默认不压缩
  7. })
复制代码
参照它的文档和结合上面自定义配置
  1. package main

  2. import (
  3.         "fmt"

  4.         "go.uber.org/zap"
  5.         "go.uber.org/zap/zapcore"
  6.         "gopkg.in/natefinch/lumberjack.v2"
  7. )

  8. func main() {
  9.         lumberjacklogger := &lumberjack.Logger{
  10.                 Filename:   "./log-rotate-test.json",
  11.                 MaxSize:    1, // megabytes
  12.                 MaxBackups: 3,
  13.                 MaxAge:     28,   //days
  14.                 Compress:   true, // disabled by default
  15.         }
  16.         defer lumberjacklogger.Close()

  17.         config := zap.NewProductionEncoderConfig()

  18.         config.EncodeTime = zapcore.ISO8601TimeEncoder // 设置时间格式
  19.         fileEncoder := zapcore.NewJSONEncoder(config)

  20.         core := zapcore.NewCore(
  21.                 fileEncoder,                       //编码设置
  22.                 zapcore.AddSync(lumberjacklogger), //输出到文件
  23.                 zap.InfoLevel,                     //日志等级
  24.         )

  25.         logger := zap.New(core)
  26.         defer logger.Sync()

  27.     // 测试分割日志
  28.         for i := 0; i < 8000; i++ {
  29.                 logger.With(
  30.                         zap.String("url", fmt.Sprintf("www.test%d.com", i)),
  31.                         zap.String("name", "jimmmyr"),
  32.                         zap.Int("age", 23),
  33.                         zap.String("agradege", "no111-000222"),
  34.                 ).Info("test info ")
  35.         }

  36. }
复制代码
全局logger

zap提供了 2 种全局 Logger,一个是 zap.Logger,调用 zap.L() 获取;
另外一个是 zap.SugaredLogger ,调用 zap.S() 获取
直接调用 zap.L() 或 zap.S() 记录日志的话,它是不会记录任何日志信息。需要调用 ReplaceGlobals() 函数将它设置为全局 Logger。
ReplaceGlobals 替换全局 Logger 和 SugaredLogger,并返回一个函数来恢复原始值
简单使用例子
  1. package main

  2. import (
  3.         "go.uber.org/zap"
  4. )

  5. func main() {
  6.         // 直接调用是不会记录日志信息的,所以下面日志信息不会输出
  7.         zap.L().Info("no log info")
  8.         zap.S().Info("no log info [sugared]")

  9.         logger := zap.NewExample()
  10.         defer logger.Sync()

  11.         zap.ReplaceGlobals(logger) // 全局logger,zap.L() 和 zap.S() 需要调用 ReplaceGlobals 函数才会记录日志信息
  12.         zap.L().Info("log info")
  13.         zap.S().Info("log info [sugared]")
  14. }
复制代码
到此这篇关于golang整合日志zap的实现示例的文章就介绍到这了,更多相关golang整合日志zap内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
17
积分
14
注册时间
2022-12-27
最后登录
2022-12-27

发表于 2025-4-7 22:32:48 | 显示全部楼层
感谢楼主,顶。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表