Datadogでカスタムモニタリングを試してみた

# 背景・目的
以前、下記の記事でDatadogを整理しました。今回はカスタムメトリクスを作成してみます。

https://qiita.com/zumax/items/c0c5d689edb17169483c


# まとめ
下記に特徴をまとめます

|特徴|説明|
|:--|:--|
|カスタムメトリクス|アプリケーションの KPI を追跡するのに役立つ<BR>メトリクス名とタグ値 (ホストタグを含む) のユニークな組み合わせによって識別される|
|カスタムメトリクスのプロパティ|下記のものがある<BR>・METRIC_NAME<BR>・METRIC_VALUE<BR>・タイムスタンプ<BR>・タグ<BR>・METRIC_TYPE<BR>・INTERVAL|
|メトリクスタイプの種類|COUNT<BR>RATE<BR>GAUGE<BR>HISTOGRAM<BR>DISTRIBUTION


# 概要
## カスタムメトリクス
下記の記事を基に整理します。

https://docs.datadoghq.com/ja/metrics/custom_metrics/

> カスタムメトリクスは、訪問者数、平均顧客バスケットサイズ、リクエストレイテンシー、カスタムアルゴリズムのパフォーマンス分布など、アプリケーションの KPI を追跡するのに役立ちます。カスタムメトリクスは、メトリクス名とタグ値 (ホストタグを含む) のユニークな組み合わせによって識別されます。以下の例では、メトリクス request.Latency は 2 つのタグキーから 4 つのユニークなタグ値の組み合わせを持っています。

- アプリケーションの KPI を追跡するのに役立つ
- メトリクス名とタグ値 (ホストタグを含む) のユニークな組み合わせによって識別される

### カスタムメトリクスのプロパティ

|プロパティ|説明|
|:--|:--|
|METRIC_NAME|メトリクスの名前|
|METRIC_VALUE|メトリクスの値。注: メトリクスの値は 32 ビットである必要がある。値は日付またはタイムスタンプを反映できない|
|タイムスタンプ|メトリクスの値に関連付けられたタイムスタンプ。注: メトリクスのタイムスタンプは、未来は 10 分、過去は 1 時間を超えることはできない|
|タグ|メトリクスに関連付けられているタグセット|
|METRIC_TYPE|	メトリクスのタイプ|
|INTERVAL|メトリクスの <TYPE> が RATE または COUNT の場合は、その間隔を定義する|

#### メトリクスタイプ
下記の記事を基に整理します。

https://docs.datadoghq.com/ja/metrics/types/?tab=count

|定義|説明|
|:--|:--|
|COUNT|ある時間間隔内のイベント発生の合計数|
|RATE|ある時間間隔の 1 秒あたりのイベント発生の合計数|
|GAUGE|時間間隔のイベントのスナップショット<BR>使用可能なディスク容量や使用中のメモリなど、継続的にレポートする何かの測定を行うことが可能|
|HISTOGRAM|ある時間間隔の Agent 側で計算された一連の値の統計分布|
|DISTRIBUTION|ある時間間隔内に分散インフラストラクチャー全体で計算された一連の値のグローバルな統計分布|


# 実装
## 前提
- PCは、MacOSを利用
- エディタはCursorを利用
- 言語はPython
- 下記の構成とします

    ```bash
    datadog-progress-sender/
    ├── main.py
    ├── .env
    ├── requirements.txt
    └── README.md
    ```


## 準備
1. GitHubにリポジトリを作成します
    ```bash
    % gh repo create datadog-progress-sender --public --clone
    ✓ Created repository XXXXXX/datadog-progress-sender on GitHub
      https://github.com/XXXXXX/datadog-progress-sender
    % 
    ```
1. プロジェクトを移動します
    ```bash
    % cd datadog-progress-sender 
    ```
1. Cursorを開き、「フォルダーをワークスペースで開く」を選択します
1. 作成したフォルダを選択します


## パッケージの準備
1. `requirements.txt`を作成します
    ```py
    python-dotenv
    requests
    ```

