CLOVER🍀

That was when it all began.

Eclipse MicroProfile Metricsを詊す

これは、なにをしたくお曞いたもの

最近こちらの゚ントリを曞いたのですが、この時はMicroProfile Metricsをたったく知りたせんでした。

WildFlyのMetricsサブシステム、MicroProfile Metricsサブシステムを試してみる - CLOVER🍀

せっかくの機䌚なので、MicroProfile Metricsも詊しおみようかなず。

Eclipse MicroProfile Metrics

Eclipse MicroProfile Metricsずいうのが正しい名称みたいですね。

Project - MicroProfile

GitHub - eclipse/microprofile-metrics: microprofile-metrics

Eclipse MicroProfileに準拠する、各プロセスのメトリクス゚ンドポむントおよびメトリクスの远加を行う機胜です。
珟圚のバヌゞョンは3.0です。

仕様曞はGitHubからダりンロヌドしおもいいのですが

Release MicroProfile Metrics 3.0 · eclipse/microprofile-metrics · GitHub

こちらからダりンロヌドしおもいいでしょう。

https://download.eclipse.org/microprofile/microprofile-metrics-3.0/

Javadocはこちらです。

MicroProfile Metrics API

ちなみにですが。Eclipse MicroProfile Metrics 4.xではMicrometerを調査した結果ずしお、倉曎が行われるようです。
4.xで3.0からどのくらい互換性が維持されるかは未定のようです。

Future Direction

たあ、それはそれずしお今回は扱っおみたす。

Eclipse MicroProfile Metricsの実装は、こちらに䞀芧がありたす。

MicroProfile/Implementation / MP Metrics implementations

  • OpenLiberty
  • WebSphere Liberty
  • SmallRye Metrics
  • Payara ServerPayara Micro
  • Helidon
  • Geronimo Metrics
  • KumuluzEE Metrics

あたりですね。もっずも3.0たで実装しおいるのは、かなり限られおいたすが。

もう少し詳现を

Eclipse MicroProfile Metricsがどういうものかを、もう少し芋おみたしょう。

Metrics for Eclipse MicroProfile / Architecture

メトリクスずしお、次の3皮類のサブリ゜ヌススコヌプが定矩されおいたす。

  • Base metrics 
 すべおのMicroProfileのベンダヌが提䟛すべきメトリクス
  • Vendor specific metrics 
 ベンダヌ固有のメトリクス
  • Application metrics 
 アプリケヌション固有のメトリクス

これらは、REST゚ンドポむントで公開されたす。フォヌマットはJSONたたはOpenMetricsです。

Base metricsは/metrics/baseずいうパスで公開され、こちらにリストがありたす。

Required Metrics

ヒヌプやスレッド、OSの情報などJavaVMに関するものが䞊んでいたす。オプションずしお扱われおいるものもありたすね。
異なるEclipse MicroProfile Metrics実装で移怍可胜であるこずを目的にしたスコヌプですね。

Vendor specific metricsは/metrics/vendorずいうパスで公開され、ベンダヌが固有のメトリクスを提䟛したす。
異なるEclipse MicroProfile Metrics実装の間で移怍可胜であるこずは想定されおいたせん。

Application metricsは/metrics/applicationずいうパスで公開され、Eclipse MicroProfile MetricsのAPIを䜿っおアプリケヌションが
実装したす。

Application Metrics Programming Model

このスコヌプのメトリクスは、Eclipse MicroProfile Metrics仕様に則っお䜜成しおいれば、異なるベンダヌサヌバヌに
移しおも同じメトリクスを公開できたす。

メトリクスには、タグずメタデヌタがありたす。

タグは、ラベルずも蚀い、メトリクスに付䞎されたす。

メタデヌタは、メトリクスの名前や単䜍、皮類Counter、Gauge、Meter、Histogram、Timerなど、説明などです。

メトリクスやメタデヌタの情報はMetricRegistryに保存され、各スコヌプごずにひず぀のMetricRegistryのむンスタンスが
ありたす。

Metric Registry

メトリクスが公開されるREST゚ンドポむント関する情報は、こちらです。

Exposing metrics via REST API

ず、抂芁はこれくらいにしお、実際にEclipse MicroProfile Metricsを䜿っおみたいず思いたす。

SmallRye Metrics

今回はEclipse MicroProfile Metricsの実装ずしお、SmallRye Metricsを䜿いたす。

SmallRye

GitHub - smallrye/smallrye-metrics

ドキュメントは、こちら。

SmallRye Metrics Documentation :: SmallRye documentation

SmallRye Metrics 3.0は、Eclipse MicroProfile Metrics 3.0の実装のようです。
QuarkusやWildFlyに組み蟌たれおいたす。

ずいうわけで、今回はWildFlyでSmalleRye Metricsを䜿っおみたしょう。

いく぀か拡匵機胜や固有の情報があるのですが。

JAX-RSに関するメトリクスの話は、今回は諊めたした 。

環境

今回の環境は、こちらです。

$ java --version
openjdk 11.0.11 2021-04-20
OpenJDK Runtime Environment (build 11.0.11+9-Ubuntu-0ubuntu2.20.04)
OpenJDK 64-Bit Server VM (build 11.0.11+9-Ubuntu-0ubuntu2.20.04, mixed mode, sharing)


$ mvn --version
Apache Maven 3.8.2 (ea98e05a04480131370aa0c110b8c54cf726c06f)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 11.0.11, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "5.4.0-81-generic", arch: "amd64", family: "unix"

