区块链教程Fabric1.0源代码分析flogging(Fabric日志系统)兄弟连区块链
区块链教程之Fabric1.0源代码分析flogging(Fabric日志系统),2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。
Fabric 1.0源代码笔记 之 flogging(Fabric日志系统)
1、flogging概述
flogging,即fabric logging,对第三方日志包go-logging做了封装,供全局使用。go-logging地址:github.com/op/go-logging。
flogging代码集中在common/flogging目录下,包括logging.go和grpclogger.go。
- logging.go,定义了默认的日志格式、日志级别和日志输出,以及modules和peerStartModules做模块和日志级别的映射。并定义了若干对go-logging封装的函数。
- grpclogger.go,基于封装go-logging定义了结构体grpclogger及其方法,并用于设置grpclog。grpclog默认使用go标准库日志包,此举可使得grpclog也使用go-logging和flogging功能。
2、flogging的常量和全局变量
涉及常量:pkgLogID、defaultFormat和defaultLevel,分别表示仅在flogging包内代码使用的go-logging名称、默认的日志格式和默认的日志级别。
涉及全局变量如下:
var ( logger *logging.Logger //仅在flogging包内代码使用的logging.Logger对象 defaultOutput *os.File //默认的日志输出 modules map[string]string //保存所有模块及其各自的日志级别的映射 peerStartModules map[string]string //存储内容与modules相同 lock sync.RWMutex //RWMutex读写锁 once sync.Once //对于从全局的角度只需要运行一次的代码,比如全局初化操始作,go语言提供了一个Once类型来保证全局的唯一性操作 ) //代码在common/flogging/logging.go
3、flogging对go-logging的封装
3.1、flogging包初始化
flogging包初始化,即init()函数,代码如下:
func init() { logger = logging.MustGetLogger(pkgLogID) //创建仅在flogging包内代码使用的logging.Logger对象 Reset() //全局变量初始化为默认值 initgrpclogger() //初始化gRPC Logger,即创建logging.Logger对象,并用这个对象设置grpclog } //代码在common/flogging/logging.go
其中func Reset()代码如下。
其作用为:初始化modules和lock,创建一个日志输出对象并设置为默认的日志格式和默认的日志级别。
设置各模块的日志级别,并更新modules。
func Reset() { modules = make(map[string]string) //初始化modules lock = sync.RWMutex{} //初始化lock defaultOutput = os.Stderr //默认的日志输出置为os.Stderr //SetFormat()设置并获取go-logging日志格式,InitBackend()创建一个日志输出对象并设置输出格式和日志级别 InitBackend(SetFormat(defaultFormat), defaultOutput) InitFromSpec("") //设置各模块日志级别,并更新modules } //代码在common/flogging/logging.go
func InitBackend(formatter logging.Formatter, output io.Writer)代码如下。
创建一个日志输出对象并设置输出格式和日志级别。
func InitBackend(formatter logging.Formatter, output io.Writer) { backend := logging.NewLogBackend(output, "", 0) //创建一个日志输出对象 backendFormatter := logging.NewBackendFormatter(backend, formatter) //设置日志输出对象的输出格式 logging.SetBackend(backendFormatter).SetLevel(defaultLevel, "") //设置日志输出对象的日志级别 } //代码在common/flogging/logging.go
func InitFromSpec(spec string) string代码如下。
其中spec格式为:[[,...]=][:[[,...]=]...]。
此处传入spec为"",将""模块日志级别设置为defaultLevel,并会将modules初始化为defaultLevel。
levelAll := defaultLevel //defaultLevel为logging.INFO var err error if spec != "" { //如果spec不为空,则按既定格式读取 fields := strings.Split(spec, ":") //按:分割 for _, field := range fields { split := strings.Split(field, "=") //按=分割 switch len(split) { case 1: //只有level if levelAll, err = logging.LogLevel(field); err != nil { //levelAll赋值为logging.LogLevel枚举中定义的Level级别 levelAll = defaultLevel // 如果没有定义,则使用默认日志级别 } case 2: //针对module,module...=level,split[0]为模块集,split[1]为要设置的日志级别 levelSingle, err := logging.LogLevel(split[1]) //levelSingle赋值为logging.LogLevel枚举中定义的Level级别 modules := strings.Split(split[0], ",") //按,分割获取模块名 for _, module := range modules { logging.SetLevel(levelSingle, module) //本条规则中所有模块日志级别均设置为levelSingle } default: //... } } } logging.SetLevel(levelAll, "") // 将""模块日志级别设置为levelAll,如果logging.GetLevel(module)没找到时将使用""模块日志级别 for k := range modules { MustGetLogger(k) //获取模块日志级别,并更新modules } MustGetLogger(pkgLogID) //pkgLogID及其日志级别,更新至modules return levelAll.String() //返回levelAll //代码在common/flogging/logging.go
MustGetLogger会调取go-logging包中GetLevel(),附GetLevel()代码如下。
优先按module获取日志级别,如未找到则按""模块获取日志级别,如仍未找到则默认按DEBUG级别。
func (l *moduleLeveled) GetLevel(module string) Level { level, exists := l.levels[module] if exists == false { level, exists = l.levels[""] if exists == false { level = DEBUG } } return level } //代码在github.com/op/go-logging/level.go
3.2、flogging包封装的方法
flogging包封装的方法,如下:
func Reset() //全局变量初始化为默认值 func SetFormat(formatSpec string) logging.Formatter //设置并获取go-logging日志格式 func InitBackend(formatter logging.Formatter, output io.Writer) //创建一个日志输出对象并设置输出格式和日志级别 func DefaultLevel() string //获取defaultLevel func GetModuleLevel(module string) string //调用logging.GetLevel(module)获取模块日志级别 func SetModuleLevel(moduleRegExp string, level string) (string, error) //包装setModuleLevel func setModuleLevel(moduleRegExp string, level string, isRegExp bool, revert bool) (string, error) //设置模块日志级别并更新modules func MustGetLogger(module string) *logging.Logger //创建logging.Logger实例,获取模块日志级别,并更新modules func InitFromSpec(spec string) string //设置各模块日志级别,并更新modules func SetPeerStartupModulesMap() //modules内容复制给peerStartModules func GetPeerStartupLevel(module string) string //从peerStartModules中获取模块日志级别 func RevertToPeerStartupLevels() error //按peerStartModules中内容,设置模块日志级别并更新modules //代码在common/flogging/logging.go
4、grpclogger实现
grpclogger结构体定义:
type grpclogger struct { logger *logging.Logger } //代码在common/flogging/grpclogger.go
grpclogger初始化:
func initgrpclogger() { glogger := MustGetLogger(GRPCModuleID) //创建logging.Logger对象,获取模块日志级别,并更新modules grpclog.SetLogger(&grpclogger{glogger}) //用创建的logging.Logger对象设置grpclog } //代码在common/flogging/grpclogger.go
其他方法均为对go-logging的包装,代码如下:
func (g *grpclogger) Fatal(args ...interface{}) { g.logger.Fatal(args...) } func (g *grpclogger) Fatalf(format string, args ...interface{}) { g.logger.Fatalf(format, args...) } func (g *grpclogger) Fatalln(args ...interface{}) { g.logger.Fatal(args...) } // NOTE: grpclog does not support leveled logs so for now use DEBUG func (g *grpclogger) Print(args ...interface{}) { g.logger.Debug(args...) } func (g *grpclogger) Printf(format string, args ...interface{}) { g.logger.Debugf(format, args...) } func (g *grpclogger) Println(args ...interface{}) { g.logger.Debug(args...) } //代码在common/flogging/grpclogger.go
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Java性能优化的50个细节(珍藏版)
在JAVA程序中,性能问题的大部分原因并不在于JAVA语言,而是程序本身。养成良好的编码习惯非常重要,能够显著地提升程序性能。 1. 尽量在合适的场合使用单例 使用单例可以减轻加载的负担,缩短加载的时间,提高加载的效率,但并不是所有地方都适用于单例,简单来说,单例主要适用于以下三个方面: 第一,控制资源的使用,通过线程同步来控制资源的并发访问; 第二,控制实例的产生,以达到节约资源的目的; 第三,控制数据共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信。 2. 尽量避免随意使用静态变量 当某个对象被定义为static变量所引用,那么GC通常是不会回收这个对象所占有的内存,如 public class A{ private static B b = new B(); } 此时静态变量b的生命周期与A类同步,如果A类不会卸载,那么b对象会常驻内存,直到程序终止。 3. 尽量避免过多过常地创建Java对象 尽量避免在经常调用的方法,循环中new对象,由于系统不仅要花费时间来创建对象,而且还要花时间对这些对象进行垃圾回收和处理,在我们可以控制的范围内,最大限度地重用对象,最...
- 下一篇
CTF入门篇writeup——D0g3 Games
今天在网上找到一个CTF的小游戏,题目我做了几道感觉挺简单,很适合入门,之前了解CTF,参加各种杯或者是看各种比赛题的writeup,感觉太难了,想到这我还是决定从点滴做起,记录一下学习过程,同时也想做一套CTF从入门到精通的教程。 网址:http://ctf.d0g3.cn/ image.png 下面就简单记录下每道题的解题过程,希望能一点一点积累知识点 WEB 1. _GET 题目地址:http://106.12.21.77:8080/get/get.php image.png 题目分析:很简单了,通过get接受一个变量what,其值等于字符串flag. 解题方法: image.png 2. _POST 题目地址:http://106.12.21.77:8080/post/post.php image.png 题目分析:同理同上,只不过通过POST方式传参。 解题方法: image.png 3. 突破物理极限 题目地址:http://106.12.21.77:8080/length/length.html image.png 题目分析:根据提示输入12345提交,但是由于限制只能输...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
推荐阅读
最新文章
- SpringBoot2全家桶,快速入门学习开发网站教程
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- MySQL8.0.19开启GTID主从同步CentOS8
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Windows10,CentOS7,CentOS8安装Nodejs环境
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果