5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Datadog Workflow AutomationでAPMエラーからGitHub Issueを自動生成してみた

5
Last updated at Posted at 2025-12-20

はじめに

この記事は「Medley (メドレー) Advent Calendar 2025」の21日目の記事です。

こんにちは、メドレーのSREチームに所属する@gongon282828です!

SREチームでは、サービスの監視の一部にDatadogを利用しています。

10月ごろにSRE強化の一環としてDatadogを色々いじくり回していて、Workflow Automationなるものを活用してみたので、その使い方について紹介します。

動機

そもそも、Datadogに限らず、監視アラートをトリガーにオートメーションを展開する場合、複数の処理ステップを介して、実装を行う必要があると思います。

特に、現在、生成AI真っ盛りです。
私の場合は、アラートをトリガーにして、発火したアラートをAIで解析したいと考え、何かしら良い方法はないかと考えていました。

同じようなニーズは増えているのではないでしょうか。

そういった中間処理のパイプラインとして、DatadogのWorkflow Automationを検証してみました。

Datadog Workflow Automationとは

簡単に言ってしまえば、AWSのStep Functionsのようなサービスです。
(以上!って感じでもある)

元々Datadogでは、多くのインテグレーションが存在しますが、それらを利用して柔軟性の高いアクションを実行することができ、テンプレート(Action Catalog)もたくさんあるみたいです。

0.png

(↑の他にも、GitHub、Slack、Anthropicへのアクションとか、他にも色々あった!)

個人的にメリットを感じたのが、Monitorの情報をトリガーにし、そのままDatadog完結でワークフローを実行できる点で、Datadogをメインの監視として活用している場合は便利に使えそうだと思いました。

例えば、以下のような煩雑なワークフローについて、それらがDatadogに集約できれば便利です!

  • Datadog Export APIを利用してMonitorの情報をAPI Gateway + Lambdaで検知(PULL型 or PUSH型のどちらかで?)して、場合によってはさらにAWS外のサービスに展開してゴニョゴニョ...

実際にDatadogでワークフローを作ってみた!

要件は、以下のような形で、作ってみました!

  1. テストアプリにてAPM情報の収集とError Tracking設定の追加
    • APMのError Trackingは、有効化しておく(理由は後述)
  2. DatadogとGitHubを連携する
  3. Error TrackingをトリガーにDatadog Workflow Automationを動かす

では、一つずつ、進めていきましょう!

テストアプリでAPM情報の収集とError Tracking設定の追加

まず、テストアプリでAPM周りとそのError Tracking設定の確認まで行います。

今回はAIで生成してもらった、Railsで動くテストアプリ(todo管理アプリ)に対して、APMの設定を導入しました。docker-compose.ymlに詳述してますが、Rails、nginx、MySQLで動かすアプリになっています。

以下のように、Datadog向けの設定を入れることで、APMとError Trackingの有効化設定が反映されます。

# config/initializers/datadog.rb
  # トレーシング設定
  c.tracing.enabled = true
  c.tracing.report_hostname = true  # ホスト名のレポート
  c.tracing.log_injection = true    # ログとトレースの関連付け

  # Railsインストゥルメンテーション
  c.tracing.instrument :rails, analytics_enabled: true

1.png

ここで注意が必要なのは、全てのAPMエラーを対象にワークフローを発火させた場合、ワークフローが大量発生してしまう点です。

そこで、APMのError Trackingを活用します。

Error Trackingでは、類似エラーを集約し、ひとまとまりとして拾えるようになるので、Error Tracking単位でワークフローを発火させることで、参照するエラーが重複したワークフローの発火を防ぐことができます。

以下、APM画面上でも確認できますが、ここでのError Trackingのエラーは、同じエラーが9つ発生しており、それらが一つのエラーとしてグルーピングされていることがわかります。

2.png

Datadog上のError専用の画面でも、エラーが集約されていることを確認できます。

3.png

ここまでで、APM設定とError Trackingの設定確認までができました。

DatadogとGitHubの連携

次に、DatadogとGitHubを連携します。

まず、DatadogのIntegrationsから、GitHubのアプリをインストールし、Datadogと連携させます。

4.png

GitHub側のGitHub Appの設定で、Datadogのインテグレーションを確認できればOKです。

5.png

まぁ、普段からやってそうな作業ですね!

Error TrackingをトリガーにDatadog Workflow Automationを動かす

