欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

GO語言框架快速集成日志模塊的操作方法

 更新時間:2022年07月13日 09:28:02   作者:Masters  
zap是一個可以在go項目中進行快速,?結構化且分級的日志記錄包,?git?star數(shù)高達16.3k,?Git?項目地址,?在各大公司項目中被廣泛使用,這篇文章主要介紹了GO語言框架中如何快速集成日志模塊,需要的朋友可以參考下

前言

在我們的日常開發(fā)中, 日志模塊永遠是最基礎且最重要的一個模塊, 它可以有效的幫我們發(fā)現(xiàn)問題, 定位問題, 最后去解決問題;

zap包的集成

簡介

zap是一個可以在go項目中進行快速, 結構化且分級的日志記錄包, git star數(shù)高達16.3k, Git 項目地址, 在各大公司項目中被廣泛使用;

最基礎的使用

package main
import (
	"go.uber.org/zap"
	"time"
)
func main() {
	logger, _ := zap.NewProduction()
	defer logger.Sync()
	logger.Info(" log info msg",
		zap.String("name", "掘金"),
		zap.Int("num", 3),
		zap.Duration("timer", time.Minute),
	)
}
{"level":"info","ts":1657600159.826612,"caller":"log/main.go:11","msg":" log info msg","name":"腳本","num":3,"timer":60}
{"level":"warn","ts":1657600159.8266969,"caller":"log/main.go:16","msg":" this is err msg","msg":"code err"}

可以看到上面就是打印出來的log, 當然這是用的默認配置, 所以格式和輸出可能不太符合我們的要求, 我們可以自己修改配置來完成定制化log;

定制化

// NewProduction builds a sensible production Logger that writes InfoLevel and
// above logs to standard error as JSON.
//
// It's a shortcut for NewProductionConfig().Build(...Option).
func NewProduction(options ...Option) (*Logger, error) {
   return NewProductionConfig().Build(options...)
}

可以看到生成log的方法其實就是用 configbuild 來構造一個記錄器, 我們試試自定義一下;

package main
import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"time"
)
func main() {
	conf := zap.NewProductionConfig()

	// 可以把輸出方式改為控制臺編碼, 更容易閱讀
	conf.Encoding = "console"
	// 時間格式自定義
	conf.EncoderConfig.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
		enc.AppendString("[" + t.Format("2006-01-02 15:04:05") + "]")
	}
	// 打印路徑自定義
	conf.EncoderConfig.EncodeCaller = func(caller zapcore.EntryCaller, encoder zapcore.PrimitiveArrayEncoder) {
		encoder.AppendString("[" + caller.TrimmedPath() + "]")
	}
	// 級別顯示自定義
	conf.EncoderConfig.EncodeLevel = func(level zapcore.Level, encoder zapcore.PrimitiveArrayEncoder) {
		encoder.AppendString("[" + level.String() + "]")
	}

	logger, _ := conf.Build()
	logger.Info("service start")

	logger.Info("info msg",
		zap.String("name", "掘金"),
		zap.Int("num", 3),
		zap.Duration("timer", time.Minute),
	)
}
[2022-07-12 14:57:18]   [info]  [log/main.go:28]        service start
[2022-07-12 14:57:18]   [info]  [log/main.go:30]        info msg        {"name": "掘金", "num": 3, "timer": 60}

這種日志一般大家看起來就比較舒服了, 特別是打印json結構的話可以直接復制解析器里面去看, 沒有json編碼的各種轉義;

zap包還是很靈活的, 基本上配置參數(shù)都支持自定義(輸出鍵名, 格式等等), 大家可以按需配置使用;

