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.最終效果
可以看到,日誌以json格式輸出,並顯示了日誌列印時的程式碼行數,同時當出現error時進行了呼叫棧的追蹤.