やったことのまとめ
- ログファイルをtailしてメトリクス化する
mtail
を使ってnginx
のアクセスログをメトリクス化した
つかうもの
- macOS Big Sur 11.2.3
- Docker Desktop for Mac
- Version 3.5.2
- Docker Engine Version 20.10.7
- Docker Compose Version 1.29.2
- mtail version 3.0.0-rc47
- nginx 1.21.1
- Prometheus v2.29.1
やったこと
mtailのビルド
mtail
はアプリケーションのログをメトリクス化するツール。
自身でメトリクスを公開できないアプリの監視なんかに使えそう。
nginx
のメトリクスを扱うexporterとしてはnginx-prometheus-exporterがあるんだけど、
stub_statusの設定が必要だったりOSS版nginx
だとメトリクスの種類が少なかったりするので今回はmtail
を使ってみる。
mtail
のビルド方法はいくつかある1が、今回はかんたんに試したいのでGitHub Releases
で配布されているバイナリ2を仕込んだDocker
イメージを作成する。
(自前でビルドしようとしたら自分の環境ではテストのエラーが発生してうまくできなかった…)
# Docker imageのビルド
$ ls Dockerfile
Dockerfile
$ docker image build -t mtail .
$ docker container run -it --rm mtail --version
mtail version 3.0.0-rc47 git revision 5e0099f843e4e4f2b7189c21019de18eb49181bf go version go1.16.5 go arch amd64 go os linux
mtail programの作成
続いてログをメトリクスに変換するためのmtail program
と呼ばれるスクリプトを作成する。mtail program
はpattern
(ログの各行に対する条件)とaction
(patternを満たしたログに関する処理)から構成されている。3
(awk
にちょっと似ている)
pattern
は主に正規表現で記述するので、まずはメトリクス化したいnginx
のアクセスログのフォーマットを確認する。
# nginxのログフォーマットを確認
$ docker container run -it --rm nginx:1.21.1 cat /etc/nginx/nginx.conf
...(省略)
http {
...
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
...
}
このときのログの具体例は次のとおり。
172.20.0.1 - - [18/Aug/2021:14:04:48 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36" "-"
このフォーマットのログに対して正規表現で名前付きキャプチャグループを設定すると次のような感じになる。$request
はメソッド、URI、バージョンに分割するようにした。
^(?P<remote_addr>\S+) - (?P<remote_user>.+) \[(?P<time_local>.+)\] "(?P<request_method>\S+) (?P<request_uri>\S+) (?P<request_version>\S+)" (?P<status>\S+) (?P<body_bytes_sent>\S+) "(?P<http_referer>\S+)" "(?P<http_user_agent>.+)" "(?P<http_x_forwarded_for>\S+)"$
この正規表現をpattern
としたmtail program
を次のように作成した。nginx_request
はリクエスト数を数えるカウンタで、ラベルとしてリクエストメソッドとステータスコードを付与するようにした。nginx_request_pattern_matching_failed
はpattern
にマッチしなかったログの行数を数えるカウンタとして使用する。
また、どちらもログファイル名としてsourceラベルを付与するようにした。
動作確認
これでmtail
を使う準備ができたのでDocker Compose
でnginx
やPrometheus
と一緒に起動してみる。mtail
の実行時引数などは公式ドキュメント4を参考にした。
Docker
版のnginx
はアクセスログ(/var/log/nginx/access.log
)とエラーログ(/var/log/nginx/error.log
)がそれぞれ標準出力(/dev/stdout
)と標準エラー出力(/dev/stderr
)へのシンボリックリンクになっていて、
ファイルとして参照するのが難しかったのでログの出力先を変更するようにした。
# ログファイルが標準出力へのシンボリックリンクになっている
$ docker container run -it --rm nginx:1.21.1 ls -l /var/log/nginx
total 0
lrwxrwxrwx 1 root root 11 Aug 17 11:46 access.log -> /dev/stdout
lrwxrwxrwx 1 root root 11 Aug 17 11:46 error.log -> /dev/stderr
# 起動前のディレクトリの状態
$ tree
.
├── Dockerfile
├── README.md
├── docker-compose.yaml
├── mtail
│ └── nginx.mtail
├── nginx
│ └── nginx.conf
└── prometheus
└── prometheus.yml
# 起動
$ docker compose up -d --force-recreate
$ docker compose ps
NAME COMMAND SERVICE STATUS PORTS
mtail-nginx_mtail_1 "./mtail --progs=/et…" mtail running 0.0.0.0:3903->3903/tcp, :::3903->3903/tcp
mtail-nginx_nginx_1 "/docker-entrypoint.…" nginx running 0.0.0.0:80->80/tcp, :::80->80/tcp
mtail-nginx_prometheus_1 "/bin/prometheus --c…" prometheus running 0.0.0.0:9090->9090/tcp, :::9090->9090/tcp
この状態でhttp://localhost:3903/を開くとmtail
が正常に動作していることを確認できる。
次にnginx
http://localhost/に対していくつかリクエストを送ってみる。
# nginxにホストOSからリクエストを送る
$ curl -X GET "http://localhost/index.html"
$ curl -X GET "http://localhost/index.html"
$ curl -X GET "http://localhost/hogehoge.html"
$ curl -X POST "http://localhost/index.html"
$ curl -X PUT "http://localhost/index.html"
$ curl -X DELETE "http://localhost/index.html"
# ログファイルの内容
$ docker compose exec nginx cat /var/log/mtail-nginx/access.log
172.22.0.1 - - [19/Aug/2021:11:09:05 +0000] "GET /index.html HTTP/1.1" 200 612 "-" "curl/7.64.1" "-"
172.22.0.1 - - [19/Aug/2021:11:09:06 +0000] "GET /index.html HTTP/1.1" 200 612 "-" "curl/7.64.1" "-"
172.22.0.1 - - [19/Aug/2021:11:09:12 +0000] "GET /hogehoge.html HTTP/1.1" 404 153 "-" "curl/7.64.1" "-"
172.22.0.1 - - [19/Aug/2021:11:09:18 +0000] "POST /index.html HTTP/1.1" 405 157 "-" "curl/7.64.1" "-"
172.22.0.1 - - [19/Aug/2021:11:09:22 +0000] "PUT /index.html HTTP/1.1" 405 157 "-" "curl/7.64.1" "-"
172.22.0.1 - - [19/Aug/2021:11:09:27 +0000] "DELETE /index.html HTTP/1.1" 405 157 "-" "curl/7.64.1" "-"
$ docker compose exec nginx cat /var/log/mtail-nginx/error.log
2021/08/19 11:09:12 [error] 31#31: *3 open() "/usr/share/nginx/html/hogehoge.html" failed (2: No such file or directory), client: 172.22.0.1, server: localhost, request: "GET /hogehoge.html HTTP/1.1", host: "localhost"
mtail
のメトリクスはPrometheusのフォーマットに対応していて、
http://localhost:3903/metricsで内容を確認できる。
nginx.mtail
で定義したとおり、
アクセスログの内容は正規表現のpattern
にマッチするのでメソッドとステータスがラベル化されてnginx_request
としてカウントされていて、
エラーログの内容はpattern
にマッチしないのでnginx_request_pattern_matching_failed
としてカウントされている。
最後に一応Prometheus
http://localhost:9090/graphでもメトリクスを確認する。
mtail
のメトリクスは通常のexporterと同様に扱えるので、時系列データとしてグラフ化もできている。
やったぜ。🎉
おわり
mtail
でnginx
のログファイルをメトリクス化できた。nginx
に限らず、ログのフォーマットが決まっていてそれにマッチする正規表現が書ければ何でもメトリクス化できるのでかなり便利だと思った。