// An EncoderConfig allows users to configure the concrete encoders supplied by
// zapcore.
type EncoderConfig struct {
	// Set the keys used for each log entry. If any key is empty, that portion
	// of the entry is omitted.
	MessageKey    string `json:"messageKey" yaml:"messageKey"`
	LevelKey      string `json:"levelKey" yaml:"levelKey"`
	TimeKey       string `json:"timeKey" yaml:"timeKey"`
	NameKey       string `json:"nameKey" yaml:"nameKey"`
	CallerKey     string `json:"callerKey" yaml:"callerKey"`
	FunctionKey   string `json:"functionKey" yaml:"functionKey"`
	StacktraceKey string `json:"stacktraceKey" yaml:"stacktraceKey"`
	LineEnding    string `json:"lineEnding" yaml:"lineEnding"`
	// Configure the primitive representations of common complex types. For
	// example, some users may want all time.Times serialized as floating-point
	// seconds since epoch, while others may prefer ISO8601 strings.
	EncodeLevel    LevelEncoder    `json:"levelEncoder" yaml:"levelEncoder"`
	EncodeTime     TimeEncoder     `json:"timeEncoder" yaml:"timeEncoder"`
	EncodeDuration DurationEncoder `json:"durationEncoder" yaml:"durationEncoder"`
	EncodeCaller   CallerEncoder   `json:"callerEncoder" yaml:"callerEncoder"`
	// Unlike the other primitive type encoders, EncodeName is optional. The
	// zero value falls back to FullNameEncoder.
	EncodeName NameEncoder `json:"nameEncoder" yaml:"nameEncoder"`
	// Configures the field separator used by the console encoder. Defaults
	// to tab.
	ConsoleSeparator string `json:"consoleSeparator" yaml:"consoleSeparator"`
}

進階封裝

項目里面生產(chǎn)環(huán)境為了方便收集日志可能都比較喜歡用json, 開發(fā)環(huán)境中大家又都比較喜歡console方便調試, 還有比如希望接口/服務日志帶上屬于自己的唯一請求標識這種, 以及對日志進行分類保存等等, 就需要對zap包進行再一次的封裝;

下面是我自己封裝的log包代碼, 可以很方便的解決上面的問題, 大家可以當做參考;

index.go 記錄器初始化, 根據(jù)配置選擇編碼輸出方式及日志文件保存邏輯, 以及一些自己自定義的輸出標準;

package logging

import (
	"go.uber.org/zap"
	"go.uber.org/zap/buffer"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
	"os"
	"path"
	"strings"
)

type (
	Conf struct {
		Path    string // 日志路徑
		Encoder string // 編碼器選擇
	}
	logItem struct {
		FileName string
		Level    zap.LevelEnablerFunc
	}
	Encoder interface {
		Config() zapcore.Encoder
		WithKey(key string) Encoder
		WithField(key, val string) Encoder
		Debug(msg string)
		Debugf(format string, v ...interface{})
		Info(msg string)
		Infof(format string, v ...interface{})
		Warn(msg string)
		Warnf(format string, v ...interface{})
		Error(msg string)
		Errorf(format string, v ...interface{})
		Fatal(msg string)
		Fatalf(format string, v ...interface{})
	}
)

var (
	maxSize    = 200 // 每個日志文件最大尺寸200M
	maxBackups = 20  // 日志文件最多保存20個備份
	maxAge     = 30  // 保留最大天數(shù)
	_logger    *zap.Logger
	_pool      = buffer.NewPool()
	c          Conf

	ConsoleEncoder = "console" // 控制臺輸出
	JsonEncoder    = "json"    // json輸出
)

// Init 初始化日志.
func Init(conf Conf) {
	c = conf
	prefix, suffix := getFileSuffixPrefix(c.Path)

	infoPath := path.Join(prefix + ".info" + suffix)
	errPath := path.Join(prefix + ".err" + suffix)
	items := []logItem{
		{
			FileName: infoPath,
			Level: func(level zapcore.Level) bool {
				return level <= zap.InfoLevel
			},
		},
		{
			FileName: errPath,
			Level: func(level zapcore.Level) bool {
				return level > zap.InfoLevel
			},
		},
	}

	NewLogger(items)
}

