[Dynatrace] 監視ツールの通知文をJinjaテンプレートを使って究極にカスタマイズしたい！

監視ツールを使っていると、メールやチャットに通知する場面がよくありますが、通知文の設定が柔軟でなく、思うようにカスタマイズできないこともあります。Dynatraceでは[jinjaテンプレート](https://jinja.palletsprojects.com)を活用して、かなり自由にカスタマイズできますので、ご紹介していきます。

# 概要

本記事では、DynatraceのWorkflow機能を活用して、ディスクの残り容量を定期的にメールでレポートするような場面を想定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325973/a39b7cc9-7cd9-c914-e148-2b864c0550c8.png)

# DynatraceのWorkflow

Dynatraceでは、定型作業をWorkflowとして定義し、トリガーによって実行することができます。今回使うWorkflowは以下のようになっています。

![Dynatraec Workflow](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325973/22f30a1f-1090-f390-4aec-1544b9e7e97d.png)

### トリガー
まずトリガーとして"Schedule"を置いています。これは定期的に自動起動するトリガーで、毎日東京時間の0時に起動する設定になっています。
トリガーはこの他に"On demand" (手動起動のみ、外向けのAPIエンドポイントが生成される)、"Davis problem" (問題発生時に起動)、"Event" (イベント発生時に起動) などがあります。"Davis problem"をトリガーにすると、従来のアラートの代替として、より複雑なステップを実行することができます。

### アクション1: ディスクの残り容量の情報収集
トリガーから呼び出される一連の作業は「アクション」で構成されます。最初のアクションはディスクの残り容量の情報を集める"disk_free_percentage"です。情報自体はDynatraceのOneAgentにより常時収集されていますので、使いやすく整形するだけです。
Workflow内でDQLクエリを行うために、ここでは「DQLアクション」を使っています。データレークに蓄積されたデータから、必要なものを取り出すのにDQLというクエリ言語を使用します。例えば全ホストの全ディスクの残り容量を知りたい場合は以下のようにします。
```timeseries``` コマンドでメトリクスを取得します。```dt.host.disk.free```というメトリクスの一定時間の平均値を、ホストごと、ディスクごとに取り出します。取り出したメトリクスには```free```という名前を付けています。

```
timeseries free = avg(dt.host.disk.free), by:{dt.entity.host, dt.entity.disk} 
```

Notebookでクエリ結果を確認してみます。以下のようにホストとディスクでグループ化された、ディスク残り容量のメトリクスが得られます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325973/96ea0177-24ac-2a62-292a-5582fd45543f.png)

この状態だと、ホスト名やディスク名がID表記なのでわかりづらいのと、メトリクスが１分刻みの数値のリストになっていますが、ディスクにつき1つの平均値がほしいので、クエリを少し足してみます。

```
timeseries free = avg(dt.host.disk.free), by:{dt.entity.host, dt.entity.disk} 
| lookup [fetch dt.entity.host], sourceField:dt.entity.host, lookupField:id, prefix:"h."
| lookup [fetch dt.entity.disk], sourceField:dt.entity.disk, lookupField:id, prefix:"d."
| fields host = h.entity.name, disk = d.entity.name, free = round(arrayAvg(free), decimals: 1)
| sort host, disk
```

1行目は前と同じ、2行目以降はその結果に追加する操作を書いています。
2行目は、ホストIDに対するホスト名を、別のデータ```dt.entity.host```からlookupして取得しています。3行目は同じくディスク名を```dt.entity.disk```からlookupしています。
4行目は必要なフィールドだけを表示するように整えています。freeはリスト内のメトリクスの平均値を小数点以下1位まで取っています。
5行目で、ホスト名とディスク名で並び替えています。
この結果をNotebookで確認してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325973/7c09eb39-fc32-4619-b8af-5b4cd14e2525.png)

これで必要な情報が整いました。

:::note info
2024年4月末のアップデートで、[entityName](https://docs.dynatrace.com/docs/whats-new/release-notes/saas/sprint-290#new-dql-functions)というDQL関数が追加されました。これは上でlookupで行っていた、エンティティ名を取得するための関数です。これにより、下記のようにかなり短く簡単に書けるようになりました。
```
timeseries free = avg(dt.host.disk.free), by:{dt.entity.host, dt.entity.disk} 
| fields host = entityName(dt.entity.host), disk = entityName(dt.entity.disk),
         free = round(arrayAvg(free),decimals: 1)
| sort host, disk
```
:::

### アクション2: メール送信

さて、通知するための情報が用意できましたので、メールで通知するアクション```send_email```を設定します。メールだけではなく、SlackやJiraなどさまざまな連携が可能です。
宛先のメールアドレスや件名を設定し、さらに本文を設定します。
ここで今回のテーマである[Jinjaテンプレート](https://jinja.palletsprojects.com/)が活躍します。Jinjaテンプレートは、テキストファイル中に変数や制御を埋め込む書式で、DjangoやPythonにヒントを得て作られているとのことです。実際の本文の設定は以下のようになります。

```
{{now('Asia/Tokyo').strftime("%Y/%m/%d (%a) %H:%M")}} 時点のディスクの残り容量です。

{% for disk in result("disk_free_percentage").records %}
  {{ disk.host }} - {{ disk.disk }} : {{ disk.free }}%
{% endfor %}
```

```{{ }}```で変数の参照、```{% %}```に制御を記述します。
1行目は現在時刻をフォーマット付きで埋め込んでいます。
2～4は、Workflowの前のアクションの"disk_free_percentage"の結果(records)でループしています。それぞれの結果からホスト名、ディスク名、ディスクの残り容量を取り出して埋め込んでいます。`disk.host`の`host`の部分は、DQLの4行目で設定したフィールド名です。
このWorkflowを実行してみると、以下のような本文が生成されます。

```
2024/04/11 (Thu) 12:04 時点のディスクの残り容量です。

  st-linux-01 - / : 93.9%
  st-linux-01 - /boot : 86.2%
  st-linux-01 - /boot/efi : 99.4%
  st-win-01 - C:\ : 84.3%
  st-win-01 - D:\ : 89.8%
  st-win-01 - F:\ : 17.6%
```

これをより見やすくするために、コロンで縦を揃えたい時には、ループ部分を以下のようにします。2行目に文字列の結合を書いています。ホスト名とディスク名をつなげたものを、3行目のフォーマット付き文字列出力で、30桁の枠で右詰にしています。

```
{% for disk in result("disk_free_percentage").records %}
  {% set hostdisk = disk.host + " - " + disk.disk %}
  {{ "%30s" |format(hostdisk) }} : {{ disk.free }}%
{% endfor %}
```

そうすると以下のようになります。

```
2024/04/11 (Thu) 12:04 時点のディスクの残り容量です。

                 st-linux-01 - / : 93.9%
             st-linux-01 - /boot : 86.2%
         st-linux-01 - /boot/efi : 99.4%
                 st-win-01 - C:\ : 84.3%
                 st-win-01 - D:\ : 89.8%
                 st-win-01 - F:\ : 17.6%
```

なお、テキストメールを等幅フォントを使って表示しないメールアプリでは、実際には縦に揃いません。

このように、Jinjaテンプレートにより、ループや条件分岐、文字列操作や数値の計算など多彩で強力な機能が使えるようになり、通知文を究極にカスタマイズすることができます。ぜひお試しを！

Dynatraceフリートライアル → [https://www.dynatrace.com/ja/trial/](https://www.dynatrace.com/ja/trial/)