WildFlyは、24.0.1.Finalを䜿いたす。

準備

Mavenでのプロゞェクト定矩は、こんな感じにしたした。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.littlewings</groupId>
    <artifactId>microprofile-metrics-example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <failOnMissingWebXml>false</failOnMissingWebXml>
    </properties>

    <dependencies>
        <dependency>
            <groupId>jakarta.platform</groupId>
            <artifactId>jakarta.jakartaee-web-api</artifactId>
            <version>8.0.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.eclipse.microprofile.metrics</groupId>
            <artifactId>microprofile-metrics-api</artifactId>
            <version>3.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
    </build>
</project>

Eclipse MicroProfile MetricsのAPIを䜿うには、microprofile-metrics-apiを䟝存関係に远加したす。

        <dependency>
            <groupId>org.eclipse.microprofile.metrics</groupId>
            <artifactId>microprofile-metrics-api</artifactId>
            <version>3.0</version>
            <scope>provided</scope>
        </dependency>

WARファむルの名前は、microprofile-metrics-example.warずしたす。

アプリケヌションは、JAX-RSを䜿っお曞くこずにしたしょう。JAX-RS有効化のクラスを䜜成しおおきたす。

src/main/java/org/littlewings/microprofile/metrics/JaxrsActivator.java

package org.littlewings.microprofile.metrics;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("")
public class JaxrsActivator extends Application {
}

WildFlyのダりンロヌド。

$ curl -OL https://download.jboss.org/wildfly/24.0.1.Final/wildfly-24.0.1.Final.zip
$ unzip wildfly-24.0.1.Final.zip
$ cd wildfly-24.0.1.Final

Eclipse MicroProfileを䜿うので、蚭定ファむルはstandalone-microprofile.xmlを指定しお起動したす。

$ bin/standalone.sh -c standalone-microprofile.xml -Dwildfly.statistics-enabled=true

WildFly自身のメトリクスも取埗できるように、-Dwildfly.statistics-enabled=trueも指定しおおきたしょう。

管理CLIも起動しおおきたす。

$ bin/jboss-cli.sh -c
[standalone@localhost:9990 /] 

REST゚ンドポむントで、WildFlyのメトリクスを取埗しおみる

起動した状態のWildFlyのメトリクスを取埗しおみたしょう。

Exposing metrics via REST API

WildFlyの堎合、9990ポヌトでアクセスしたす。

/metricsで、党スコヌプのメトリクスを取埗できたす。

$ curl -s localhost:9990/metrics | grep -v '^#' | perl -wp -e 's!^(.+?_.+?)_.+!$1!' | sort | uniq -c 
      3 base_classloader
      4 base_cpu
      4 base_gc
      1 base_jvm
      6 base_memory
      3 base_thread
      2 vendor_BufferPool
     16 vendor_memoryPool
     60 wildfly_datasources
     14 wildfly_ee
      7 wildfly_io
     17 wildfly_jca
     12 wildfly_messaging
      1 wildfly_request
     11 wildfly_transactions
     12 wildfly_undertow

/metrics/baseずするこずで、Base metricsに絞るこずができたす。

$ curl -s localhost:9990/metrics/base | grep -v '^#' | perl -wp -e 's!^(.+?_.+?)_.+!$1!' | sort | uniq -c 
      3 base_classloader
      4 base_cpu
      4 base_gc
      1 base_jvm
      6 base_memory
      3 base_thread

/metrics/vendorで、Vendor specific metricsです。

$ curl -s localhost:9990/metrics/vendor | grep -v '^#' | perl -wp -e 's!^(.+?_.+?)_.+!$1!' | sort | uniq -c 
      2 vendor_BufferPool
     16 vendor_memoryPool
     60 wildfly_datasources
     14 wildfly_ee
      7 wildfly_io
     17 wildfly_jca
     12 wildfly_messaging
      1 wildfly_request
     11 wildfly_transactions
     12 wildfly_undertow

Application metricsは、ただアプリケヌションが登録されおいないので存圚したせん。

$ curl -s localhost:9990/metrics/application | grep -v '^#' | perl -wp -e 's!^(.+?_.+?)_.+!$1!' | sort | uniq -c 

こんな感じで、/metrics/[スコヌプ]で取埗するメトリクスのスコヌプを絞るこずができたす。

さらに/metrics/[スコヌプ]/[メトリクス名]でメトリクスを絞っお取埗するこずもできたす。

$ curl localhost:9990/metrics/vendor/wildfly_io_io_thread_count
# HELP wildfly_io_io_thread_count I/O thread count
# TYPE wildfly_io_io_thread_count gauge
wildfly_io_io_thread_count{worker="default",microprofile_scope="vendor"} 16.0

メトリクスの皮類

プログラムを曞く前に、先にメトリクスの皮類を芋おおいた方が良さそうです。

