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

你可能感兴趣的:(HyperLedgerFabric日志系统改造(源码改造))