## Pythonスクリプトの作成
1. `main.py`を作成します
    ```py
    import os
    import time
    import requests
    from dotenv import load_dotenv
    
    # 環境変数読み込み
    load_dotenv()
    DATADOG_API_KEY = os.getenv("DATADOG_API_KEY")
    
    if not DATADOG_API_KEY:
        raise ValueError("DATADOG_API_KEY is not set in environment variables.")
    
    # Datadog API URL
    url = "https://api.ap1.datadoghq.com/api/v1/series"
    
    # 進捗送信関数
    def send_progress(progress: int):
        timestamp = int(time.time())
        payload = {
            "series": [
                {
                    "metric": "custom.job.progress", # Datadog上で表示されるメトリクス名
                    "points": [[timestamp, progress]], # 測定データ（時刻と値のペア） 
                    "type": "gauge", #メトリクスの種類
                    "host": "macbook-pro", # 送信元のホスト
                    "tags": ["job:python-cursor"] # タグ。フィルタにつかう
                }
            ]
        }
        headers = {
            "Content-Type": "application/json",
            "DD-API-KEY": DATADOG_API_KEY
        }
    
        response = requests.post(url, json=payload, headers=headers)
        if response.status_code == 202:
            print(f"[OK] Progress {progress}% sent to Datadog.")
        else:
            print(f"[ERROR] Failed to send progress: {response.text}")
    
    # 例: 5%ずつ進捗送信
    if __name__ == "__main__":
        for progress in range(5, 101, 5):
            send_progress(progress)
            time.sleep(5)  # 5秒ごとに進捗を送信
    ```

## README
1. READMEを作成します

## インストール
1. `pip install -r requirements.txt`でパッケージをインストールします
    ```bash
    % pip install -r requirements.txt
    
    Collecting python-dotenv (from -r requirements.txt (line 1))
      Downloading python_dotenv-1.0.1-py3-none-any.whl.metadata (23 kB)
    Requirement already satisfied: requests in /Users/XXXXX/.pyenv/versions/3.12.5/lib/python3.12/site-packages (from -r requirements.txt (line 2)) (2.32.3)
    Requirement already satisfied: charset-normalizer<4,>=2 in /Users/XXXXX/.pyenv/versions/3.12.5/lib/python3.12/site-packages (from requests->-r requirements.txt (line 2)) (3.3.2)
    Requirement already satisfied: idna<4,>=2.5 in /Users/XXXXX/.pyenv/versions/3.12.5/lib/python3.12/site-packages (from requests->-r requirements.txt (line 2)) (3.10)
    Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/XXXXX/.pyenv/versions/3.12.5/lib/python3.12/site-packages (from requests->-r requirements.txt (line 2)) (2.2.3)
    Requirement already satisfied: certifi>=2017.4.17 in /Users/XXXXX/.pyenv/versions/3.12.5/lib/python3.12/site-packages (from requests->-r requirements.txt (line 2)) (2024.8.30)
    Downloading python_dotenv-1.0.1-py3-none-any.whl (19 kB)
    Installing collected packages: python-dotenv
    Successfully installed python-dotenv-1.0.1
    % 
    ```

## 環境変数ファイルを作成
### Datadog
1. Datadogにサインインします
1. ナビゲーションペインで「アカウント」＞「Organization settings」の「API Keys」をクリックします
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/fba91ce5-5faa-4919-a765-3c2a9df4b75d.png)

1. すでに作成済みのKeyがありますのでコピーします


### .envファイル
1. `.env`ファイルを作成します。上記で作成したKEYを指定します
    ```py
    DATADOG_API_KEY=XXXXXX
    ```

1. `.gitignore` に `.env` を追加してGitHubにアップしないように作成します
    ```bash
    echo ".env" >> .gitignore
    ```

## 実行
1. `python main.py`で実行します
    ```bash
    % python main.py
    [OK] Progress 5% sent to Datadog.
    [OK] Progress 10% sent to Datadog.
    ・・・・
    ```

## Datadogで確認する
1. Datadogにサインインします

### メトリクス
1. ナビゲーションペインで、「Metrics」をクリックします
    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/7312833b-746d-4b97-84ed-9bb5eaaf41d9.png" width=150 />

1. 「Explorer」をクリックします
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/c3a0137b-8a49-4246-a782-c74e34ef20e6.png)

1. 検索ウィンドウに「custom.job.progress」を入力し、選択します
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/744114d4-7ece-4b06-adfd-9d8190da944e.png)

1. 見えました！！
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/52ddc41d-0e68-4ab9-82ca-1aff834760b6.png)

### ダッシュボード
1. ナビゲーションペインで、「Dashboards」をクリックします
    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/a5526b73-4245-4772-bcda-4ff84d9fcb5c.png" width=150 />

1. 「New Dashboard」をクリックします
1. Dashboard Nameに「Progress Monitor」を入力し、「New Dashboard」をクリックします
1. 「Add Widgets」をクリックします
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/d7ba4010-18e5-4ced-81f5-dc738633bdca.png)