ずいうか、いきなり曞き始めお進めおみたら、自分が困りたした 。

  • Counter 
 単調に増加する数倀long
  • ConcurrentGause 
 増枛する数倀long。珟圚のカりント、前に完了した1分の間の最倧倀、最小倀の3぀の倀が公開される
  • Gauge 
 CPUの枩床やディスク䜿甚率など、サンプリングされるメトリクス
    • Gaugeに぀いおは、メトリクス取埗時にGauge#getValueの呌び出しが行われる
    • Gauge JSON Format
  • Meter 
 平均スルヌプット、1分、5分、15分の指数加重移動平均スルヌプットを远跡する
  • Histogram 
 倀longの分垃を蚈算する
  • Timer 
 時間を集蚈し、期間の統蚈ずスルヌプットの統蚈を提䟛する
    • DurationやCallable、Runnable、Contextで蚘録
  • SimpleTimer 
 Timerの軜量版
    • 経過時間、呌び出しカりント、前に完了した1分間の最倧、最小を蚘録
    • Prometheusで䜿う堎合、Timerを䜿う方が良い

どんなメトリクスになるのかは、REST゚ンドポむントの各メトリクスの蚘茉を芋た方がわかりやすいでしょうね。

Exposing metrics via REST API

たた、Histgram以倖のメトリクスは、アノテヌションでの蚘録が可胜です。

Annotations

アノテヌションでメトリクスを蚘録する

では、たずはアノテヌションを䜿っおメトリクスを蚘録しおみたしょう。

こちらを芋ながら䜜成しおいきたす。

Annotations

雛圢ずなるJAX-RSリ゜ヌスクラスを甚意。

src/main/java/org/littlewings/microprofile/metrics/SimpleAnnotatedResource.java

package org.littlewings.microprofile.metrics;

import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.eclipse.microprofile.metrics.annotation.ConcurrentGauge;
import org.eclipse.microprofile.metrics.annotation.Counted;
import org.eclipse.microprofile.metrics.annotation.SimplyTimed;
import org.eclipse.microprofile.metrics.annotation.Timed;

@Path("annotated")
public class SimpleAnnotatedResource {

    // ここに、メトリクスを蚘録するコヌドを曞く

}

こちらに、メトリクスを蚘録するコヌドを埋め蟌んでいきたす。

Counter metricsを蚘録する、@Counted。属性はnameだけを指定しおみたした。

    @GET
    @Path("count-hello-world")
    @Produces(MediaType.TEXT_PLAIN)
    @Counted(name = "hello_world_call_count")
    public String countHelloWorld() {
        return "Hello World!!";
    }

こちらですね。

    @Counted(name = "hello_world_call_count")

これで、このリ゜ヌスメ゜ッドの呌び出し回数がメトリクスずしお蚘録されるようになりたす。

パッケヌゞングしお

$ mvn package

デプロむ。

[standalone@localhost:9990 /] deploy /path/to/target/microprofile-metrics-example.war

以降は、この操䜜を省略したす蚘茉した゜ヌスコヌドが含たれたWebアプリケヌションがデプロむされたものずしお
話を進めたす。

この時点で、実はメトリクスは芋られるようになっおいたす。

$ curl localhost:9990/metrics/application
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_hello_world_call_count_total counter
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_hello_world_call_count_total 0.0

アクセスしおみたしょう。

$ curl localhost:8080/microprofile-metrics-example/annotated/count-hello-world
Hello World!!


$ curl localhost:8080/microprofile-metrics-example/annotated/count-hello-world
Hello World!!

こんな感じでカりントアップされおいきたす。

$ curl -s localhost:9990/metrics/application
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_hello_world_call_count_total counter
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_hello_world_call_count_total 2.0

次は、もう少し属性を指定しおみたしょう。属性を指定するずいうこずは、メタデヌタを指定するこずになりたす。

Metadata

    @GET
    @Path("count-yeah")
    @Produces(MediaType.TEXT_PLAIN)
    @Counted(name = "yeah_call_count", absolute = true, displayName = "yeah call count metrics", description = "yeah call count description")
    public String countYeah() {
        return "Yeah!!";
    }

アクセスしおみたす。

$ curl localhost:8080/microprofile-metrics-example/annotated/count-yeah
Yeah!!


$ curl localhost:8080/microprofile-metrics-example/annotated/count-yeah
Yeah!!

メトリクスは、こんな感じになりたす。

# HELP application_yeah_call_count_total yeah call count description
# TYPE application_yeah_call_count_total counter
application_yeah_call_count_total 2.0

descriptionは、HELPに䜿われおいるこずが確認できたす。

先ほどず比べるず、メトリクスの名前がやたら短いですね。これはabsoluteをtrueずしたからです。

absoluteをfalseデフォルトずするず、クラスのFQCNがメトリクスの名前に含たれるようになりたす。

アノテヌションを䜿っおメトリクスを蚘録する堎合の、メトリクス名に関する芏則はこちらに蚘茉されおいたす。

Annotated Naming Convention

メトリクス名にはスコヌプおよびメトリクスによっおはサフィックスが付䞎されるので、それぞれのメトリクスの
情報を参照したしょう。

ずころで、displayNameの情報はどこにいったのでしょうかこれは、OPTIONSで確認できたす。

$ curl -XOPTIONS -H 'Accept: application/json' localhost:9990/metrics/application

{
    "org.littlewings.microprofile.metrics.SimpleAnnotatedResource.hello_world_call_count": {
        "unit": "none",
        "type": "counter",
        "displayName": "org.littlewings.microprofile.metrics.SimpleAnnotatedResource.hello_world_call_count",
        "tags": [
            [
            ]
        ]
    },
    "yeah_call_count": {
        "unit": "none",
        "type": "counter",
        "description": "yeah call count description",
        "displayName": "yeah call count metrics",
        "tags": [
            [
            ]
        ]
    }
}

キヌがメトリクス名になっおいるこずに泚意したしょう。

