fireworqのメトリクスを収集する方法について考えた

こんにちは。qudoを打倒している者です。

https://qiita.com/stk0724/items/269328262d5a1f0eaa28

以前上記の記事を書いたんですが、最近fireworqをサービスインしていくつかのqudoジョブをリプレイスしました。

動作は問題ないんですが、滞留してるジョブの数など、各種メトリクスがとれていない状態なので、今回はそれらのメトリクスをモニタリングする方法を考えます。


## mackerelを利用する

mackerelをモニタリングツールとして利用している場合、fireworq公式のmackerel-agent-pluginが存在するため、それを利用するだけで済みます。(fireworqははてな社が開発しているOSSです)

https://github.com/fireworq/mackerel-plugin-fireworq

## cloudwatch + telegrafを利用する

cloudwatchにメトリクスを保管する場合を考えます。

弊社はお金ないのでこちらです。

### メトリクスの収集パート

メトリクスの収集にはtelegrafを利用します。

https://www.influxdata.com/time-series-platform/telegraf/

telegrafはinfxludb社がOSSとして開発しているメトリクス収集用のエージェントです。

telegrafはプラグイン方式をとっており、様々なミドルウェアに対応したプラグインが存在します。
fireworq対応のプラグインは存在しないのですが、コマンド実行結果を入力として取り込むプラグイン「Exec」がありますので、こちらを利用してメトリクスを取り込みます。

https://docs.influxdata.com/telegraf/v1.18/plugins/#exec


>The Exec input plugin parses supported Telegraf input data formats (line protocol, JSON, Graphite, Value, Nagios, Collectd, and Dropwizard) into metrics

Execインプットプラグインでは、データフォーマットとして複数種のフォーマットに対応しているようです。ここではシンプルにJSONで取り込むことにします。

#### fireworqのメトリクス取得エンドポイントについて

fireworqにはGETリクエストでメトリクスを取得できるエンドポイントが用意されています。

たとえば、

- /queues/stats

を叩くと、以下のように各キューのメトリクスがJSON形式で返却されます

``` bash
curl ドメイン/queues/stats | jq .
```

``` json
{
  "default": {
    "total_pushes": 0,
    "total_pops": 0,
    "total_successes": 0,
    "total_failures": 0,
    "total_permanent_failures": 0,
    "total_completes": 0,
    "total_elapsed": 0,
    "pushes_per_second": 0,
    "pops_per_second": 0,
    "outstanding_jobs": 0,
    "total_workers": 20,
    "idle_workers": 20,
    "active_nodes": 1
  }
}
```

この例ですと、「default」がキュー名に相当します。

あとはゴニョゴニョ加工するなりして、Execインプットプラグインに入力すればよさそうです。


### mackerel-plugin-fireworqを流用できそう

上述のエンドポイントを自分で叩いてもいいんですが、mackerel-plugin-fireworqを流用する方法を考えます。

