Golang Zap日誌

来源:https://www.cnblogs.com/xiaofua/archive/2022/04/21/16173894.html
-Advertisement-
Play Games

來啦,老弟 python 我們已經知道怎麼使用 Requests 進行各種請求騷操作 也知道了對伺服器返回的數據如何使用 正則表達式 來過濾我們想要的內容 … 那麼接下來 Python學習交流Q群:906715085### 我們就使用 requests 和 re 來寫一個爬蟲 作為一個愛看書的你(說 ...


Zap日誌解析

Config.yaml

zap:
  level: 'info' #日誌級別
  format: 'console' #輸出的級別,有console和json
  prefix: '[catering]' #輸出的首碼,[catering]xxxxxxxxxxx
  director: 'log' #存放的文件夾
  show-line: true #是否顯示行號
  encode-level: 'LowercaseColorLevelEncoder' #編碼級別,目前支持四種LowercaseLevelEncoder,LowercaseColorLevelEncoder,CapitalLevelEncoder,CapitalColorLevelEncoder
  stacktrace-key: 'stacktrace' #棧名
  log-in-console: true #輸出控制台

配置文件

package config

type Zap struct {
	Level         string `mapstructure:"level" json:"level" yaml:"level"`                           // 級別
	Format        string `mapstructure:"format" json:"format" yaml:"format"`                        // 輸出
	Prefix        string `mapstructure:"prefix" json:"prefix" yaml:"prefix"`                        // 日誌首碼
	Director      string `mapstructure:"director" json:"director"  yaml:"director"`                 // 日誌文件夾
	ShowLine      bool   `mapstructure:"show-line" json:"showLine" yaml:"showLine"`                 // 顯示行
	EncodeLevel   string `mapstructure:"encode-level" json:"encodeLevel" yaml:"encode-level"`       // 編碼級
	StacktraceKey string `mapstructure:"stacktrace-key" json:"stacktraceKey" yaml:"stacktrace-key"` // 棧名
	LogInConsole  bool   `mapstructure:"log-in-console" json:"logInConsole" yaml:"log-in-console"`  // 輸出控制台
}

初始化

func InitZap() {
	cfg := global.Config.Zap //獲取上述的配置文件
    
    // 判斷是否有Director文件夾
	if ok, _ := pkg.PathExists(cfg.Director); !ok { 
		fmt.Printf("create %v directory\n", cfg.Director)
		_ = os.Mkdir(cfg.Director, os.ModePerm)
	}
    
    // zap.LevelEnablerFunc(func(lev zapcore.Level) bool 用來劃分不同級別的輸出
    // 根據不同的級別輸出到不同的日誌文件
    
	// 調試級別
	debugPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool {
		return lev == zap.DebugLevel
	})
	// 日誌級別
	infoPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool {
		return lev == zap.InfoLevel
	})
	// 警告級別
	warnPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool {
		return lev == zap.WarnLevel
	})
	// 錯誤級別
	errorPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool {
		return lev >= zap.ErrorLevel
	})

	cores := [...]zapcore.Core{
		getEncoderCore(fmt.Sprintf("./%s/server_debug.log", cfg.Director), debugPriority),
		getEncoderCore(fmt.Sprintf("./%s/server_info.log", cfg.Director), infoPriority),
		getEncoderCore(fmt.Sprintf("./%s/server_warn.log", cfg.Director), warnPriority),
		getEncoderCore(fmt.Sprintf("./%s/server_error.log", cfg.Director), errorPriority),
	}
    
    //zapcore.NewTee(cores ...zapcore.Core) zapcore.Core
    //NewTee創建一個Core,將日誌條目複製到兩個或更多的底層Core中
    
	logger := zap.New(zapcore.NewTee(cores[:]...))

    //用文件名、行號和zap調用者的函數名註釋每條消息
	if cfg.ShowLine {
		logger = logger.WithOptions(zap.AddCaller())
	}

    //把初始化好的logger賦值到全局日誌變數中
	global.Log = logger
}

getEncoderCode函數

