阅读 929

HyperLedgerFabric日志系统改造(源码改造)

目前fabric的日志系统是将所有的日志输出定向到stderr,这在生产环境中显然是不可以接受的,日志持久化成了一个亟待解决的问题。

本篇文章将从源码入手,改造fabric的日志系统,实现日志的持久化、日志自动切割等功能。

源码修改

环境准备

  1. 获取源码
go get github.com/hyperledger/fabric
复制代码
  1. 切换到 1.4.4版本(这里我本地已经搭建了1.4.4版本的fabric链,为了方便测试,选择1.4.4版本的源码进行修改)
git checkout v1.4.4
复制代码

修改源码

  1. 要支持日志自动切割、自动清理,需要用到一个日志切割框架https://github.com/lestrrat-go/file-rotatelogs

  2. fabric的日志模块在common/flogging下

  3. 经过摸索,问题定位到common/flogging/logging.go文件的Apply函数,

func (s *Logging) Apply(c Config) error {
  err := s.SetFormat(c.Format)
	if err != nil {
		return err
	}

	if c.LogSpec == "" {
		c.LogSpec = os.Getenv("FABRIC_LOGGING_SPEC")
	}
	if c.LogSpec == "" {
		c.LogSpec = defaultLevel.String()
	}

	err = s.LoggerLevels.ActivateSpec(c.LogSpec)
	if err != nil {
		return err
	}
	
  // 这行代码一定执行
	if c.Writer == nil {
		c.Writer = os.Stderr
	}
  s.SetWriter(c.Writer)
	var formatter logging.Formatter
	switch s.Encoding() {
	case JSON, LOGFMT:
		formatter = SetFormat(defaultFormat)
	default:
		formatter = SetFormat(c.Format)
	}
	InitBackend(formatter, c.Writer)
	return nil
}
复制代码

这个函数接收Config对象,而在common/flogging包的初始化方法中,Config仅仅只是毫无内容对象,所以c.Writer最终指向了os.Stderr。

func init() {
	logging, err := New(Config{})
	if err != nil {
		panic(err)
	}

	Global = logging
	logger = Global.Logger("flogging")
	grpcLogger := Global.ZapLogger("grpc")
	grpclog.SetLogger(NewGRPCLogger(grpcLogger))
}
复制代码

4.可以修改c.Writer使它指向文件输出,这里使用环境变量控制日志的持久化以及持久化的路径,完整代码如下

func (s *Logging) Apply(c Config) error {
	err := s.SetFormat(c.Format)
	if err != nil {
		return err
	}

	if c.LogSpec == "" {
		c.LogSpec = os.Getenv("FABRIC_LOGGING_SPEC")
	}
	if c.LogSpec == "" {
		c.LogSpec = defaultLevel.String()
	}

	err = s.LoggerLevels.ActivateSpec(c.LogSpec)
	if err != nil {
		return err
	}

	if c.Writer == nil {
		c.Writer = os.Stderr
	}
  // 如果开启了持久化,则持久化到文件,并且使用rotatelogs来管理日志
	if enable,err:=strconv.ParseBool(os.Getenv("FABRIC_LOG_PERSISTENCE"));err==nil&&enable{
		filePath:=os.Getenv("FABRIC_LOG_PERSISTENCE_PATH")
		if filePath == ""{
      // 持久化路径未配置的情况下,使用默认路径
			filePath = "/var/log/hyperledger/fabric/logs"
		}
		fileName := path.Join(filePath,"log")
		logWriter, err := rotatelogs.New(fileName + ".%Y%m%d.log",
			rotatelogs.WithLinkName(fileName),// 软链接
			rotatelogs.WithMaxAge(7*24*time.Hour), //日志保留7天
			rotatelogs.WithRotationTime(24*time.Hour))// 每天切割一次
		if err!=nil{
			panic("build logWriter failed")
		}
		c.Writer = logWriter
	}
	s.SetWriter(c.Writer)
	var formatter logging.Formatter
	switch s.Encoding() {
	case JSON, LOGFMT:
		formatter = SetFormat(defaultFormat)
	default:
		formatter = SetFormat(c.Format)
	}
	InitBackend(formatter, c.Writer)
	return nil
}
复制代码

构建镜像

官方已经写好了所有镜像制作过程,在根目录下执行即可(建议在linux下执行)

make all
复制代码

执行完后即可以看到制作好的镜像:

image-20200422192629784

可以想办法将镜像保存下来,通过docker save 或者将它推到镜像仓库。

运行测试

这里只需注意设置好环境变量即可

FABRIC_LOG_PERSISTENCE=true
FABRIC_LOG_PERSISTENCE_PATH=/var/run/hyperlerdger/fabric/peer/logs
复制代码
文章分类
阅读
文章标签