図解で、Datadogのログからメトリックを生成する

# 図解で、Datadogのログからメトリックを生成する

Datadog で収集したテキストログはログ・パイプラインを使って、アラート閾値やグラフ可視化するためのメトリックを生成することが可能です。例えばテキストログ［20:57:37 load average 11 minutes］があったとして動作時間の折れ線グラフを描くためにメトリック[load.average]とその値[11]を生成できたりします。テキストログから特定の文字列を抽出して（パースして）、[Generate Metrics]という機能でメトリックを生成します。その手順を検証しました。

### シナリオ
サードパーティのソフトウェア製品が出力するテキストログをパースしてメトリック生成してみます。マルチプレイ用のマインクラフトサーバーにログインしたユーザー名を記録して遊び過ぎを抑制するというシナリオを想定。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/489a21c9-81ff-7db1-cebf-d39e2633b52b.png)

## テキストログからメトリック生成手順（STEP）
- STEP1. ログの取り込み（Datadogエージェントの設定）
- STEP2. ログ送信を検査
- STEP3. ログ・パイプラインの設定
- STEP4. メトリックの生成
- STEP5. メトリックを検索


## STEP1. ログの取り込み（Datadogエージェントの設定）
ゲームサーバーのログをDatadogエージェント経由で、インターネット側のDatadogインテークサーバーに転送します。ログファイルのパスを指定した設定ファイルを記述してDatadogエージェントを再起動します。

``` /etc/datadog-agent/conf.d/custom_log_collection.yaml
logs:
  - type: file
    path: /opt/minecraft-server/logs/latest.log
    source: kanoGame
    service: minecraft
```

## STEP2. ログ送信を検査
Datadogポータルにログインして、ログエクスプローラー[Logs]でログを受信できたことを検査します。[Logs] > [Search]

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/6ada58ec-b6c4-c69f-7e85-6c7659350427.png)

## STEP3. ログ・パイプラインの設定
受信したログを抽出（パース）するため、テキストログのサンプルをクリップボードにコピーします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/e2e159b6-e018-b394-e03e-fc24f35c13b3.png)

ログパイプラインに新しい[pipeline]を追加します。
[Logs] > [Configuration]
パイプラインの入口として、様々なログの中から対象とするログをフィルタリングします。このシナリオの場合は［kanogameサーバー］の［minecraftサービス］だけ抽出します。Name項目には好きな説明を記入します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/d27665aa-06e3-a50b-5098-b69af7200821.png)

### パースの設定
次にパースを追加します［Add processor］です。
DatadogはJSON形式のログならば自動でパースしてくれますが、JSON形式でないテキストログなどはGrokパーサーを使います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/895a0813-7091-c0e1-f681-93b44ae6e339.png)

Grok パーサーにテキストログから属性を抽出するルールを定義します。
ここで貼り付けたテキストログは『[20:57:37] 　[Server 　thread/INFO]: 　FunnyKano joined the game』です。一旦、抽出ルールにも同じテキストを貼り付けます。この時点ではルールに「ルール名」の記載がなかったり、特殊記号をスケープしていないので［NO MATCH］と赤く表示されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/961ecc93-ccaa-a9e9-653c-c9bbaefd04df.png)

この時点のルールでは何もログ属性を取得できていません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/74df74a4-21e4-e411-0823-41b472013a4b.png)

### Grok パーサーのルール定義
ルール名称を追加します。続けて、パースの規則を記載します。テキストログの[時刻]情報は刻々と変化するので時刻属性かもしくは無視します。今回はシンプルに無視するので[notSpace]でマスクします。特殊記号部分［カギカッコ］はエスケープ文字”\[”で置き換えるかもしくは無視します。その他のテキストは一旦、残します。下記のルールを設定すると［Match］になりました。日付やINFOステータスもパースする場合は後述のパースルールサンプルに記載します。
意味のあるパースなら『 rule \[%{date("HH: mm: ss"):date}\] \[Server thread/%{word:level}\]: %{word:userName} joined the game 』とします。
ユーザー名以外は無視するなら『 rule %{notSpace} %{notSpace} %{notSpace} %{word:userName} joined the game 』でもMATCHになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/15bec681-7af7-f7fa-04f8-b7ddb875f1f4.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/662ae223-7bb1-b424-4545-469dd77b20cc.png)

