filebeat 数据采集流程

filebeat启动流程 讲解了filebeat的启动流程,filebeat在构建完crawler对象,开始采集流程。


Crawlerstart方法内,会启动Inputs

func (c *Crawler) Start(
	pipeline beat.Pipeline,
	r *registrar.Registrar,
	configInputs *common.Config,
	configModules *common.Config,
	pipelineLoaderFactory fileset.PipelineLoaderFactory,
	overwritePipelines bool,
) error {

	...
	for _, inputConfig := range c.inputConfigs {
		err := c.startInput(pipeline, inputConfig, r.GetStates())
		if err != nil {
			return err
		}
	}

	...
}

c.startInput(pipeline, inputConfig, r.GetStates())方法初始化Input

  1. 首先构建Input对象
  2. 运行Input
func (c *Crawler) startInput(
	pipeline beat.Pipeline,
	config *common.Config,
	states []file.State,
) error {
	if !config.Enabled() {
		return nil
	}
	connector := channel.ConnectTo(pipeline, c.out)
	p, err := input.New(config, connector, c.beatDone, states, nil)
	...

	// 开始收集
	p.Start()

	return nil
}

p.Start()方法内启动Input,他在一个单独的协程里运行。

这里的p是对Input的封装,他的Run方法是对某个接口的实现,因为我们用来收集日志,所以我们只需要关心filebeat/input/log/input.go文件内的Run方法。Run方法内部调用了Inputscan方法,开始采集数据。

// Run runs the input
func (p *Input) Run() {
	...
	p.scan()

	...
}

scan方法内首先获取所有的文件。其次获取文件状态,根据状态来判定收集最新数据,还是从历史文件收集。文件收集会构建Harvester对象。

// Scan starts a scanGlob for each provided path/glob
func (p *Input) scan() {
	var sortInfos []FileSortInfo
	var files []string

	// 获取应该获取到的所有文件
	paths := p.getFiles()

	var err error

	...

	for i := 0; i < len(paths); i++ {

		var path string
		var info os.FileInfo

		if sortInfos == nil {
			path = files[i]
			info = paths[path]
		} else {
			path = sortInfos[i].path
			info = sortInfos[i].info
		}

		select {
		case <-p.done:
			logp.Info("Scan aborted because input stopped.")
			return
		default:
		}

		newState, err := getFileState(path, info, p)
		if err != nil {
			logp.Err("Skipping file %s due to error %s", path, err)
		}

		// Load last state
		lastState := p.states.FindPrevious(newState)
		...
		// Decides if previous state exists
		if lastState.IsEmpty() {
			logp.Debug("input", "Start harvester for new file: %s", newState.Source)
			// 准备构建 harvester 了
			err := p.startHarvester(newState, 0)
			if err == errHarvesterLimit {
				logp.Debug("input", harvesterErrMsg, newState.Source, err)
				continue
			}
			if err != nil {
				logp.Err(harvesterErrMsg, newState.Source, err)
			}
		} else {
			// 从历史文件开始处理
			p.harvestExistingFile(newState, lastState)
		}
	}
}

p.startHarvester(newState, 0)内构建harvester。(harvester是另一个filebeat官网描述的核心组件之一)

func (p *Input) startHarvester(state file.State, offset int64) error {
	if p.numHarvesters.Inc() > p.config.HarvesterLimit && p.config.HarvesterLimit > 0 {
		p.numHarvesters.Dec()
		harvesterSkipped.Add(1)
		return errHarvesterLimit
	}
	// Set state to "not" finished to indicate that a harvester is running
	state.Finished = false
	state.Offset = offset

	// Create harvester with state
	// 这部分构建了 harvester
	h, err := p.createHarvester(state, func() { p.numHarvesters.Dec() })
	if err != nil {
		p.numHarvesters.Dec()
		return err
	}

    // 配置 harvester
	err = h.Setup()
	if err != nil {
		p.numHarvesters.Dec()
		return fmt.Errorf("error setting up harvester: %s", err)
	}

	// Update state before staring harvester
	// This makes sure the states is set to Finished: false
	// This is synchronous state update as part of the scan
	h.SendStateUpdate()

	// 启动 harvester
	if err = p.harvesters.Start(h); err != nil {
		p.numHarvesters.Dec()
	}
	return err
}
  1. p.createHarvester构建harvester
  2. p.Setup配置harvesterSetup方法内会初始化文件相关的内容,以及构建文件reader
  3. p.harvesters.Start(h)运行harvester

主要还是要看harvesters.Start方法,会在单独的协程内运行harvester

func (r *Registry) Start(h Harvester) error {
	// Make sure stop is not called during starting a harvester
	r.Lock()
	defer r.Unlock()

	...

	go func() {
		defer func() {
			r.remove(h)
			r.wg.Done()
		}()
		// 异步运行
		err := h.Run()
		if err != nil {
			logp.Err("Error running input: %v", err)
		}
	}()
	return nil
}

harvester.Run方法真是长。。

func (h *Harvester) Run() error {
    // 这坨简直了
	for {
		...

		// 读取文件内容
		message, err := h.reader.Next()
		// 糟糕的异常处理。。。
		if err != nil {
			switch err {
			    ...
			}
			return nil
		}

		state := h.getState()
		startingOffset := state.Offset
		state.Offset += int64(message.Bytes)

		...
        // 读取到的文件内容
		text := string(message.Content)

        ...

		
		// 数据内容都包装在 data 内,harvester 发送 data,其实就是 forwarder 转发的
		if !h.sendEvent(data, forwarder) {
			return nil
		}

		// Update state of harvester as successfully sent
		h.state = state
	}
}

h.sendEvent(data, forwarder)这段代码将采集的数据发送到下游,内部其实就是用forwarder转发了数据。

到这里数据的采集流程应该就差不多了,剩下的是数据的发送流程。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值