ここからは、Error Trackingからワークフローを発火する流れを以下の順番で説明していきます。

  • Datadog Workflow Automation自体の作成
    • GitHubリポジトリでIssueを生成するDatadog Workflow Automationを作成
  • Error Trackingをトリガーにする設定を追加
  • Issue内のbodyにエラー詳細を出力する

Datadog Workflow Automation自体の作成

まずは、骨格となるワークフロー、GitHubリポジトリでIssueを生成するDatadog Workflow Automationを作成していきます。

メニューバーの[Automation]>>[Workflow Automation]に遷移し、New Workflowで、新しいワークフローを作成します。

AIでワークフローを作成できたりしますが、ここではTriggerをMonitorに設定します。

7.png

すると、以下のように、Monitorを出発点にしたMonitorだけのフローチャートが出現します。

9.png

また、Monitorのワークフロー名を、「@workflow-datadog-test」に変更します。
このワークフロー名は、追ってError Trackingを設定する際に、トリガー時の発火対象として必要になります。

10.png

さらに、ワークフローの「+」を押下すると、次のアクションを選択できるようになります。

11.png

今回は、GitHubリポジトリに対してIssueを作成させることが目的なので、「Create issue」のアクションを選択します。

12.png

Inputの中身は一旦、以下のように仮設定します。

Repository:
<your-org>/<your-repository>
Issue title:
APM Error Tracking test
Issue body:
test

その他、LabelやAssignees、期限等も設定できます。

Error Trackingをトリガーにする設定を追加

骨格となるワークフローができたので、発火元のError Trackingの設定を反映します。

メニューバーの[Monitors]の[New Monitor]で、新しいMonitorのError Trackingを作成します。

13.png

直近のエラーを見て、該当するエラーであれば、Trigger Workflowで先ほど作成したワークフローを指定して保存します。

14.png

15-x.png

ここまでで、一旦エラーが発生したのち、ワークフローからIssueを作成するところまでの設定は完了です。

ここから、動作検証を進めます。

今回作ったアプリでは、エラーを発生させた際に、ワークフローが発火したことを確認できるように仕込みを入れています。

# StandardError: これは意図的なテストエラーです (APM監視用)
curl -s http://localhost/error/test

# ActiveRecord::RecordNotFound: Couldn't find Todo with 'id'=999999999
curl -s http://localhost/error/database

上記のコマンドでエラーを発生させると、発火したワークフローをワークフロー一覧から確認できます。
下の画像では、Automatically via a Monitorと記載されているフローが、エラー発生時に自動で発火したワークフローになります。

16.png

実際に作成されたIssueはこちらです。

また、各ワークフローの詳細を見ることで、input/outputやワークフロー失敗時のエラーを確認することができます。

17.png

ここまでで、ワークフロー自体の発火は確認できました。

Issue内のbodyにエラー詳細を出力させる

作成したIssueのbodyがtestだけだと、発火させても何を目的としたエラーかは判断できません。

そのため、Monitorの情報からIssueのbodyに記載したい情報を抽出し、テンプレートをMarkdown形式で作成していきます。

以下のサンプルのように、ワークフローのトリガーであるMonitorのアウトプットを加工・整形し、適切なIssue用のBodyを作成します。

