iLogtail专题十:iLogtail插件开发

 公司一直使用的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 的开发分为以下步骤:

  1. 创建Issue,描述开发插件功能,会有社区同学参与讨论插件开发的可行性,如果社区review 通过,请参考步骤2继续进行。
  2. 实现MetricInput 接口,这里我们使用样例模式进行介绍,详细样例请查看input/example/metric,你可以使用 example.json 试验此插件功能。
  3. 通过init将插件注册到MetricInputs,MetricInputs插件的注册名(即json配置中的plugin_type)必须以"metric_"开头,详细样例请查看input/example/metric。
  4. 将插件加入全局插件定义中心, 如果仅运行于指定系统,请添加到Linux插件定义中心 或 Windows插件定义中心.
  5. 进行单测或者E2E测试,请参考如何使用单测 与 如何使用E2E测试.
  6. 使用 make lint 检查代码规范。
  7. 提交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 的开发分为以下步骤:

  1. 创建Issue,描述开发插件功能,会有社区同学参与讨论插件开发的可行性,如果社区review 通过,请参考步骤2继续进行。
  2. 实现 ServiceInput 接口,这里我们使用样例模式进行介绍,详细样例请查看input/example/service, 你可以使用 example.json 试验此插件功能。
  3. 通过init将插件注册到ServiceInputs,ServiceInputs插件的注册名(即json配置中的plugin_type)必须以"service_"开头,详细样例请查看input/example/service。
  4. 将插件加入全局插件定义中心, 如果仅运行于指定系统,请添加到Linux插件定义中心 或 Windows插件定义中心.
  5. 进行单测或者E2E测试,请参考如何使用单测 与 如何使用E2E测试.
  6. 使用 make lint 检查代码规范。
  7. 提交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 的开发分为以下步骤:

  1. 创建Issue,描述开发插件功能,会有社区同学参与讨论插件开发的可行性,如果社区review 通过,请参考步骤2继续进行。
  2. 实现Processor 接口,这里我们使用样例模式进行介绍,详细样例请查看processor/addfields,你可以使用 example.json 试验此插件功能。
  3. 通过init将插件注册到Processors,Processor插件的注册名(即json配置中的plugin_type)必须以"processor_"开头,详细样例请查看processor/addfields。
  4. 将插件加入全局插件定义中心, 如果仅运行于指定系统,请添加到Linux插件定义中心 或 Windows插件定义中心.
  5. 进行单测或者E2E测试,请参考如何使用单测 与 如何使用E2E测试.
  6. 使用 make lint 检查代码规范。
  7. 提交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 的开发分为以下步骤:

  1. 创建Issue,描述开发插件功能,会有社区同学参与讨论插件开发的可行性,如果社区review 通过,请参考步骤2继续进行。
  2. 实现 Aggregator 接口,这里我们使用样例模式进行介绍,详细样例请查看aggregator/defaultone。
  3. 通过init将插件注册到Aggregators,Aggregator插件的注册名(即json配置中的plugin_type)必须以"aggregator_"开头,详细样例请查看aggregator/defaultone。
  4. 将插件加入全局插件定义中心, 如果仅运行于指定系统,请添加到Linux插件定义中心 或 Windows插件定义中心.
  5. 进行单测或者E2E测试,请参考如何使用单测 与 如何使用E2E测试.
  6. 使用 make lint 检查代码规范。
  7. 提交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 的开发分为以下步骤:

  1. 创建Issue,描述开发插件功能,会有社区同学参与讨论插件开发的可行性,如果社区review 通过,请参考步骤2继续进行。
  2. 实现 Flusher 接口,这里我们使用样例模式进行介绍,详细样例请查看flusher/stdout
  3. 通过init将插件注册到Flushers,Flusher插件的注册名(即json配置中的plugin_type)必须以"flusher_"开头,详细样例请查看flusher/stdout。 ,你可以使用 example.json 试验此插件功能。
  4. 将插件加入全局插件定义中心, 如果仅运行于指定系统,请添加到Linux插件定义中心 或 Windows插件定义中心.
  5. 进行单测或者E2E测试,请参考如何使用单测 与 如何使用E2E测试.
  6. 使用 make lint 检查代码规范。
  7. 提交Pull Request。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值