Telegraf:Go 集成代理

导航到

收集代理是任何监控基础设施的关键部分:它们可以在您的宿主上运行,收集有关您的系统和应用程序的数据,或者它们可以在远程操作,通过您的应用程序暴露的端点在网络中收集数据。

2015年,InfluxData 发布了 Telegraf:一个由 Go 编写的轻量级、插件驱动的收集代理。虽然许多开发者已经使用各种收集代理将指标发送到 InfluxDB 和其他时间序列数据库,但 InfluxData 想要一个围绕标签度量概念设计的项目,这是 InfluxDB 和 OpenTSDB 等数据库中使用的数据模型。

Telegraf 具有基于插件的架构,并且设计成让用户可以轻松地为项目贡献功能,而无需了解任何代码库。Telegraf 有四种不同的插件类型:输入处理器聚合器输出插件,每个插件处理数据路径的一部分。自 2015 年成立以来,Telegraf 插件的数量已增长到超过 150 个——其中大部分都是由社区贡献的——使 Telegraf 能够从各种输入收集指标并将它们写入各种输出。

一些示例插件

  • postgresql — 一个输入插件,可以收集关于您 Postgres 安装的性能指标。它使用内置的 pg_stat_databasepg_stat_bgwriter 视图中的数据。
  • apache — 一个输入插件,使用 mod_status 模块从 Apache HTTP 服务器 收集服务器性能信息
  • prometheus — 一个输入插件,从暴露 Prometheus 格式指标的 HTTP 服务器收集指标。
  • influxdb — 一个输出插件,通过 HTTP 或 UDP 将数据写入 InfluxDB
  • opentsdb — 一个输出插件,通过“telnet”或 HTTP 模式将数据写入 OpenTSDB 实例

使用 Telegraf

如果您想运行 Telegraf,首先 安装 Telegraf

Telegraf具有根据您指定的插件生成配置文件的能力。您可以在运行Telegraf时使用-sample-config参数创建新的配置。

$ telegraf -sample-config -input-filter apache -output filter influxdb > telegraf.conf

这将创建一个位于您工作目录下的telegraf.conf文件。接下来,您可以使用新配置启动Telegraf。

$ telegraf -config telegraf.conf

如果您以服务形式运行Telegraf,则需要将新生成的配置文件放入适当的目录(例如Linux上的/etc/telegraf),然后重启Telegraf。在Debian / Ubuntu上,配置文件将放入/etc/telegraf,而可以使用systemctl restart telegraf命令重启Telegraf。

接口 & 编写插件

Telegraf使用Go接口实现插件。每种插件类型由一个接口定义,编写新插件就像实现这些接口并将您的插件导入Telegraf主包一样简单。

如果您已创建新插件,或修复或添加了现有插件的功能,请在GitHub上提交PR并分享您的辛勤工作!对于贡献者来说,还有一些额外的步骤需要完成,例如添加适当的文档和测试,您可以在Telegraf仓库中的贡献文档中找到更多关于这些信息。

该文档还提供了有关编写Telegraf不同插件接口的详细信息。

入门

如果您对开发自己的Telegraf插件感兴趣,您需要在您的机器上安装Go 1.5+。Golang网站有一个很好的入门指南,其中包含安装说明和下载页面链接。

安装Go后,使用go get下载Telegraf源代码,在git中检出您的工作分支,并尝试使用make构建二进制文件。

$ go get github.com/influxdata/telegraf
$ cd $GOPATH/github.com/influxdata/telegraf
$ git checkout -b MyPlugin $ make

源代码将被下载到您的Gopath中的src目录,而make命令将在bin目录下创建Telegraf二进制文件。

让我们看看一个现有的示例。Telegraf有一个名为Trig的插件,它通常用于演示目的,并基于三角函数正弦和余弦发出数据。我们将在下一节中介绍创建Trig插件的过程。

输入插件

首先,将以下行添加到telegraf/plugins/inputs/all/all.go

github.com/influxdata/telegraf/plugin/inputs/trig

以导入您的插件并确保Telegraf可以运行您编写的代码。因为任何创建插件的任何人都需要编辑此文件,所以在准备合并代码时可能会遇到合并冲突。但是,在开始本地开发之前添加此信息是必不可少的——没有它,您编写的代码将无法运行。

Telegraf的输入插件只需要满足三个接口。从Godoc

type Input interface { 
     // SampleConfig returns the default configuration of the Input 
     SampleConfig() string
     // Description returns a one-sentence description on the Input 
     Description() string
     // Gather takes in an accumulator and adds the metrics that the Input 
     // gathers. This is called every "interval" 
     Gather(Accumulator) error }

都使用DescriptionSampleConfig,Telegraf用于生成配置文件。Telegraf配置使用TOML编写;每个部分前面都有一个包含Description()函数返回的字符串的一行注释,后面是插件本身的配置变量,由SampleConfig()函数返回。

插件配置有一个变量,即amplitude