MonitorのアウトプットJSON
{
  "initiator": {
    "email": "",
    "id": "",
    "name": "",
    "orgId": ""
  },
  "monitor": {
    "created": "YYYY-MM-DDTHH:MM:SS+00:00",
    "created_at": 0,
    "creator": {
      "email": "***",
      "handle": "***",
      "id": "***",
      "name": "***"
    },
    "deleted": null,
    "draft_status": "published",
    "evaluated_query": "sum:trace.rack.request.errors{...}by{env,service}.as_rate() / sum:trace.rack.request.hits{...}by{env,service}.as_rate()",
    "event": {
      "alert_type": "error",
      "date_happened": 0,
      "device_name": null,
      "host": null,
      "id": "***",
      "payload": {
        "alert_cycle_key": "***",
        "assets": [],
        "avalanche_window": null,
        "group_transition_type": "no_grouping",
        "message_parts": {
          "last_triggered_ts": "YYYY-MM-DDTHH:MM:SSZ",
          "links": [
            {
              "key": "status",
              "text": "Monitor Status",
              "url": "/monitors/***"
            },
            {
              "key": "edit",
              "text": "Edit Monitor",
              "url": "/monitors/***/edit"
            },
            {
              "key": "logs",
              "text": "Related Logs",
              "url": "/logs?query=..."
            }
          ],
          "message": "@workflow-name\n\nAlert message content.",
          "message_prefix": "",
          "message_suffix": "",
          "query_plain": "min(last_15m):... > 0.1",
          "query_summary": "min(last_15m):... > 0.1"
        },
        "monitor": {
          "created_at": 0,
          "deleted": null,
          "draft_status": "published",
          "id": "***",
          "message": "@workflow-name\n\nAlert message content.",
          "modified": 0,
          "name": "[SAMPLE] High Error Rate on {{service.name}}",
          "options": {
            "escalation_message": "",
            "include_tags": true,
            "new_group_delay": 0,
            "notify_audit": false,
            "on_missing_data": "default",
            "renotify_interval": 0,
            "require_full_window": false,
            "silenced": {},
            "thresholds": {
              "critical": 0.1
            }
          },
          "org_id": "***",
          "query": "min(last_15m):... > 0.1",
          "tags": ["monitor_pack:apm"],
          "templated_name": "[SAMPLE] High Error Rate on ",
          "type": "query alert"
        },
        "reduced_message_text": "@workflow-name\n\nAlert message content.\n\nMetric value: 0.0",
        "result": {
          "avalanche": false,
          "display_logs_sample": {},
          "evaluation_ts": 0,
          "group": null,
          "group_key": null,
          "groups": {
            "*": {
              "status": 1
            }
          },
          "logs_url": "/logs?query=...",
          "metadata": {
            "alert_url": "/monitors/***",
            "is_usertest": false,
            "metric": "trace.rack.request.errors,trace.rack.request.hits",
            "monitor_id": "***",
            "priority_list": {
              "message": null,
              "original_priority": null,
              "recovery_message": null
            },
            "snap_url": "***"
          },
          "num_groups": 1,
          "result_id": 0,
          "result_ts": 0,
          "scheduled_ts": 0,
          "state_counts": {
            "0": 0,
            "1": 1,
            "2": 0,
            "3": 0,
            "5": 0,
            "6": 0
          },
          "state_id": 1
        },
        "states": {
          "dest_state": "Alert",
          "source_state": "OK"
        },
        "sub_group_count": null,
        "sub_groups_sample": null,
        "text_only_message": "@workflow-name\n\nAlert message content.\n\nMetric value: 0.0",
        "transition": {
          "trans_name": "Triggered",
          "trans_type": "alert"
        }
      },
      "priority": "normal",
      "tag_value": {
        "monitor": "monitor",
        "monitor_pack": "apm",
        "source": "alert"
      },
      "tag_value_list": {
        "monitor": ["monitor"],
        "monitor_pack": ["apm"],
        "source": ["alert"]
      },
      "tags": ["monitor", "monitor_pack:apm", "source:alert"],
      "text": "@workflow-name\n\nAlert message content.",
      "title": "[Triggered] [SAMPLE] High Error Rate on ",
      "url": "https://app.datadoghq.com/event/event?id=***"
    },
    "group_value": {
      "*": "*"
    },
    "group_value_list": {
      "*": ["*"]
    },
    "id": "***",
    "message": "@workflow-name\n\nAlert message content.",
    "modified": "YYYY-MM-DDTHH:MM:SS+00:00",
    "multi": true,
    "name": "[SAMPLE] High Error Rate on ",
    "options": {
      "escalation_message": "",
      "include_tags": true,
      "new_group_delay": 0,
      "notify_audit": false,
      "on_missing_data": "default",
      "renotify_interval": 0,
      "require_full_window": false,
      "silenced": {},
      "thresholds": {
        "critical": 0.1
      }
    },
    "org_id": "***",
    "overall_state": "Alert",
    "overall_state_modified": "YYYY-MM-DDTHH:MM:SS+00:00",
    "priority": null,
    "query": "min(last_15m):... > 0.1",
    "restricted_roles": null,
    "state": {
      "groups": {
        "env:ENV_NAME,service:SERVICE_NAME": {
          "last_nodata_ts": null,
          "last_notified_ts": 0,
          "last_resolved_ts": 0,
          "last_triggered_ts": 0,
          "name": "env:ENV_NAME,service:SERVICE_NAME",
          "status": "Alert"
        }
      }
    },
    "tag_value": {
      "monitor_pack": "apm"
    },
    "tag_value_list": {
      "monitor_pack": ["apm"]
    },
    "tags": ["monitor_pack:apm"],
    "type": "query alert",
    "url": "https://app.datadoghq.com/monitors/***"
  },
  "name": "[Triggered] [SAMPLE] High Error Rate on ",
  "runAsUser": {
    "email": "***",
    "id": "***",
    "name": "***",
    "orgId": "***"
  },
  "type": "monitor",
  "url": "https://app.datadoghq.com/monitors/***"
}

