Datadogのログのパースとカテゴリプロセッサとステータスリマップ


Datadog画面上でやるログのパースなどの備忘録です。

参考サイト:
https://docs.datadoghq.com/ja/logs/processing/processors/?tab=ui
https://docs.datadoghq.com/ja/logs/processing/parsing/?tab=matcher
http://htnosm.hatenablog.com/entry/2018/07/21/090000
https://qiita.com/smallpalace/items/d002715d9a79f852a9db

今回は、ECSクラスタのコンテナからCloudwatchLogsを経てLambdaで飛んできたNginxとPHP(Laravel)ログが対象でした。
マニュアルとログ自体をじっとみるとわりとできないこともなかったです。ログ飛ばすための設定については省略します。

サンプルログをSearchから採集

右上のエクスポートっぽいアイコンを押すとログのjsonデータが取れるのでそれをみながらパースしたいmessageがmessageというアトリビュートの中身であることを確認。もしそうであれば、messageリマッパーを使う必要がないので、Source絞り込んだあとにGrokParser使えます。

パイプラインを追加する

どのログのパースをするかパイプライン追加(Add new Pipeline)押して選んでいきます。
CloudwatchからきてるNginxとPHPのログのパイプラインをそれぞれ絞り込みます。
Lambdaで飛ばす時にロググループ毎にフィルタ名追加していて、それがHostというアトリビュートに入って飛んできてるようだったのでHost指定して対象ログを絞り込みます。

GrokParserを書く

つぎにGrokParserでサンプルログを上のフォームに貼って、そのしたのフォームにパース書いていくと、指定したアトリビュートにちゃんとパースされてる様子がリアルタイムでわかります。(パース間違ってないかその場でわかる)
入れ子のパース書きたいときはAdvancedSettingsにかいてくようです。

以下のように、パースの種類は文字列だったらword、ipアドレスならipv4、スペースのない文字列ならnotSpace、数字だったらnumber、正規表現だったらregex("[a-zA-Z0-9-]*")、ダブルクォートで囲まれた文字列ならdoubleQuotedString、などをつかいます。アトリビュート名はデータに対するキー名で、ありがちなのは決まった値にすると勝手にインデックスされて便利。なので既存の同じ意味のELBのログなどがどういうアトリビュート名で来てるか確認するとわかるしStandardAttributesみてもいいと思います。

パースの名前 %{パースの種類:アトリビュート名} %{パースの種類:アトリビュート名} %{パースの種類:アトリビュート名} .... 

以下がサンプルを元にして書いたもの。何時でも試せるようにコメントにログのサンプル書いておくのがベストプラクティスだそうです。

laravelのログのパース
# 172.17.0.28 -  25/Oct/2019:01:54:23 +0000 \"GET /index.php\" 200
lara_parser1 %{ipv4:remote-ip-addr} - %{regex("[a-zA-Z0-9-]*")} %{date("dd/MMM/yyyy:HH:mm:ss Z"):date} \\\"%{notSpace:http.method} %{notSpace:http.url}\\\" %{number:http.status_code}
lara_parser2 %{ipv4:remote-ip-addr} - %{regex("[a-zA-Z0-9-]*")} %{date("dd/MMM/yyyy:HH:mm:ss Z"):date} \"%{notSpace:http.method} %{notSpace:http.url}\" %{number:http.status_code}
nginxのログのパース
# sample log
# 192.168.10.49 - - [25/Oct/2019:02:47:26 +0000] "GET / HTTP/1.1" 200 29 "-" "ELB-HealthChecker/2.0"
# 192.168.10.49 - - [10/Oct/2019:04:17:30 +0000]  "GET / HTTP/1.1" 200 29 "-" "ELB-HealthChecker/2.0"
nginx_parser1 %{ipv4:remote-ip-addr} - - %{date("[dd/MMM/yyyy:HH:mm:ss Z]"):date} %{regex("[a-zA-Z0-9]*")} "%{word:http.method} %{regex("[a-zA-Z0-9./]*"):http.url} %{regex("[a-zA-Z0-9./]*"):http.version}" %{number:http.status_code} %{word:http.status_suffix} %{doubleQuotedString:http.body_byte_sent} %{doubleQuotedString:http.referer}
nginx_parser2 %{ipv4:remote-ip-addr} - - %{date("[dd/MMM/yyyy:HH:mm:ss Z]"):date} "%{word:http.method} %{regex("[a-zA-Z0-9./]*"):http.url} %{regex("[a-zA-Z0-9./]*"):http.version}" %{number:http.status_code} %{word:http.status_suffix} %{doubleQuotedString:http.body_byte_sent} %{doubleQuotedString:http.referer}

ちなみにこのようにパースして使えるアトリビュートが増えたことで、リファラがELBのヘルスチェックだったらIndexで除外設定して課金されないようにすることが可能に。(本当はLambdaの実行回数とかも課金あるので元から出さないようにNginx設定したほうがいいですが)

マッチしやすいのはnotSpaceとかですが、http.status_codeはnumberじゃないとIndexされないかんじでした。
以下マニュアルみてもわかりやすいですが?マーク押すと親切なわかりやすい解説が出てくるので?みたらとりあえず押すといいと思います。
https://docs.datadoghq.com/ja/logs/processing/parsing/?tab=matcher

カテゴリプロセッサでhttpのステータスコードをカテゴリ分け

カテゴリプロセッサを追加して、http.status_code:500 を Errorというカテゴリとして、http.status_groupという名前のアトリビュートとして追加します。やりたければ400とか200とかも追加。

Status Remapperでステータスコード500をErrorで赤い表示にする

ステータスリマッパーではマニュアルによるとwで始まる文字列だとwarningでeで始まる文字列だとErrorとしてステータスリマップしてくれるということみたいで、自分でステータスを細かく定義するのは無理そうでした。で、さっきのカテゴリプロセッサでのアトリビュート定義する際にそのカテゴリの値をそれらしい文字列で始まるようにしてあげるわけです。そうするとステータスリマッパーではリマップしたいアトリビュートを指定するだけで済みます。

ServerityでステータスリマップしたいときはそちらのパースをGrokParserで頑張って、Serverityとして出したアトリビュートをステータスリマッパーで指定します。複数のアトリビュートでステータスリマップしたいときはカンマ区切りで指定できそうでしたが評価されるのは1つだけで指定した順になる模様。

以上