mtail + Prometheus + Grafanaでリアルタイムログ監視の仕組みを作る

#はじめに
この記事は[NIFTY Advent Calendar 2017](https://qiita.com/advent-calendar/2017/nifty)の22日目の記事です。
21日目は[@machinanette](https://qiita.com/machinanette)さんの[ATTinyで離着席検出装置を自作してみた](https://qiita.com/machinanette/items/f12e18ee010a8f64e935)でした。
Prometheusを利用したリアルタイムログ監視について書いています。
#Prometheusとは
SoundCloud社が開発しているオープンソースの監視ツール。Googleの監視ツールであるBorgmonにインスパイアされており、特徴としては単バイナリで動き、Pull型でデータを取得します。PrometheusはXORencodingをベースとしたvarbitencodingを採用されており、1サンプルごとに1.5バイト程度まで抑えることができているようです。時系列DBのエンコーディングの話はすごく面白いのでぜひ一度こちらを読んで見てください。
・[時系列データベースに関する基礎知識と時系列データの符号化方式について](http://techlife.cookpad.com/entry/timeseries-database-001)


他にもPrometheusにはservice discoveryというPull型の欠点を補う仕組みが用意されています。詳しくはこちらのページが参考になりますのでぜひ一度読んでみてください。
・[次世代監視の大本命！ Prometheus を実運用してみた](http://qiita.com/sugitak/items/ff8f5ad845283c5915d2)
#mtailとは
Google製のログをパースするためのツール。tailfのようにログを読み込み続け、パースしてメトリクスとしてPrometeheusからHTTPでPullできるようにします。
#Grafanaとは
Prometheusに格納されているデータを可視化するためのビジュアライゼーションツール。Prometheusのデータを取得するには、PromQLというSQLライクなPrometheusの独自言語を利用します。
#今回作るやつのイメージ
![prometheus.001.jpeg](https://qiita-image-store.s3.amazonaws.com/0/218049/6fe9f30d-bcff-b806-2dcd-5c05d4611b05.jpeg)

#構築
##docker-composeを使って構築をする
では、構築をしていきます。構築方法はdocker-composeを利用して構築を行います。まず、作業ディレクトリを作成し、作業ディレクトリ内にPrometheusのconfigを作ります。configでは、PrometheusがPullをする周期を設定したり、監視対象をここで追加することができます。今回は、監視対象をmtailを対象にするためtargetsにはmtailのノードがあるホスト名とデフォルトポートの3903を指定しています。Prometheusのコンテナとmtailのコンテナを同一ホスト内に立ち上げる場合に気をつけないといけない事として、targetにlocalhostを指定すると自身のコンテナを指してしまうため、別名にしないとうまく動作しないため気をつけてください。

```yaml:prometheus.yml
global:
  scrape_interval:     10s  
  evaluation_interval: 10s
  external_labels:
      monitor: 'codelab-monitor'

rule_files:
#   - "/var/app/prometheus/alert.rules"

scrape_configs:
  - job_name: 'mtail'
    static_configs:
      - targets:
        - 'xxxxxxxxhost:3903'
```
Prometheusのconfigが完成したらあとはdocker-composeファイルを作って立ち上げれば終了です。今回はこのように作りました。mtailのコンテナを立ち上げるときにentrypointとしてパースの条件を記載したプログラムのパスと監視するログのパスを指定してあげる必要があります。今回は、mtailのサンプルプログラムとして最も簡単なline_count(行数を数えるだけ)を利用します。監視対象は、ローカルディレクトリのとマウントさせたvar/log/syslogを監視対象としています。

```yaml:docker-compose.yml
version: '3'
services:
  prometheus:
    image: prom/prometheus
    container_name: prometheus
    volumes:
      - /usr/local/src/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - 9090:9090

  mtail:
    image: dylanmei/mtail
    container_name: mtail
    volumes:
      - /var/log/:/var/log/
    ports:
      - 3903:3903
    entrypoint:
           - mtail
           -  --progs
           -  /go/src/github.com/google/mtail/examples/linecount.mtail
           -  --logs
           - /var/log/syslog
  grafana:
    image: grafana/grafana
    container_name: grafana
    ports:
      - 3000:3000
```


docker-composeファイルが書けたら以下のコマンドを叩きます。
```$ docker-compose masuta docker-compose -f docker-compose.yml up```
問題なければ<http://localhost:9090>にアクセスすれば下のような画面が出ると思います。
<img width="1197" alt="スクリーンショット 2017-12-23 18.01.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/218049/4922dbe3-43ad-b39b-55d4-c306c1772d64.png">
mtaiとも問題なく通信ができていればこのようにline_countというメトリクスが表示されます。
<img width="1197" alt="スクリーンショット 2017-12-23 18.03.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/218049/6b9275f2-c75f-2be0-4210-67bbe08480b2.png">

ここまで確認できれば、あとはGrafanaの設定をするだけです。
<http://localhost:3000>にアクセスしてadmin:adminでログインをし、データソースの設定をします。
<img width="620" alt="スクリーンショット 2017-12-23 18.08.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/218049/fd94395c-d14e-6d84-7c4a-fd1615368e13.png">



データソースの設定ができればユーザの設定などをしますが、ここは後回しでも大丈夫です。上にあるホームボタンからダッシュボードを選択し、New Dashboardからダッシュボードの作成を行います。この画面でダッシュボードを作成していきます。<img width="1197" alt="スクリーンショット 2017-12-23 18.11.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/218049/dccaa740-cadc-aea3-4f9f-3605e6e8adb7.png">
Graphを選択してEditを押すとグラフの作成画面に移ります。ここでデータソースの設定や、PromQLと呼ばれるSQLライクな言語を使って必要なデータを可視化します。
この例では、rate()と呼ばれるPromQLの関数を使っています。rate関数は指定した時間内の平均の１分間での上昇を測る関数です。PromQLには他にも様々な関数が用意されており、SQLよりも簡単に欲しい情報を可視化することができます。ぜひ活用してみてください。
[参考:PromQLのファンクション集](https://prometheus.io/docs/prometheus/latest/querying/functions/)
<img width="1188" alt="スクリーンショット 2017-12-23 18.30.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/218049/b2fccec1-acf7-f097-f2df-3a6bc6e99226.png">

他にもGrafanaには、template機能など便利な機能がたくさんあるのでぜひ調べてみてください。

#mtailのパースプログラムについて
mtailのパースプログラムについて、軽くだけ話します。パースプログラムでは、ログを正規表現し、ログの一部を変数化することができます。例えば下記の例では、category="start" id="1" status="success" time="100ms"のようなログが来ると想定してください。まず、ログのデータをカウントするためのカウンター変数を用意します。カウンター変数ではタグのようなものを指定することができ、PromQLで利用することができます。次に"{"の前に書いてある正規表現が一致すれば、"{"内のプログラムが実行されるという条件分岐が行えるとともに(?P<hoge>\w+)と囲んであげるとこの部分に入っていた文字列がhogeという変数に格納されます。ログを数字として捉えたければ(?P<hoge>\d+)とすればできます。ここで変数にしたものを条件文として利用することもでき、下記の例では、$timeによって条件を分岐しています。条件によって分岐させ、データを別々のサンプルに入れておき、その蓄積されたデータをPromQLが分析して可視化をするというのが、このシステムの仕組みとなっています。

```go:sample.mtail

counter total_time by category
counter total_count by time category

category="(?P<category>\w+)" id="(?P<id>\d+)" status="(?P<status>\w+)" time="(?P<time>\d+)ms"/ {

  $time < 50 {
    total_count["50"][$category]++
  }

  $time < 100 {
    total_count["100"][$category]++
  }

  $time < 200 {
    total_count["200"][$category]++
  }

  total_count[$category]++
  total_elapsed_time[$category] += $time
}

```
#最後に
最後になりましたが、mtailを利用するケースとして、自作プログラムやソフトウェアなどのログを可視化したい時に利用するのが良いと思います。理由としては、Prometheusでは、汎用的なソフトウェアについての情報をメトリクスとして集計してくれるサードパーティ製のExporterが多く作られています。例えば、Apacheのメトリクスを可視化したい場合には、[ApacheExporter](https://github.com/Lusitaniae/apache_exporter)を利用する方が導入も楽ですし、正確性も高いと思います。そのため、自作プログラムやソフトウェアなどあまり汎用的でない独自のフォーマットになっているログの情報を可視化したいときに利用するのが良いと思います。パースプログラムについては、情報源が多くなく、[サンプルプログラム](https://github.com/google/mtail/tree/master/examples)を見ながら自分で利用方法を覚えていくのが良いと思います。かなり文章も内容も雑な記事となってしまいましたが少しでもPrometheusやmtailに興味が湧いてくれたら嬉しいです。

23日目の記事は[@megane42](https://qiita.com/megane42)さんの[Neo4j を駆使して格ゲーに勝つ](https://qiita.com/megane42/items/8d9dfc52d63531e4a644)です。ぜひ見てください。