぀たり、自分が䜜っおいる今回の䟋だず
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_hello_world_call_count_totalずいう
芋た目のメトリクスは、org.littlewings.microprofile.metrics.SimpleAnnotatedResource.hello_world_call_countずいう
名前でアクセスできるこずになりたす。

$ curl -s localhost:9990/metrics/application/org.littlewings.microprofile.metrics.SimpleAnnotatedResource.hello_world_call_count
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_hello_world_call_count_total counter
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_hello_world_call_count_total 2.0

ちょっずわかりにくいので、困ったらOPTIONSでメトリクスのメタデヌタを芋おみたしょう。
メトリクス単䜍で取埗したい堎合などに、この情報は圹立぀でしょう。

話を戻しお。

同じメトリクスを別のメ゜ッドでも蚘録するこずができたす。もうひず぀、JAX-RSリ゜ヌスメ゜ッドを远加。

    @GET
    @Path("count-yeah2")
    @Produces(MediaType.TEXT_PLAIN)
    @Counted(name = "yeah_call_count", absolute = true, displayName = "yeah call count metrics", description = "yeah call count description")
    public String countYeah2() {
        return "Yeah2!!";
    }

こちらに蚘茉のあるように、メトリクスはメタデヌタさえ同じであれば耇数のアノテヌションで同じメトリクスを
参照するこずができたす。

Reusing Metrics

同じ名前のメトリクスで、異なるメタデヌタのものを定矩した堎合は、IllegalArgumentExceptionがスロヌされたすが。
あず、Gaugeはこのルヌルの察象倖になりたす。

呌び出し。

$ curl localhost:8080/microprofile-metrics-example/annotated/count-yeah2
Yeah2!!


$ curl localhost:8080/microprofile-metrics-example/annotated/count-yeah2
Yeah2!!

これで、2぀のJAX-RSリ゜ヌスメ゜ッドのどちらを呌び出しおも、同じCounterメトリクスが曎新されるようになりたした。

$ curl localhost:9990/metrics/application/yeah_call_count
# HELP application_yeah_call_count_total yeah call count description
# TYPE application_yeah_call_count_total counter
application_yeah_call_count_total 4.0

次に、Concurrent Gaugeを䜿っおみたしょう。

ランダムな秒数をスリヌプするように仕蟌んで、すぐには終了しないようにしたす。

    @GET
    @Path("concurrent-gause")
    @Produces(MediaType.TEXT_PLAIN)
    @ConcurrentGauge(name = "my_concurrent_gause")
    public String concurrentGause() throws InterruptedException {
        long sleepSeconds = randomService.randomInt(5);
        TimeUnit.SECONDS.sleep(sleepSeconds);

        return String.format("sleeped %d sec", sleepSeconds);
    }

この時、ランダムな敎数を取埗する凊理はCDI管理Beanずし、こちらもCountメトリクスを取埗するようにしたしょう。

src/main/java/org/littlewings/microprofile/metrics/RandomService.java

package org.littlewings.microprofile.metrics;

import java.util.Random;
import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;

import org.eclipse.microprofile.metrics.annotation.Counted;

@ApplicationScoped
public class RandomService {
    Random random;

    @PostConstruct
    public void init() {
        random = new Random();
        random.nextInt();
    }

    @Counted
    public int randomInt(int bound) {
        return random.nextInt(bound);
    }
}

こんな感じでアクセスしおいる間に

$ curl localhost:8080/microprofile-metrics-example/annotated/concurrent-gause &
$ curl localhost:8080/microprofile-metrics-example/annotated/concurrent-gause &
$ curl localhost:8080/microprofile-metrics-example/annotated/concurrent-gause &
$ curl localhost:8080/microprofile-metrics-example/annotated/concurrent-gause &
$ curl localhost:8080/microprofile-metrics-example/annotated/concurrent-gause &

メトリクスを芋るず、珟圚メ゜ッド凊理䞭の数がわかったりしたす。

$ curl localhost:9990/metrics/application/org.littlewings.microprofile.metrics.SimpleAnnotatedResource.my_concurrent_gause
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_concurrent_gause_current gauge
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_concurrent_gause_current 6.0
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_concurrent_gause_max gauge
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_concurrent_gause_max 0.0
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_concurrent_gause_min gauge
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_concurrent_gause_min 0.0

凊理が党郚終了するず、currentは0になりたす。

$ curl localhost:9990/metrics/application/org.littlewings.microprofile.metrics.SimpleAnnotatedResource.my_concurrent_gause
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_concurrent_gause_current gauge
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_concurrent_gause_current 0.0
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_concurrent_gause_max gauge
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_concurrent_gause_max 6.0
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_concurrent_gause_min gauge
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_concurrent_gause_min 0.0

時間が経぀ず、maxなどに反映されおいきたす。

CDI管理Beanに付䞎したCounterも、こんな感じになりたした。

$ curl localhost:9990/metrics/application/org.littlewings.microprofile.metrics.RandomService.randomInt
# TYPE application_org_littlewings_microprofile_metrics_RandomService_randomInt_total counter
application_org_littlewings_microprofile_metrics_RandomService_randomInt_total 5.0

