Datadog を用いて Prometheus Exporter の監視をする

# Motivation
Prometheus は最近デファクトスタンダードになる勢いで普及していて、メトリクス収集用の Prometheus Exporter も非常に多種多様なものが揃ってきたため、Datadog でもメトリクスの収集は Prometheus Exporter を用いて行いたい。

# prometheus_check.py
最新版の datadog agent の中には、現在 **prometheus_check.py** という Prometheus Exporter を監視するためのスクリプトが内包されています。

https://github.com/DataDog/dd-agent/blob/master/checks/prometheus_check.py

prometheus_check.py は AgentCheck クラス ( https://docs.datadoghq.com/ja/guides/agent_checks/ ) を継承しており、このまま Datadog の checks plugin として使用することができる、ようにみえるのですが、実際には check メソッドが以下のように実装されていないため、prometheus_check.py を用いて独自に拡張をする必要があります。

```python
def check(self, instance):
    """
    check should take care of getting the url and other params
    from the instance and using the utils to process messages and submit metrics.
    """
    raise NotImplementedError()
```

# latency-at/datadog-agent-prometheus
https://github.com/latency-at/datadog-agent-prometheus

prometheus_check.py の実装例として、上記のリポジトリで checks スクリプトが公開されていたので、今回はこちらを使用してみます。

上記リポジトリの check.d ディレクトリに prometheus.py ファイルが置かれており、こちらを datadog の checks.d ディレクトリに設置してあげると Datadog agent から呼び出すことができるようになります。

設定ファイルの書式は、README にも記載されていますが、以下のような形で指定をすることになります。

```yaml
init_config:
 
instances:
  - target: http://localhost:9100/metrics
    config:
      drop:
        - .*
      keep:
        - node_cpu.*
        - node_memory.*
```
target に監視すべき endpoint を指定します。その他拡張設定もいくつか行えるようです。

実装を見る限り、今は以下のような設定に対応しているようです。

- tags 
  - Datadog のタグとして付与したい文字列を指定します (foo:var,env:prd ...)
- format
  - Prometheus Exporter に接続するフォーマットを強制したい場合はここで指定します。
    - PROTOBUF
    - TEXT
- config.drops
  - メトリクスのうち、対象にしないものを明示的に指定できます。ワイルドカード指定可。
- config.keeps
  - メトリクスのうち、これだけは必ず対象として残す、というものを明示的に指定できます。drops で指定されていても、keeps の条件に合致するものはメトリクス対象となるようです。
- config.headers
  - Prometheus Exporter へのリクエスト時に送信する HTTP Header について指定します。

# Spring Metrics
実際に Prometheus Exporter を用意し、Datadog から Exporter に接続をしてメトリクスを収集してみたいと思います。

ここでは、Java のアプリケーションに対して Prometheus Exporter を設定してみます。Prometheus Exporter の Endpoint の設置には、Spring Metrics を使用してみます。

https://docs.spring.io/spring-metrics/docs/current/public/prometheus

実は Spring Metrics は標準で Datadog への連携機能が対応されています。。
ただ、Spring Boot のアプリケーション自体が Datadog の API Key 情報などを知っていないといけないことや、情報のバッファリングの部分が独自実装されているところを若干嫌い、よりシンプルなアーキテクチャで監視が実現できる Prometheus Exporter の機能の方を今回は選択します。

## pom.xml
以下のような形で Spring Metrics と、Prometheus の提供している simpleclient を追加すると、有効になります。

```xml
<dependency>
  <groupId>org.springframework.metrics</groupId>
  <artifactId>spring-metrics</artifactId>
  <version>${metrics.version}</version>
</dependency>
<dependency>
  <group>io.prometheus</group>
  <artifact>simpleclient_common</artifact>
  <version>${prom.version}</version>
</dependency>
```

## Java(Spring Boot Application)
**@EnablePrometheusMetrics** をアノテーションで設定することで、自動的に Prometheus の Endpoint が有効になります。

```java
@SpringBootApplication
@EnablePrometheusMetrics
public class Bootstrap {
    public static void main(String[] args) {
        SpringApplication.run(Bootstrap.class, args);
    }
}
```

Spring Boot Actuator であらかじめ /metrics というエンドポイントが使用されていることもあり、追加されるエンドポイントは /prometheus という名前になります。


```shell
$ curl http://localhost:8080/prometheus
# HELP jvm_buffer_total_capacity 
# TYPE jvm_buffer_total_capacity gauge
jvm_buffer_total_capacity{id="direct",} 81920.0
jvm_buffer_total_capacity{id="mapped",} 0.0
# HELP jvm_memory_committed 
# TYPE jvm_memory_committed gauge
jvm_memory_committed{id="Par Survivor Space",} 1.07347968E8
jvm_memory_committed{id="CMS Old Gen",} 2.147483648E9
jvm_memory_committed{id="Code Cache",} 7.2548352E7
jvm_memory_committed{id="Compressed Class Space",} 1.1145216E7
jvm_memory_committed{id="Metaspace",} 9.6305152E7
jvm_memory_committed{id="Par Eden Space",} 8.59045888E8
# HELP http_server_requests 
(snip.)
```

なお、Spring Metrics では **@Timed** というアノテーションを Controller クラスに追加してあげることで、その Controller に関する統計（ステータスコードごとの呼び出し回数など）を取得することができるようです。

その他、メトリクスの拡張については Spring Metrics のドキュメントに詳しいので、こちらを参照ください。

https://docs.spring.io/spring-metrics/docs/current/public/prometheus



# Datadog x Prometheus Exporter
実際に連携してみると、以下のような感じで Datadog に Prometheus Exporter の値が取り込めることが確認できます。

Prometheus Exporter の **jvm_memory_committed{id="Par Eden Space",}** などの書式についても、{} 内の値は Datadog の tag というかたちで翻訳されて Datadog 上で検索の絞り込みに使用できるようになっています。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/44364/d360aeda-5cc5-682e-ec9c-442273d3ea8c.png)


# まとめにかえて
Prometheus Exporter は非常に様々なものが提供されていて便利なので、Datadog を用いた監視にも使えると便利ですね。