golang zap日志庫的具體使用
一、日志是什么
首先需要明確什么是日志
在程序運行的過程中,我們不可能總是能在控制臺看到全部信息
因為
程序是黑盒運行的
一旦程序啟動,內部狀態(tài)、變量值、執(zhí)行路徑都是“看不到的”,除非你在特定位置打日志或調試
生產環(huán)境不能用調試器(debug)
在開發(fā)環(huán)境你可以斷點調試,但上線后的服務不能暫停調試,只能通過日志了解程序的行為
問題多是間歇性或難復現的
比如用戶在某個特定時間點請求超時,過一會又正常,這類問題無法穩(wěn)定復現,只有日志能還原問題。
多人協(xié)作/遠程運維需要可追溯
如果有運維、測試、后端、前端一起協(xié)作,只靠“肉眼”觀察或靠猜是遠遠不夠的
這時我們要想知道程序運行過程中更多的信息,就需要用到日志,給出日志的概念
Go語言中的日志(logging),是指在程序運行過程中記錄信息的機制,通常用于追蹤程序執(zhí)行流程、調試問題、記錄錯誤、監(jiān)控運行狀態(tài)等
說白了,日志就是記錄把程序運行時關鍵的信息記錄下來(作用是 調試程序、監(jiān)控服務、追溯時間、異常報警)
舉個例子,下面是一條比較完整的日志信息
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
所以總的來說,日志是你程序“說話”的方式,它盡可能多地還原程序在某一刻的狀態(tài)、操作內容、上下文,幫助開發(fā)者和運維人員快速定位問題
已經知道了日志是什么,接下來就該了解如何使用日志了
二、 Sugared Logger vs Logger
zap提供了兩種日志類型:Sugared Logger 和 Logger
- 在性能很好但不是很關鍵的上下文中,使用 SugaredLogger 。它比其他結構化日志記錄包快4-10倍,并且支持結構化和printf風格的日志記錄。
- 在每一微秒和每一次內存分配都很重要的上下文中,使用 Logger 。它甚至比 SugaredLogger 更快,內存分配次數也更少,但它只支持強類型的結構化日志記錄。
這樣說還是太吃理解了,能不能說人話!
舉個例子,想象你在寫日志,其實就是“說一句話”告訴別人發(fā)生了什么:
Logger 就像一個非常講究的人,說話必須格式規(guī)范、用詞準確。
SugaredLogger 就像你平時聊天,語法寬松,說什么都行,只要別人聽懂。
zap.Logger(原生 logger)
?? 特點:強類型、高性能、格式固定你必須這么說:
logger.Info("用戶登錄", zap.String("用戶名", "alice"), zap.Int("ID", 1001))就像你必須填一張表格,每一欄都得按格式來寫,不允許亂來
優(yōu)點:格式清晰、適合機器分析、性能高
缺點:寫起來略麻煩,不像日常說話*zap.SugaredLogger(帶糖 logger)
?? 特點:語法更輕松,像聊天一樣記錄日志你可以這樣說:
sugar.Infof("用戶 %s 登錄成功,ID=%d", "alice", 1001) sugar.Infow("用戶登錄成功", "用戶名", "alice", "ID", 1001)就像你發(fā)微信說話,不拘小節(jié),怎么說都行。
優(yōu)點:寫起來簡單、省事
缺點:性能略低一點(但對大多數業(yè)務沒影響)
開發(fā)階段我們常用 SugaredLogger,
高性能系統(tǒng)或日志采集模塊則更推薦用 Logger
如果你現在用的是 zap.NewProduction() 創(chuàng)建的 logger,只要加一行就可以用帶糖版本:
sugar := logger.Sugar()
反過來,如果你用了 SugaredLogger,也可以通過 sugar.Desugar() 還原成 Logger
三、 zap的基本配置
前面提到了日志包含的幾部分內容,這些內容是需要配置的
zap給我們提供了兩個預設工廠函數zap.NewProduction() 和 zap.NewDevelopment() ,可以快速創(chuàng)建一個配置好的logger,當然了,如果不想用這兩個函數,也可以自己配置一個logger,這里我們稍后再說
默認情況下,zap.NewProduction() 和 zap.NewDevelopment() 創(chuàng)建的 logger 都會把日志打印到終端(標準輸出,也就是 os.Stdout)。具體表現如下:
zap.NewProduction()
輸出格式是 JSON,適合生產環(huán)境日志采集和分析
默認日志級別是 Info 及以上
日志內容會打印到終端(控制臺)zap.NewDevelopment()
輸出格式是易讀的控制臺文本格式,適合開發(fā)調試
默認日志級別是 Debug,能打印更多詳細信息
日志內容也打印到終端,方便開發(fā)時即時查看
它們的作用總結如下:
| 函數名 | 適用場景 | 日志格式 | 默認日志級別 | 額外特性 |
|---|---|---|---|---|
| zap.NewProduction() | 生產環(huán)境 | JSON 格式 | Info | 自動添加 caller 信息、stacktrace |
| zap.NewDevelopment() | 開發(fā)調試 | 人類可讀文本 | Debug | 更詳細、更寬松、更適合調試 |
zap配置包含哪幾方面
zap的基本配置,可以理解為一個日志要包含哪些方面的內容:
輸出位置(Output Paths)
決定日志打印到哪:
- 終端(console)
- 文件(如 logs/app.log)
- 同時打印多個位置
日志級別(Level)
你可以控制哪些日志會被打印:
- debug:調試用,最詳細
- info:普通日志(業(yè)務日志)
- warn:警告,不影響業(yè)務但需要注意
- error:錯誤日志(業(yè)務或系統(tǒng)異常)
- fatal:致命錯誤,程序會崩潰
你可以通過配置或代碼動態(tài)設置級別,過濾不需要的日志。
編碼方式(Encoding)
決定日志內容的格式:- json:結構化,適合線上,便于日志系統(tǒng)解析
- console:可讀性強,適合本地開發(fā)調試
字段格式(EncoderConfig)
控制時間戳、日志級別、調用位置的格式,示例:zapcore.EncoderConfig{ TimeKey: "time", LevelKey: "level", NameKey: "logger", CallerKey: "caller", MessageKey: "msg", StacktraceKey: "stacktrace", EncodeLevel: zapcore.CapitalColorLevelEncoder, EncodeTime: zapcore.ISO8601TimeEncoder, EncodeCaller: zapcore.ShortCallerEncoder, }這個是非常重要的配置,決定你打印出來的日志長什么樣。
是否打印調用位置(Caller)
打印日志時是否帶上調用該日志的文件和行號:logger = logger.WithOptions(zap.AddCaller())
開發(fā)/生產環(huán)境區(qū)別
zap.NewDevelopment():
默認日志級別是 debug
編碼是 console
更適合本地調試zap.NewProduction():
默認日志級別是 info
編碼是 json
默認輸出文件和標準輸出
四、 自定義logger
想自定義一個logger,需要用到函數zap.New()
zap.New() 是 zap 庫中最底層、最核心的函數之一,用于創(chuàng)建一個 Logger 實例。你可以把它理解為 “構建一個完整日志器的工廠函數”。它的作用是把你配置好的日志核心(Core)和可選的日志選項(Options)組合在一起,生成一個真正能用的 Logger
函數簽名
func New(core zapcore.Core, options ...Option) *Logger
參數解釋:
| 參數 | 作用 |
|---|---|
| core | 必須;日志的核心組件,定義“日志要寫到哪、寫什么、寫多少級別”。必須使用 zapcore.NewCore() 來創(chuàng)建。 |
| options… | 可選;附加功能,用于增強 logger,比如是否記錄調用行號、是否打印堆棧、默認字段等。 |
core
我們先看第一個參數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() 來創(chuàng)建
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):適合開發(fā)環(huán)境,輸出人類能看懂的日志(例如 key=value 的形式)
- zapcore.NewJSONEncoder(cfg):適合生產環(huán)境,輸出 JSON 格式的結構化日志,方便 ELK 等系統(tǒng)采集
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
options
后面的參數是可選的,它們是一些 功能性增強選項,比如:
| 可選參數 | 含義 |
|---|---|
| zap.AddCaller() | 日志中加入調用的源碼文件名和行號 |
| zap.AddCallerSkip(n) | 調整調用棧深度(比如封裝日志函數時常用) |
| zap.AddStacktrace(lv) | 在某個級別及以上打印調用堆棧 |
| zap.Fields(…) | 給 logger 添加默認的字段信息(結構化日志) |
| zap.Development() | 啟用開發(fā)模式(比如日志校驗更嚴格) |
五、 使用Lumberjack進行日志切割歸檔
當服務產生日志很多,且希望控制文件大小/數量/時長時,就該用 Lumberjack 來切割歸檔日志
Lumberjack 是 Go 中一個輕量級的日志滾動庫,常和 zap 搭配使用,用于日志切割與歸檔。這在生產環(huán)境中非常實用,能避免日志無限增長導致磁盤爆滿
什么是 Lumberjack?
Lumberjack 是一個實現了 io.Writer 接口的日志文件滾動庫
用一句話說:它可以根據文件大小、備份數量、保留天數等規(guī)則自動切割日志文件。
常用配置項
使用 *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. 創(chuàng)建 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. 創(chuàng)建 core
core := zapcore.NewCore(encoder, writeSyncer, zapcore.InfoLevel)
// 4. 創(chuàng)建 logger
logger := zap.New(core)
defer logger.Sync()
// 5. 打印日志
logger.Info("這是一個日志條目", zap.String("user", "tinG"))
}
Lumberjack 的優(yōu)勢
| 優(yōu)點 | 說明 |
|---|---|
| 自動切割 | 避免單個日志文件過大 |
| 自動清理 | 根據時間或數量清理舊日志 |
| 自動壓縮 | 節(jié)省磁盤空間 |
| 與 zap 無縫配合 | 不需要額外適配代碼 |
補充:zap 自帶不支持切割 zap 默認是將日志打印到文件或終端,但不自帶日志切割能力
到此這篇關于golang zap日志庫的具體使用的文章就介紹到這了,更多相關golang zap日志庫內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
GoLang RabbitMQ TTL與死信隊列以及延遲隊列詳細講解
這篇文章主要介紹了GoLang RabbitMQ TTL與死信隊列以及延遲隊列,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧2022-12-12