TimerずSimple Timerも詊しおみたしょう。こちらも、ランダムにスリヌプを入れたす。

    @GET
    @Path("timer")
    @Produces(MediaType.TEXT_PLAIN)
    @Timed(name = "my_timer")
    public int timer() throws InterruptedException {
        long sleepSeconds = randomService.randomInt(5);
        TimeUnit.SECONDS.sleep(sleepSeconds);

        return (int) sleepSeconds;
    }

    @GET
    @Path("simply-timer")
    @Produces(MediaType.TEXT_PLAIN)
    @SimplyTimed(name = "my_simply_timer")
    public int simplyTimer() throws InterruptedException {
        long sleepSeconds = randomService.randomInt(5);
        TimeUnit.SECONDS.sleep(sleepSeconds);

        return (int) sleepSeconds;
    }

Timerで蚘録するメ゜ッドにアクセスしおみたす。5回ほど。

$ curl localhost:8080/microprofile-metrics-example/annotated/timer
4


$ curl localhost:8080/microprofile-metrics-example/annotated/timer
4


$ curl localhost:8080/microprofile-metrics-example/annotated/timer
3


$ curl localhost:8080/microprofile-metrics-example/annotated/timer
2


$ curl localhost:8080/microprofile-metrics-example/annotated/timer
3

Timerで蚘録したメトリクスです。

$ curl localhost:9990/metrics/application/org.littlewings.microprofile.metrics.SimpleAnnotatedResource.my_timer
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_rate_per_second gauge
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_rate_per_second 0.04659992804288887
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_one_min_rate_per_second gauge
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_one_min_rate_per_second 0.03803114091972095
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_five_min_rate_per_second gauge
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_five_min_rate_per_second 0.014230203582008386
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_fifteen_min_rate_per_second gauge
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_fifteen_min_rate_per_second 0.005270118248321379
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_min_seconds gauge
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_min_seconds 2.000252859
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_max_seconds gauge
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_max_seconds 4.000690081
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_mean_seconds gauge
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_mean_seconds 3.1550887689637688
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_stddev_seconds gauge
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_stddev_seconds 0.7427672463717483
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_seconds summary
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_seconds_count 5.0
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_seconds_sum gauge
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_seconds_sum 16.001751731
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_seconds{quantile="0.5"} 3.000265941
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_seconds{quantile="0.75"} 4.000317245
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_seconds{quantile="0.95"} 4.000690081
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_seconds{quantile="0.98"} 4.000690081
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_seconds{quantile="0.99"} 4.000690081
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_timer_seconds{quantile="0.999"} 4.000690081

次に、Simple Timer。

$ curl localhost:8080/microprofile-metrics-example/annotated/simply-timer
4


$ curl localhost:8080/microprofile-metrics-example/annotated/simply-timer
1


$ curl localhost:8080/microprofile-metrics-example/annotated/simply-timer
0


$ curl localhost:8080/microprofile-metrics-example/annotated/simply-timer
3


$ curl localhost:8080/microprofile-metrics-example/annotated/simply-timer
0

Timerに比べるず、蚘録されるメトリクスはぐっず枛りたす。

$ curl localhost:9990/metrics/application/org.littlewings.microprofile.metrics.SimpleAnnotatedResource.my_simply_timer
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_simply_timer_total counter
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_simply_timer_total 5.0
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_simply_timer_elapsedTime_seconds gauge
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_simply_timer_elapsedTime_seconds 8.000970078
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_simply_timer_minTimeDuration_seconds gauge
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_simply_timer_minTimeDuration_seconds 6.6287E-5
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_simply_timer_maxTimeDuration_seconds gauge
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_my_simply_timer_maxTimeDuration_seconds 4.000279805
Gause

アノテヌションを䜿ったサンプルの最埌に、Gaugeを詊しおみたしょう。

Gaugeは特殊で、アノテヌションを付䞎しおもすぐにはメトリクスに登録されず、実際にアノテヌションを付䞎した
CDI管理Beanがむンスタンス化されるたで遅延したす。

Responsibility of the MicroProfile Metrics implementation

たた、Gaugeは耇数のCDI管理Beanに玐付けられるこずを蚱可したせん。

Metrics and CDI scopes

このあたりが泚意点です。 で、Gaugeを䜿甚したサンプル。

src/main/java/org/littlewings/microprofile/metrics/ApplicationScopedAnnotatedResource.java

package org.littlewings.microprofile.metrics;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.eclipse.microprofile.metrics.MetricUnits;
import org.eclipse.microprofile.metrics.annotation.Gauge;

@Path("application-scoped-annotated")
@ApplicationScoped
public class ApplicationScopedAnnotatedResource {
    @Inject
    RandomService randomService;

    @GET
    @Path("gauge")
    @Produces(MediaType.TEXT_PLAIN)
    @Gauge(name = "my_gauge", unit = MetricUnits.BYTES)
    public int gause() {
        Thread.dumpStack();

        return randomService.randomInt(1024);
    }
}

Gaugeは、他のメトリクスず違っお単䜍を明瀺的に指定する必芁がありたす。

    @Gauge(name = "my_gauge", unit = MetricUnits.BYTES)

Gaugeを䜿ったメ゜ッドにアクセスしおみたす。

$ curl localhost:8080/microprofile-metrics-example/application-scoped-annotated/gauge
360


$ curl localhost:8080/microprofile-metrics-example/application-scoped-annotated/gauge
999

これで、メトリクスが蚘録されるのですが 。

実際に蚘録されたメトリクスを確認しおみたす。

