1. 序章

Metrics は、Javaアプリケーション用の測定器を提供するJavaライブラリです。

いくつかのモジュールがあります。この記事では、参考のために、メトリクス-コアモジュール、メトリクス-ヘルスチェックモジュール、メトリクス-サーブレットモジュール、メトリクス-サーブレットモジュールについて詳しく説明し、残りをスケッチします。

2. モジュールメトリクス-コア

2.1. Mavenの依存関係

metrics-core モジュールを使用するには、pom.xmlファイルに追加する必要がある依存関係は1つだけです。

<dependency>
    <groupId>io.dropwizard.metrics</groupId>
    <artifactId>metrics-core</artifactId>
    <version>3.1.2</version>
</dependency>

そして、あなたはその最新バージョンここを見つけることができます。

2.2. MetricRegistry

簡単に言うと、 MetricRegistry クラスを使用して、1つまたは複数のメトリックを登録します。

すべてのメトリクスに1つのメトリクスレジストリを使用できますが、メトリクスごとに異なるレポート方法を使用する場合は、メトリクスをグループに分割し、グループごとに異なるメトリクスレジストリを使用することもできます。

ここでMetricRegistryを作成しましょう。

MetricRegistry metricRegistry = new MetricRegistry();

次に、このMetricRegistryにいくつかのメトリックを登録できます。

Meter meter1 = new Meter();
metricRegistry.register("meter1", meter1);

Meter meter2 = metricRegistry.meter("meter2");

新しいメトリックを作成するには、2つの基本的な方法があります。自分でインスタンス化する方法と、メトリックレジストリからメトリックを取得する方法です。 ご覧のとおり、上記の例では両方を使用し、 Meter オブジェクト「meter1」をインスタンス化しており、によって作成された別のMeterオブジェクト「meter2」を取得しています。 metricRegistry

上記のメトリック名として「meter1」と「meter2」を使用したため、メトリックレジストリでは、すべてのメトリックに一意の名前が付けられます。 MetricRegistry は、適切なメトリック名を作成するのに役立つ一連の静的ヘルパーメソッドも提供します。

String name1 = MetricRegistry.name(Filter.class, "request", "count");
String name2 = MetricRegistry.name("CustomFilter", "response", "count");

一連のメトリックレジストリを管理する必要がある場合は、シングルトンでスレッドセーフなSharedMetricRegistriesクラスを使用できます。 メトリックレジスタを追加し、そこからこのメトリックレジスタを取得して、削除することができます。

SharedMetricRegistries.add("default", metricRegistry);
MetricRegistry retrievedMetricRegistry = SharedMetricRegistries.getOrCreate("default");
SharedMetricRegistries.remove("default");

3. メトリクスの概念

メトリックコアモジュールは、一般的に使用されるいくつかのメトリックタイプを提供します: Meter Gauge Counter Histogram Timer 、およびレポーターは、メトリックの値を出力します

3.1。メーター

Meter は、イベントの発生数とレートを測定します。

Meter meter = new Meter();
long initCount = meter.getCount();
assertThat(initCount, equalTo(0L));

meter.mark();
assertThat(meter.getCount(), equalTo(1L));

meter.mark(20);
assertThat(meter.getCount(), equalTo(21L));

double meanRate = meter.getMeanRate();
double oneMinRate = meter.getOneMinuteRate();
double fiveMinRate = meter.getFiveMinuteRate();
double fifteenMinRate = meter.getFifteenMinuteRate(); 

getCount()メソッドはイベント発生数を返し、 mark()メソッドはイベント発生数に1またはnを追加します。 Meter オブジェクトは、 Meter のライフタイム全体、最近1分間、最近5分間、および最近四半期の平均レートをそれぞれ表す4つのレートを提供します。

3.2。ゲージ

Gauge は、特定の値を返すために使用されるインターフェイスです。 メトリックコアモジュールは、 RatioGauge CachedGauge DerivativeGauge 、およびJmxAttributeGaugeのいくつかの実装を提供します。

RatioGauge は抽象クラスであり、ある値と別の値の比率を測定します。

使い方を見てみましょう。 まず、クラスAttendanceRatioGaugeを実装します。

public class AttendanceRatioGauge extends RatioGauge {
    private int attendanceCount;
    private int courseCount;

    @Override
    protected Ratio getRatio() {
        return Ratio.of(attendanceCount, courseCount);
    }
    