// NewLogger 日志.
func NewLogger(items []logItem) {
	var (
		cfg   zapcore.Encoder
		cores []zapcore.Core
	)
	switch c.Encoder {
	case JsonEncoder:
		cfg = NewJsonLog().Config()
	case ConsoleEncoder:
		cfg = NewConsoleLog().Config()
	default:
		cfg = NewConsoleLog().Config()
	}

	for _, v := range items {
		hook := lumberjack.Logger{
			Filename:   v.FileName,
			MaxSize:    maxSize,    // 每個日志文件保存的最大尺寸 單位:M
			MaxBackups: maxBackups, // 日志文件最多保存多少個備份
			MaxAge:     maxAge,     // 文件最多保存多少天
			Compress:   true,       // 是否壓縮
			LocalTime:  true,       // 備份文件名本地/UTC時間
		}
		core := zapcore.NewCore(
			cfg, // 編碼器配置;
			zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(&hook)), // 打印到控制臺和文件
			v.Level, // 日志級別
		)
		cores = append(cores, core)
	}

	// 開啟開發(fā)模式,堆棧跟蹤
	caller := zap.AddCaller()
	// 開發(fā)模式
	development := zap.Development()
	// 二次封裝
	skip := zap.AddCallerSkip(1)
	// 構造日志
	_logger = zap.New(zapcore.NewTee(cores...), caller, development, skip)
	return
}

// GetEncoder 獲取自定義編碼器.
func GetEncoder() Encoder {
	switch c.Encoder {
	case JsonEncoder:
		return NewJsonLog()
	case ConsoleEncoder:
		return NewConsoleLog()
	default:
		return NewConsoleLog()
	}
}

// GetLogger 獲取日志記錄器.
func GetLogger() *zap.Logger {
	return _logger
}

// getFileSuffixPrefix 文件路徑切割
func getFileSuffixPrefix(fileName string) (prefix, suffix string) {
	paths, _ := path.Split(fileName)
	base := path.Base(fileName)
	suffix = path.Ext(fileName)
	prefix = strings.TrimSuffix(base, suffix)
	prefix = path.Join(paths, prefix)
	return
}

// getFilePath 自定義獲取文件路徑.
func getFilePath(ec zapcore.EntryCaller) string {
	if !ec.Defined {
		return "undefined"
	}
	buf := _pool.Get()
	buf.AppendString(ec.Function)
	buf.AppendByte(':')
	buf.AppendInt(int64(ec.Line))
	caller := buf.String()
	buf.Free()
	return caller
}

console.go 控制臺編碼輸出, 支持自定義;

package logging

import (
	"fmt"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"time"
)

type ConsoleLog struct {
	val string
}

func NewConsoleLog() Encoder {
	return new(ConsoleLog)
}

// Config 自定義配置.
func (slf *ConsoleLog) Config() zapcore.Encoder {
	var (
		cfg = zap.NewProductionEncoderConfig()
	)

	// 時間格式自定義
	cfg.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
		enc.AppendString("[" + t.Format("2006-01-02 15:04:05") + "]")
	}
	// 打印路徑自定義
	cfg.EncodeCaller = func(caller zapcore.EntryCaller, encoder zapcore.PrimitiveArrayEncoder) {
		encoder.AppendString("[" + getFilePath(caller) + "]")
	}
	// 級別顯示自定義
	cfg.EncodeLevel = func(level zapcore.Level, encoder zapcore.PrimitiveArrayEncoder) {
		encoder.AppendString("[" + level.String() + "]")
	}
	return zapcore.NewConsoleEncoder(cfg)
}

// WithKey 添加單個鍵.
func (slf *ConsoleLog) WithKey(key string) Encoder {
	slf.val = slf.val + "[" + key + "]    "
	return slf
}

// WithField 添加字段.
func (slf *ConsoleLog) WithField(key, val string) Encoder {
	slf.val = slf.val + fmt.Sprintf("[%s:%s]    ", key, val)
	return slf
}

func (slf *ConsoleLog) Debug(msg string) {
	_logger.Debug(slf.val + msg)
}

func (slf *ConsoleLog) Debugf(format string, v ...interface{}) {
	_logger.Debug(fmt.Sprintf(slf.val+format, v...))
}