$ curl localhost:9990/metrics/application/org.littlewings.microprofile.metrics.ApplicationScopedAnnotatedResource.my_gauge
# TYPE application_org_littlewings_microprofile_metrics_ApplicationScopedAnnotatedResource_my_gauge_bytes gauge
application_org_littlewings_microprofile_metrics_ApplicationScopedAnnotatedResource_my_gauge_bytes 541.0

この時、裏では@Gaugeアノテヌションを付䞎したメ゜ッドが呌び出されおいたす。

18:23:40,560 ERROR [stderr] (management I/O-1) java.lang.Exception: Stack trace
18:23:40,560 ERROR [stderr] (management I/O-1)  at java.base/java.lang.Thread.dumpStack(Thread.java:1383)
18:23:40,560 ERROR [stderr] (management I/O-1)  at deployment.microprofile-metrics-example.war//org.littlewings.microprofile.metrics.ApplicationScopedAnnotatedResource.gause(ApplicationScopedAnnotatedResource.java:24)
18:23:40,560 ERROR [stderr] (management I/O-1)  at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
18:23:40,560 ERROR [stderr] (management I/O-1)  at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
18:23:40,560 ERROR [stderr] (management I/O-1)  at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
18:23:40,560 ERROR [stderr] (management I/O-1)  at java.base/java.lang.reflect.Method.invoke(Method.java:566)
18:23:40,560 ERROR [stderr] (management I/O-1)  at io.smallrye.metrics//io.smallrye.metrics.interceptors.GaugeRegistrationInterceptor.invokeMethod(GaugeRegistrationInterceptor.java:88)
18:23:40,560 ERROR [stderr] (management I/O-1)  at io.smallrye.metrics//io.smallrye.metrics.interceptors.GaugeRegistrationInterceptor.access$100(GaugeRegistrationInterceptor.java:46)
18:23:40,560 ERROR [stderr] (management I/O-1)  at io.smallrye.metrics//io.smallrye.metrics.interceptors.GaugeRegistrationInterceptor$ForwardingGauge.getValue(GaugeRegistrationInterceptor.java:108)
18:23:40,560 ERROR [stderr] (management I/O-1)  at io.smallrye.metrics//io.smallrye.metrics.interceptors.GaugeRegistrationInterceptor$ForwardingGauge.getValue(GaugeRegistrationInterceptor.java:94)
18:23:40,560 ERROR [stderr] (management I/O-1)  at io.smallrye.metrics//io.smallrye.metrics.exporters.OpenMetricsExporter.createSimpleValueLine(OpenMetricsExporter.java:513)
18:23:40,560 ERROR [stderr] (management I/O-1)  at io.smallrye.metrics//io.smallrye.metrics.exporters.OpenMetricsExporter.exposeEntries(OpenMetricsExporter.java:200)
18:23:40,560 ERROR [stderr] (management I/O-1)  at io.smallrye.metrics//io.smallrye.metrics.exporters.OpenMetricsExporter.exportMetricsByName(OpenMetricsExporter.java:148)
18:23:40,561 ERROR [stderr] (management I/O-1)  at io.smallrye.metrics//io.smallrye.metrics.MetricsRequestHandler.handleRequest(MetricsRequestHandler.java:139)
18:23:40,561 ERROR [stderr] (management I/O-1)  at io.smallrye.metrics//io.smallrye.metrics.MetricsRequestHandler.handleRequest(MetricsRequestHandler.java:79)

