最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

golang整合日志zap的實現(xiàn)示例

 更新時間:2024年10月22日 10:17:41   作者:code:404-not-found  
Go語言中的zap庫提供了強大的日志管理功能,支持日志記錄到文件、日志切割、多日志級別、結(jié)構(gòu)化日志輸出等,它通過三種方法zap.NewProduction()、zap.NewDevelopment()和zap.NewExample(),快速構(gòu)建適用于不同環(huán)境的logger,感興趣的可以了解一下

在許多Go語言項目中,我們需要一個好的日志記錄器能夠提供下面這些功能:

  • 能夠?qū)⑹录涗浀轿募?,而不是?yīng)用程序控制臺;
  • 日志切割-能夠根據(jù)文件大小、時間或間隔等來切割日志文件;
  • 支持不同的日志級別。例如INFO,DEBUG,ERROR等;
  • 能夠打印基本信息,如調(diào)用文件/函數(shù)名和行號,日志時間等;
  • 日志分級:有 Debug,Info,Warn,Error,DPanic,Panic,F(xiàn)atal 等
  • 日志記錄結(jié)構(gòu)化:日志內(nèi)容記錄是結(jié)構(gòu)化的,比如 json 格式輸出
  • 自定義格式:用戶可以自定義輸出的日志格式
  • 自定義公共字段:用戶可以自定義公共字段,大家輸出的日志內(nèi)容就共同擁有了這些字段
  • 調(diào)試:可以打印文件名、函數(shù)名、行號、日志時間等,便于調(diào)試程序
  • 自定義調(diào)用棧級別:可以根據(jù)日志級別輸出它的調(diào)用棧信息
  • Namespace:日志命名空間。定義命名空間后,所有日志內(nèi)容就在這個命名空間下。命名空間相當于一個文件夾
  • 支持 hook 操作

安裝

go get -u go.uber.org/zap

基本使用

package main

import "go.uber.org/zap"

var logger *zap.Logger

func main() {
	logger, _ = zap.NewProduction() // 使用生產(chǎn)環(huán)境
    // logger, _ := zap.NewDevelopment() // 使用開發(fā)環(huán)境
	defer logger.Sync() // 刷新緩存
    
    
    suger := logger.Sugar() // 開啟日志語法糖
    
    suger.Debug("我是Debug級別的日志")
	suger.Debugw("我是Debug級別的日志", "key1", "value1", "key2", "value2")
	suger.Debugf("我是Debug級別的日志%s", "value")

	suger.Warn("我是Warn級別的日志")
	suger.Warnw("我是Warn級別的日志", "key1", "value1", "key2", "value2")
	suger.Warnf("我是Warn級別的日志%s", "value")

	suger.Info("我是Info級別的日志")
	suger.Infow("我是Info級別的日志", "key1", "value1", "key2", "value2")
	suger.Infof("我是Info級別的日志 %s", "info")

	suger.Error("我是Error級別的日志")
	suger.Errorw("我是Error級別的日志", "key1", "value1", "key2", "value2")
	suger.Errorf("我是Error級別的日志 %s", "value")

	suger.Panic("我是Panic級別的日志")
	suger.Panicw("我是Panic級別的日志", "key1", "value1", "key2", "value2")
	suger.Panicf("我是Panic級別的日志 %s", "value")
    
    // 使用不帶語法糖的日志
    logger.Debug("我是Debug級別的日志", zap.String("key", "value"), zap.Int("num", 10))
	logger.Warn("我是Warn級別的日志", zap.String("key", "value"), zap.Int("num", 10))
	logger.Info("我是Info級別的日志", zap.String("key", "value"), zap.Int("num", 10))
	logger.Error("我是Error級別的日志", zap.String("key", "value"), zap.Int("num", 10))
	logger.Panic("我是Panic級別的日志", zap.String("key", "value"), zap.Int("num", 10))
}

NewExample/NewDevelopment/NewProduction使用

zap 為我們提供了三種快速創(chuàng)建 logger 的方法: zap.NewProduction(),zap.NewDevelopment(),zap.NewExample()

Example 一般用在測試代碼中,Development 用在開發(fā)環(huán)境中,Production 用在生成環(huán)境中

NewExample()使用