    // standard constructors
}

そしてそれをテストします:

RatioGauge ratioGauge = new AttendanceRatioGauge(15, 20);

assertThat(ratioGauge.getValue(), equalTo(0.75));

CachedGauge は、値をキャッシュできる別の抽象クラスであるため、値の計算にコストがかかる場合に非常に役立ちます。 これを使用するには、クラスActiveUsersGaugeを実装する必要があります。

public class ActiveUsersGauge extends CachedGauge<List<Long>> {
    
    @Override
    protected List<Long> loadValue() {
        return getActiveUserCount();
    }
 
    private List<Long> getActiveUserCount() {
        List<Long> result = new ArrayList<Long>();
        result.add(12L);
        return result;
    }

    // standard constructors
}

次に、それをテストして、期待どおりに機能するかどうかを確認します。

Gauge<List<Long>> activeUsersGauge = new ActiveUsersGauge(15, TimeUnit.MINUTES);
List<Long> expected = new ArrayList<>();
expected.add(12L);

assertThat(activeUsersGauge.getValue(), equalTo(expected));

ActiveUsersGauge をインスタンス化するときに、キャッシュの有効期限を15分に設定しました。

DerivativeGauge も抽象クラスであり、他のGaugeから値を派生させることができます。

例を見てみましょう:

public class ActiveUserCountGauge extends DerivativeGauge<List<Long>, Integer> {
    
    @Override
    protected Integer transform(List<Long> value) {
        return value.size();
    }

    // standard constructors
}

このGaugeは、 ActiveUsersGauge から値を取得するため、ベースリストのサイズからの値であると予想されます。

Gauge<List<Long>> activeUsersGauge = new ActiveUsersGauge(15, TimeUnit.MINUTES);
Gauge<Integer> activeUserCountGauge = new ActiveUserCountGauge(activeUsersGauge);

assertThat(activeUserCountGauge.getValue(), equalTo(1));

JmxAttributeGauge は、JMXを介して公開されている他のライブラリのメトリックにアクセスする必要がある場合に使用されます。

3.3。カウンター

カウンターは、インクリメントとデクリメントを記録するために使用されます。

Counter counter = new Counter();
long initCount = counter.getCount();
assertThat(initCount, equalTo(0L));

counter.inc();
assertThat(counter.getCount(), equalTo(1L));

counter.inc(11);
assertThat(counter.getCount(), equalTo(12L));

counter.dec();
assertThat(counter.getCount(), equalTo(11L));

counter.dec(6);
assertThat(counter.getCount(), equalTo(5L));

3.4。ヒストグラム

ヒストグラムは、 Long 値のストリームを追跡するために使用され、最大、最小、平均、中央値、標準偏差、75パーセンタイルなどの統計的特性を分析します。 ] 等々:

Histogram histogram = new Histogram(new UniformReservoir());
histogram.update(5);
long count1 = histogram.getCount();
assertThat(count1, equalTo(1L));

Snapshot snapshot1 = histogram.getSnapshot();
assertThat(snapshot1.getValues().length, equalTo(1));
assertThat(snapshot1.getValues()[0], equalTo(5L));

histogram.update(20);
long count2 = histogram.getCount();
assertThat(count2, equalTo(2L));

Snapshot snapshot2 = histogram.getSnapshot();
assertThat(snapshot2.getValues().length, equalTo(2));
assertThat(snapshot2.getValues()[1], equalTo(20L));
assertThat(snapshot2.getMax(), equalTo(20L));
assertThat(snapshot2.getMean(), equalTo(12.5));
assertEquals(10.6, snapshot2.getStdDev(), 0.1);
assertThat(snapshot2.get75thPercentile(), equalTo(20.0));
assertThat(snapshot2.get999thPercentile(), equalTo(20.0));

Histogram は、リザーバーサンプリングを使用してデータをサンプリングします。 Histogram オブジェクトをインスタンス化するときは、そのリザーバーを明示的に設定する必要があります。

Reservoir はインターフェースであり、metrics-coreはそれらの4つの実装を提供します: ExponentiallyDecayingReservoir UniformReservoir SlidingTimeWindowReservoir SlidingWindow X223X]

上記のセクションで、メトリックは次の方法でも作成できることを説明しました MetricRegistry、 コンストラクターを使用する以外に使用する場合 metricRegistry.histogram() 、それはヒストグラムとのインスタンス ExponentiallyDecayingReservoir 実装。