// getEncoderCore 獲取Encoder的zapcore.Core
func getEncoderCore(fileName string, level zapcore.LevelEnabler) (core zapcore.Core) {
	writer := pkg.GetWriteSyncer(fileName) // 使用file-rotatelogs進行日誌分割
	return zapcore.NewCore(getEncoder(), writer, level)
}

getEncoder函數

// getEncoder 獲取zapcore.Encoder
func getEncoder() zapcore.Encoder {
    //獲取配置文件的輸出格式,json or console
	cfg := global.Config.Zap
	if cfg.Format == "json" {
		return zapcore.NewJSONEncoder(getEncoderConfig())
	}
	return zapcore.NewConsoleEncoder(getEncoderConfig())
}

getEncoderConfig函數

獲取自定義的編碼器的配置

// getEncoderConfig 獲取zapcore.EncoderConfig
func getEncoderConfig() (config zapcore.EncoderConfig) {
	cfg := global.Config.Zap
	config = zapcore.EncoderConfig{
		MessageKey:     "message",
		LevelKey:       "level",
		TimeKey:        "time",
		NameKey:        "logger",
		CallerKey:      "caller",
		StacktraceKey:  cfg.StacktraceKey, //棧名
		LineEnding:     zapcore.DefaultLineEnding, //預設的結尾\n
		EncodeLevel:    zapcore.LowercaseLevelEncoder, //小寫字母輸出
		EncodeTime:     CustomTimeEncoder, //自定義時間格式
		EncodeDuration: zapcore.SecondsDurationEncoder, //編碼間隔 s
		EncodeCaller:   zapcore.FullCallerEncoder, //控制列印的文件位置是絕對路徑,ShortCallerEncoder 是相對路徑
	}
    //根據配置文件重新配置編碼顏色和字體
	switch {
	case cfg.EncodeLevel == "LowercaseLevelEncoder": // 小寫編碼器(預設)
		config.EncodeLevel = zapcore.LowercaseLevelEncoder
	case cfg.EncodeLevel == "LowercaseColorLevelEncoder": // 小寫編碼器帶顏色
		config.EncodeLevel = zapcore.LowercaseColorLevelEncoder
	case cfg.EncodeLevel == "CapitalLevelEncoder": // 大寫編碼器
		config.EncodeLevel = zapcore.CapitalLevelEncoder
	case cfg.EncodeLevel == "CapitalColorLevelEncoder": // 大寫編碼器帶顏色
		config.EncodeLevel = zapcore.CapitalColorLevelEncoder
	default:
		config.EncodeLevel = zapcore.LowercaseLevelEncoder
	}
	return config
}

CustomTimeEncoder函數

用於自定義日誌首碼的輸出格式

// 自定義日誌輸出時間格式
// 輸出格式為 prfix + 具體的時間日期
func CustomTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
	cfg := global.Config.Zap
	enc.AppendString(t.Format(cfg.Prefix + "2006-01-02 15:04:05.000"))
}

pkg.GetWriteSyncer函數

用於切割文件,防止日誌文件過大

func GetWriteSyncer(file string) zapcore.WriteSyncer {
	lumberJackLogger := &lumberjack.Logger{
		Filename:   file, // 日誌文件的位置
		MaxSize:    10,   // 在進行切割之前,日誌文件的最大大小(以MB為單位)
		MaxBackups: 200,  // 保留舊文件的最大個數
		MaxAge:     30,   // 保留舊文件的最大天數
		Compress:   true, // 是否壓縮/歸檔舊文件
	}

	if global.Config.Zap.LogInConsole {
		return zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(lumberJackLogger))
	}
	return zapcore.AddSync(lumberJackLogger)
}

用法

偽代碼,切勿直接粘貼複製

package global

var log *zap.Logger
package main

import (
	"catering/initialize"
    "catering/global"
)

func main() {
    initialize.InitZap()
    global.log.Info("test")
}

列印日誌示例

log
├── server_error.log
├── server_info.log

server_info.log