NewExample 構(gòu)建一個 logger,專門為在 zap 的測試示例使用。它將 DebugLevel 及以上日志用 JSON 格式標準輸出,但它省略了時間戳和調(diào)用函數(shù),以保持示例輸出的簡短和確定性

因為在這個方法里,zap 已經(jīng)定義好了日志配置項部分默認值

// https://github.com/uber-go/zap/blob/v1.24.0/logger.go#L127
func NewExample(options ...Option) *Logger {
	encoderCfg := zapcore.EncoderConfig{
        MessageKey:     "msg",  // 日志內(nèi)容key:val, 前面的key設(shè)為msg
		LevelKey:       "level", // 日志級別的key設(shè)為level
		NameKey:        "logger", // 日志名
		EncodeLevel:    zapcore.LowercaseLevelEncoder, //日志級別,默認小寫
		EncodeTime:     zapcore.ISO8601TimeEncoder, // 日志時間
		EncodeDuration: zapcore.StringDurationEncoder,
	}
	core := zapcore.NewCore(zapcore.NewJSONEncoder(encoderCfg), os.Stdout, DebugLevel)
	return New(core).WithOptions(options...)
}

使用例子

package main
import (
	"go.uber.org/zap"
)
func main() {
	logger := zap.NewExample()
	logger.Debug("this is debug message")
}

NewDevelopment()使用

NewDevelopment() 構(gòu)建一個開發(fā)使用的 Logger

使用例子

package main

import (
	"time"

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

	logger.Info("failed to fetch url",
		// 強類型字段
		zap.String("url", "http://example.com"),
		zap.Int("attempt", 3),
		zap.Duration("duration", time.Second),
	)

	logger.With(
		// 強類型字段
		zap.String("url", "http://development.com"),
		zap.Int("attempt", 4),
		zap.Duration("duration", time.Second*5),
	).Info("[With] failed to fetch url")
}

NewProduction()使用

NewProduction() 構(gòu)建了一個合理的 Prouction 日志記錄器,它將 info 及以上的日志內(nèi)容以 JSON 格式記寫入標準錯誤里

使用例子

package main

import (
	"time"

	"go.uber.org/zap"
)

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

	url := "http://zap.uber.io"
	sugar := logger.Sugar()
	sugar.Infow("failed to fetch URL",
		"url", url,
		"attempt", 3,
		"time", time.Second,
	)

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

	// 或更簡潔 Sugar() 使用
	// sugar := zap.NewProduction().Sugar()
	// defer sugar.Sync()
}

傳入配置項

在這 3 個函數(shù)中,可以傳入一些配置項。

func NewExample(options …Option) *Logger

package main

