Spring Boot ✕ Prometheus ✕ Grafana でアプリケーションのモニタリング その２


[前回の記事](https://qiita.com/AHA_oretama/items/984f8f63ac95a7192174)を書いたあとに気づいたが、
Spring側に[Spring Metrics](https://docs.spring.io/spring-metrics/docs/current/public/prometheus)というプロジェクトが動いているようで、その中にPrometheusが含まれていた。

前回の記事である[Spring Boot ✕ Prometheus ✕ Grafana でアプリケーションのモニタリング](https://qiita.com/AHA_oretama/items/984f8f63ac95a7192174)の内容は間違いというわけではなく、現状は以下の２つの方法がある、ということになる。

* spring,spring boot向けのPrometheusクライアントライブラリを使用する。（Prometheusが提供しているSpring向けの機能）
* spring-metricsでPrometheus向けの設定をする。（Springが提供しているPrometheus向けの機能）

つまり、お互いが相手向けの機能を提供している状態になっている。

前者が[前回の記事](https://qiita.com/AHA_oretama/items/984f8f63ac95a7192174)で紹介した内容となり、後者が今回、紹介する機能となる。

# Spring Metrics

## 試した環境

* OS: macOS Sierra 10.12.6
* Java: 1.8.0_102
* Spring Boot: 1.5.10.RELEASE
* Spring Metrics: 0.5.1.RELEASE
* Docker For Mac: 17.12.0-ce-mac49
* Prometheus: v2.1.0
* Grafana: 5.0.0-beta4

## Spring Metricsの設定

設定はシンプルで`dependency`とアノテーションの追加のみ。

`spring-metrics`,`spring-boot-actuator`,`simpleclient_common`をpom.xmlに追加する。
（WEBアプリケーションとして生成したため`spring-boot-starter-web`が追加されている。）

```xml:pom.xml
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.metrics</groupId>
			<artifactId>spring-metrics</artifactId>
			<version>${metrics.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-actuator</artifactId>
		</dependency>
		<dependency>
			<groupId>io.prometheus</groupId>
			<artifactId>simpleclient_common</artifactId>
			<version>${prom.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
```

あとは`@EnablePrometheusMetrics`を付与するだけでOK。

```java:Application.java
@SpringBootApplication
@EnablePrometheusMetrics
public class SpringBootPrometheusGrafanaSampleApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringBootPrometheusGrafanaSampleApplication.class, args);
	}
}
```

これで、自動でメトリックスが集計され、エンドポイント`/prometheus`のレスポンスとしてそのメトリックスが返される。

## メソッド単位の所要時間メトリックスの追加

クラスに`@Timed`をつければOK.

```java:HelloController.java
@RestController
@Timed
public class HelloController {

    @GetMapping("/hello")
    public String sayHello() {
        return "hello";
    }
}
```

## 個別実装

いくつか実装があるが、今回はCounterを紹介する。それ以外は[ドキュメント](https://docs.spring.io/spring-metrics/docs/current/public/prometheus)を参照してほしい。
`@EnablePrometheusMetrics`により、`PrometheusMeterRegistry`がBean登録されるため、コンストラクタでインジェクションできる。

```java:CounterController.java
@RestController
public class CounterController {
    private static int num = 0;
    private final Counter counter;

    public CounterController(MeterRegistry registry) {
        counter = registry.counter("count_requests_total");
    }

    @GetMapping("count")
    public int count() {
        counter.increment();
        return ++num;
    }
}
```


## 集計されるメトリックス

サンプルアプリケーションで確認したところ、以下の値が出力されている。

* JVM
* logレベル
* 個別実装 （count_requests_total部分）
* メソッド単位の所要時間（http_server_requests_count,http_server_requests_sum部分）

```
# HELP count_requests_total  
# TYPE count_requests_total counter
count_requests_total 1.0
# HELP jvm_buffer_memory_used
# TYPE jvm_buffer_memory_used gauge
jvm_buffer_memory_used{id="direct",} 49152.0
jvm_buffer_memory_used{id="mapped",} 0.0
# HELP jvm_memory_committed
# TYPE jvm_memory_committed gauge
jvm_memory_committed{id="Code Cache",} 8126464.0
jvm_memory_committed{id="PS Eden Space",} 1.42082048E8
jvm_memory_committed{id="PS Old Gen",} 1.1534336E8
jvm_memory_committed{id="PS Survivor Space",} 1.3631488E7
jvm_memory_committed{id="Compressed Class Space",} 4636672.0
jvm_memory_committed{id="Metaspace",} 3.3734656E7
# HELP logback_events
# TYPE logback_events counter
logback_events{level="warn",} 93.0
logback_events{level="debug",} 3162.0
logback_events{level="error",} 0.0
logback_events{level="trace",} 7588.0
logback_events{level="info",} 90.0
# HELP jvm_memory_used
# TYPE jvm_memory_used gauge
jvm_memory_used{id="Code Cache",} 8064000.0
jvm_memory_used{id="PS Eden Space",} 2.1646824E7
jvm_memory_used{id="PS Old Gen",} 1.248472E7
jvm_memory_used{id="PS Survivor Space",} 1.3624504E7
jvm_memory_used{id="Compressed Class Space",} 4319216.0
jvm_memory_used{id="Metaspace",} 3.2767784E7
# HELP jvm_memory_max
# TYPE jvm_memory_max gauge
jvm_memory_max{id="Code Cache",} 2.5165824E8
jvm_memory_max{id="PS Eden Space",} 1.4024704E9
jvm_memory_max{id="PS Old Gen",} 2.863661056E9
jvm_memory_max{id="PS Survivor Space",} 1.3631488E7
jvm_memory_max{id="Compressed Class Space",} 1.073741824E9
jvm_memory_max{id="Metaspace",} -1.0
# HELP jvm_buffer_total_capacity
# TYPE jvm_buffer_total_capacity gauge
jvm_buffer_total_capacity{id="direct",} 49152.0
jvm_buffer_total_capacity{id="mapped",} 0.0
# HELP http_server_requests
# TYPE http_server_requests summary
http_server_requests_count{method="GET",uri="hello",exception="None",status="200",} 1.0
http_server_requests_sum{method="GET",uri="hello",exception="None",status="200",} 0.004397129
# HELP jvm_buffer_count
# TYPE jvm_buffer_count gauge
jvm_buffer_count{id="direct",} 6.0
jvm_buffer_count{id="mapped",} 0.0
```

※ 前回のメトリックスとしての差分は[Garbage collection, Memory pools, JMX, Classloading, Thread counts の追加](https://qiita.com/AHA_oretama/items/984f8f63ac95a7192174#garbage-collection-memory-pools-jmx-classloading-thread-counts-%E3%81%AE%E8%BF%BD%E5%8A%A0)の部分のみ。個別で追加すればほぼ差分はなくなる。

## 

# Prometheus,Grafana設定

[前回紹介した方法](https://qiita.com/AHA_oretama/items/984f8f63ac95a7192174#prometheusgrafana%E3%81%AE%E8%A8%AD%E5%AE%9A)と同じため、割愛。


# 注意事項

Spring Metricsはまだ1.0.0.RELEASEになっておらず、未成熟なプロジェクトであり、本番環境での使用は控えたほうがよさそうだ。
ドキュメントにも以下のように記載がある。

> Pre-release artifacts are being published frequently, but are NOT intended for production use.

# 所感

Prometheusクライアントライブラリ側もSpring側もほぼ同じ機能を提供している。
ただSpringが提供している機能を使用したほうがシンプルな設定で行うことができるので、SpringメインであればSpring側の機能を使おうかと思った。

またSpringはそれ以外にDataDog,Netflix Atlasをサポートしており、かつインタフェースによる実装ができているので、たとえばDataDogに変更したとしても同じインタフェースでアクセスできるため、便利。

あとはPrometheus,Spring双方で歩み寄っていってほしいなぁと思った。（２つの同じようなライブラリを調べるのは大変ｗ

# GitHub

今回のサンプルアプリは以下。※ ブランチがspring-metricsなので注意

https://github.com/aha-oretama/spring-boot-prometheus-grafana-sample/tree/spring-metrics

# 参考

https://docs.spring.io/spring-metrics/docs/current/public/prometheus
https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-metrics.html#production-ready-metrics-export-prometheus