ユーザー名を取得したいので、ユーザー名をパースします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/0c3e05c2-5f67-5ad4-d9c3-b7f6cc948ea7.png)


このルール規則の場合、属性 userName にユーザー名を取得できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/6e3283aa-cea5-d705-333f-0dcb6ed03a78.png)

### ログのパース規則を書くためのヒント
テキストログをパースするために「パース規則（Parsing rules）」を記載しますが、記載方法を忘れた時に便利な、パース規則を自動生成してくれる機能「Show Parse Rule」があります。機能を見つけにくいので下記に別途記載しました。

[パース規則の自動生成はこちら「Show Parse Rule」](https://qiita.com/1Kano/items/5da81366e1012c0a4bea)


## STEP4. メトリックの生成
ログパイプラインをずっと下にスクロールすると見えてくる［Generate Metrics］というメニューを選択して、新しいメトリック［New Metric］を実行します。
(1) Set Metric Name には自由に新しいメトリックの名称を決めます。
(2) Define Query ではメトリックの値を選びます。ログをパースして取得した　userName属性 をセットします。

今回は［kanoGameUser］という新しいメトリックを生成しました。値は userName:属性にパースしたユーザ名を設定します。
メトリック[kanoGameUser]には、[userName:<ユーザー名1>]や[userName:<ユーザー名2>]などの値が追加されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/ff27dbfc-8fed-5797-70d8-8659757c6355.png)


## STEP5. メトリックを検索
メトリックエクスプローラーを使って生成したメトリックを検索できることを検査します。
新しく生成したメトリック[kanoGameUser]を検索して値を見つけました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/6d34052f-fbfd-6bfa-69a3-22fc36ab85cc.png)

### メトリックの可視化
ログから生成したメトリックを可視化できました（ユーザー名毎のログイン数をカウントしています）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/47ae7287-d95f-4499-446d-38228422ed71.png)

### まとめ

テキストログでもメトリックを取得できれば、監視もしやすいです。
- グラフで可視化できる（ダッシュボードでのグラフ共有等）
- アラート通知できる（例えばユーザーが５人以上ログインしたら等）

テキストログからメトリックを生成して可視化できました。
- ログをパースできた
- パースしたログ属性のメトリックを生成できた
- メトリックをグラフ化できた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/956b1da5-5ee1-efbf-bd09-1bffcd24af88.png)

## （おまけ）パースのサンプル１

テキストログが［時刻］、［特殊記号 "[" や "]" の時］
時刻が 'HH : mm : ss' の形式だったら date 属性に値を代入する。
INFO箇所は、文字列'word'形式で level 属性に代入する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/78b07d74-8ea1-a6e7-42f6-f919cd671b05.png)

このルールの結果はこうなりました（↓）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/da53d472-494c-3da0-a467-ec17bc81644b.png)

## （おまけ）パースのサンプル２
マイクラのログインログには、IPアドレスやゲーム世界のXYZ座標が含まれていて複雑です。この場合のパースルールを試します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/95d3d192-1944-fbc1-c294-babaed8d00eb.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/d93c7c91-b6a1-da13-9b9b-3cff58617c79.png)

## その他 パース規則の例

|ログタイプ| ログ例 | パース規則 |
|---|---|---|
|日付     |　[21:48:09]　|　\[%{date("HH: mm: ss"):date}\] |
|ステータス|　[Server thread/INFO]: 　|　 \[Server thread/%{word:level}\]: |
|ユーザ名とかテキスト|　FunnyKano　|　%{word:username} |
|IPアドレス|　[/220.000.000.000] |　\[/%{ipv4:ipv4}\]  |
|数値変数|　47, 69, 101　|　\(%{number:x}, %{number:y}, %{number:z} |