最近捣鼓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...

可以看到,报错原因就很详细了。

大功告成!

参考文章:

go基于grpc构建微服务框架-结构化日志输出

如何在golang中打印grpc详细日志的更多相关文章

  1. iOS中打印系统详细日志

    Q:如何打印当前的函数和行号? A:我们可以在打印时使用一些预编译宏作为打印参数,来打印当前的函数和行号.如: 1 NSLog(@"%s:%d obj=%@", __func__, ...

  2. golang中打印格式化的一些占位符

    package main import ( "fmt" ) func main() { var a byte = 255 // byte = uint8 rune = int32 ...

  3. golang 中 channel 的详细使用、使用注意事项及死锁分析

    目录 1.什么是 channel,介绍管道 2.channel 的基本使用 3.channel 的使用场景 4.使用 channel的注意事项及死锁分析 什么是 channel 管道 它是一个数据管道 ...

  4. 如何在shell中打印出带颜色的字符?

    先看如下的效果: 方法: 先看如下的脚本sh3.sh: #!/bin/bash echo "peng" echo "$(color bold yellow) ------ ...

  5. windows环境变量如何在cmd中打印

    在windows的cmd下,用"set"命令可以得到全部的环境变量,如何想得到某个环境变量,直接这样"set path"就可以了. set不仅如何,还有其他功能 ...

  6. 在EF6.0中打印数据库操作日志

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  7. 如何在Rust中打印变量的类型?

    #![feature(core_intrinsics)] fn print_type_of<T>(_: T) { println!("{}", unsafe { std ...

  8. JNI的native代码中打印日志到eclipse的logcat中

    1 添加ndk对log支持若需要添加ndk对log的支持,只需要通过以下2步即可实现. 1.1 修改Android.mk如生成的库文件是“.so文件”,则在Android.mk中添加如下内容:LOCA ...

  9. Golang中的自动伸缩和自防御设计

    Raygun服务由许多活动组件构成,每个组件用于特定的任务.其中一个模块是用Golang编写的,负责对iOS崩溃报告进行处理.简而言之,它接受本机iOS崩溃报告,查找相关的dSYM文件,并生成开发者可 ...

随机推荐

  1. linux防火墙放行了端口,但是仍然访问不到

    我们的防火墙默认规则如下: 如果防火墙放行了端口,但是仍然访问不到的话,可能是因为添加规则的时候,用的是iptables -A 选项,这样,增加的规则会排列在 第6条 规则后面,虽然service i ...

  2. CopyOnWriteArrayList对比ArrayList

    ArrayList非线程安全,CopyOnWriteArrayList线程安全 ArrayList添加元素的时候内部会预先分配存储空间,CopyOnWriteArrayList每次添加元素都会重新co ...

  3. iText中输出 中文

    iText中输出中文,有三种方式: 1.使用iTextAsian.jar中的字体    BaseFont.createFont("STSong-Light", "UniG ...

  4. 关于notify() 和notifyAll() 一个需要注意的地方

    notify() 和 notifyAll()都是唤醒其他正在等待同一个对象锁的线程. 下面是我遇到的一个问题,记下来,免得忘了. 直接上代码,有错误的代码: 代码描述:有一个Caculate类,类中又 ...

  5. Java获取虚拟机内存和操作系统内存及其线程

    为什么要获取虚拟机内存和操作系统内存呢? 虚拟机内存,这里主要指JVM.为了防止有的时候因为JVM内存问题导致服务器宕机,所以有必要监控JVM的内存.当达到一定值时,通过邮件及时通知,防止线上宕机造成 ...

  6. PAT——1016. 部分A+B

    正整数A的“DA(为1位整数)部分”定义为由A中所有DA组成的新整数PA.例如:给定A = 3862767,DA = 6,则A的“6部分”PA是66,因为A中有2个6. 现给定A.DA.B.DB,请编 ...

  7. java中StringBuffer与String、StringBuilder的区别

    在java中我们经常可以看到StringBuffer和String的用法,但是我自己在使用过程中,经常会将两者弄混淆,今天我们就来了解一下两者的区别: 我们首先来看一下我们的官方API中的简单介绍: ...

  8. Css animation 与 float 、flex 布局问题

    1. 有这样一段css html 代码 <div class="container"> <div class="float-left"> ...

  9. Spring Bean自动注册的实现方案

    这里Spring管理的Bean,可以认为是一个个的Service,每个Service都是一个服务接口 自动注册Service的好处: 1.根据指定的name/id获取对应的Service,实现简单工厂 ...

  10. winform 里 如何实现文件上传

    看了网上写的 用webclient类的uploadfile方法, 我在本地建立了个webform,winform窗体,  现在可以本地实现文件传递,可以选择文件传到d:\temp路径下,但怎们传到服务 ...