3.5。タイマー

Timer は、 Context オブジェクトによって表される複数のタイミング期間を追跡するために使用され、それらの統計データも提供します。

Timer timer = new Timer();
Timer.Context context1 = timer.time();
TimeUnit.SECONDS.sleep(5);
long elapsed1 = context1.stop();

assertEquals(5000000000L, elapsed1, 1000000);
assertThat(timer.getCount(), equalTo(1L));
assertEquals(0.2, timer.getMeanRate(), 0.1);

Timer.Context context2 = timer.time();
TimeUnit.SECONDS.sleep(2);
context2.close();

assertThat(timer.getCount(), equalTo(2L));
assertEquals(0.3, timer.getMeanRate(), 0.1);

3.6. レポーター

測定値を出力する必要がある場合は、Reporterを使用できます。 これはインターフェースであり、metrics-coreモジュールは、 ConsoleReporter CsvReporter Slf4jReporter JmxReporter など、いくつかの実装を提供します。等々。

ここでは、例としてConsoleReporterを使用します。

MetricRegistry metricRegistry = new MetricRegistry();

Meter meter = metricRegistry.meter("meter");
meter.mark();
meter.mark(200);
Histogram histogram = metricRegistry.histogram("histogram");
histogram.update(12);
histogram.update(17);
Counter counter = metricRegistry.counter("counter");
counter.inc();
counter.dec();

ConsoleReporter reporter = ConsoleReporter.forRegistry(metricRegistry).build();
reporter.start(5, TimeUnit.MICROSECONDS);
reporter.report();

ConsoleReporterの出力例は次のとおりです:

-- Histograms ------------------------------------------------------------------
histogram
count = 2
min = 12
max = 17
mean = 14.50
stddev = 2.50
median = 17.00
75% <= 17.00
95% <= 17.00
98% <= 17.00
99% <= 17.00
99.9% <= 17.00

-- Meters ----------------------------------------------------------------------
meter
count = 201
mean rate = 1756.87 events/second
1-minute rate = 0.00 events/second
5-minute rate = 0.00 events/second
15-minute rate = 0.00 events/second

4. モジュールメトリクス-ヘルスチェック

Metricsには、ヘルスチェックを処理するための拡張metrics-healthchecksモジュールがあります。

4.1. Mavenの依存関係

metrics-healthchecksモジュールを使用するには、この依存関係をpom.xmlファイルに追加する必要があります。

<dependency>
    <groupId>io.dropwizard.metrics</groupId>
    <artifactId>metrics-healthchecks</artifactId>
    <version>3.1.2</version>
</dependency>

そして、あなたはその最新バージョンここを見つけることができます。

4.2. 使用法

まず、特定のヘルスチェック操作を担当するいくつかのクラスが必要であり、これらのクラスはHealthCheckを実装する必要があります。

たとえば、DatabaseHealthCheckおよびUserCenterHealthCheckを使用します。

public class DatabaseHealthCheck extends HealthCheck {
 
    @Override
    protected Result check() throws Exception {
        return Result.healthy();
    }
}
public class UserCenterHealthCheck extends HealthCheck {
 
    @Override
    protected Result check() throws Exception {
        return Result.healthy();
    }
}

次に、 HealthCheckRegistry MetricRegistry と同じ)が必要で、DatabaseHealthCheckUserCenterHealthCheckを登録します。

HealthCheckRegistry healthCheckRegistry = new HealthCheckRegistry();
healthCheckRegistry.register("db", new DatabaseHealthCheck());
healthCheckRegistry.register("uc", new UserCenterHealthCheck());

assertThat(healthCheckRegistry.getNames().size(), equalTo(2));

HealthCheckの登録を解除することもできます。

healthCheckRegistry.unregister("uc");
 
assertThat(healthCheckRegistry.getNames().size(), equalTo(1));

すべてのHealthCheckインスタンスを実行できます。

Map<String, HealthCheck.Result> results = healthCheckRegistry.runHealthChecks();
for (Map.Entry<String, HealthCheck.Result> entry : results.entrySet()) {
    assertThat(entry.getValue().isHealthy(), equalTo(true));
}

最後に、特定のHealthCheckインスタンスを実行できます。