というのも、mackerel-plugin-fireworqは上述のメトリクスをいい感じに集約してmackerelに出力しているためです。
どういう風にデータを集約するかなど、なるべく自分で考えたくありません！！(怠惰

で、具体的にどう流用するかですが、mackerelのプラグインは単体実行できるコマンドとして提供されているため、mackerel-plugin-fireworqの実行結果をtelegrafのExecインプットプラグインに入力すればいいことになります。

しかし、mackerelプラグインは

```
項目名\t値\tタイムスタンプ
```

という複数行のTSVの形式でメトリクスを標準出力に出すため、そのままではExecインプットプラグインには取り込めません。

mackerel-plugin-fireworqの場合、以下のような出力になります。

```
fireworq.jobs.elapsed.jobs_average_elapsed_time 0       1620055407
fireworq.node.active_nodes      1       1620055407
fireworq.node.active_nodes_percentage   100     1620055407
fireworq.queue.workers.queue_idle_workers       20      1620055407
fireworq.queue.workers.queue_running_workers    0       1620055407
fireworq.queue.buffer.queue_outstanding_jobs    0       1620055407
fireworq.jobs.jobs_failure      0       1620055407
fireworq.jobs.jobs_success      0       1620055407
fireworq.jobs.jobs_outstanding  0       1620055407
fireworq.jobs.jobs_waiting      0       1620055407
fireworq.jobs.events.jobs_events_pushed 0       1620055407
fireworq.jobs.events.jobs_events_popped 0       1620055407
fireworq.jobs.events.jobs_events_failed 0       1620055407
fireworq.jobs.events.jobs_events_succeeded      0       1620055407
fireworq.jobs.events.jobs_events_completed      0       1620055407
```

上記のデータをJSONに加工できればよさそうです。

そこでgolangでちょっとしたCLIをしたためました。

https://github.com/stk132/kanning

canning(缶詰)をもじってkanningと命名しました。
mackerelがサバなので、それを加工するイメージです。(サバ缶的な

kanningはmackerel-agent-pluginの出力を標準入力からくわせると、JSONに整形して出力します。

たとえば、上記のmackerel-plugin-fireworqの出力を入力すると、

``` bash
cat _test/fireworq_metrics.tsv | kanning | jq .
```

以下のようになります。

``` json
{
  "jobs": {
    "elapsed": {
      "jobs_average_elapsed_time": 0
    },
    "events": {
      "jobs_events_completed": 0,
      "jobs_events_failed": 0,
      "jobs_events_popped": 0,
      "jobs_events_pushed": 0,
      "jobs_events_succeeded": 0
    },
    "jobs_failure": 0,
    "jobs_outstanding": 0,
    "jobs_success": 0,
    "jobs_waiting": 0
  },
  "node": {
    "active_nodes": 1,
    "active_nodes_percentage": 100
  },
  "queue": {
    "buffer": {
      "queue_outstanding_jobs": 0
    },
    "workers": {
      "queue_idle_workers": 20,
      "queue_running_workers": 0
    }
  }
}
```

現在、rootのfireworqとタイムスタンプは出力から落としています。

(kanningはテストまだ書いてないので、利用しないでください。しないと思いますが)

#### 最終的なtelegrafのinput設定

mackerel-plugin-fireworqとkanningを組み合わせると、Execインプットプラグインの設定は以下のようになります。

```
[[inputs.exec]]
  ## Commands array
  commands = [
    "/tmp/fireworq.sh"
  ]

  ## Timeout for each command to complete.
  timeout = "5s"

  ## measurement name suffix (for separating different commands)
  name_suffix = "_mycollector"

  ## Data format to consume.
  ## Each data format has its own unique set of configuration options, read
  ## more about them here:
  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md
  data_format = "json"

```

```shell:/tmp/fireworq.sh
#!/bin/sh
mackerel-plugin-fireworq | kanning
```

### メトリクスの入力パート(cloudwatchへの出力)

https://docs.influxdata.com/telegraf/v1.18/plugins/#output-plugins

cloudwatchへの出力用プラグインが存在しますので、そちらを利用しましょう。


### 余談

cloudwatch-agentはtelegrafのforkのようです。

https://github.com/aws/amazon-cloudwatch-agent

go.modでreplaceをかけてる

https://github.com/aws/amazon-cloudwatch-agent/blob/master/go.mod#L5

telegrafのExecインプットプラグインのようなものがあるかと期待したのですが、独自にメトリクスを取り込むような機能はオミットされているようなので、今回は利用を見送りました。

### 最後に

メトリクスコレクターって何を使うのがいいんでしょうか？

mackerelやdatadogを利用している場合、それぞれで提供されているエージェントを利用すればいいと思うのですが、cloudwatchを利用している場合、選択に悩みます。

今回は入力、出力に対応するプラグインが存在するということでtelegrafを利用しましたが、他に選択肢があればコメント欄でご教示いただけますと幸いです。