公司一直使用的Filebeat进行日志采集
由于Filebeat采集组件一些问题,现需要使用iLogtail进行代替
现记录下iLogtail介绍和实际使用过程
这是iLogtail系列的第十篇文章
如何开发Input 插件
了解如何开发Input插件前你需要先了解Input 插件接口,目前的Input 插件分为2类,分别为MetricInput 与ServiceInput,分别为MetricInput可以由全局控制采集频率,适合Metric指标拉取等情况,ServiceInput 更适合接收外部输入情况,比如接收SkyWalking的Trace 数据推送。
MetricInput 接口定义
- Init:插件初始化接口,主要供插件做一些参数检查,并为其提供上下文对象 Context。 返回值的第一个参数表示调用周期(毫秒),插件系统会以该值作为数据获取周期。如果返回 0 的话,插件系统会使用全局的数据获取周期。 返回值的第二个参数表示初始化中发生的错误,一旦发生错误该插件实例将被忽略,插件系统不会向获取数据。
- Description:插件自描述接口。
- Collect: MetricInput 最关键的接口,插件系统通过此接口从插件实例中获取数据。插件系统会周期性地调用此接口,将数据收集到传入 Collector 中。
// MetricInput ...
type MetricInput interface {
// Init called for init some system resources, like socket, mutex...
// return call interval(ms) and error flag, if interval is 0, use default interval
Init(Context) (int, error)
// Description returns a one-sentence description on the Input
Description() string
// Collect takes in an accumulator and adds the metrics that the Input
// gathers. This is called every "interval"
Collect(Collector) error
}
MetricInput 开发
MetricInput 的开发分为以下步骤:
- 创建Issue,描述开发插件功能,会有社区同学参与讨论插件开发的可行性,如果社区review 通过,请参考步骤2继续进行。
- 实现MetricInput 接口,这里我们使用样例模式进行介绍,详细样例请查看input/example/metric,你可以使用 example.json 试验此插件功能。
- 通过init将插件注册到MetricInputs,MetricInputs插件的注册名(即json配置中的plugin_type)必须以"metric_"开头,详细样例请查看input/example/metric。
- 将插件加入全局插件定义中心, 如果仅运行于指定系统,请添加到Linux插件定义中心 或 Windows插件定义中心.
- 进行单测或者E2E测试,请参考如何使用单测 与 如何使用E2E测试.
- 使用 make lint 检查代码规范。
- 提交Pull Request。
ServiceInput 接口定义
- Init/Description:同 MetricInput 接口,但是 Init 的一个返回值对于 ServiceInput 没有意义,因为它不会被周期性调用。
- Start:由于 ServiceInput 的定位是常驻型输入,所以插件系统为此类型的插件实例都创建了独立的 goroutine,在 goroutine 中调用此接口来开始数据收集。Collector 的作用依旧是充当插件实例和插件系统之间的数据管道。
- Stop:提供终止插件的能力。插件必须正确地实现此接口,以避免 hang 住插件系统导致 Logtail 也无法正确退出。
// ServiceInput ...
type ServiceInput interface {
// Init called for init some system resources, like socket, mutex...
// return interval(ms) and error flag, if interval is 0, use default interval
Init(Context) (int, error)
// Description returns a one-sentence description on the Input
Description() string
// Start starts the ServiceInput's service, whatever that may be
Start(Collector) error
// Stop stops the services and closes any necessary channels and connections
Stop() error
}
ServiceInput 开发
ServiceInput 的开发分为以下步骤:
- 创建Issue,描述开发插件功能,会有社区同学参与讨论插件开发的可行性,如果社区review 通过,请参考步骤2继续进行。
- 实现 ServiceInput 接口,这里我们使用样例模式进行介绍,详细样例请查看input/example/service, 你可以使用 example.json 试验此插件功能。
- 通过init将插件注册到ServiceInputs,ServiceInputs插件的注册名(即json配置中的plugin_type)必须以"service_"开头,详细样例请查看input/example/service。
- 将插件加入全局插件定义中心, 如果仅运行于指定系统,请添加到Linux插件定义中心 或 Windows插件定义中心.
- 进行单测或者E2E测试,请参考如何使用单测 与 如何使用E2E测试.
- 使用 make lint 检查代码规范。
- 提交Pull Request。
如何开发Processor 插件
Processor 插件对输入数据进行二次加工,以下将从接口定义与案例2方面指导如何开发Processor 插件
Processor 接口定义
Processor 插件接口方法非常容易理解,除 Init/Description 这两个标准方法外,只有一个 ProcessLogs 接口,它的输入输出都是 []*Log,即接受一个 Log 列表,经过处理后返回一个 Log 列表。很自然地,processor 插件实例之间通过此接口构成了一个串行的处理链。
// Processor also can be a filter
type Processor interface {
// Init called for init some system resources, like socket, mutex...
Init(Context) error
// Description returns a one-sentence description on the Input
Description() string
// Apply the filter to the given metric
ProcessLogs(logArray []*protocol.Log) []*protocol.Log
}
Processor 开发
Processor 的开发分为以下步骤:
- 创建Issue,描述开发插件功能,会有社区同学参与讨论插件开发的可行性,如果社区review 通过,请参考步骤2继续进行。
- 实现Processor 接口,这里我们使用样例模式进行介绍,详细样例请查看processor/addfields,你可以使用 example.json 试验此插件功能。
- 通过init将插件注册到Processors,Processor插件的注册名(即json配置中的plugin_type)必须以"processor_"开头,详细样例请查看processor/addfields。
- 将插件加入全局插件定义中心, 如果仅运行于指定系统,请添加到Linux插件定义中心 或 Windows插件定义中心.
- 进行单测或者E2E测试,请参考如何使用单测 与 如何使用E2E测试.
- 使用 make lint 检查代码规范。
- 提交Pull Request。
如何开发Aggregator 插件
Aggregator 插件对输入数据进行打包,以下将从接口定义与案例2方面指导如何开发 Aggregator 插件
Aggregator 接口定义
Aggregator 插件的作用就是将一条条独立的 Log 根据一定规则聚合成 LogGroup,进而提交给下一级的 flusher 插件处理。
-
Add 接口供外部输入 Log
-
Flush 接口供外部获取聚合得到的 LogGroug
-
Reset 接口目前仅在内部使用,可以忽略
-
Init 接口,类似于 input 插件的 Init 接口,该接口返回值的第一个参数表示插件系统调用 Flush 接口的周期值,该值为 0 时使用全局参数,第二个参数表示一个初始化错误。 但不同于 input 插件,aggregator 插件的 Init 接口新增了一个 LogGroupQueue 类型的参数,该类型定义于 loggroup_queue.go 文件中,如下:
type LogGroupQueue interface { // Returns errAggAdd immediately if queue is full. Add(loggroup *LogGroup) error // Wait at most @duration if queue is full and returns errAggAdd if timeout. // Do not use this method if you are unsure. AddWithWait(loggroup *LogGroup, duration time.Duration) error }
该接口对应的实例实际上充当了一个队列,aggregator 插件实例可以将聚合得到的 LogGroup 对象立即通过 AddXXX 接口插入队列。 这是一个可选项,从之前的描述可以看到,Add->Flush 是一个周期性调用的数据链路,而 LogGroupQueue 可以提供一个实时性更高的链路,在 aggregator 一得到新聚合的 LogGroup 后就直接提交,不必等到 Flush 被调用。
但需要注意的是,在队列满的时候,Add 会返回错误,这一般意味着 flusher 发生了阻塞,比如网络异常。
// Aggregator is an interface for implementing an Aggregator plugin.
// the RunningAggregator wraps this interface and guarantees that
// Add, Push, and Reset can not be called concurrently, so locking is not
// required when implementing an Aggregator plugin.
type Aggregator interface {
// Init called for init some system resources, like socket, mutex...
// return flush interval(ms) and error flag, if interval is 0, use default interval
Init(Context, LogGroupQueue) (int, error)
// Description returns a one-sentence description on the Input.
Description() string
// Add the metric to the aggregator.
Add(log *protocol.Log) error
// Flush pushes the current aggregates to the accumulator.
Flush() []*protocol.LogGroup
// Reset resets the aggregators caches and aggregates.
Reset()
}
Aggregator 开发
Aggregator 的开发分为以下步骤:
- 创建Issue,描述开发插件功能,会有社区同学参与讨论插件开发的可行性,如果社区review 通过,请参考步骤2继续进行。
- 实现 Aggregator 接口,这里我们使用样例模式进行介绍,详细样例请查看aggregator/defaultone。
- 通过init将插件注册到Aggregators,Aggregator插件的注册名(即json配置中的plugin_type)必须以"aggregator_"开头,详细样例请查看aggregator/defaultone。
- 将插件加入全局插件定义中心, 如果仅运行于指定系统,请添加到Linux插件定义中心 或 Windows插件定义中心.
- 进行单测或者E2E测试,请参考如何使用单测 与 如何使用E2E测试.
- 使用 make lint 检查代码规范。
- 提交Pull Request。
如何开发 Flusher 插件
Flusher 插件与外部系统进行交互,将数据发送到外部,以下将从接口定义与案例2方面指导如何开发 Flusher 插件
Flusher 接口定义
-
Init: 插件初始化接口,对于Flusher 主要作用是创建外部资源链接
-
Description: 插件描述
-
IsReady:插件系统在调用 Flush 前会调用该接口检查当前 flusher 是否仍能够处理更多数据,如果答案为否的话,它会等待一段时间再重试。
-
Flush 接口是插件系统向 flusher 插件实例提交数据的入口,用于将数据输出到外部系统。为了映射到日志服务的概念中,我们增加了三个 string 参数,它代表这个 flusher 实例所属的 project/logstore/config。详细解释请参与数据结构 与 基本结构 。
-
SetUrgent: 标识iLogtail 即将退出,将系统状态传递给具体Flusher 插件,可以供Flusher 插件自动适应系统状态,比如加快输出速率等。(SetUrgent调用发生在其他类型插件的Stop之前,当前尚无有意义的实现)
-
Stop:停止Flusher 插件,比如断开与外部系统交互的链接
type Flusher interface {
// Init called for init some system resources, like socket, mutex...
Init(Context) error
// Description returns a one-sentence description on the Input.
Description() string
// IsReady checks if flusher is ready to accept more data.
// @projectName, @logstoreName, @logstoreKey: meta of the corresponding data.
// Note: If SetUrgent is called, please make some adjustment so that IsReady
// can return true to accept more data in time and config instance can be
// stopped gracefully.
IsReady(projectName string, logstoreName string, logstoreKey int64) bool
// Flush flushes data to destination, such as SLS, console, file, etc.
// It is expected to return no error at most time because IsReady will be called
// before it to make sure there is space for next data.
Flush(projectName string, logstoreName string, configName string, logGroupList []*protocol.LogGroup) error
// SetUrgent indicates the flusher that it will be destroyed soon.
// @flag indicates if main program (Logtail mostly) will exit after calling this.
//
// Note: there might be more data to flush after SetUrgent is called, and if flag
// is true, these data will be passed to flusher through IsReady/Flush before
// program exits.
//
// Recommendation: set some state flags in this method to guide the behavior
// of other methods.
SetUrgent(flag bool)
// Stop stops flusher and release resources.
// It is time for flusher to do cleaning jobs, includes:
// 1. Flush cached but not flushed data. For flushers that contain some kinds of
// aggregation or buffering, it is important to flush cached out now, otherwise
// data will lost.
// 2. Release opened resources: goroutines, file handles, connections, etc.
// 3. Maybe more, it depends.
// In a word, flusher should only have things that can be recycled by GC after this.
Stop() error
}
Flusher 开发
Flusher 的开发分为以下步骤:
- 创建Issue,描述开发插件功能,会有社区同学参与讨论插件开发的可行性,如果社区review 通过,请参考步骤2继续进行。
- 实现 Flusher 接口,这里我们使用样例模式进行介绍,详细样例请查看flusher/stdout
- 通过init将插件注册到Flushers,Flusher插件的注册名(即json配置中的plugin_type)必须以"flusher_"开头,详细样例请查看flusher/stdout。 ,你可以使用 example.json 试验此插件功能。
- 将插件加入全局插件定义中心, 如果仅运行于指定系统,请添加到Linux插件定义中心 或 Windows插件定义中心.
- 进行单测或者E2E测试,请参考如何使用单测 与 如何使用E2E测试.
- 使用 make lint 检查代码规范。
- 提交Pull Request。