golangzap日志库的具体使用

Written by

in

文章目录
  • 首先需要明确什么是日志 在程序运行的过程中,我们不可能总是能在控制台看到全部信息 因为 程序是黑盒运行的 一旦程序启动,内部状态、变量值、执行路径都是“看不到的”,除非你在特定位置打日志或调试 生产环境不能用调试器(debug) 在开发环境你可以断点调试,但上线后的服务不能暂停调试,只能通过日志了解程序的行为 问题多是间歇性或难复现的 比如用户在某个特定时间点请求超时,过一会又正常,这类问题无法稳定复现,只有日志能还原问题。 多人协作/远程运维需要可追溯 如果有运维、测试、后端、前端一起协作,只靠“肉眼”观察或靠猜是远远不够的 这时我们要想知道程序运行过程中更多的信息,就需要用到日志,给出日志的概念 Go语言中的日志(logging),是指在程序运行过程中记录信息的机制,通常用于追踪程序执行流程、调试问题、记录错误、监控运行状态等 说白了,日志就是记录把程序运行时关键的信息记录下来(作用是 调试程序、监控服务、追溯时间、异常报警) 举个例子,下面是一条比较完整的日志信息 2025/07/30 10:25:00 [ERROR] [user_handler.go:45] 登录失败:用户名不存在,userID=1234, IP=192.168.1.10 这条日志告诉我们: 时间:2025/07/30 10:25:00 级别:ERROR(表示错误) 文件位置:user_handler.go 的第 45 行 内容:用户登录失败 附加信息:userID=1234,IP=192.168.1.10 所以总的来说,日志是你程序“说话”的方式,它尽可能多地还原程序在某一刻的状态、操作内容、上下文,帮助开发者和运维人员快速定位问题 已经知道了日志是什么,接下来就该了解如何使用日志了
  • zap提供了两种日志类型:Sugared Logger 和 Logger 在性能很好但不是很关键的上下文中,使用 SugaredLogger 。它比其他结构化日志记录包快4-10倍,并且支持结构化和printf风格的日志记录。 在每一微秒和每一次内存分配都很重要的上下文中,使用 Logger 。它甚至比 SugaredLogger 更快,内存分配次数也更少,但它只支持强类型的结构化日志记录。 这样说还是太吃理解了,能不能说人话! 举个例子,想象你在写日志,其实就是“说一句话”告诉别人发生了什么: Logger 就像一个非常讲究的人,说话必须格式规范、用词准确。 SugaredLogger 就像你平时聊天,语法宽松,说什么都行,只要别人听懂。 zap.Logger(原生 logger)🧱 特点:强类型、高性能、格式固定 你必须这么说: logger.Info(“用户登录”, zap.String(“用户名”, “alice”), zap.Int(“ID”, 1001)) 就像你必须填一张表格,每一栏都得按格式来写,不允许乱来 优点:格式清晰、适合机器分析、性能高缺点:写起来略麻烦,不像日常说话 *zap.SugaredLogger(带糖 logger)🍬 特点:语法更轻松,像聊天一样记录日志 你可以这样说: sugar.Infof(“用户 %s 登录成功,ID=%d”, “alice”, 1001) sugar.Infow(“用户登录成功”, “用户名”, “alice”, “ID”, 1001) 就像你发微信说话,不拘小节,怎么说都行。 优点:写起来简单、省事缺点:性能略低一点(但对大多数业务没影响) 开发阶段我们常用 SugaredLogger,高性能系统或日志采集模块则更推荐用 Logger 如果你现在用的是 zap.NewProduction() 创建的 logger,只要加一行就可以用带糖版本: sugar := logger.Sugar() 反过来,如果你用了 SugaredLogger,也可以通过 sugar.Desugar() 还原成 Logger
  • 前面提到了日志包含的几部分内容,这些内容是需要配置的zap给我们提供了两个预设工厂函数zap.NewProduction() 和 zap.NewDevelopment() ,可以快速创建一个配置好的logger,当然了,如果不想用这两个函数,也可以自己配置一个logger,这里我们稍后再说 默认情况下,zap.NewProduction() 和 zap.NewDevelopment() 创建的 logger 都会把日志打印到终端(标准输出,也就是 os.Stdout)。具体表现如下: zap.NewProduction()输出格式是 JSON,适合生产环境日志采集和分析默认日志级别是 Info 及以上日志内容会打印到终端(控制台) zap.NewDevelopment()输出格式是易读的控制台文本格式,适合开发调试默认日志级别是 Debug,能打印更多详细信息日志内容也打印到终端,方便开发时即时查看 它们的作用总结如下: 函数名 适用场景 日志格式 默认日志级别 额外特性 zap.NewProduction() 生产环境 JSON 格式 Info 自动添加 caller 信息、stacktrace zap.NewDevelopment() 开发调试 人类可读文本 Debug 更详细、更宽松、更适合调试
  • 想自定义一个logger,需要用到函数zap.New() zap.New() 是 zap 库中最底层、最核心的函数之一,用于创建一个 Logger 实例。你可以把它理解为 “构建一个完整日志器的工厂函数”。它的作用是把你配置好的日志核心(Core)和可选的日志选项(Options)组合在一起,生成一个真正能用的 Logger 函数签名 func New(core zapcore.Core, options …Option) *Logger 参数解释: 参数 作用 core 必须;日志的核心组件,定义“日志要写到哪、写什么、写多少级别”。必须使用 zapcore.NewCore() 来创建。 options… 可选;附加功能,用于增强 logger,比如是否记录调用行号、是否打印堆栈、默认字段等。
  • 当服务产生日志很多,且希望控制文件大小/数量/时长时,就该用 Lumberjack 来切割归档日志 Lumberjack 是 Go 中一个轻量级的日志滚动库,常和 zap 搭配使用,用于日志切割与归档。这在生产环境中非常实用,能避免日志无限增长导致磁盘爆满 什么是 Lumberjack?Lumberjack 是一个实现了 io.Writer 接口的日志文件滚动库用一句话说:它可以根据文件大小、备份数量、保留天数等规则自动切割日志文件。 常用配置项使用 *lumberjack.Logger 配置日志行为: &lumberjack.Logger{ Filename: “./logs/server.log”, // 日志文件路径 MaxSize: 100, // 每个日志文件最大尺寸(MB) MaxBackups: 5, // 最多保留的旧日志文件数量 MaxAge: 30, // 最长保留时间(天) Compress: true, // 是否压缩归档旧日志 } 和 zap 结合使用因为 zapcore.AddSync(io.Writer) 接收的是 io.Writer,而 lumberjack.Logger 实现了这个接口,所以可以无缝对接。 完整示例: import ( “go.uber.org/zap” “go.uber.org/zap/zapcore” “gopkg.in/natefinch/lumberjack.v2” ) func main() { // 1. 创建 lumberjack logger writeSyncer := zapcore.AddSync(&lumberjack.Logger{ Filename: “./logs/server.log”, MaxSize: 10, // 10 MB MaxBackups: 3, // 最多3个备份 MaxAge: 7, // 保留7天 Compress: true, }) // 2. 设置编码器 encoder := zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()) // 3. 创建 core core := zapcore.NewCore(encoder, writeSyncer, zapcore.InfoLevel) // 4. 创建 logger logger := zap.New(core) defer logger.Sync() // 5. 打印日志 logger.Info(“这是一个日志条目”, zap.String(“user”, “tinG”)) } Lumberjack 的优势 优点 说明 自动切割 避免单个日志文件过大 自动清理 根据时间或数量清理旧日志 自动压缩 节省磁盘空间 与 zap 无缝配合 不需要额外适配代码 补充:zap 自带不支持切割 zap 默认是将日志打印到文件或终端,但不自带日志切割能力 到此这篇关于golang zap日志库的具体使用的文章就介绍到这了,更多相关golang zap日志库内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客! 您可能感兴趣的文章: golang 日志库ZAP[uber-go zap]示例详解 golang整合日志zap的实现示例 Golang日志操作库zap的使用详解 golang框架gin的日志处理和zap lumberjack日志使用方式 GoLang基于zap日志库的封装过程详解 Golang定制化zap日志库使用过程分析 golang xorm 自定义日志记录器之使用zap实现日志输出、切割日志(最新) golang默认Logger日志库在项目中使用Zap日志库 golang有用的库及工具 之 zap.Logger包的使用指南 深入浅析golang zap 日志库使用(含文件切割、分级别存储和全局使用等)
  • 目录
    • 一、日志是什么
    • 二、 Sugared Logger vs Logger
    • 三、 zap的基本配置
      • zap配置包含哪几方面
    • 四、 自定义logger
      • core
      • options
    • 五、 使用Lumberjack进行日志切割归档

      首先需要明确什么是日志

      在程序运行的过程中,我们不可能总是能在控制台看到全部信息

      因为

      • 程序是黑盒运行的

        一旦程序启动,内部状态、变量值、执行路径都是“看不到的”,除非你在特定位置打日志或调试

      • 生产环境不能用调试器(debug)

        在开发环境你可以断点调试,但上线后的服务不能暂停调试,只能通过日志了解程序的行为

      • 问题多是间歇性或难复现的

        比如用户在某个特定时间点请求超时,过一会又正常,这类问题无法稳定复现,只有日志能还原问题。

      • 多人协作/远程运维需要可追溯

        如果有运维、测试、后端、前端一起协作,只靠“肉眼”观察或靠猜是远远不够的

      这时我们要想知道程序运行过程中更多的信息,就需要用到日志,给出日志的概念

      Go语言中的日志(logging),是指在程序运行过程中记录信息的机制,通常用于追踪程序执行流程、调试问题、记录错误、监控运行状态等

      说白了,日志就是记录把程序运行时关键的信息记录下来(作用是 调试程序、监控服务、追溯时间、异常报警

      举个例子,下面是一条比较完整的日志信息

      2025/07/30 10:25:00 [ERROR] [user_handler.go:45] 登录失败:用户名不存在,
      userID=1234, IP=192.168.1.10

      这条日志告诉我们:

      • 时间:2025/07/30 10:25:00
      • 级别:ERROR(表示错误)
      • 文件位置:user_handler.go 的第 45 行
      • 内容:用户登录失败
      • 附加信息:userID=1234,IP=192.168.1.10

      所以总的来说,日志是你程序“说话”的方式,它尽可能多地还原程序在某一刻的状态、操作内容、上下文,帮助开发者和运维人员快速定位问题

      已经知道了日志是什么,接下来就该了解如何使用日志了

      zap提供了两种日志类型:Sugared Logger 和 Logger

      • 在性能很好但不是很关键的上下文中,使用 SugaredLogger 。它比其他结构化日志记录包快4-10倍,并且支持结构化和printf风格的日志记录。
      • 在每一微秒和每一次内存分配都很重要的上下文中,使用 Logger 。它甚至比 SugaredLogger 更快,内存分配次数也更少,但它只支持强类型的结构化日志记录。

      这样说还是太吃理解了,能不能说人话!

      举个例子,想象你在写日志,其实就是“说一句话”告诉别人发生了什么:

      Logger 就像一个非常讲究的人,说话必须格式规范、用词准确。

      SugaredLogger 就像你平时聊天,语法宽松,说什么都行,只要别人听懂。

      1. zap.Logger(原生 logger)
        🧱 特点:强类型、高性能、格式固定

        你必须这么说:

        logger.Info("用户登录", zap.String("用户名", "alice"), zap.Int("ID", 1001))
        

        就像你必须填一张表格,每一栏都得按格式来写,不允许乱来

        优点:格式清晰、适合机器分析、性能高
        缺点:写起来略麻烦,不像日常说话

      2. *zap.SugaredLogger(带糖 logger)
        🍬 特点:语法更轻松,像聊天一样记录日志

        你可以这样说:

        sugar.Infof("用户 %s 登录成功,ID=%d", "alice", 1001)
        sugar.Infow("用户登录成功", "用户名", "alice", "ID", 1001)
        

        就像你发微信说话,不拘小节,怎么说都行。

        优点:写起来简单、省事
        缺点:性能略低一点(但对大多数业务没影响)

      开发阶段我们常用 SugaredLogger,
      高性能系统或日志采集模块则更推荐用 Logger

      如果你现在用的是 zap.NewProduction() 创建的 logger,只要加一行就可以用带糖版本:

      sugar := logger.Sugar()
      

      反过来,如果你用了 SugaredLogger,也可以通过 sugar.Desugar() 还原成 Logger

      前面提到了日志包含的几部分内容,这些内容是需要配置的
      zap给我们提供了两个预设工厂函数zap.NewProduction()zap.NewDevelopment() ,可以快速创建一个配置好的logger,当然了,如果不想用这两个函数,也可以自己配置一个logger,这里我们稍后再说

      默认情况下,zap.NewProduction() 和 zap.NewDevelopment() 创建的 logger 都会把日志打印到终端(标准输出,也就是 os.Stdout)。具体表现如下:

      • zap.NewProduction()
        输出格式是 JSON,适合生产环境日志采集和分析
        默认日志级别是 Info 及以上
        日志内容会打印到终端(控制台)

      • zap.NewDevelopment()
        输出格式是易读的控制台文本格式,适合开发调试
        默认日志级别是 Debug,能打印更多详细信息
        日志内容也打印到终端,方便开发时即时查看

      它们的作用总结如下:

      函数名 适用场景 日志格式 默认日志级别 额外特性
      zap.NewProduction() 生产环境 JSON 格式 Info 自动添加 caller 信息、stacktrace
      zap.NewDevelopment() 开发调试 人类可读文本 Debug 更详细、更宽松、更适合调试

      zap的基本配置,可以理解为一个日志要包含哪些方面的内容:

      1. 输出位置(Output Paths)

        决定日志打印到哪:

        • 终端(console)
        • 文件(如 logs/app.log)
        • 同时打印多个位置
      2. 日志级别(Level)
        你可以控制哪些日志会被打印:

      • debug:调试用,最详细
      • info:普通日志(业务日志)
      • warn:警告,不影响业务但需要注意
      • error:错误日志(业务或系统异常)
      • fatal:致命错误,程序会崩溃

      你可以通过配置或代码动态设置级别,过滤不需要的日志。

      1. 编码方式(Encoding)
        决定日志内容的格式:

        • json:结构化,适合线上,便于日志系统解析
        • console:可读性强,适合本地开发调试
      2. 字段格式(EncoderConfig)
        控制时间戳、日志级别、调用位置的格式,示例:

        zapcore.EncoderConfig{
            TimeKey:        "time",
            LevelKey:       "level",
            NameKey:        "logger",
            CallerKey:      "caller",
            MessageKey:     "msg",
            StacktraceKey:  "stacktrace",
            EncodeLevel:    zapcore.CapitalColorLevelEncoder,
            EncodeTime:     zapcore.ISO8601TimeEncoder,
            EncodeCaller:   zapcore.ShortCallerEncoder,
        }
        

        这个是非常重要的配置,决定你打印出来的日志长什么样。

      3. 是否打印调用位置(Caller)
        打印日志时是否带上调用该日志的文件和行号:

        logger = logger.WithOptions(zap.AddCaller())
        
      4. 开发/生产环境区别

        • zap.NewDevelopment():
          默认日志级别是 debug
          编码是 console
          更适合本地调试

        • zap.NewProduction():
          默认日志级别是 info
          编码是 json
          默认输出文件和标准输出

      想自定义一个logger,需要用到函数zap.New()

      zap.New() 是 zap 库中最底层、最核心的函数之一,用于创建一个 Logger 实例。你可以把它理解为 “构建一个完整日志器的工厂函数”。它的作用是把你配置好的日志核心(Core)和可选的日志选项(Options)组合在一起,生成一个真正能用的 Logger

      函数签名

      func New(core zapcore.Core, options ...Option) *Logger
      

      参数解释:

      参数 作用
      core 必须;日志的核心组件,定义“日志要写到哪、写什么、写多少级别”。必须使用 zapcore.NewCore() 来创建。
      options… 可选;附加功能,用于增强 logger,比如是否记录调用行号、是否打印堆栈、默认字段等。

      我们先看第一个参数core

      core的类型是 zapcore.Core, 我们找到Core的源码,可以知道core是一个接口类型

      zapCore.Core:

      type Core interface {
      	LevelEnabler
      	With([]Field) Core
      	Check(Entry, *CheckedEntry) *CheckedEntry
      	Write(Entry, []Field) error
      	Sync() error
      }
      

      core必须使用zapcore.NewCore() 来创建

      func NewCore(enc Encoder, ws WriteSyncer, enab LevelEnabler) Core {
      	return &ioCore{
      		LevelEnabler: enab,
      		enc:          enc,
      		out:          ws,
      	}
      }
      

      可以看到返回一个 *ioCore 类型的结构体
      那么再看一下 ioCore 的源码

      type ioCore struct {
      	LevelEnabler
      	enc Encoder
      	out WriteSyncer
      }
      

      可以看到这个结构体由三部分组成,

      encoder:日志内容格式化方式
      决定了日志内容以什么格式输出
      常用的 encoder 有:

      • zapcore.NewConsoleEncoder(cfg):适合开发环境,输出人类能看懂的日志(例如 key=value 的形式)
      • zapcore.NewJSONEncoder(cfg):适合生产环境,输出 JSON 格式的结构化日志,方便 ELK 等系统采集

      writeSyncer:写日志的地方
      告诉 zap:日志要写到哪去,可以是:

      • os.Stdout:控制台
      • 文件:通过 lumberjack 实现日志切割
      • 组合:zapcore.NewMultiWriteSyncer() 支持同时写多个地方

      logLevel:最低日志级别
      只有大于等于这个级别的日志才会被记录,比如:

      go语言中关于日志级别的定义:

      const (
      DebugLevel Level = iota - 1
      InfoLevel
      WarnLevel
      ErrorLevel
      DPanicLevel
      PanicLevel
      FatalLevel
      
      _minLevel = DebugLevel
      _maxLevel = FatalLevel
      
      InvalidLevel = _maxLevel + 1
      

      后面的参数是可选的,它们是一些 功能性增强选项,比如:

      可选参数 含义
      zap.AddCaller() 日志中加入调用的源码文件名和行号
      zap.AddCallerSkip(n) 调整调用栈深度(比如封装日志函数时常用)
      zap.AddStacktrace(lv) 在某个级别及以上打印调用堆栈
      zap.Fields(…) 给 logger 添加默认的字段信息(结构化日志)
      zap.Development() 启用开发模式(比如日志校验更严格)

      当服务产生日志很多,且希望控制文件大小/数量/时长时,就该用 Lumberjack 来切割归档日志

      Lumberjack 是 Go 中一个轻量级的日志滚动库,常和 zap 搭配使用,用于日志切割与归档。这在生产环境中非常实用,能避免日志无限增长导致磁盘爆满

      什么是 Lumberjack?
      Lumberjack 是一个实现了 io.Writer 接口的日志文件滚动库
      用一句话说:它可以根据文件大小、备份数量、保留天数等规则自动切割日志文件。

      常用配置项
      使用 *lumberjack.Logger 配置日志行为:

      &lumberjack.Logger{
          Filename:   "./logs/server.log", // 日志文件路径
          MaxSize:    100,                 // 每个日志文件最大尺寸(MB)
          MaxBackups: 5,                   // 最多保留的旧日志文件数量
          MaxAge:     30,                  // 最长保留时间(天)
          Compress:   true,                // 是否压缩归档旧日志
      }
      

      和 zap 结合使用
      因为 zapcore.AddSync(io.Writer) 接收的是 io.Writer,而 lumberjack.Logger 实现了这个接口,所以可以无缝对接。

      完整示例:

      import (
          "go.uber.org/zap"
          "go.uber.org/zap/zapcore"
          "gopkg.in/natefinch/lumberjack.v2"
      )
      
      func main() {
          // 1. 创建 lumberjack logger
          writeSyncer := zapcore.AddSync(&lumberjack.Logger{
              Filename:   "./logs/server.log",
              MaxSize:    10,  // 10 MB
              MaxBackups: 3,   // 最多3个备份
              MaxAge:     7,   // 保留7天
              Compress:   true,
          })
      
          // 2. 设置编码器
          encoder := zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
      
          // 3. 创建 core
          core := zapcore.NewCore(encoder, writeSyncer, zapcore.InfoLevel)
      
          // 4. 创建 logger
          logger := zap.New(core)
          defer logger.Sync()
      
          // 5. 打印日志
          logger.Info("这是一个日志条目", zap.String("user", "tinG"))
      }
      

      Lumberjack 的优势

      优点 说明
      自动切割 避免单个日志文件过大
      自动清理 根据时间或数量清理旧日志
      自动压缩 节省磁盘空间
      与 zap 无缝配合 不需要额外适配代码

      补充:zap 自带不支持切割 zap 默认是将日志打印到文件或终端,但不自带日志切割能力

      到此这篇关于golang zap日志库的具体使用的文章就介绍到这了,更多相关golang zap日志库内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!

      您可能感兴趣的文章:

      • golang 日志库ZAP[uber-go zap]示例详解
      • golang整合日志zap的实现示例
      • Golang日志操作库zap的使用详解
      • golang框架gin的日志处理和zap lumberjack日志使用方式
      • GoLang基于zap日志库的封装过程详解
      • Golang定制化zap日志库使用过程分析
      • golang xorm 自定义日志记录器之使用zap实现日志输出、切割日志(最新)
      • golang默认Logger日志库在项目中使用Zap日志库
      • golang有用的库及工具 之 zap.Logger包的使用指南
      • 深入浅析golang zap 日志库使用(含文件切割、分级别存储和全局使用等)

      站内搜索