func (slf *ConsoleLog) Info(msg string) {
	_logger.Info(slf.val + msg)
}

func (slf *ConsoleLog) Infof(format string, v ...interface{}) {
	_logger.Info(fmt.Sprintf(slf.val+format, v...))
}

func (slf *ConsoleLog) Warn(msg string) {
	_logger.Warn(slf.val + msg)
}

func (slf *ConsoleLog) Warnf(format string, v ...interface{}) {
	_logger.Warn(fmt.Sprintf(slf.val+format, v...))
}

func (slf *ConsoleLog) Error(msg string) {
	_logger.Error(slf.val + msg)
}

func (slf *ConsoleLog) Errorf(format string, v ...interface{}) {
	_logger.Error(fmt.Sprintf(slf.val+format, v...))
}

func (slf *ConsoleLog) Fatal(msg string) {
	_logger.Fatal(slf.val + msg)
}

func (slf *ConsoleLog) Fatalf(format string, v ...interface{}) {
	_logger.Fatal(fmt.Sprintf(slf.val+format, v...))
}

json.go json編碼輸出, 支持自定義;

package logging

import (
	"fmt"
	"go.uber.org/zap/zapcore"
	"time"

	"go.uber.org/zap"
)

type JsonLog struct {
	fields []zap.Field
	val    string
}

// NewJsonLog  自定義添加log field.
func NewJsonLog() Encoder {
	return &JsonLog{fields: make([]zap.Field, 0)}
}

// Config 自定義配置.
func (slf *JsonLog) Config() zapcore.Encoder {
	var (
		cfg = zap.NewProductionEncoderConfig()
	)

	// 時間格式自定義
	cfg.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
		enc.AppendString(t.Format("2006-01-02 15:04:05"))
	}
	// 打印路徑自定義
	cfg.EncodeCaller = func(caller zapcore.EntryCaller, encoder zapcore.PrimitiveArrayEncoder) {
		encoder.AppendString(getFilePath(caller))
	}
	// 級別顯示自定義
	cfg.EncodeLevel = func(level zapcore.Level, encoder zapcore.PrimitiveArrayEncoder) {
		encoder.AppendString(level.String())
	}
	return zapcore.NewJSONEncoder(cfg)
}

// WithKey 添加單個鍵.
func (slf *JsonLog) WithKey(key string) Encoder {
	slf.val = slf.val + key + " "
	return slf
}

// WithField 添加字段.
func (slf *JsonLog) WithField(key, val string) Encoder {
	slf.fields = append(slf.fields, zap.String(key, val))
	return slf
}

func (slf *JsonLog) Debug(msg string) {
	_logger.Debug(slf.val+msg, slf.fields...)
}

func (slf *JsonLog) Debugf(format string, v ...interface{}) {
	_logger.Debug(fmt.Sprintf(slf.val+format, v...), slf.fields...)
}

func (slf *JsonLog) Info(msg string) {
	_logger.Info(slf.val+msg, slf.fields...)
}

func (slf *JsonLog) Infof(format string, v ...interface{}) {
	_logger.Info(fmt.Sprintf(slf.val+format, v...), slf.fields...)
}

func (slf *JsonLog) Warn(msg string) {
	_logger.Warn(slf.val+msg, slf.fields...)
}

func (slf *JsonLog) Warnf(format string, v ...interface{}) {
	_logger.Warn(fmt.Sprintf(slf.val+format, v...), slf.fields...)
}

func (slf *JsonLog) Error(msg string) {
	_logger.Error(slf.val+msg, slf.fields...)
}

func (slf *JsonLog) Errorf(format string, v ...interface{}) {
	_logger.Error(fmt.Sprintf(slf.val+format, v...), slf.fields...)
}

func (slf *JsonLog) Fatal(msg string) {
	_logger.Fatal(slf.val+msg, slf.fields...)
}

func (slf *JsonLog) Fatalf(format string, v ...interface{}) {
	_logger.Fatal(fmt.Sprintf(slf.val+format, v...), slf.fields...)
}

service.go 標準輸出方法, 方便直接調用;