import (
	"os"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

func main() {

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

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

	core := zapcore.NewCore(encoder, sync, zapcore.InfoLevel)
	logger := zap.New(core)
	logger.Info("info 日志", zap.Int("line", 1))
}

zap.Hook() 添加回調(diào)函數(shù)

Hook (鉤子函數(shù))回調(diào)函數(shù)為用戶提供一種簡單方法,在每次日志內(nèi)容記錄后運行這個回調(diào)函數(shù),執(zhí)行用戶需要的操作。也就是說記錄完日志后你還想做其它事情就可以調(diào)用這個函數(shù)

package main

import (
	"fmt"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

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

	logger.Info("test output")

	logger.Warn("warn info")
}

自定義配置項

快速構(gòu)建 logger 日志記錄器最簡單的方法就是用 zap 預(yù)定義了配置的方法:NewExample(), NewProduction() 和NewDevelopment(),這 3 個方法通過單個函數(shù)調(diào)用就可以構(gòu)建一個日志計記錄器,也可以簡單配置

Config 配置項源碼

// zap v1.24.0
type Config struct {
    // 動態(tài)改變?nèi)罩炯墑e,在運行時你可以安全改變?nèi)罩炯墑e
	Level AtomicLevel `json:"level" yaml:"level"`
    // 將日志記錄器設(shè)置為開發(fā)模式,在 WarnLevel 及以上級別日志會包含堆棧跟蹤信息
	Development bool `json:"development" yaml:"development"`
    // 在日志中停止調(diào)用函數(shù)所在文件名、行數(shù)
	DisableCaller bool `json:"disableCaller" yaml:"disableCaller"`
    // 完全禁止自動堆棧跟蹤。默認情況下,在 development 中,warnlevel及以上日志級別會自動捕獲堆棧跟蹤信息
    // 在 production 中,ErrorLevel 及以上也會自動捕獲堆棧信息
	DisableStacktrace bool `json:"disableStacktrace" yaml:"disableStacktrace"`
    // 設(shè)置采樣策略。沒有 SamplingConfing 將禁止采樣
	Sampling *SamplingConfig `json:"sampling" yaml:"sampling"`
    // 設(shè)置日志編碼??梢栽O(shè)置為 console 和 json。也可以通過 RegisterEncoder 設(shè)置第三方編碼格式
	Encoding string `json:"encoding" yaml:"encoding"`
    // 為encoder編碼器設(shè)置選項。詳細設(shè)置信息在 zapcore.zapcore.EncoderConfig
	EncoderConfig zapcore.EncoderConfig `json:"encoderConfig" yaml:"encoderConfig"`
    // 日志輸出地址可以是一個 URLs 地址或文件路徑,可以設(shè)置多個
	OutputPaths []string `json:"outputPaths" yaml:"outputPaths"`
    // 錯誤日志輸出地址。默認輸出標準錯誤信息
	ErrorOutputPaths []string `json:"errorOutputPaths" yaml:"errorOutputPaths"`
    // 可以添加自定義的字段信息到 root logger 中。也就是每條日志都會攜帶這些字段信息,公共字段
	InitialFields map[string]interface{} `json:"initialFields" yaml:"initialFields"`
}

EncoderConfig 結(jié)構(gòu)源碼,它里面也有很多配置選項

// zapcore@v1.24.0
type EncoderConfig struct {
    // 為log entry設(shè)置key。如果 key 為空,那么在日志中的這部分信息也會省略
	MessageKey     string `json:"messageKey" yaml:"messageKey"`//日志信息的健名,默認為msg
	LevelKey       string `json:"levelKey" yaml:"levelKey"`//日志級別的健名,默認為level
	TimeKey        string `json:"timeKey" yaml:"timeKey"`//記錄日志時間的健名,默認為time
	NameKey        string `json:"nameKey" yaml:"nameKey"`
	CallerKey      string `json:"callerKey" yaml:"callerKey"`
	FunctionKey    string `json:"functionKey" yaml:"functionKey"`
	StacktraceKey  string `json:"stacktraceKey" yaml:"stacktraceKey"`
	SkipLineEnding bool   `json:"skipLineEnding" yaml:"skipLineEnding"`
	LineEnding     string `json:"lineEnding" yaml:"lineEnding"`
    // 日志編碼的一些設(shè)置項
	EncodeLevel    LevelEncoder    `json:"levelEncoder" yaml:"levelEncoder"`
	EncodeTime     TimeEncoder     `json:"timeEncoder" yaml:"timeEncoder"`
	EncodeDuration DurationEncoder `json:"durationEncoder" yaml:"durationEncoder"`
	EncodeCaller   CallerEncoder   `json:"callerEncoder" yaml:"callerEncoder"`
    // 與其它編碼器不同, 這個編碼器可選
	EncodeName NameEncoder `json:"nameEncoder" yaml:"nameEncoder"`
    // 配置 interface{} 類型編碼器。如果沒設(shè)置,將用 json.Encoder 進行編碼
	NewReflectedEncoder func(io.Writer) ReflectedEncoder `json:"-" yaml:"-"`
    // 配置 console 中字段分隔符。默認使用 tab 
	ConsoleSeparator string `json:"consoleSeparator" yaml:"consoleSeparator"`
}
type Entry struct {
	Level      Level
	Time       time.Time
	LoggerName string
	Message    string
	Caller     EntryCaller
	Stack      string
}zap 提供了 2 種日志記錄器:`SugaredLogger` 和 `Logger`

SugaredLogger日志

在需要性能但不是很重要的情況下,使用 SugaredLogger 較合適。它比其它結(jié)構(gòu)化日志包快 4-10 倍,包括 結(jié)構(gòu)化日志和 printf 風格的 API

使用: suger.[日志級別]x

w 支持鍵值對方式傳入日志

f 支持%s 方式插值

suger := logger.Sugar() // 開啟日志語法糖
    
suger.Debug("我是Debug級別的日志")
suger.Debugw("我是Debug級別的日志", "key1", "value1", "key2", "value2")
suger.Debugf("我是Debug級別的日志%s", "value")

suger.Warn("我是Warn級別的日志")
suger.Warnw("我是Warn級別的日志", "key1", "value1", "key2", "value2")
suger.Warnf("我是Warn級別的日志%s", "value")

suger.Info("我是Info級別的日志")
suger.Infow("我是Info級別的日志", "key1", "value1", "key2", "value2")
suger.Infof("我是Info級別的日志 %s", "info")

suger.Error("我是Error級別的日志")
suger.Errorw("我是Error級別的日志", "key1", "value1", "key2", "value2")
suger.Errorf("我是Error級別的日志 %s", "value")

suger.Panic("我是Panic級別的日志")
suger.Panicw("我是Panic級別的日志", "key1", "value1", "key2", "value2")
suger.Panicf("我是Panic級別的日志 %s", "value")

logger日志

當性能和類型安全很重要時,請使用 Logger。它比 SugaredLogger 更快,分配的資源更少,但它只支持結(jié)構(gòu)化日志和強類型字段

第一個參數(shù)打印日志名,后邊支持傳入可變參, …zapcore.Field類型

zap.String(“key”, “value”) 表示打印key為字符串 value為字符串的 map

logger.Debug("我是Debug級別的日志", zap.String("key", "value"), zap.Int("num", 10))
logger.Warn("我是Warn級別的日志", zap.String("key", "value"), zap.Int("num", 10))
logger.Info("我是Info級別的日志", zap.String("key", "value"), zap.Int("num", 10))
logger.Error("我是Error級別的日志", zap.String("key", "value"), zap.Int("num", 10))
logger.Panic("我是Panic級別的日志", zap.String("key", "value"), zap.Int("num", 10))

輸出日志到文件

cfg := zap.NewProductionConfig()
cfg.OutputPaths = []string{
   "./OUTPUT.log", "stderr", "stdout",
}
logger, _ = cfg.Build()

logger.Debug("打印日志到文件")

日志切割歸檔

lumberjack 這個庫是按照日志大小切割日志文件。

go get -u github.com/natefinch/lumberjack@v2
log.SetOutput(&lumberjack.Logger{
    Filename:   "/var/log/myapp/foo.log", // 文件位置
    MaxSize:    500,  // megabytes,M 為單位,達到這個設(shè)置數(shù)后就進行日志切割
    MaxBackups: 3,    // 保留舊文件最大份數(shù)
    MaxAge:     28,   //days , 舊文件最大保存天數(shù)
    Compress:   true, // disabled by default,是否壓縮日志歸檔,默認不壓縮
})

參照它的文檔和結(jié)合上面自定義配置

package main

import (
	"fmt"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

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

	config := zap.NewProductionEncoderConfig()

	config.EncodeTime = zapcore.ISO8601TimeEncoder // 設(shè)置時間格式
	fileEncoder := zapcore.NewJSONEncoder(config)

	core := zapcore.NewCore(
		fileEncoder,                       //編碼設(shè)置
		zapcore.AddSync(lumberjacklogger), //輸出到文件
		zap.InfoLevel,                     //日志等級
	)

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

    // 測試分割日志
	for i := 0; i < 8000; i++ {
		logger.With(
			zap.String("url", fmt.Sprintf("www.test%d.com", i)),
			zap.String("name", "jimmmyr"),
			zap.Int("age", 23),
			zap.String("agradege", "no111-000222"),
		).Info("test info ")
	}

}

全局logger

zap提供了 2 種全局 Logger,一個是 zap.Logger,調(diào)用 zap.L() 獲??;
另外一個是 zap.SugaredLogger ,調(diào)用 zap.S() 獲取

直接調(diào)用 zap.L() 或 zap.S() 記錄日志的話,它是不會記錄任何日志信息。需要調(diào)用 ReplaceGlobals() 函數(shù)將它設(shè)置為全局 Logger。
ReplaceGlobals 替換全局 Logger 和 SugaredLogger,并返回一個函數(shù)來恢復(fù)原始值

簡單使用例子

package main

import (
	"go.uber.org/zap"
)

func main() {
	// 直接調(diào)用是不會記錄日志信息的,所以下面日志信息不會輸出
	zap.L().Info("no log info")
	zap.S().Info("no log info [sugared]")

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

	zap.ReplaceGlobals(logger) // 全局logger,zap.L() 和 zap.S() 需要調(diào)用 ReplaceGlobals 函數(shù)才會記錄日志信息
	zap.L().Info("log info")
	zap.S().Info("log info [sugared]")
}

到此這篇關(guān)于golang整合日志zap的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)golang整合日志zap內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • 詳解Golang time包中的結(jié)構(gòu)體time.Time

    詳解Golang time包中的結(jié)構(gòu)體time.Time

    在日常開發(fā)過程中,會頻繁遇到對時間進行操作的場景,使用 Golang 中的 time 包可以很方便地實現(xiàn)對時間的相關(guān)操作,本文先講解一下 time 包中的結(jié)構(gòu)體 time.Time,需要的朋友可以參考下
    2023-07-07
  • Golang源碼分析之golang/sync之singleflight

    Golang源碼分析之golang/sync之singleflight

    golang/sync庫拓展了官方自帶的sync庫,提供了errgroup、semaphore、singleflight及syncmap四個包,本次先分析第一個包errgroup的源代碼,下面這篇文章主要給大家介紹了關(guān)于Golang源碼分析之golang/sync之singleflight的相關(guān)資料,需要的朋友可以參考下
    2022-11-11
  • golang API開發(fā)過程的中的自動重啟方式(基于gin框架)

    golang API開發(fā)過程的中的自動重啟方式(基于gin框架)

    這篇文章主要介紹了golang API開發(fā)過程的中的自動重啟方式(基于gin框架),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • golang 格式化輸入輸出操作

    golang 格式化輸入輸出操作

    這篇文章主要介紹了golang 格式化輸入輸出操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Golang切片Slice功能操作詳情

    Golang切片Slice功能操作詳情

    這篇文章主要介紹了Golang切片功能操作詳情,切片是一個擁有相同類型元素的可變長度的序列。它是基于數(shù)組類型做的一層封,切片是一個引用類型,它的內(nèi)部結(jié)構(gòu)包含地址、長度和容量
    2022-09-09
  • Go語言中緩沖bufio的原理解讀與應(yīng)用實戰(zhàn)

    Go語言中緩沖bufio的原理解讀與應(yīng)用實戰(zhàn)

    Go語言標準庫中的bufio包提供了帶緩沖的I/O操作,它通過封裝io.Reader和io.Writer接口,減少頻繁的I/O操作,提高讀寫效率,本文就來詳細的介紹一下,感興趣的可以學習
    2024-10-10
  • Golang中map的三種聲明定義方式實現(xiàn)

    Golang中map的三種聲明定義方式實現(xiàn)

    本文主要介紹了Golang中map的三種聲明定義方式實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-02-02
  • golang 實現(xiàn)時間滑動窗口的示例代碼

    golang 實現(xiàn)時間滑動窗口的示例代碼

    滑動時間窗口就是把一段時間片分為多個樣本窗口,可以通過更細粒度對數(shù)據(jù)進行統(tǒng)計,這篇文章主要介紹了golang 實現(xiàn)時間滑動窗口,需要的朋友可以參考下
    2022-10-10
  • 詳解Golang編程中的常量與變量

    詳解Golang編程中的常量與變量

    這篇文章主要介紹了詳解Golang編程中的常量與變量,是Go語言入門學習中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-10-10
  • Go語言打包優(yōu)化之減小二進制文件體積的多種方法

    Go語言打包優(yōu)化之減小二進制文件體積的多種方法

    這篇文章主要介紹了Go語言打包優(yōu)化之減小二進制文件體積的多種方法,Go語言提供了許多工具和技巧來幫助我們進行代碼優(yōu)化,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2025-05-05

最新評論

长武县| 和平县| 会宁县| 沂南县| 珲春市| 平谷区| 阿克陶县| 靖州| 乌兰县| 新平| 海南省| 南充市| 乡城县| 桑日县| 子洲县| 突泉县| 苗栗市| 尚志市| 葵青区| 梁平县| 定边县| 兴国县| 青海省| 石家庄市| 沛县| 东安县| 临颍县| 驻马店市| 兰溪市| 神池县| 白玉县| 锡林郭勒盟| 郁南县| 手游| 谷城县| 镇巴县| 沅陵县| 雷波县| 改则县| 永德县| 江口县|