SpringBootのActuatorでカスタムメトリクスをPrometheusに出力するときの注意点

757
NO IMAGE

概要

SpringBootのActuatorでPrometheusに出力した際に、カスタムメトリクスが正しく出力されませんでした。こちらの原因の調査にある程度時間がかかったので、原因と調査方法についてまとめます。

SpringBootのActuatorでPrometheusの出力を行う設定

以下のサイトに従って、Prometheusでメトリクスが取得できるようにします。
Spring Boot 2で/actuator/prometheusを有効にする

SpringBootでMicrometerのカスタムメトリクスを出力する

SpringBoot Actuatorはメトリクスの計測にMicrometerを利用しています。SpringBootは、Actuatorの設定をするとMicrometerのMeterRegistryを初期化してくれます。こちらを使って以下のように、Micrometerのカスタムメトリクスを導入します。
問題を単純にするためにAOPを使用しない方法で初期化します

@Component
public class MyService {

    @Autowired
    private MeterRegistry _registry;

    public void someMethod(String path) {
        Timer.Builder builder = Timer.builder("sample.metrics");
       builder.tags("path", path);
       var timer = builder.register(_registry);
       timer.record(()->{
          // 任意の処理
       });
    }
}

Prometheusにエクスポートする際の問題

上記のコードだと、Prometheus経由で正常にメトリクスを取得できるのですが、以下のコードだとタグなしのメトリクスは取得出来るのですが、pathタグありのものは取得できません。

@Component
public class MyService {

    @Autowired
    private MeterRegistry _registry;

    @PostConstruct
    public void initialize() {
        Timer.Builder builder = Timer.builder("sample.metrics");
       var timer = builder.register(_registry);

    }

    public void someMethod(String path) {
        Timer.Builder builder = Timer.builder("sample.metrics");
       builder.tags("path", path);
       var timer = builder.register(_registry);
       timer.record(()->{
          // 任意の処理
       });
    }
}

Micrometerでメトリクスが出力されない問題の調査方法

MeterRegistryには登録時に発生した問題をレポートする機能が用意されています。以下のようにしてそちらを利用します。


@Component
public class MyService {

    @Autowired
    private MeterRegistry _registry;

        @PostConstruct
        public void initialize() {
            _registry.config().onMeterRegistrationFailed((meterId, message)->{
                    System.out.println(meterId + ":" + message);
            });
            Timer.Builder builder = Timer.builder("sample.metrics");
           var timer = builder.register(_registry);
        }

        public void someMethod(String path) {
            Timer.Builder builder =     Timer.builder("sample.metrics");
        builder.tags("path", path);
           var timer = builder.register(_registry);
           timer.record(()->{
              // 任意の処理
        });
        }
}

上記のコードを実行すると、path指定のtimerを登録した際にエラーが発生している事が分かります。

今回の原因

Prometheusにエクスポートする際には、同一の名前を持つ測定器ではタグの種類を変える事が出来ませんでした。初期処理では、タグなしで登録し、メソッド実行時にはpathタグで登録したためにエラーになっていました。

結論

SpringBootでも、プレーンなMicrometerを使用するのとあまり変わらないイメージでMicrometerを使用できます。また問題が発生した場合には、エラーハンドラーを設定する事で、問題の解決が容易になります。