# Inserts sine and cosine waves for demonstration purposes 
[[inputs.trig]] 
  ## Set the amplitude 
  amplitude = 10.0

以下是trig.go中的实现

var TrigConfig = ` 
  ## Set the amplitude 
  amplitude = 10.0 
` 

func (s *Trig) SampleConfig() string { 
     return TrigConfig 
} 

func (s *Trig) Description() string { 
     return "Inserts sine and cosine waves for demonstration purposes" 
}

注意:在编写TOML配置时,请确保使用两个空格来缩进一行,而不是制表符,这样当Telegraf生成配置时,您的条目就可以很好地与其他条目对齐。

对于输入插件来说,最后的接口方法是Gather。这就是我们收集输入数据所有相关工作的地方。在这个阶段,它返回nil,因为我们还没有为Gather方法添加任何代码,但我们可以继续构建Telegraf并测试生成配置以确保其工作正常。

在您的当前工作目录中输入以下内容:

$ make $ telegraf -sample-config -input-filter trig -output-filter influxdb -debug

-debug标志会向输出添加额外的信息,以帮助识别您可能遇到的问题。

您应该在输出的底部看到以下内容:

# 
# INPUTS: 
# 

# Inserts sine and cosine waves for demonstration purposes 
[[inputs.trig]] 
  # Sets the amplitude 
  amplitude = 10.0

由于我们在配置中添加了配置参数,我们还需要在我们的结构体中添加相应的属性。您将在trig.go中看到以下行:

type Trig struct { 
     x float64 
     Amplitude float64 
}

Amplitude是我们配置中定义的值,而x是用于在收集间隔之间存储插件状态的变量。

经过测试并正常工作的配置,以及添加到结构体中的适当属性,我们现在可以为Gather方法创建实现。

Telegraf定期收集并将指标“刷新”到您的输出;收集和刷新间隔都可以在Telegraf配置中的[agent]部分定义,使用intervalflush_interval变量。如果您将前者设置为1s,后者设置为10s,Trig插件将每秒生成新点,但您不会看到它们出现在数据库中,直到Telegraf每10秒将数据刷新到数据库。

Gather()方法接受一个参数,即telegraf.Accumulator,它通过telegraf.Accumulator.AddFields(measurement, tags, fields)方法创建新的测量值。该方法接受三个参数:一个measurement,它是string类型;tags,它是一个字符串键和值的map[string]string;以及fields,它是一个键为字符串、字段为任何类型的map[string]interface{}

让我们看看Trig的Gather方法:

func (s *Trig) Gather(acc telegraf.Accumulator) error {
     sinner := math.Sin((s.x*math.Pi)/5.0) * s.Amplitude 
     cosinner := math.Cos((s.x*math.Pi)/5.0) * s.Amplitude 

     fields := make(map[string]interface{}) 
     fields["sine"] = sinner 
     fields["cosine"] = cosinner 

     tags := make(map[string]string) 

     s.x += 1.0 
     acc.AddFields("trig", fields, tags) 

     return nil 
}

首先,我们使用之前值以及我们在配置中定义的振幅,在正弦和余弦波上生成一个新的点。然后我们创建字段和标签,并分配适当的信息,在调用AddFields生成测量值之前,更新我们的状态以便下一次调用Gather

注意:在您设计Telegraf插件时,设计良好的模式非常重要。需要考虑的一个常见问题是所谓的“系列基数”,即您在数据库中存储的唯一系列数量。例如,如果您为每个测量值分配一个UUID,那么可以快速达到大量系列,这将影响数据库的内存使用和性能。

Trig插件所需的最后一件事是一个起始状态,我们将在trig.goinit函数中定义它。

func init() {
     inputs.Add("trig", func() telegraf.Input { return &Trig{x: 0.0} }) 
}

此函数接受整个插件并将其传递给Telegraf代理,然后每当收集间隔过去时,它都会遍历所有活动插件,并在每次收集间隔过去时调用Gather函数。

是时候测试了!让我们重新生成我们的配置并运行Telegraf

$ make 
$ telegraf -sample-config -input-filter trig -output-filter influxdb >> telegraf.conf.test 
$ telegraf -config telegraf.conf.test -debug

调试输出将显示插件正在运行并收集指标。

您在这个阶段也应该为您的插件编写一些测试。如果您想将您的插件贡献到上游,这是一个要求。每次有新的构建时都会运行测试,以捕获任何可能的回归或引入的问题。在Go中,编写测试相对简单,并且是语言本身的一部分。您将编写传递测试结构的方法,并使用它来断言插件的行为。您可以在相应的trig_test.go文件中找到trig.go的测试(GitHub上的链接)。

贡献

除了测试之外,您还需要为您的插件创建一个README.md文件,其中包含有关插件功能的信息。您还需要确保您有一个LICENSE文件和输入/输出格式的样本。如果您的插件有其他依赖项,您也想要添加这些依赖项。如果您有兴趣进行贡献,请查看GitHub上的优秀指南