Docker中json日志驱动.构造函数的注册

  Docker提供了多种日志机制以动态记录容器运行过程中的痕迹。Docker通过"--log-driver"标志来指定使用哪种类型的日志驱动。在docker-1.12.6版本中合法的log driver包括json-file,journald,syslog等等,其中默认使用的是json-file。

  这里我们就以json-file为例子,来探索一下docker中的日志机制的运转过程。
  Docker充分利用了golang中提供的面向对象的机理,将各个不同的log driver的创建方法代理给一个工厂来执行,这样调用者就无需了解各个log driver的创建细节,只需要简单的知道自己使用的log driver的名字即可。

1 相关结构和变量

1.1 日志驱动的工厂结构

  日志驱动的工厂结构类型用于屏蔽具体的日志驱动实现,为日志驱动的使用者提供一个统一平台。

  ######daemon/logger/factory.go
type logdriverFactory struct {
	registry     map[string]Creator				//logdriver的构造方法
	optValidator map[string]LogOptValidator		//log option检查方法
	m            sync.Mutex						
}
  这个logdriverFactory中有三个成员:registry,optValidator和互斥锁m。
  其中registry是map[string]Creator类型,它以log driver的名字作为key,以log driver的构造方法作为value;
  与registry类似,optValidator也是map类型,只不过map的key对应的不是构造函数而是option检查函数。

1.2 log driver工厂实例

  在docker中,定义了一个工厂实例factory:

// global factory instance
var factory = &logdriverFactory{registry: make(map[string]Creator), optValidator: make(map[string]LogOptValidator)} 
  系统中所有log driver的构造方法都会注册到这个实例factory中。

1.3 json-file 日志驱动与构造器

  在docker中通过logger.Logger这个结构来表示所有的log driver,不过它只是一个接口类型,具体的日志驱动实现了根据自己的特点对logger.Logger提供的接口做了不同的实现。

// Logger is the interface for docker logging drivers.
type Logger interface {
	Log(*Message) error
	Name() string
	Close() error
}

  而json-file定义了自己的logger.Logger:

  ######daemon/logger/jsonfilelog/jsonfilelog.go

// JSONFileLogger is Logger implementation for default Docker logging.
type JSONFileLogger struct {
	buf     *bytes.Buffer
	writer  *loggerutils.RotateFileWriter
	mu      sync.Mutex
	readers map[*logger.LogWatcher]struct{} // stores the active log followers
	extra   []byte                          // json-encoded extra attributes
}

  JSONFileLogger要称为一个logger.Logger接口,必须实现Logger提供的Log()、Name()、Close()三个函数。其中最重要的就是Log()函数,它实现了具体的日志记录方法,这个后面涉及到。

1.4 日志驱动名字

  到此我们已经了解到日志驱动的注册都由factory屏蔽底层实现原理来统一安排,但是要使用不同的日志驱动如何来鉴别呢?答案就是日志驱动的“名字”。

  每个日志驱动都预定义了表示自己的 string类型的名字,这些名字都定义在各自的包中。这里的json日志驱动的名字为"json-file",定义如下:

// Name is the name of the file that the jsonlogger logs to.
const Name = "json-file"

  即json日志驱动的名字就叫"json-file",使用json日志时就用此名字来注册。

2 json-file 日志驱动构造器的注册

  前面已经了解到各个日志驱动的实例通过自己的构造方法来构造,而不同日志驱动的构造方法都注册到factory中以便为调用者提供统一的接口。下面来看下json-file构造器的注册。

  json-file的构造器是在jsonfilelog包的init()函数中注册的:

func init() {
	if err := logger.RegisterLogDriver(Name, New); err != nil {
		logrus.Fatal(err)
	}
	if err := logger.RegisterLogOptValidator(Name, ValidateLogOpt); err != nil {
		logrus.Fatal(err)
	}
}
  我们知道golang中包的init()函数比main()函数要先执行,因而在实际使用factory创建日志驱动之前,json-file就在自己的包中完成了初始化。jsonfilelog.init()完成两个事情:1) 注册日志驱动的构造方法;2) 注册日志参数检查器。下面我们来依次分析。

2.1 注册构造方法

  这一部分由logger.RegisterLogDriver(Name, New)来完成。我们来解释一下涉及到几个变量和参数:

    1) logger.RegisterLogDriver()函数定义在github.com/docker/docker/daemon/logger包中;

    2) Name在1.1节讲过,其值为"json-file";

    3) New是json日志驱动实现了Creator接口的构造方法。

  我们看下整个logger包的RegisterLogDriver()函数的细节:

// RegisterLogDriver registers the given logging driver builder with given logging
// driver name.
func RegisterLogDriver(name string, c Creator) error {
	return factory.register(name, c)
}
  看到RegisterLogDriver()函数是转手交给无所不能的factory处理:
func (lf *logdriverFactory) register(name string, c Creator) error {
	if lf.driverRegistered(name) {
		return fmt.Errorf("logger: log driver named '%s' is already registered", name)
	}

	lf.m.Lock()
	lf.registry[name] = c
	lf.m.Unlock()
	return nil
}

  factory.register()函数首先判断"json-file"这个名字是否已经注册;然后再将名字 "json-file"作为key,构造方法jsonfilelog.New()作为value放到factory.registry[]这个map中。

  到此,json日志驱动的构造方法就已经注册到factory中。后续有使用json日志驱动时,就可以通过"json-file"这个名字找到json日志驱动的构造方法jsonfilelog.New();进而通过jsonfilelog.New()创建出实现了logger.Logger接口的结构JSONFileLogger,然后就可以JSONFileLogger提供的方法来记录json日志了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值