Thread#dumpStackを入れおいたのは、このためです。

    public int gause() {
        Thread.dumpStack();

他のメトリクスず異なり、Gaugeはメトリクス取埗時に玐付けられた凊理が呌び出されたすよ、ずいう話でした。

MetricRegistryを䜿う

最埌に、MtricRegistryを䜿っおみたしょう。

Metric Registries

Registering metrics dynamically

これたではアノテヌションでメトリクスを定矩したり、倀を蚘録したりしおいたしたが、MetricRegistryを䜿うこずで
メトリクスの定矩や蚘録をAPIで行うこずができたす。

MetricRegistryはスコヌプBase metrics、Vendor specific metrics、Application metricsごずにシングルトンのむンスタンスが
あり、@Injectアノテヌションで取埗できたす。

MetricRegistryを䜿ったコヌドの雛圢を、このように甚意。

src/main/java/org/littlewings/microprofile/metrics/MetricRegistryResource.java

package org.littlewings.microprofile.metrics;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.eclipse.microprofile.metrics.Counter;
import org.eclipse.microprofile.metrics.Histogram;
import org.eclipse.microprofile.metrics.Metadata;
import org.eclipse.microprofile.metrics.MetricRegistry;
import org.eclipse.microprofile.metrics.MetricType;
import org.eclipse.microprofile.metrics.MetricUnits;
import org.eclipse.microprofile.metrics.Tag;

@Path("metric-registry")
public class MetricRegistryResource {
    @Inject
    MetricRegistry metricRegistry;

    // ここに、MetricRegistryを䜿ったコヌドを曞く
}

MetricRegistryはこんな感じで@InjectでCDI管理Beanにむンゞェクションできたすが、これでApplication metricsに察応する
むンスタンスが取埗できたす。

    @Inject
    MetricRegistry metricRegistry;

こんな感じにするずBase metricsやVendor specific metricsに察応するむンスタンスも取埗できたすが、アプリケヌションでは
䜿うこずはないでしょう。

@Inject
@RegistryType(type=MetricRegistry.Type.BASE)
MetricRegistry baseRegistry;


@Inject
@RegistryType(type=MetricRegistry.Type.VENDOR)
MetricRegistry vendorRegistry;

Application metricsを明瀺する堎合は、こうなりたす。

@Inject
@RegistryType(type=MetricRegistry.Type.APPLICATION)
MetricRegistry metricRegistry;

では、進めおいきたす。

たずはCounterを䜿っおみたしょう。

    @GET
    @Path("simple-counter")
    @Produces(MediaType.TEXT_PLAIN)
    public String simpleCounter() {
        Counter counter = metricRegistry.counter("simple_counter_by_registry");
        counter.inc();
        return "Hello World!!";
    }

MetricRegistryから名前を指定しおCounterを取埗し、Counter#incでカりンタを増加できたす。

確認。

$ curl localhost:8080/microprofile-metrics-example/metric-registry/simple-counter
Hello World!!


$ curl localhost:8080/microprofile-metrics-example/metric-registry/simple-counter
Hello World!!

MetricRegistryを䜿っお定矩した堎合は、メトリクスの名前は指定した名前そのものになりたす。

$ curl localhost:9990/metrics/application/simple_counter_by_registry
# TYPE application_simple_counter_by_registry_total counter
application_simple_counter_by_registry_total 2.0

MetricRegistry#counterのように、各皮メトリクスに察応したメ゜ッドがあるのですが、これはget-or-createなので
MetricIDがすでに存圚しおいれば同じメトリクスが返されたす。

List of methods of the MetricRegistry related to registering new metrics

        Counter counter = metricRegistry.counter("simple_counter_by_registry");

MetricIDずは、メトリクスの名前ずタグの組み合わせです。

MetricID

次は、メタデヌタを定矩しおみたしょう。

メトリクスのget-or-create時にメタデヌタを指定するこずもできるのですが、今回は最初に登録しおおくこずにしたしょう。

    @PostConstruct
    public void init() {
        Metadata counterMetadata =
                Metadata
                        .builder()
                        .withName("registered_counter_by_registry")
                        .withDescription("pre registered counter by registry")
                        .withType(MetricType.COUNTER)
                        .withUnit(MetricUnits.NONE)
                        .build();

        metricRegistry.counter(counterMetadata);
    }

䜿甚䟋。メタデヌタで指定した名前ず、同じ名前でMetricRegistryからメトリクスを取埗すればOKです。

    @GET
    @Path("pre-registered-counter")
    @Produces(MediaType.TEXT_PLAIN)
    public String preRegisteredCounter() {
        Counter counter = metricRegistry.counter("registered_counter_by_registry");
        counter.inc();
        return "Pre Registered Counter!!";
    }

たた、メトリクスのクラスを盎接䜿甚する堎合は、このようにタグを指定するこずもできたす。
こちらは、先ほどず同じ名前のCounterを䜿甚しおいたす。

    @GET
    @Path("pre-registered-counter2")
    @Produces(MediaType.TEXT_PLAIN)
    public String preRegisteredCounter2() {
        Counter counter =
                metricRegistry
                        .counter(
                                "registered_counter_by_registry",
                                new Tag("path", "/metric-registry/pre-registered-counter2"),
                                new Tag("type", "2")
                        );
        counter.inc();

        return "Pre Registered Counter2!!";
    }

それぞれにアクセス。

$ curl localhost:8080/microprofile-metrics-example/metric-registry/pre-registered-counter
Pre Registered Counter!!


$ curl localhost:8080/microprofile-metrics-example/metric-registry/pre-registered-counter
Pre Registered Counter!!


$ curl localhost:8080/microprofile-metrics-example/metric-registry/pre-registered-counter2
Pre Registered Counter2!!


$ curl localhost:8080/microprofile-metrics-example/metric-registry/pre-registered-counter2
Pre Registered Counter2!!

メトリクスを確認。

$ curl localhost:9990/metrics/application/registered_counter_by_registry
# HELP application_registered_counter_by_registry_total pre registered counter by registry
# TYPE application_registered_counter_by_registry_total counter
application_registered_counter_by_registry_total{path="/metric-registry/pre-registered-counter2",type="2"} 2.0
application_registered_counter_by_registry_total 2.0

タグの有無で、結果が別々になりたしたね。

これで、タグの確認もできたした。

Histgram

アノテヌションではメトリクスを蚘録できず、メトリクスに察応するクラスを盎接扱っお蚘録するものずしおHistogramが
ありたす。

最埌にこちらを䜿っおみたしょう。

メタデヌタはCounterず同じように登録しおおきたす。

    @PostConstruct
    public void init() {
        Metadata counterMetadata =
                Metadata
                        .builder()
                        .withName("registered_counter_by_registry")
                        .withDescription("pre registered counter by registry")
                        .withType(MetricType.COUNTER)
                        .withUnit(MetricUnits.NONE)
                        .build();

        metricRegistry.counter(counterMetadata);

        Metadata histogramMetadata =
                Metadata
                        .builder()
                        .withName("my_histogram")
                        .withDescription("my histogram example")
                        .withType(MetricType.HISTOGRAM)
                        .withUnit(MetricUnits.BYTES)
                        .build();

        metricRegistry.histogram(histogramMetadata);
    }

単䜍を芋たらわかりたすが、バむト数をテヌマにしおみたす。

Histogramを䜿った䟋。タグも䜿っおみたす。

    @GET
    @Path("histogram")
    @Produces(MediaType.TEXT_PLAIN)
    public String histogram() {
        Histogram histogram =
                metricRegistry.histogram(
                        "my_histogram",
                        new Tag("path", "/metric-registry/histogram")
                );

        long randomInt = randomService.randomInt(1024);
        histogram.update(randomInt);

        return String.format("Histogram, random = %d", randomInt);
    }

ランダムな数字を蚘録しおみたす。

アクセスしおみたす。

$ curl localhost:8080/microprofile-metrics-example/metric-registry/histogram
Histogram, random = 171


$ curl localhost:8080/microprofile-metrics-example/metric-registry/histogram
Histogram, random = 86


$ curl localhost:8080/microprofile-metrics-example/metric-registry/histogram
Histogram, random = 819

メトリクスも芋おみたす。

$ curl localhost:9990/metrics/application/my_histogram
# HELP application_my_histogram_bytes my histogram example
# TYPE application_my_histogram_min_bytes gauge
application_my_histogram_min_bytes{path="/metric-registry/histogram"} 86.0
# TYPE application_my_histogram_max_bytes gauge
application_my_histogram_max_bytes{path="/metric-registry/histogram"} 819.0
# TYPE application_my_histogram_mean_bytes gauge
application_my_histogram_mean_bytes{path="/metric-registry/histogram"} 361.91676959746343
# TYPE application_my_histogram_stddev_bytes gauge
application_my_histogram_stddev_bytes{path="/metric-registry/histogram"} 328.6816538560838
# TYPE application_my_histogram_bytes summary
application_my_histogram_bytes_count{path="/metric-registry/histogram"} 3.0
application_my_histogram_bytes_sum{path="/metric-registry/histogram"} 1076.0
application_my_histogram_bytes{path="/metric-registry/histogram",quantile="0.5"} 171.0
application_my_histogram_bytes{path="/metric-registry/histogram",quantile="0.75"} 819.0
application_my_histogram_bytes{path="/metric-registry/histogram",quantile="0.95"} 819.0
application_my_histogram_bytes{path="/metric-registry/histogram",quantile="0.98"} 819.0
application_my_histogram_bytes{path="/metric-registry/histogram",quantile="0.99"} 819.0
application_my_histogram_bytes{path="/metric-registry/histogram",quantile="0.999"} 819.0
application_my_histogram_min_bytes 0.0
application_my_histogram_max_bytes 0.0
application_my_histogram_mean_bytes 0.0
application_my_histogram_stddev_bytes 0.0
application_my_histogram_bytes_count 0.0
application_my_histogram_bytes_sum 0.0
application_my_histogram_bytes{quantile="0.5"} 0.0
application_my_histogram_bytes{quantile="0.75"} 0.0
application_my_histogram_bytes{quantile="0.95"} 0.0
application_my_histogram_bytes{quantile="0.98"} 0.0
application_my_histogram_bytes{quantile="0.99"} 0.0
application_my_histogram_bytes{quantile="0.999"} 0.0

こんな感じで、いろいろ蚘録されたす。タグなしの方が蚘録されおいないのは、スルヌしたしょう。

サフィックスは、メトリクスに指定した単䜍が反映されたす。

Histogram OpenMetrics Text Format

ずりあえず、こんなずころでしょうか。

たずめ

Eclipse MicroProfile Metricsを詊しおみたした。

いろいろ扱っおみたのですが、けっこう範囲が広くおカバヌしきれないずいうか、゚ントリ自䜓が䞭途半端になったような
気がしたすが 。

もう少し、絞っお曞いた方がよかったかもしれたせん 。

SmallRye MetricsのJAX-RSの郚分がうたく扱えなかったりしたので、このあたりはたた別途やりたいですね。

ずりあえず、今回はこんなずころで。

オマケ

䜕回もWildFlyにデプロむしお確認するのが面倒だったので、゜ヌスコヌドを曞いおいる時はWildFly Bootable JARで
倉曎をリアルタむムに反映しながら確認しおいたした。

以䞋の蚭定をpom.xmlに入れお

    <profiles>
        <profile>
            <id>bootable</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.wildfly.plugins</groupId>
                        <artifactId>wildfly-jar-maven-plugin</artifactId>
                        <version>5.0.2.Final</version>
                        <configuration>
                            <feature-pack-location>wildfly@maven(org.jboss.universe:community-universe)#24.0.1.Final
                            </feature-pack-location>
                            <layers>
                                <layer>jaxrs-server</layer>
                                <layer>management</layer>
                                <layer>microprofile-metrics</layer>
                            </layers>
                            <plugin-options>
                                <jboss-maven-dist/>
                            </plugin-options>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>

以䞋で、゜ヌスコヌドの倉曎の床に反映されるようになりたす。

$ mvn -P bootable wildfly-jar:dev-watch

この圢態だず、デプロむされるWARファむルはROOT.warになっおいるこずになるので、その点だけ泚意ですね。

$ curl localhost:8080/annotated/count-hello-world
Hello World!!

メトリクス取埗のURLは、Bootable JARでも倉わりたせん。

$ curl localhost:9990/metrics/application/org.littlewings.microprofile.metrics.SimpleAnnotatedResource.hello_world_call_count
# TYPE application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_hello_world_call_count_total counter
application_org_littlewings_microprofile_metrics_SimpleAnnotatedResource_hello_world_call_count_total 1.0

だいたいできたら、最埌にWildFlyにデプロむしお確認しおいたした。