[catering]2022-03-17 17:36:42.200	info	E:/GoPath/project/go-catering/admin/initialize/router.go:32	use middleware logger
[catering]2022-03-17 17:36:42.201	info	E:/GoPath/project/go-catering/admin/initialize/router.go:36	use middleware cors
[catering]2022-03-17 17:36:42.201	info	E:/GoPath/project/go-catering/admin/initialize/router.go:38	register swagger handler
[catering]2022-03-17 17:36:42.225	info	E:/GoPath/project/go-catering/admin/initialize/router.go:104	router register success
[catering]2022-03-17 17:36:42.228	info	E:/GoPath/project/go-catering/admin/core/server.go:27	server run success on 	{"address": ":8888"}

server_error.log

[catering]2022-03-09 21:35:33.812	error	D:/goProject/src/catering/admin/pkg/app/request.go:13	Id.Required.	{"message": "Id Can not be empty"}
[catering]2022-03-09 21:35:33.813	error	D:/goProject/src/catering/admin/pkg/app/request.go:13	LevelName.Required.	{"message": "LevelName Can not be empty"}
[catering]2022-03-09 21:35:33.813	error	D:/goProject/src/catering/admin/pkg/app/request.go:13	UpNeedIntegration.Required.	{"message": "UpNeedIntegration Can not be empty"}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • return語句用於退出函數,向調用方返回一個表達式。 return在不帶參數的情況下(或者沒有寫return語句),預設返回None。 None是一個特殊的值,它的數據類型是NoneType。NoneType是Python的特殊類型,它只有一個取值None。 它不支持任何運算也沒有任何內建方法,和 ...
  • DFA 演算法是通過提前構造出一個 樹狀查找結構,之後根據輸入在該樹狀結構中就可以進行非常高效的查找。 設我們有一個敏感詞庫,詞酷中的辭彙為:我愛你我愛他我愛她我愛你呀我愛他呀我愛她呀我愛她啊 那麼就可以構造出這樣的樹狀結構: 設玩家輸入的字元串為:白菊我愛你呀哈哈哈 我們遍歷玩家輸入的字元串 str ...
  • 前言 又到每日分享Python小技巧的時候了,今天給大家分享啥呢?大家要不要猜一猜,今天給大家分享矢量影像批量裁剪以及合併。 聽起來有點不懂,看完你就懂了,擴展知識。 矢量批量裁剪的代碼 在:chp10\python\矢量批量裁剪.tbx\矢量批量裁剪,可以直接運行,右鍵編輯查看代碼 代碼如下: P ...
  • 目錄 一.簡介 二.效果演示 三.源碼下載 四.猜你喜歡 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 轉場 零基礎 O ...
  • 由於微服務架構中每個服務可能分散在不同的伺服器上,因此需要一套分散式日誌的解決方案。spring-cloud提供了一個用來trace服務的組件sleuth。它可以通過日誌獲得服務的依賴關係。基於sleuth,可以通過現有的日誌工具實現分散式日誌的採集。 這裡使用的是ELK,也就是elasticsea ...
  • 一提到Spring,大家最先想到的是啥?是AOP和IOC的兩大特性?是Spring中Bean的初始化流程?還是基於Spring的Spring Cloud全家桶呢? 今天我們就從Spring的IOC特性入手,聊一聊Spring中把Bean註入Spring容器的幾種方式。 我們先來簡單瞭解下IOC的概念 ...
  • JVM(Java虛擬機) 學習String類前,先瞭解一下JVM,也稱為Java虛擬機。 JVM記憶體分有幾大區域,其中,常見有堆、桟、方法區、常量池。 堆是運行時數據區,類通過new指令創建的對象會在堆記憶體里分配空間。堆記憶體的數據是由java垃圾回收器自動回收。堆的優勢是可以動態地分配記憶體大小。缺點 ...
  • 前言 今天給大家透露了我們這篇要說的牛逼利器 selenium + phantomjs Python學習交流Q群:906715085### 如果你知道 selenium 是什麼了 它能做到自動操作 比如我們上次說的自動百度蒼老師 將帶你爬取b站上的NBA形象大使蔡徐坤和他的球友們 但有時候 我們不想 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...