package logging

import (
	"fmt"
)

func Sync() {
	_ = _logger.Sync()
}

func Debug(msg string) {
	_logger.Debug(msg)
}

func Debugf(format string, v ...interface{}) {
	_logger.Debug(fmt.Sprintf(format, v...))
}

func Info(msg string) {
	_logger.Info(msg)
}

func Infof(format string, v ...interface{}) {
	_logger.Info(fmt.Sprintf(format, v...))
}

func Warn(msg string) {
	_logger.Warn(msg)
}

func Warnf(format string, v ...interface{}) {
	_logger.Warn(fmt.Sprintf(format, v...))
}

func Error(msg string) {
	_logger.Error(msg)
}

func Errorf(format string, v ...interface{}) {
	_logger.Error(fmt.Sprintf(format, v...))
}

func Fatal(msg string) {
	_logger.Fatal(msg)
}

func Fatalf(format string, v ...interface{}) {
	_logger.Fatal(fmt.Sprintf(format, v...))
}

上面的進階代碼摘自我開發(fā)的一個git項目中, 主要是一個Go的標準項目布局, 封裝了一些常用的組件, 有興趣的朋友可以了解一下, 對新手還是很友好的;

到此這篇關于GO語言框架快速集成日志模塊的操作方法的文章就介紹到這了,更多相關go語言日志模塊內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Go語言到底有沒有引用傳參(對比 C++ )

    Go語言到底有沒有引用傳參(對比 C++ )

    這篇文章主要介紹了Go 到底有沒有引用傳參(對比 C++ ),需要的朋友可以參考下
    2017-09-09
  • go 壓縮解壓zip文件源碼示例

    go 壓縮解壓zip文件源碼示例

    這篇文章主要為大家介紹了go壓縮及解壓zip文件的源碼示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07
  • 利用Golang生成整數(shù)隨機數(shù)方法示例

    利用Golang生成整數(shù)隨機數(shù)方法示例

    這篇文章主要介紹了利用Golang生成整數(shù)隨機數(shù)的相關資料,文中給出了詳細的介紹和完整的示例代碼,相信對大家具有一定的參考價值,需要的朋友們下面來一起看看吧。
    2017-04-04
  • Golang中的四個括號示例詳解

    Golang中的四個括號示例詳解

    這篇文章主要介紹了Golang中的四個括號,本文通過實例代碼給大家介紹的非常詳細,通過實例代碼補充介紹了有效的括號golang實現(xiàn),需要的朋友可以參考下
    2024-03-03
  • 淺析Go常量為什么只支持基本數(shù)據(jù)類型

    淺析Go常量為什么只支持基本數(shù)據(jù)類型

    這篇文章主要來和大家一起討論一下Golang中常量為什么只支持基本數(shù)據(jù)類型,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-09-09
  • Golang使用MinIO的方案詳解

    Golang使用MinIO的方案詳解

    這篇文章主要介紹了Golang使用MinIO的過程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-08-08
  • golang time包下定時器的實現(xiàn)方法

    golang time包下定時器的實現(xiàn)方法

    定時器的實現(xiàn)大家應該都遇到過,最近在學習golang,所以下面這篇文章主要給大家介紹了關于golang time包下定時器的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-12-12
  • Golang?Configor配置文件工具的使用詳解

    Golang?Configor配置文件工具的使用詳解

    Configor是一個支持?yaml、json、toml、shell?的配置文件工具,這篇文中主要為大家詳細介紹了Configor的具體使用,感興趣的小伙伴可以學習一下
    2023-08-08
  • Golang unsafe.Sizeof函數(shù)代碼示例使用解析

    Golang unsafe.Sizeof函數(shù)代碼示例使用解析

    這篇文章主要為大家介紹了Golang unsafe.Sizeof函數(shù)代碼示例使用解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • web項目中golang性能監(jiān)控解析

    web項目中golang性能監(jiān)控解析

    這篇文章主要為大家介紹了web項目中golang性能監(jiān)控詳細的解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪
    2022-04-04

最新評論