はじめに
本投稿の目的
- Elasticsearchでログ収集を行う際、ApacheやSyslog等の代表的なものであれば、既存のgrokパターンが存在しているが、たいていはオリジナルで作成が必要なケースがほとんど。
- また運用者の分析したい観点に合わせるため、既存のgrokパターンが在ったとしても、修正したいケースがある。
- このように、Logstashのgrokパターンの生成は、Elasticsearchでのログ収集にあたって、不可欠なスキルである。にもかかわらず、Logstashを利用する上での最難関のConfigであるため、一人でも多くこの難関を超えてほしいという思いから、入門用のチュートリアルを作成する。
本投稿のゴール
- grokパターンを自分で作成できるようになること
ステップ1:取り組み方
ログは頭から順番に分解していく。
- まずは簡単なログサンプルを見てみる。以下、Syslogのとある1行。
Apr 23 10:17:01 oya1ELK02 CRON[3732]: (root) CMD ( cd / && run-parts --report /etc/cron.hourly)
- 頭から見ていくと、最初に現れているのは、タイムスタンプが表示されていることがわかる。
- そうしたら、まずはタイムスタンプとそれ以外、という風に分解してみる。
- その際のgrokパターンは以下。
PATTERN %{SYSLOGTIMESTAMP:time} %{GREEDYDATA:restof}
- PATTERN
- まずは、定義名を付けてあげる必要があるので。PATTERNという名前にした。この名前でLogstashのConfigから後で指定する。
- %{SYSLOGTIMESTAMP:time}
- Syslogのタイムスタンプを示す正規表現は、「SYSLOGTIMESTAMP」という定義ですでに実装されているため、それにマッチする文字列を、「time」というタグを付けてあげる。
- 正規表現の実装が無い場合は、自分で作ってあげる必要がある。例えば「yyyy年mm月dd日」の形式の場合だと、「(¥d{4})年(0[1-9]|1[0-2])月(0[1-9]|[12][0-9]|3[01])日」のようになる。詳細はあとで説明する。
- %{GREEDYDATA:restof}
- あらゆる文字列を無差別にマッチさせる定義「GREEDYDATA」を利用し、それに「restof」というタグを付ける。
参考に、logstashのconfigファイルも掲載する。
input {
stdin {}
}
filter {
grok {
patterns_dir => ["/home/tu-itou/patterns.d"]
match => { "message" => "%{PATTERN}" }
}
}
output {
stdout { codec => rubydebug }
}
実行し結果を見てみる。
- LogstashのConfigで、入出力をそれぞれ標準入出力としているため、コマンドで実行する。
~$ cat sample.log | sudo /usr/share/logstash/bin/logstash -f sample.conf
{
"@timestamp" => 2017-04-23T02:21:58.017Z,
"restof" => "oya1ELK02 CRON[3732]: (root) CMD ( cd / && run-parts --report /etc/cron.hourly)",
"@version" => "1",
"host" => "oya1ELK02",
"time" => "Apr 23 10:17:01",
"message" => "Apr 23 10:17:01 oya1ELK02 CRON[3732]: (root) CMD ( cd / && run-parts --report /etc/cron.hourly)"
}
- 意図どおりに、「time」というタグと、「restof」というタグに分解されていることがわかる。
ステップ2:分解の実績を積み上げていく
- 考え方は、先頭から順番にタグ付けし切り離していき、「restof」を徐々に縮めていくこととなる。
Logstashの既存Grokパターン
- SYSLOGTIMESTAMPのように、Logstashにはいくつかの既存パターンが存在するので、それを積極的に活用しながらgrokパターンを自作することとなる。
- Logstashの既存パターンは公式情報を参照。
- Grok-patterns
正規表現を自作する場合
- Logstashの既存Grokパターンに存在しない文字列パターンの場合は、正規表現を自作してマッチングする必要がある。
- 以下のサイトを利用すると、簡単に作成・検証ができる。
- Regexper
- 正規表現を貼りつけて、「Display」を押すと、その正規表現でマッチされる文字列パターンが視覚的にわかる。
自作した正規表現は定義づけしよう
- 例えば、「yyyy年mm月dd日」という形式を「JAPANDATE」として定義づけする場合
JAPANDATE (¥d{4})年(0[1-9]|1[0-2])月(0[1-9]|[12][0-9]|3[01])日
ステップ3:grokフィルタのパフォーマンスを考慮する
共通部分は別で切り出す。
- システムのログなどは、ある部分までは共通で、それ以降で複数のパターンになる、というケースが多い。
- 例えばSyslogのある10行を抜き出してみると、
Apr 23 10:16:14 oya1ELK02 systemd[3555]: Reached target Timers.
Apr 23 10:16:14 oya1ELK02 systemd[3555]: Reached target Sockets.
Apr 23 10:16:14 oya1ELK02 systemd[3555]: Reached target Paths.
Apr 23 10:16:14 oya1ELK02 systemd[3555]: Reached target Basic System.
Apr 23 10:16:14 oya1ELK02 systemd[3555]: Reached target Default.
Apr 23 10:16:14 oya1ELK02 systemd[3555]: Startup finished in 9ms.
Apr 23 10:16:14 oya1ELK02 systemd[1]: Started User Manager for UID 1000.
Apr 23 10:17:01 oya1ELK02 CRON[3732]: (root) CMD ( cd / && run-parts --report /etc/cron.hourly)
Apr 23 10:29:21 oya1ELK02 systemd[1]: Started Session 1069 of user tu-itou.
Apr 23 11:17:01 oya1ELK02 CRON[6424]: (root) CMD ( cd / && run-parts --report /etc/cron.hourly)
- タイムスタンプ、ホスト名(oya1ELK02)まで共通で、それ以降で複数のパターンとなっている。
- これを、grokフィルタを2回に分けて実行し、grokが解析する範囲を小刻みにしてやる。
filter {
grok {
"match" => { "message" => '%{SYSLOGTIMESTAMP:time} %{WORD:hostname}
%{GREEDYDATA:message}' },
"overwrite" => "message"
}
grok {
"match" => { "message" => "%{PATTERN}" }
}
}
- 参考サイト:elastic公式ブログ
- Do you grok grok?