Pushgatewayを使ってSpringBatchのメトリクス収集

# 概要

- APIだと、メトリクス用のエンドポイントによってメトリクス収集が可能だが、バッチだと処理終了とともにアプリケーションが終了してしまうため、APIと同じようにはいかない
- そこでバッチ終了時にPushgatewayにメトリクスを送信することで、メトリクスをprometheusから収集可能な状態にする

# 構成

```
SpringBatch --> pushgateway <-- prometheus
```

この記事では`SpringBatch --> pushgateway`の部分をメインで

# Pushgatewayを構築する

ここではローカルにPushgatewayを構築する

### 1. ダウンロード

[こちら](https://prometheus.io/download/)から端末にあったものをダウンロード  
Macの場合は「prometheus-2.19.2.darwin-amd64.tar.gz」

### 2. 解凍

```
gunzip pushgateway-1.2.0.darwin-amd64.tar.gz
tar -xf pushgateway-1.2.0.darwin-amd64.tar
```

### 3. 起動

```
cd pushgateway-1.2.0.darwin-amd64
./pushgateway
```

### 4. UIにアクセス

`localhost:9091`にアクセスして、こんな画面が出ればOK！  
メトリクスが送信されると、メトリクス表示されるようになります  

<img width="673" alt="Screen Shot 2020-07-05 at 0.11.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361020/3898ba35-45fe-f179-367e-119b3e46948f.png">

# SpringBatchを実装

### 1. アプリケーションを生成

[spring initializer](https://start.spring.io/)を利用

gradle利用の場合のbuild.gradleはこんな感じ
※若干手で追加が必要です

```groovy:build.gradle
plugins {
    id 'org.springframework.boot' version '2.3.1.RELEASE'
    id 'io.spring.dependency-management' version '1.0.9.RELEASE'
    id 'java'
    id 'com.github.ben-manes.versions' version '0.28.0'
}

sourceCompatibility = 11
targetCompatibility = 11

repositories {
    mavenCentral()
}

dependencies {
    compileOnly('org.projectlombok:lombok')
    annotationProcessor('org.projectlombok:lombok')

    implementation 'org.springframework.boot:spring-boot-starter-batch'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'io.micrometer:micrometer-registry-prometheus'
    implementation 'io.prometheus:simpleclient_pushgateway'
    runtimeOnly 'com.h2database:h2'
}
```

### 2. バッチを実装

バッチ自体はメインではないため、「Hello World!」を出力するだけのバッチ

```Java:BankConfiguration
@RequiredArgsConstructor
@Configuration
@EnableBatchProcessing
public class BankConfiguration {
    
    private final StepBuilderFactory stepBuilderFactory;
    private final JobBuilderFactory jobBuilderFactory;
    
    @Bean
    public HelloWorldTasklet helloWorldTasklet() {
        return new HelloWorldTasklet();
    }

    @Bean
    public Step helloWorldStep() {
        return stepBuilderFactory.get("helloWorldStep")
                .tasklet(helloWorldTasklet())
                .build();
    }

    @Bean
    public Job helloWorldJob() {
        return jobBuilderFactory.get("helloWorldJob")
                .incrementer(new RunIdIncrementer())
                .flow(helloWorldStep())
                .end()
                .build();
    }

    public class HelloWorldTasklet implements Tasklet {
        @Override
        public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
            System.out.println("Hello world");

            return RepeatStatus.FINISHED;
        }
    }
}
```

### 3. 設定

- [Application properties](https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#actuator-properties)

```application.yml
management:
  metrics:
    export:
      prometheus:
        pushgateway:
          # Pushgatewayへのメトリクス送信を有効化（デフォルト：false）
          enabled: true
          # PushgatewayのURL（デフォルト：http://localhost:9091）
          base-url: http://localhost:9091
          # メトリクスをpushする間隔（デフォルト：1m）
          push-rate: 30s
          # アプリケーションの識別子
          job: "hello-world-job"
          # メトリクスのタグ
          grouping-key: 
            tag1: "value1"
            tag2: "value2"
          # バッチ終了時の動作
          # -   none：なにもしない（デフォルト）
          # -   push：終了前にメトリクスを送信する
          # - delete：終了前にメトリクスを削除する
          shutdown-operation: push
```

# 実行！

<img width="1431" alt="Screen Shot 2020-07-05 at 0.44.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361020/c5a810e4-fc89-6166-11bc-8be46bd94946.png">

UIに送信されたメトリクスが表示されました！！

prometheusから参照する場合は`/metrics`パスを指定すればOKです。

# おまけ

シェルスクリプトからもcurlでpushできます

```bash
# echo "<メトリクス名> <値>" | curl --data-binary @- http://<host>:<port>/metrics/job/<ジョブ名>/<タグ名1>/<値1>/<タグ名2>/<値2>/...
echo "some_metric 12.3" | curl --data-binary @- http://localhost:9091/metrics/job/jnb_name/tag1/val1
```