Logstash输出到opentsdb碰到的问题及解决方案

引子

最近笔者在项目中用到了opentsdb,用于存放采集数据指标,并提供实时的图表、曲线展示功能。

opentsdb提供了自己的指标收集工具tcollector,故事就要从这里说起。

tcollector解决不了的事

笔者编写了一个抓包程序,用于实时分析MySQL中的请求情况,每10秒会输出一行记录到日志文件中,数据内容包括:

  • 时间点
  • 查询次数,查询响应时长,查询错误次数,查询影响的行数
  • 插入次数,插入响应时长,插入错误次数,插入影响的行数
  • ......

总之,指标我放到一个日志文件了,如果用tcollector去做的话,要采集这些指标就非常困难了。
主要的实现思路和要解决的问题有:

  • 文件变化通知
  • 新的日志文件的发现和通知
  • 每个文件上次处理的位置的记录
  • 接到文件和目录变化通知后,需要根据文件上次处理的位置来读取新的数据,并输出到opentsdb
  • 解决tcollector重启问题,需要持久化每个文件上次处理的位置记录信息

笔者开始确实写了一个版本出来,测试跑起来也没问题,但是批量上线后发现有大量的无法工作,笔者有些气馁了。因为大家都知道,上面的东西都是logstash的强项。

于是决定用logstash来解决这个问题。

logstash解决问题

缺省情况下logstash是没有opentsdb的插件的,需要下载插件并进行安装,我们可以在github上找到logstash-output-opentsdb插件,并按照官方知道的安装方法,把logstash-output-opentsdb插件进行安装。因为logstash的每个官方插件的README文件都介绍了具体安装步骤,笔者这里就不赘述了。

logstash-output-opentsdb插件存在的问题

安装好了插件,笔者于是写好配置文件,启动logstash。

output {
 
    opentsdb {
            host => "127.0.0.1"
            port => 4242
            metrics => [
                    "%{metris_name}",
                    "%{value}",
                    "ip",
                    "%{ip}",
                    "port",
                    "%{port}"
            ]
    }
}

数据果然进到logstash之中了,一起看起来都很简单顺畅,然而,大家可能也想到了一个问题,数据的时间戳呢???,我们并没有输入时间戳,那么插件是否帮我们正确的完成了呢?

这里就不得不检查一下插件的代码,这里我只展示关键的部分:

      # The first part of the message
      message = ['put',
                 event.sprintf(name),
                 event.sprintf("%{+%s}"),
                 event.sprintf(value),
      ].join(" ")

从上面的代码我们可以看出,该插件在每次输出metrics到opentsdb时,实时生成时间戳。这显然无法达到笔者的目的,而且在多数据日志抓取中,都会存在日志文件中已经有自己的时间戳,这时候希望输出到opentsdb的数据的时间戳是该日志中的时间戳。否则,一旦因为某些原因logstash重启,需要处理历史日志数据的时候,真实生成的时间戳数据就会与我们期望的大相近庭了。

改造logstash-output-opentsdb插件

从前面的代码看起来,我们除了改造以外,别无他法。

首先,logstash本身自带了@timestamp,而且是一个通用的变量;
其次,logstash提供了各种版本可以修改@timestamp的值;
所以,笔者决定在输出的时候,直接输出@timestamp的值作为opentsdb指标的时间戳。

改动的代码很简单,如下所示:

      # The first part of the message
      message = ['put',
                 event.sprintf(name),
                 event.get("@timestamp").to_i.to_s,
                 event.sprintf(value),
      ].join(" ")

当然我们还需要捕获日志中的时间,方法很多,这里列举一个例子:

grok {
  match => [ "message", "^%{NUMBER:@timestamp}" ]
}

上述改造后的logstash-output-opentsdbb插件,笔者已经在生产系统使用,同时上传到了笔者的github中,如果不想改造的话,可以直接下载使用。

你可能感兴趣的:(Logstash输出到opentsdb碰到的问题及解决方案)