go基於grpc構建微服務框架-結構化日誌輸出

g4zhuj發表於2018-04-21

1.結構化日誌的意義

1.1 日誌格式化

日誌主要用於跟蹤服務的執行資訊,作為後端攻城獅,一般都會有一種想法,平時的時候希望日誌越少越好,出問題的時候又總是抱怨,怎麼才tmd這點日誌,還在關鍵的地方沒列印.

因此,日誌很重要,將日誌進行格式化也很重要,日誌格式化主要是為了方便後續進行分析.如通過將錯誤碼格式化到日誌中,我們可以對收集後的日誌分析介面的呼叫健康狀態,將介面耗時格式化後上報,可以監控延時高的操作,並查詢出關聯日誌進行分析.

所以只要是格式化輸出,很容易有很多應用.

1.2 日誌庫應該有的特性

  • 高效能
    這裡主要是兩方面,每次操作的耗時,以及每次操作分配的記憶體,作為日誌庫,兩個指標都應該要極低.

  • 日誌等級過濾
    能通過調節日誌等級列印不同級別的日誌.

  • 取樣率
    能夠設定取樣率,防止服務請求增加時輸出的日誌量劇增,從而影響服務效能.

  • 自動切分檔案
    自動按一定大小切分檔案,定期歸檔,儲存一定數量檔案.

基於以上幾點,選擇uber開源的日誌庫 zap.

2.整合到grpc中

2.1 思路

grpc 定義了grpclog包,並定義了LoggerV2的介面,因此,只要通過zap實現LoggerV2的介面,並通過SetLoggerV2(l LoggerV2)介面將實現的物件設定到grpclog包中,那麼grpc將使用zap進行日誌輸出,同時上層應用也可以使用grpclog進行業務日誌列印.

2.2 實現

完整程式碼以及使用示例見 grpc-wrapper

type ZapLogger struct {
	logger *zap.Logger
}

//建立封裝了zap的物件,該物件是對LoggerV2介面的實現
func NewZapLogger(logger *zap.Logger) *ZapLogger {
	return &ZapLogger{
		logger: logger,
	}
}
func (zl *ZapLogger) Info(args ...interface{}) {
	zl.logger.Sugar().Info(args...)
}

func (zl *ZapLogger) Infoln(args ...interface{}) {
	zl.logger.Sugar().Info(args...)
}
func (zl *ZapLogger) Infof(format string, args ...interface{}) {
	zl.logger.Sugar().Infof(format, args...)
}

func (zl *ZapLogger) Warning(args ...interface{}) {
	zl.logger.Sugar().Warn(args...)
}

func (zl *ZapLogger) Warningln(args ...interface{}) {
	zl.logger.Sugar().Warn(args...)
}

func (zl *ZapLogger) Warningf(format string, args ...interface{}) {
	zl.logger.Sugar().Warnf(format, args...)
}

func (zl *ZapLogger) Error(args ...interface{}) {
	zl.logger.Sugar().Error(args...)
}

func (zl *ZapLogger) Errorln(args ...interface{}) {
	zl.logger.Sugar().Error(args...)
}

func (zl *ZapLogger) Errorf(format string, args ...interface{}) {
	zl.logger.Sugar().Errorf(format, args...)
}

func (zl *ZapLogger) Fatal(args ...interface{}) {
	zl.logger.Sugar().Fatal(args...)
}

func (zl *ZapLogger) Fatalln(args ...interface{}) {
	zl.logger.Sugar().Fatal(args...)
}

// Fatalf logs to fatal level
func (zl *ZapLogger) Fatalf(format string, args ...interface{}) {
	zl.logger.Sugar().Fatalf(format, args...)
}

// V reports whether verbosity level l is at least the requested verbose level.
func (zl *ZapLogger) V(v int) bool {
	return false
}

複製程式碼

3.最終效果

go基於grpc構建微服務框架-結構化日誌輸出

可以看到,日誌以json格式輸出,並顯示了日誌列印時的程式碼行數,同時當出現error時進行了呼叫棧的追蹤.

參考

grpc
zap.
grpc-wrapper

相關文章