healthCheckRegistry.runHealthCheck("db");

5. モジュールメトリクス-サーブレット

Metricsは、HTTPリクエストを介してメトリック関連のデータにアクセスできるようにする便利なサーブレットをいくつか提供します。

5.1. Mavenの依存関係

metrics-servletsモジュールを使用するには、この依存関係をpom.xmlファイルに追加する必要があります。

<dependency>
    <groupId>io.dropwizard.metrics</groupId>
    <artifactId>metrics-servlets</artifactId>
    <version>3.1.2</version>
</dependency>

そして、あなたはその最新バージョンここを見つけることができます。

5.2. HealthCheckServlet使用法

HealthCheckServlet は、ヘルスチェックの結果を提供します。 まず、HealthCheckRegistryを公開するServletContextListenerを作成する必要があります。

public class MyHealthCheckServletContextListener
  extends HealthCheckServlet.ContextListener {
 
    public static HealthCheckRegistry HEALTH_CHECK_REGISTRY
      = new HealthCheckRegistry();

    static {
        HEALTH_CHECK_REGISTRY.register("db", new DatabaseHealthCheck());
    }

    @Override
    protected HealthCheckRegistry getHealthCheckRegistry() {
        return HEALTH_CHECK_REGISTRY;
    }
}

次に、このリスナーとHealthCheckServletの両方をweb.xmlファイルに追加します。

<listener>
    <listener-class>com.baeldung.metrics.servlets.MyHealthCheckServletContextListener</listener-class>
</listener>
<servlet>
    <servlet-name>healthCheck</servlet-name>
    <servlet-class>com.codahale.metrics.servlets.HealthCheckServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>healthCheck</servlet-name>
    <url-pattern>/healthcheck</url-pattern>
</servlet-mapping>

これで、Webアプリケーションを起動し、GETリクエストを「http:// localhost:8080 / healthcheck」に送信して、ヘルスチェックの結果を取得できます。 その応答は次のようになります。

{
  "db": {
    "healthy": true
  }
}

5.3。ThreadDumpServlet使用法

ThreadDumpServlet は、JVM内のすべてのライブスレッド、それらの状態、それらのスタックトレース、およびそれらが待機している可能性のあるロックの状態に関する情報を提供します。 これを使用する場合は、これらをweb.xmlファイルに追加するだけです。

<servlet>
    <servlet-name>threadDump</servlet-name>
    <servlet-class>com.codahale.metrics.servlets.ThreadDumpServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>threadDump</servlet-name>
    <url-pattern>/threaddump</url-pattern>
</servlet-mapping>

スレッドダンプデータは「http:// localhost:8080/threaddump」で入手できます。

5.4. PingServlet使用法

PingServlet を使用して、アプリケーションが実行されているかどうかをテストできます。 これらをweb.xmlファイルに追加します。

<servlet>
    <servlet-name>ping</servlet-name>
    <servlet-class>com.codahale.metrics.servlets.PingServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ping</servlet-name>
    <url-pattern>/ping</url-pattern>
</servlet-mapping>

次に、GETリクエストを「http:// localhost:8080/ping」に送信します。 応答のステータスコードは200で、その内容は「ポン」です。

5.5. MetricsServlet使用法

MetricsServletはメトリクスデータを提供します。 まず、MetricRegistryを公開するServletContextListenerを作成する必要があります。

public class MyMetricsServletContextListener
  extends MetricsServlet.ContextListener {
    private static MetricRegistry METRIC_REGISTRY
     = new MetricRegistry();

    static {
        Counter counter = METRIC_REGISTRY.counter("m01-counter");
        counter.inc();

        Histogram histogram = METRIC_REGISTRY.histogram("m02-histogram");
        histogram.update(5);
        histogram.update(20);
        histogram.update(100);
    }

    @Override
    protected MetricRegistry getMetricRegistry() {
        return METRIC_REGISTRY;
    }
}

このリスナーとMetricsServletの両方をweb.xmlに追加する必要があります。

<listener>
    <listener-class>com.codahale.metrics.servlets.MyMetricsServletContextListener</listener-class>
</listener>
<servlet>
    <servlet-name>metrics</servlet-name>
    <servlet-class>com.codahale.metrics.servlets.MetricsServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>metrics</servlet-name>
    <url-pattern>/metrics</url-pattern>
</servlet-mapping>