実際のIssueのbodyは、上記のJSONから値を抽出し、以下のようなMarkdown形式で登録しました。

JSONから抽出したMarkdown形式テンプレート
## APM Error Alert - Auto Analysis

### Monitor Information
- **Monitor Name:** {{ Source.monitor.name }}
- **Monitor ID:** {{ Source.monitor.id }}
- **Status:** {{ Source.monitor.overall_state }}
- **Type:** {{ Source.monitor.type }}

---

### Alert Details

**Query:**

{{ Source.monitor.query }}


**Threshold:** {{ Source.monitor.options.thresholds.critical }}

---

### Alert Message

{{ Source.monitor.message }}

---

### State Transition
- **From:** {{ Source.monitor.event.payload.states.source_state }}
- **To:** {{ Source.monitor.event.payload.states.dest_state }}
- **Transition:** {{ Source.monitor.event.payload.transition.trans_name }}
- **Triggered At:** {{ Source.monitor.event.payload.message_parts.last_triggered_ts }}

---

### Quick Links
- [Monitor Status]({{ Source.monitor.url }})
- [Edit Monitor](https://app.datadoghq.com/monitors/{{ Source.monitor.id }}/edit)

---

<details>
<summary>Event Details (Click to expand)</summary>

- **Event ID:** {{ Source.monitor.event.id }}
- **Alert Type:** {{ Source.monitor.event.alert_type }}
- **Priority:** {{ Source.monitor.event.priority }}
- **Tags:** {{ Source.monitor.tags }}

</details>

---

### Next Steps

- [ ] エラーの原因を調査
- [ ] 影響範囲を確認
- [ ] 修正対応
- [ ] 再発防止策の検討

---

_This issue was automatically created by Datadog Workflow Automation_

Error Trackingからワークフローを発火させ、実際に出力されたIssueはこちらになります。

以上、ここまでで、目指していたワークフローは完成です!

補足

ちなみに、今回はコンソール上でワークフローの構築を進めましたが、ワークフロー全体をJSONとして出力させることもできます。

そのため、一度コンソール上で作り込んでしまえば、IaC等でも活用できると思います。

作成したWorkflow AutomationのアウトプットJSON
{
  "id": "xxxxxxxxxxxxxxxxxx",
  "name": "datadog-test",
  "description": "",
  "tags": [],
  "published": true,
  "spec": {
    "triggers": [
      {
        "startStepNames": [
          "Create_issue"
        ],
        "monitorTrigger": {}
      }
    ],
    "steps": [
      {
        "name": "Create_issue",
        "actionId": "com.datadoghq.github.createIssue",
        "parameters": [
          {
            "name": "repository",
            "value": "md-shingo-kawamoto/datadog-test"
          },
          {
            "name": "title",
            "value": "APM Error Tracking test"
          },
          {
            "name": "body",
            "value": "## APM Error Alert - Auto Analysis\n\n### Monitor Information\n- **Monitor Name:** {{ Source.monitor.name }}\n- **Monitor ID:** {{ Source.monitor.id }}\n- **Status:** {{ Source.monitor.overall_state }}\n- **Type:** {{ Source.monitor.type }}\n\n---\n\n### Alert Details\n\n**Query:**\n```\n{{ Source.monitor.query }}\n```\n\n**Threshold:** {{ Source.monitor.options.thresholds.critical }}\n\n---\n\n### Alert Message\n\n{{ Source.monitor.message }}\n\n---\n\n### State Transition\n- **From:** {{ Source.monitor.event.payload.states.source_state }}\n- **To:** {{ Source.monitor.event.payload.states.dest_state }}\n- **Transition:** {{ Source.monitor.event.payload.transition.trans_name }}\n- **Triggered At:** {{ Source.monitor.event.payload.message_parts.last_triggered_ts }}\n\n---\n\n### Quick Links\n- [Monitor Status]({{ Source.monitor.url }})\n- [Edit Monitor](https://app.datadoghq.com/monitors/{{ Source.monitor.id }}/edit)\n\n---\n\n<details>\n<summary>Event Details (Click to expand)</summary>\n\n- **Event ID:** {{ Source.monitor.event.id }}\n- **Alert Type:** {{ Source.monitor.event.alert_type }}\n- **Priority:** {{ Source.monitor.event.priority }}\n- **Tags:** {{ Source.monitor.tags }}\n\n</details>\n\n---\n\n### Next Steps\n\n- [ ] エラーの原因を調査\n- [ ] 影響範囲を確認\n- [ ] 修正対応\n- [ ] 再発防止策の検討\n\n---\n\n_This issue was automatically created by Datadog Workflow Automation_"
          }
        ],
        "display": {
          "bounds": {
            "x": 0,
            "y": 192
          }
        }
      }
    ],
    "handle": "datadog-test"
  }
}

以上、こんな感じで、APMのエラートラッキングからGitHubへの処理まで、Datadogで完結してワークフローを作ることができました。

番外編:Error Tracking上で問題ソースを参照できるようにする

ついでに番外編として、DatadogのError Tracking側で、GitHubのソースコードを参照させ、問題を特定しやすいようにする方法を紹介します。

アプリのソースコードとGitHubのAPM連携を行うことで、簡単に設定できるので、便利です。

ソースコードの修正内容と、DatadogとGitHubの設定変更の順番で解説します。

ソースコードの修正内容

GitHubのソースコードとAPMを連携するには、Rails側では以下の設定変更が必要です。

# config/initializers/datadog.rb
# リポジトリURLを設定
  c.tags['git.repository_url'] = ENV.fetch('DD_GIT_REPOSITORY_URL', 'https://github.com/md-shingo-kawamoto/datadog-test')
  c.tags['git.commit.sha'] = ENV.fetch('DD_GIT_COMMIT_SHA', nil) if ENV['DD_GIT_COMMIT_SHA']

上記の環境変数も追加する必要があります。
ここでは、docker-compose.ymlで記載することにします。

    environment:
      # GitHub ソースコード連携
      - DD_GIT_REPOSITORY_URL=${DD_GIT_REPOSITORY_URL:-https://github.com/md-shingo-kawamoto/datadog-test}
      - DD_GIT_COMMIT_SHA=${DD_GIT_COMMIT_SHA:-}

DatadogとGitHubの設定変更

APMのソースコードリンク設定画面で、GitHubリポジトリとAPMを紐付けます。

b1.png

これだけでAPMがソースコードを追従してくれます。

設定が完了したので、再度、エラー発生テストコードを実行します。

# StandardError: これは意図的なテストエラーです (APM監視用)
curl -s http://localhost/error/test

# ActiveRecord::RecordNotFound: Couldn't find Todo with 'id'=999999999
curl -s http://localhost/error/database

以下のように、Error Tracking上で、ソースコードの問題点も含めてDatadogと連携されていることが確認できます。

  • StandardError

b2.png

  • ActiveRecord::RecordNotFound

b3.png

ちなみに、GitHub連携前に発生させたエラーのdatabase existsでは、ソースコードは確認できない画面のままです。

b4.png

Datadogコンソール上からエラー発生要因のソースコードまでチェックできるので、とても便利そうです!

まとめ

Datadog Workflow Automationで、APMエラーからGitHub Issueを自動生成してみました。

他にも、GitHub側のイベントを検知してワークフローを動かす仕組みがあったり、GitHub Actionsを動かしたりできます。実際に、GitHub ActionsのワークフローからClaudeを発火させ、APMエラーに対するソースコード修正PR生成も可能でした。

もちろん万能ではなく、思いがけない制限もあるので、そこがハマりポイントになることもありそうです。(Datadog側の問題/外部インテグレーション先の問題かは置いといて...)

本格的なCI/CDとまではいきませんが、MonitorをトリガーにDatadog Workflow Automationを発火させることで、色々捗るSRE活動もありそうです。

何にしてもそうですが、上手に活用できればと思いました!

We’re hiring!

メドレーでは様々な職種で、スペシャリストを募集しています!


22日目の担当は@izooさんの「チーム内部からQA組織を立ち上げて半年 ──品質文化醸成に向けて」についてです!!
お楽しみに!!

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?