PrometheusでのRubyアプリログ監視 

この記事は、[ケーシーエスキャロット Advent Calendar 2024](https://qiita.com/advent-calendar/2024/kcscarrot)の24日目の記事です。

# 初めに

以前の記事で、Prometheusについて[(Prometheusを調べてみました)](https://qiita.com/kawakin/items/679ec3dcf358b2163f46)載せましたが、
前回は、パフォーマンス監視までの構築でしたので、
今回はRubyアプリが出力するログ(logger)の監視までの手順を書きたいと思います。

# おさらい

前回の記事でも載せましたが、Prometheusでの監視全体図は以下になります。

![prometheus.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528499/9e47dc9c-fb45-1fa8-4132-07a1488647c2.jpeg)

今回は、ログ監視用のexporterとして、grok_exporterを利用します。
Prometheus/AlertManagerの基本的な構築方法や、exporterの簡単な紹介は、
以前の記事([(Prometheusを調べてみました)](https://qiita.com/kawakin/items/679ec3dcf358b2163f46))を参考にしてください。
　
![grok-kousei.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528499/816ddbf0-cd83-1220-9d02-6ee8f7fec2c4.png)

# grok_exporterインストール

以下手順でgrok_exporterをインストールします。

```
% wget https://github.com/fstab/grok_exporter/releases/download/v1.0.0.RC5/grok_exporter-1.0.0.RC5.linux-amd64.zip

% unzip grok_exporter-1.0.0.RC5.linux-amd64.zip

% mv grok_exporter-1.0.0.RC3.linux-amd64 /etc/grok_exporter

% cd /etc/grok_exporter
```

ここまで進めて、/etc/grok_exporter配下に監視対象ファイルや監視メッセージについての情報を、ymlファイルに定義します。

今回の監視情報は、

* 管理対象のログファイル
/var/log/ruby_app.log
* 管理対象エラーレベル
WARN/ERROR/FATAL

新たに作成するymlファイル(/etc/grok_exporter/ruby_log_config.yml)の内容は以下。
```
global:
  config_version: 3
input:
  type: file
  paths:
    - /var/log/ruby_app.log
  readall: false
  fail_on_missing_logfile: false
imports:
- type: grok_patterns
  dir: /etc/grok_exporter/patterns
metrics:
- type: counter
  name: error_count
  help: Counter metric example with labels.
  match: '%{RUBY_LOGGER}'
  labels:
    error_message: '{{.progname}} {{.loglevel}} {{.message}}'
    logfile: '{{base .logfile}}'
  retention: 1m
server:
  protocol: http
  port: 9145
```

ymlファイルの項目については、基本以下を参照。
* https://github.com/fstab/grok_exporter/blob/master/CONFIG.md

今回githubで紹介されている[例](https://github.com/fstab/grok_exporter?tab=readme-ov-file#configuration)から、修正をした項目は以下になります。

### input
* path
監視対象ファイルの/var/log/ruby_app.logを定義
* readall

| 設定値 | 内容 |
|:-----------|:-----------|
| true       | 監視対象のファイルを先頭行から読み込む    |
| false      | 監視対象のファイルを最終行(新規出力行)から読み込む|

* fail_on_missing_logfile

| 設定値 | 内容 |
|:-----------|:-----------|
| true       | 監視対象ファイルが無い場合エラー    |
| false      | 監視対象ファイルが無くても正常に起動|

### metrics
* name
metricsの名前
* match
取得したいログメッセージの正規表現を定義
今回定義している内容は [検知ログメッセージ定義](#検知ログメッセージ定義)以降で説明
#### labels
* error_message
フィールド名を定義できる為、今回、error_messageといフィールド名として、
プログラム名、ログレベル、メッセージをメトリクスから取得できるようにする
※'{{.progname}} {{.loglevel}} {{.message}}'の定義内容は以下の [rubyファイル正規表現](#rubyファイル正規表現)参照
### server
* port
metric取得時に使用するTCPポート、今回は9145を利用

# 検知ログメッセージ定義

ymlのmetrics/matchでは、検知・取得したログメッセージを正規表現で定義します。

今回は、Rubyアプリが出力するログメッセージの検知となるので、
まずはメッセージのフォーマットを確認します。

### Rubyアプリが出力するログフォーマット

Rubyアプリにてloggerを利用したログ出力のフォーマットは以下になります。

出力例：
```
I, [2024-12-19T12:30:45.129863 #8136]  INFO -- : メッセージ
W, [2024-12-19T12:35:13.498129 #8137]  WARN -- : 警告メッセージ
```

内容は以下の順で出力されています。

* ログレベル（略）
* ログ出力日付
* ログ出力をしたRubyアプリのプロセス番号
* ログレベル
* プログラム名
* ログメッセージ

### 正規表現

grok_exporterをインストールすると、patternsフォルダもダウンロードされ、
その中に正規表現が定義されている各種ファイルが存在します。
※ /etc/prometheus/patterns配下

```
-rw-r--r-- 1 root root  188  1月 13  2019 ruby
-rw-r--r-- 1 root root  104  1月 13  2019 redis
-rw-r--r-- 1 root root  845  1月 13  2019 rails
-rw-r--r-- 1 root root  142  1月 13  2019 postgresql
-rw-r--r-- 1 root root 9597  1月 13  2019 nagios
-rw-r--r-- 1 root root  614  1月 13  2019 mongodb
-rw-r--r-- 1 root root  190  1月 13  2019 mcollective-patterns
-rw-r--r-- 1 root root   49  1月 13  2019 mcollective
-rw-r--r-- 1 root root 1037  1月 13  2019 linux-syslog
-rw-r--r-- 1 root root 1087  1月 13  2019 junos
-rw-r--r-- 1 root root 1357  1月 13  2019 java
-rw-r--r-- 1 root root 3251  1月 13  2019 haproxy
-rw-r--r-- 1 root root 6199  1月 13  2019 grok-patterns
-rw-r--r-- 1 root root 9544  1月 13  2019 firewalls
-rw-r--r-- 1 root root  879  1月 13  2019 exim
-rw-r--r-- 1 root root 2154  1月 13  2019 bro
-rw-r--r-- 1 root root 4831  1月 13  2019 bacula
-rw-r--r-- 1 root root 1197  1月 13  2019 aws
```

今回はRubyアプリが対象となる為、ruby ファイルを利用します。

rubyファイルの内容は以下。

### rubyファイル(正規表現)
```
RUBY_LOGLEVEL (?:DEBUG|FATAL|ERROR|WARN|INFO)
RUBY_LOGGER [DFEWI], \[%{TIMESTAMP_ISO8601:timestamp} #%{POSINT:pid}\] *%{RUBY_LOGLEVEL:loglevel} -- +%{DATA:progname}: %{GREEDYDATA:message}
```

定義されている RUBY_LOGGER をmatchに記載する事で、
メッセージの取得は出来るのですが、そのままですと、WARN/ERROR/FATAL以外の
DEBUG/INFOも検知してしまう為、RUBY_LOGLEVELの内容を変更してみます。

```
RUBY_LOGLEVEL (?:DEBUG|FATAL|ERROR|WARN|INFO)
　　　　　　↓
RUBY_LOGLEVEL (?:FATAL|ERROR|WARN)
```
ここまでの設定で、WARN/ERROR/FATALレベルのメッセージ検知が可能になりました。

### grok_exporter起動

以下コマンドで実行します。

```
/etc/grok_exporter/grok_exporter -config /etc/grok_exporter/ruby_log_config.yml
```

次は、Prometheus/AlertManager本体の設定になります。

# Prometheus

### prometheus.yml

prometheus側のymlファイルにて、以下を追加。

```
scrape_configs:
  - job_name: 'log_ruby'

    static_configs:
    - targets: ['client-host-name:9145']
```
client-host-nameはgrok exporterがインストールされているクライアント側のホスト名になります。
ポートは今回、ruby_log_config.ymlで定義している9145を指定。

### alert_rules.yml

prometheus.yml側で読み込んでいるルール定義用のymlファイルに、以下を追加。

```
- name: log_alert
  rules:
  - alert: ruby
    expr: error_count{job='log_ruby'} >= 1
    labels:
      severity: critical
      group: "{{ $labels.error_message }}"
    annotations:
      summary:  "[{{ $labels.job }}] error happened. [{{ $labels.instance }}]"
      description:  "{{ $labels.error_message }}"
```

「$labels.error_message」 についてですが、
こちらはgrok_exporter側のymlファイルで指定している、
以下の内容が反映されます。

```
  labels:
    error_message: '{{.progname}} {{.loglevel}} {{.message}}'
```

ここまで定義して、prometheusを再起動することで完了です！

次回は機会があれば、死活監視、プロセス監視も紹介出来ればと思います。