最近搗鼓fabric,在一個tls證書問題上糾結挺久,連接orderer服務時候,grpc日志總是冷冰冰的顯示這個信息
Orderer Client Status Code: (2) CONNECTION_FAILED. Description
真想請它告訴我,這么個錯誤碼,到底有啥用?!
真是日志用時方恨少,這種時候,我們就需要詳細的日志告訴我們到底哪兒出錯了是不是?一番百度之后,參考了一篇大神的文章后,終於把問題解決了。
咱們開始上手吧!
思路
grpc包含了grpclog包,用於其日志的處理,同時定義了LoggerV2的接口。
因此,只要實現LoggerV2
的接口,並通過SetLoggerV2(l LoggerV2)
接口將實現的對象設置到grpclog
包中,就可以自定義日志輸出,同時上層應用也可以使用grpclog進行業務日志打印。
實現
就拿fabric-sdk-go的源碼來舉例:
1.添加LoogerV2
接口實現
我們可以在util
目錄下添加文件grpclogger.go
,其中內容如下
目錄和名字不重要,關鍵是內容
結構體名稱任意,之所以取名
ZapLogger
,是因為我參照的文章使用了uber的zaplogger
實現(而我們只使用了fabric-sdk-go中的實現)
package util
import (
"github.com/hyperledger/fabric-sdk-go/pkg/common/logging"
)
type ZapLogger struct {
logger logging.Logger
}
// NewZapLogger 創建封裝了zap的對象,該對象是對LoggerV2接口的實現
func NewZapLogger(logger *logging.Logger) *ZapLogger {
return &ZapLogger{
logger: *logger,
}
}
// Info returns
func (zl *ZapLogger) Info(args ...interface{}) {
zl.logger.Info(args)
}
// Infoln returns
func (zl *ZapLogger) Infoln(args ...interface{}) {
zl.logger.Info(args...)
}
// Infof returns
func (zl *ZapLogger) Infof(format string, args ...interface{}) {
zl.logger.Infof(format, args...)
}
// Warning returns
func (zl *ZapLogger) Warning(args ...interface{}) {
zl.logger.Warn(args...)
}
// Warningln returns
func (zl *ZapLogger) Warningln(args ...interface{}) {
zl.logger.Warn(args...)
}
// Warningf returns
func (zl *ZapLogger) Warningf(format string, args ...interface{}) {
zl.logger.Warnf(format, args...)
}
// Error returns
func (zl *ZapLogger) Error(args ...interface{}) {
zl.logger.Error(args...)
}
// Errorln returns
func (zl *ZapLogger) Errorln(args ...interface{}) {
zl.logger.Error(args...)
}
// Errorf returns
func (zl *ZapLogger) Errorf(format string, args ...interface{}) {
zl.logger.Errorf(format, args...)
}
// Fatal returns
func (zl *ZapLogger) Fatal(args ...interface{}) {
zl.logger.Fatal(args...)
}
// Fatalln returns
func (zl *ZapLogger) Fatalln(args ...interface{}) {
zl.logger.Fatal(args...)
}
// Fatalf logs to fatal level
func (zl *ZapLogger) Fatalf(format string, args ...interface{}) {
zl.logger.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
}
2、將實現的對象設置到grpclog
包中
如前文所述,我們通過SetLoggerV2(l LoggerV2)
接口將實現的對象設置到grpclog
包中
在將進行grpc操作的方法里,添加相關代碼。
這樣的文件可以是
# 文件: pkg\fab\comm\connector.go
func (cc *CachingConnector) createConn(ctx context.Context, target string, opts ...grpc.DialOption) (*cachedConn, error)
添加如下代碼:
var logger = logging.NewLogger("grpcLogger")
grpclog.SetLoggerV2(util.NewZapLogger(logger))
3、試一試是否成功?
隨后,我的程序得到了這樣的日志
[grpcLogger] 2019/02/13 18:53:24 UTC - util.(*ZapLogger).Warningf -> WARN grpc:
addrConn.createTransport failed to connect to {ord1-yc-leader-hlf-ord.yc-leader:7050 0 <nil>}.
Err :connection error: desc = "transport: authentication handshake failed:
x509: certificate is valid for ord1-yc-leader-hlf-ord.yc-leader, not ord1-yc-leader-hlf-ord".
Reconnecting...
可以看到,報錯原因就很詳細了。
大功告成!