目次
概要
Prometheusでログ監視をするための環境構築手順。mtailというGoogleが用意しているログパースツールを利用する。mtailのルールを自作する方法についても説明する。
mtailの簡易検証用の環境はこちら
https://github.com/Esfahan/prometheus-and-mtail
前提条件
以下の手順でPrometheus環境を構築していることを前提とする。
https://qiita.com/Esfahan/items/0feaedfd771f49ac7ee4
mtail
こちらを利用する。
https://github.com/google/mtail
環境
- mtail v3.0.0-rc46
とりあえず動かしてみる
Docker
監視対象のサーバーで立ち上げる。/var/log/messagesと/var/log/cronのメトリクスを収集し、ログの行数をカウントするだけのサンプル。
mtail公式が用意しているlinecount.mtailというルールを利用する。
自作のルールでメトリクス収集する方法は後述する。
version: '3'
services:
mtail:
image: dylanmei/mtail
container_name: mtail
hostname: mtail
volumes:
- /var/log/:/var/log/
ports:
- 3903:3903
entrypoint:
- mtail
- --progs
- /go/src/github.com/google/mtail/examples/linecount.mtail
- --logs
- /var/log/messages
- --logs
- /var/log/cron
$ sudo docker-compose up -d --build
Prometheusの設定
こちらの記事で構築したPrometheus環境の設定ファイルを編集する。
監視対象を追加
prometheus.yamlに以下を追記。
# 前略
scrape_configs:
+ - job_name: mtail
+ metrics_path: /mtail/metrics
+ static_configs:
+ - targets:
+ - your_mtail_server.com:3903
+ labels:
+ env: development
MtailのUI
http://your_mtail_server.com:3903
prometheusというリンクをクリックすると、メトリクスが見れる。
# TYPE line_count counter
# line_count defined at linecount.mtail:4:9-18
line_count{prog="linecount.mtail"} 244
PrometheusのUI
mtailと通信できていれば、「line_count」というメトリクスが表示される。
PromQL
line_countと入力すると、以下のような結果が得られる。ログの行数が表示されている。
自作のmtailでメトリクス収集する
独自のルールでメトリクス収集するため、mtailを自作する。
今回の例では、example.logに出力されたログを、正規表現でカウントするもの、特定の文字列が含まれているかどうかを判別するmtailを作る。
mtailの文法については以下で説明されている。
https://github.com/google/mtail/blob/main/docs/Language.md
また、mtailのサンプルは以下に用意されている。
https://github.com/google/mtail/tree/main/examples
ディレクトリ構成
以下のディレクトリ構成を作る。
├── docker-compose.yaml
├── logs
│ └── example.log # メトリクス収集対象のログ
└── mtail
└── example.mtail # 自作mtail
事前準備
$ mkdir {logs,mtail}
$ touch logs/example.log
example.mtail
mtail/example.mtailを作成する。どういうルールでメトリクス収集するのかはコメントアウトを参照。
変数定義をする際、counterかgaugeのどちらかのtypeを定義する。
counterは、正規表現にマッチした行数をカウントするときに使う。
gaugeは数値、文字列などを代入できるtypeで、以下の例では、正規表現にマッチした行があれば1
を、なければ0
を返すルールとなっている。0
, 1
でなく、文字列を返すことも可能。文字列の場合シングルクォートだとエラーになるのでダブルクォートにすること。line_count_info
や warn_flg_no_declared
は変数名だが、任意の名前でよい。
counter line_count_error
counter line_count_fatal
counter line_count_debug
gauge error_flg_syntax
gauge fatal_flg_oom
gauge debug_flg
# [ERROR]の行が何行あるか
/^\[ERROR/ {
line_count_error++
}
# [FATAL]の行が何行あるか
/^\[FATAL/ {
line_count_fatal++
}
# [DEBUG]の行が何行あるか
/^\[DEBUG/ {
line_count_debug++
}
# "Syntax error"を含む行があるかどうか
/Syntax error/ {
error_flg_syntax = 1
}
# "Out of memory"を含む行があるかどうか
/Out of memory/ {
fatal_flg_oom = 1
}
# "debug message"を含む行があるかどうか
/debug message/ {
debug_flg = 1
}
ちなみに、golangでは正規表現で「文字列がマッチしない場合」という否定ができないので、工夫する必要がある。以下参照。
Dockerでmtailの環境を構築
version: '3'
services:
mtail:
image: dylanmei/mtail
container_name: mtail
volumes:
- ./logs:/logs/
- ./mtail/:/mtail
ports:
- 3903:3903
entrypoint:
- mtail
- --progs
- /mtail/example.mtail
- --logs
- /logs/example.log
#######################
# 複数ファイル指定する場合
#######################
#- mtail
#- --progs
# progsはディレクトリを指定することで、その配下のファイルが全て読み込まれる
#- /mtail/
# logsは、以下の様にカンマ区切りで指定するか、もしくは--logsを複数指定することでも可能。
#- --logs
#- /logs/example.log,/logs/example02.log
#- --logs
#- /logs/example03.log
networks:
- sample-network
networks:
sample-network:
external: true
$ sudo docker-compose up -d --build mtail
mtailの文法エラーなどの確認方法
ブラウザからエラーを確認できる。
http://your_mtail_server.com:3903
対象ログ
logs/example.logに以下を書き込む。
Dockerコンテナが起動した後から出力されたログが収集されるので、docker-compose upをした後にログを書き込む。
[INFO] This is an info message.
[WARN] This is a warning message.
[WARN] No declared value.
[ERROR] This is an error message.
[ERROR] Syntax error.
[ERROR] Syntax error.
[FATAL] This is a fatal message.
[FATAL] Out of memory.
[FATAL] Disk error.
[FATAL] Kernel panic.
メトリクスをPrometheusの画面で確認
しばらくしてからPrometheusの画面を確認すると、メトリクス収集されていることが確認できる。
http://your_prometheus_server.com:9090/graph
収集項目 | PromQL | 結果 |
---|---|---|
[ERROR]の行が何行あるか | line_count_error | 3 |
[FATAL]の行が何行あるか | line_count_fatal | 4 |
[DEBUG]の行が何行あるか | line_count_debug | 0 |
"Syntax error"を含む行があるかどうか | error_flg_syntax | 1 |
"Out of memory"を含む行があるかどうか | fatal_flg_oom | 1 |
"debug message"を含む行があるかどうか | debug_flg | Empty |
障害検知、復旧の検証
example.mtailにルール追加
先程作成したexample.mtailでは、"Out of memory"を含む行がある場合にfatal_flg_oom = 1
となるルールを作成した。ここではそれに加えて、"Memory recorverd"を含む行がある場合にfatal_flg_oom = 0
となるルールを追記する。
こうすることで、ログに"Out of memory"が書き込まれたら障害発生、"Memory recorverd"が書き込まれたら復旧、という挙動にすることができる。
gauge fatal_flg_oom
# "Out of memory"を含む行があるかどうか
/Out of memory/ {
fatal_flg_oom = 1
}
+# 以下を追記
+# "Memory recorverd"を含む行があるかどうか
+/Memory recorverd/ {
+ fatal_flg_oom = 0
+}
設定反映
$ sudo docker-compose restart mtail
検証
"Out of memory"をログに追記する。
$ echo "[FATAL] Out of memory." >> logs/example.log
fatal_flg_oom
が 1
になったことを確認。
http://your_prometheus_server.com:9090/graph
"Memory recorverd"をログに追記する。
$ echo "[INFO] Memory recorverd" >> logs/example.log
fatal_flg_oom
が 0
になったことを確認。
http://your_prometheus_server.com:9090/graph
再度[FATAL] Out of memory.
が書き込まれればまたfatal_flg_oom = 1
となり、[INFO] Memory recorver
が書き込まれればfatal_flg_oom = 0
となるので何度か試してみるとよい。
ログにERRORという文字列が書き込まれたらエラー検知をする例
mtail
ERRORという文字列がログに書き込まれたらerror_countがカウントUPされるルールを作る。
mtail/mtail/example.mtail
counter error_count
/ERROR/ {
error_count++
}
log
ログにERRORという文字が書き込む。
[ERROR] Syntax error.
検知方法(PromQL)
rate関数で直近1分にERRORという文字列が書き込まれたかを確認する。
書き込まれていなければ0
を返すので、以下のPromQLでエラー検知できる。
rate(error_count[1m]) > 0
rate(error_count[5m]) > 0
rate関数については以下を参照。
参考:rate関数
mtailコマンドでメトリクス確認
以下のようにmtailコマンドに--one_shot
というオプションを付けて実行することで、メトリクスを確認する事もできる。
version: '3'
services:
mtail-checker:
image: dylanmei/mtail
container_name: mtail-checker
hostname: mtail-checker
volumes:
- ./logs:/logs/
- ./mtail/:/mtail
entrypoint:
- mtail
- --one_shot
- --progs
- /mtail/example.mtail
- --logs
- /logs/example.log
$ sudo docker-compose run --rm mtail-checker
Creating mtail_mtail-checker_run ... done
Metrics store:{
"debug_flg": [
{
"Name": "debug_flg",
"Program": "example.mtail",
"Kind": 2,
"Type": 0
}
],
"error_flg_syntax": [
{
"Name": "error_flg_syntax",
"Program": "example.mtail",
"Kind": 2,
"Type": 0,
"LabelValues": [
{
"Value": {
"Value": 1,
"Time": 1623583432182670126
}
}
]
}
],
"fatal_flg_de": [
{
"Name": "fatal_flg_de",
"Program": "example.mtail",
"Kind": 2,
"Type": 0,
"LabelValues": [
{
"Value": {
"Value": 1,
"Time": 1623583432182861408
}
}
]
}
],
"fatal_flg_kp": [
{
"Name": "fatal_flg_kp",
"Program": "example.mtail",
"Kind": 2,
"Type": 0,
"LabelValues": [
{
"Value": {
"Value": 1,
"Time": 1623583432182882874
}
}
]
}
],
"fatal_flg_oom": [
{
"Name": "fatal_flg_oom",
"Program": "example.mtail",
"Kind": 2,
"Type": 0,
"LabelValues": [
{
"Value": {
"Value": 1,
"Time": 1623583432182722713
}
}
]
}
],
"line_count_debug": [
{
"Name": "line_count_debug",
"Program": "example.mtail",
"Kind": 1,
"Type": 0,
"LabelValues": [
{
"Value": {
"Value": 0,
"Time": 0
}
}
]
}
],
"line_count_error": [
{
"Name": "line_count_error",
"Program": "example.mtail",
"Kind": 1,
"Type": 0,
"LabelValues": [
{
"Value": {
"Value": 3,
"Time": 1623583432182657661
}
}
]
}
],
"line_count_fatal": [
{
"Name": "line_count_fatal",
"Program": "example.mtail",
"Kind": 1,
"Type": 0,
"LabelValues": [
{
"Value": {
"Value": 4,
"Time": 1623583432182874744
}
}
]
}
],
"line_count_info": [
{
"Name": "line_count_info",
"Program": "example.mtail",
"Kind": 1,
"Type": 0,
"LabelValues": [
{
"Value": {
"Value": 1,
"Time": 1623583432182384349
}
}
]
}
],
"line_count_warn": [
{
"Name": "line_count_warn",
"Program": "example.mtail",
"Kind": 1,
"Type": 0,
"LabelValues": [
{
"Value": {
"Value": 2,
"Time": 1623583432182542428
}
}
]
}
],
"warn_flg_no_declared": [
{
"Name": "warn_flg_no_declared",
"Program": "example.mtail",
"Kind": 2,
"Type": 0,
"LabelValues": [
{
"Value": {
"Value": 1,
"Time": 1623583432182558035
}
}
]
}
]
}