これは、「http:// localhost:8080/metrics」のWebアプリケーションで公開されます。 その応答には、さまざまなメトリックデータが含まれている必要があります。

{
  "version": "3.0.0",
  "gauges": {},
  "counters": {
    "m01-counter": {
      "count": 1
    }
  },
  "histograms": {
    "m02-histogram": {
      "count": 3,
      "max": 100,
      "mean": 41.66666666666666,
      "min": 5,
      "p50": 20,
      "p75": 100,
      "p95": 100,
      "p98": 100,
      "p99": 100,
      "p999": 100,
      "stddev": 41.69998667732268
    }
  },
  "meters": {},
  "timers": {}
}

5.6. AdminServlet使用法

AdminServlet は、 HealthCheckServlet ThreadDumpServlet MetricsServlet 、およびPingServletを集約します。

これらをweb.xmlに追加しましょう。

<servlet>
    <servlet-name>admin</servlet-name>
    <servlet-class>com.codahale.metrics.servlets.AdminServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>admin</servlet-name>
    <url-pattern>/admin/*</url-pattern>
</servlet-mapping>

これで、「http:// localhost:8080/admin」からアクセスできます。 4つのサーブレットのそれぞれに1つずつ、合計4つのリンクを含むページが表示されます。

ヘルスチェックを実行してメトリックデータにアクセスする場合でも、これら2つのリスナーが必要であることに注意してください。

6. モジュールmetrics-servlet

metrics-servlet モジュールは、 Filter を提供します。これには、ステータスコードのメーター、アクティブなリクエスト数のカウンター、リクエスト期間のタイマーなど、いくつかのメトリックがあります。

6.1. Mavenの依存関係

このモジュールを使用するには、最初に依存関係をpom.xmlに追加しましょう。

<dependency>
    <groupId>io.dropwizard.metrics</groupId>
    <artifactId>metrics-servlet</artifactId>
    <version>3.1.2</version>
</dependency>

そして、あなたはその最新バージョンここを見つけることができます。

6.2. 使用法

これを使用するには、MetricRegistryInstrumentedFilterに公開するServletContextListenerを作成する必要があります。

public class MyInstrumentedFilterContextListener
  extends InstrumentedFilterContextListener {
 
    public static MetricRegistry REGISTRY = new MetricRegistry();

    @Override
    protected MetricRegistry getMetricRegistry() {
        return REGISTRY;
    }
}

次に、これらをweb.xmlに追加します。

<listener>
     <listener-class>
         com.baeldung.metrics.servlet.MyInstrumentedFilterContextListener
     </listener-class>
</listener>

<filter>
    <filter-name>instrumentFilter</filter-name>
    <filter-class>
        com.codahale.metrics.servlet.InstrumentedFilter
    </filter-class>
</filter>
<filter-mapping>
    <filter-name>instrumentFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

これで、InstrumentedFilterが機能するようになりました。 メトリックデータにアクセスする場合は、 MetricRegistry REGISTRYを介してアクセスできます。

7. その他のモジュール

上で紹介したモジュールを除いて、メトリクスにはさまざまな目的のための他のモジュールがいくつかあります。

  • metrics-jvm :JVM内部をインストルメント化するためのいくつかの有用なメトリックを提供します
  • metrics-ehcache :EhcacheキャッシュのデコレータであるInstrumentedEhcacheを提供します
  • メトリック-httpclient:Apache HttpClient(4.xバージョン)をインストルメント化するためのクラスを提供します
  • metrics-log4j :log4j1.xのLog4jAppender実装であるInstrumentedAppenderを提供し、ログレベルごとにログイベントの割合を記録します
  • metrics-log4j2 :metrics-log4jに似ていますが、log4j2.xの場合のみです。
  • metrics-logback InstrumentedAppender を提供します。これは、ログに記録されたイベントの割合をログレベルごとに記録するLogback Appender実装です。
  • metrics-json :ジャクソンにHealthCheckModuleMetricsModuleを提供します

さらに、これらのメインプロジェクトモジュール以外に、他のサードパーティライブラリは、他のライブラリやフレームワークとの統合を提供します。

8. 結論

アプリケーションのインスツルメンテーションは一般的な要件であるため、この記事では、問題の解決に役立つことを期待して、メトリックを紹介しました。

いつものように、この例の完全なソースコードは、GitHubから入手できます。