1. 「Timeseries」を指定します
    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/8f937b86-fca7-4572-aa9d-8ef5f6a277a3.png" width=300 />

1. 下記を指定して④「Save」をクリックします
    - ①：メトリクス：custom.job.progress
    - ②：from：job:python-cursor
    - ③：Custom time : 4 housr

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/646b3a3c-1f3b-42e4-a45d-e0aa515514c4.png)

1. できました
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/646d2784-62e0-494e-acf6-9b66c7fc2474.png)

## 複数クライアントの実行
複数マシンを想定してダッシュボードで確認したいと思います。


### コードを修正

上記で作成した、コードを修正します。変更点は下記のとおりです。
- プログラム実行時に、パラメータを受け取る
- Datadogのhostパラメータに、host−idを設定します。

1. コードを修正します
    ```py
    import os
    import time
    import requests
    import argparse
    from dotenv import load_dotenv
    
    # 環境変数読み込み
    load_dotenv()
    DATADOG_API_KEY = os.getenv("DATADOG_API_KEY")
    
    if not DATADOG_API_KEY:
        raise ValueError("DATADOG_API_KEY is not set in environment variables.")
    
    # Datadog API URL
    url = "https://api.ap1.datadoghq.com/api/v1/series"
    
    # 進捗送信関数
    def send_progress(progress: int, host_id: str):
        timestamp = int(time.time())
        payload = {
            "series": [
                {
                    "metric": "custom.job.progress", # Datadog上で表示されるメトリクス名
                    "points": [[timestamp, progress]], # 測定データ（時刻と値のペア） 
                    "type": "gauge", #メトリクスの種類
                    "host": f"client-{host_id}", # 送信元のホストID
                    "tags": ["job:python-cursor"] # タグ。フィルタにつかう
                }
            ]
        }
        headers = {
            "Content-Type": "application/json",
            "DD-API-KEY": DATADOG_API_KEY
        }
    
        response = requests.post(url, json=payload, headers=headers)
        if response.status_code == 202:
            print(f"[OK] Progress {progress}% sent to Datadog.")
        else:
            print(f"[ERROR] Failed to send progress: {response.text}")
    
    # 例: 5%ずつ進捗送信
    if __name__ == "__main__":
        parser = argparse.ArgumentParser(description="送信元のホスト情報を設定する")
        parser.add_argument("--host-id", type=str, default="1", help="ホストID")
        args = parser.parse_args()
    
        for progress in range(5, 101, 5):
            send_progress(progress, args.host_id)
            time.sleep(5)  # 5秒ごとに進捗を送信
    ```

### 実行
1. host-idに`1`を指定し実行します
    ```bash
    % python main.py --host-id 1
    [OK] Progress 5% sent to Datadog.
    [OK] Progress 10% sent to Datadog.
    [OK] Progress 15% sent to Datadog.
    [OK] Progress 20% sent to Datadog.
    [OK] Progress 25% sent to Datadog.
    [OK] Progress 30% sent to Datadog.
    [OK] Progress 35% sent to Datadog.
    [OK] Progress 40% sent to Datadog.
    [OK] Progress 45% sent to Datadog.
    [OK] Progress 50% sent to Datadog.
    [OK] Progress 55% sent to Datadog.
    [OK] Progress 60% sent to Datadog.
    [OK] Progress 65% sent to Datadog.
    [OK] Progress 70% sent to Datadog.
    [OK] Progress 75% sent to Datadog.
    [OK] Progress 80% sent to Datadog.
    [OK] Progress 85% sent to Datadog.
    [OK] Progress 90% sent to Datadog.
    [OK] Progress 95% sent to Datadog.
    [OK] Progress 100% sent to Datadog.
    % 
    ```

### ダッシュボードの修正と確認
1. Datadogにサインインします
1. ナビゲーションペインで、「Dashboards」をクリックします
1. 以前、作成したダッシュボードを編集します
    - Metrics：custom.job.progress（変更なし）
    - from: host:client-*（clientすべてを対象）
    - max by: host
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/355d2d76-7bc0-4609-bf87-99fd05366f67.png)
1. 変更されました！
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/53acb47c-eea2-4703-b694-f393648d7b23.png)


# 考察
今回は、カスタムメトリクスを試してみました。
次回は、AWS Batchのジョブなどの進捗を計測してみたいと思います

# 参考
https://docs.datadoghq.com/ja/metrics/?utm_source=chatgpt.com

https://docs.datadoghq.com/ja/metrics/types/?tab=count