Spring Boot で micrometer を使ってメトリクスを計測・送信する

ベンダー非依存のインタフェースを提供する micrometer を使って、メトリクスを計測して外部のサービス (具体的には Datadog) に送信する方法のメモです。

はじめに

Web アプリケーションに代表されるように常時稼動し続けることを前提としたアプリケーションを構築して運用する場合、その稼働中のアプリケーション内部がどのような状態にあるのかを 定量的に 監視したいことがよくあるかと思います。アプリケーションの監視というと、こちらの ブログエントリ の定義を借りるならば「メトリクス」「トレーシング」「ロギング」といった 3 つの方法があり、定量的な監視はそのうちの メトリクス を計測することに当てはまるでしょう。

アプリケーション内で計測されたメトリクスはアプリケーション外部に送出することで、Datadog などのモニタリングシステムで可視化したり、設けられたしきい値に従ってアラートを発報する監視項目の設定に使えるようになります。なおモニタリングシステムは Datadog 以外にも様々ありますが、メトリクスを受信するためのインタフェースは必ずしも統一されているわけではなく、モニタリングシステムを提供するベンダーごとに異なるインタフェースが提供されています。

今回取り上げる micrometer はアプリケーションのコードに対し、特定のベンダーに依存することなくメトリクスを計測し、各種モニタリングシステムに送出するインタフェースを提供しています。

このブログエントリでは、Spring Boot 1.5.x もしくは 2.0.x で構築したアプリケーションを題材に、micrometer を使ってメトリクスを計測して Datadog に送信する具体的な方法についてメモしています。

Micrometer を Spring Boot アプリケーションに組み込む

Spring Boot アプリケーションに micrometer を導入する方法について、順を追って見ていきます (micrometer の公式ドキュメントを多分に参考にしています)。

依存ライブラリを追加する

まずは micrometer 関連のライブラリを Gradle (もしくは Maven) の依存に追加します。

Micrometer を利用するには、コアライブラリ (io.micrometer:micrometer-core) とモニタリングシステムごとのライブラリの両方を合わせて依存に追加します。なお、利用する Spring Boot のバージョンによって指定すべきアーティファクトが異なることに注意が必要です。

具体的には、以下の build.gradle の例にあるように、

とします。

plugins {
    id 'org.springframework.boot' version '2.0.0.RELEASE'
    // Spring Boot 1.5.x の場合はこちら
    // id 'org.springframework.boot' version '1.5.10.RELEASE'
}

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-web'

    // Spring Boot 2.0.x の場合
    compile('org.springframework.boot:spring-boot-starter-actuator') {
        // 最新バージョンの micrometer を使いたい場合は
        // 推移的依存から micrometer-core を exclude しておく
        exclude group: 'io.micrometer', module: 'micrometer-core'
    }
    compile group: 'io.micrometer', name: 'micrometer-core', version: '1.0.2'

    // Spring Boot 1.5.x の場合
    // compile group: 'io.micrometer', name: 'micrometer-spring-legacy', version: '1.0.2'

    // 以下は Spring Boot のバージョンに寄らず、メトリクスを送信する先の
    // モニタリングシステムにあったアーティファクトを指定する
​​    compile group: 'io.micrometer', name: 'micrometer-registry-datadog', version: '1.0.2'
}

モニタリングシステムごとのライブラリには、アーティファクトの名前に micrometer-registry- のプレフィックス が付与されています。これを手がかりに、お使いのモニタリングシステム向けのアーティファクトを依存ライブラリとして指定しましょう。

必要に応じて設定する

Spring Boot で micrometer を使うのであれば、auto-configuration によって設定をほとんど記述せずに使い始める準備が整います。

ただし、New Relic や Datadog のように API key の指定を必要とするモニタリングシステムにメトリクスを送る場合は、その限りではありません (何かしらの方法で API key をしないと、bean の生成に失敗してアプリケーションが起動しません)。例えば Datadog の API key を指定するなら、以下のように Spring Boot の設定ファイル (application.yml) に直接記述すれば OK です。

# Datadog の設定詳細については、こちらの URL を参照
# http://micrometer.io/docs/registry/datadog#_installation_and_configuration
management.metrics.export.datadog.apiKey: '(your_datadog_api_key)'

設定ファイルにパスワードをハードコードするのが躊躇われるのであれば、次のように実行時に環境変数を経由して設定するなどしましょう。

# 環境変数 DATADOG_API_KEY 経由で API key を設定する場合
management.metrics.export.datadog.apiKey: ${DATADOG_API_KEY}

また、すべてのメトリクスにアプリケーションで共通のタグを付与したり、メトリクス名にプレフィックスを付与したいことがあるかと思います。その場合は例えば下記のように、それに応じたコードを記述する必要があります。

import io.micrometer.core.instrument.*;
import io.micrometer.core.instrument.config.MeterFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.context.annotation.*;
import org.springframework.core.env.Environment;

@Configuration
public class BeanConfig {
    private final Environment env;

    @Autowired
    public BeanConfig(Environment env) {
        this.env = env;
    }

    @Bean
    public MeterRegistryCustomizer<MeterRegistry> customizer() {
        return registry -> registry.config()
                // メトリクス名に一律にプレフィックス 'example.' を付与する
                .meterFilter(new MeterFilter() {
                    @Override
                    public Meter.Id map(Meter.Id id) {
                        return id.withName("example." + id.getName());
                    }
                })
                // アプリケーションと実行環境 (Spring Boot のアクティブなプロファイル) でメトリクスを区別するためにタグを付与する
                .commonTags("app", "example-app")
                .commonTags("profile", env.getActiveProfiles().length > 0 ? env.getActiveProfiles()[0] : "none");
    }
}

メトリクスを計測する

依存ライブラリの追加と利用のための設定を終えれば、あとはアプリケーションコード上でメトリクス計測の実装をするだけです。

Spring Boot で micrometer を利用すると、以下に示す Spring Boot のドキュメント からの引用にあるように、CPU や JVM に関わるメトリクスなどのアプリケーションによらない標準的なメトリクスを自動的に計測してくれます。

  • JVM metrics, report utilization of:
    • Various memory and buffer pools
    • Statistics related to garbage collection
    • Threads utilization
    • Number of classes loaded/unloaded
  • CPU metrics
  • File descriptor metrics
  • Logback metrics: record the number of events logged to Logback at each level
  • Uptime metrics: report a gauge for uptime and a fixed gauge representing the application’s absolute start time
  • Tomcat metrics

上記以外のメトリクスを計測したい場合は、MeterRegistry の bean を用いて明示的にメトリクスを登録して計測する必要があります。 例えば、カウンタ1 を利用するのであれば、以下のような実装になります。

import io.micrometer.core.instrument.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
public class EchoController {
    private final Counter emptyCounter;

    @Autowired
    public EchoController(MeterRegistry meterRegistry) {
        // 空メッセージを受け取った件数をカウントするメトリクスを用意する
        emptyCounter = meterRegistry.counter("message.empty.count");
    }

    @RequestMapping("/")
    public String echo(@RequestParam(value = "message", required = false) String message) {
        if (message == null || message.isEmpty()) {
            // イベントが発生したところでカウンタをインクリメントする
            emptyCounter.increment();
            return "";
        }
        return message;
    }
}

Micrometer で Datadog にメトリクスを送る

ここまで Spring Boot のアプリケーションでメトリクスを計測する方法について見てきました。ここからは Datadog を対象として、micrometer によって計測したメトリクスを Datadog に送る具体的な方法について見ていきます。

Spring Boot アプリケーションから micrometer を使って Datadog にメトリクスを送る方法には、次の 2 つがあります。

この 2 つの方法はそれぞれ一長一短があるかと思いますが、例えば開発者個人のローカルの開発環境など、DogStatsD の稼動が期待できない環境では前者の方法でメトリクスが送られることを検証し、一方でプロダクション環境では datadog-agent を利用する前提で後者の方法を採用する、というように、環境によって使い分けることも考えられます。

この場合、依存ライブラリには両者のアーティファクトを指定しつつ、以下のように設定ファイルでプロファイルごとメトリクス送信先を切り替える必要があります。

# 開発時は直接 Datadog の API を呼び出す
spring.profiles: development

management:
  metrics:
    export:
      statsd:
        enabled: false
      datadog:
        enabled: true
        api-key: ${DATADOG_API_KEY}

---

# プロダクションでは、DogStatsD 経由で送る
spring.profiles: production

management:
  metrics:
    export:
      statsd:
        enabled: true
        flavor: datadog
      datadog:
        enabled: false

まとめ

  • Micrometer を使えば、特定のモニタリングシステムに依存しないインタフェースでメトリクスを計測できるよ
  • 特に Spring Boot で micrometer を使う場合は、設定も少量で済むし自動的に計測されるメトリクスもあって便利だよ

  1. Micrometer が提供するメトリクスの種類はカウンタ以外にもありますが、その他の種類のメトリクスについてはまた別の機会にご紹介します