Datadogのアラートの通知メッセージに入れているもの

SRE Advent Calendar 2023の10日目の記事です。


業務でDatadogを使っていてモニターは以下のような感じでterraformで管理しているんですが、通知メッセージに入れているものをつらつら書いてみます。

resource "datadog_monitor" "elb_http_5xx" {
  name = "Too many ELB HTTP 5XX on {{name.name}}"
  type = "metric alert"

  message = <<-EOT
    @slack-hogehoge
    @pd-hogehoge
    @hoge@example.com
    (このへんに書いているものをつらつらと)
  EOT

  query = "sum(last_5m):avg:aws.applicationelb.httpcode_elb_5xx{service:my-service} by {name,service}.as_count() > 200"

  monitor_thresholds {
    warning  = 100
  }
}

Runbook

esaのRunbookへのリンクです。ヒューマンリーダブルなURLで開けるやつを作ったのでそれ経由でesaのRunbookを開くようにしてます。

ログ

SFnのイベント経由で通知されるバッチのエラーなどにDatadog Logsのリンクを入れています。アラート通知ですぐにログを見れるのでなかなか便利です。

※Datadogのカスタムサブドメインでsub-org(サービス)ごとにドメイン分けてます。

SFnのExecution

SFn側でエラー時にリンクを組み立てて、バッチのエラー時にメッセージに失敗したExecutionへのリンクを含めるようにしてます。

※アカウントを固定できるpersistent linkが欲しいところですが…

APM

WebアプリのステータスコードのモニターとかににバックエンドのアプリのAPMへのリンクを書いてます。 あと、WebアプリだけではなくJob WorkerにもAPMを仕込んでいたりするので、workerのジョブエラーのモニターでもAPMへのリンクを書いていたりします。

APM・ログ・エラートラッキングはDatadog上で関連付けるようにしているので、APMのリンクを開くとそこからログ・エラートラッキングも開けて便利です。

Slackチャンネル

通知先のSlackのチャンネルを開くためのリンクです。メールで通知を受け取った場合に、通知メッセージからSlackチャンネルを開けます。エラーが起きた場合に通知先チャンネルで会話が進んでいることが多いので、メールで気づいた場合には便利です。

Error Tracking/Trace

エラートラッキングのモニターではIssue IDなどがとれるので、そこからエラートラッキング情報・トレースへのリンクを作成できます。

Stack Trace

これもエラートラッキングのモニターですが、{{span.attributes.error.details}}のような感じでスタックトレースがとれる(場合もある)ので、それをメッセージに埋め込んでます。 ただし、たまに長すぎて切れます。

curlで叩けるURL

外形監視のモニターにすぐに手元で動作確認ができるよう、curlで叩けるヘルスチェック先のURLを入れてます。

その他Tipsなど

  • Datadogのリンクは一見長いんですが、?query=service:my-service+env:stgのようにURLエンコードしない文字を使ったり、余計なパラメータをカットしたりすれば結構短くできます
  • last_triggered_at_epochなどを使うと、アラート発生時刻に合わせたリンクにできます
  • モニターがリカバリしたのSlack通知がノイズになる場合、リカバリの時は通知しないようにしてます
{{#is_alert}}
@slack-hoge
{{/is_alert}}

EventBridgeのcron式のバリデーション用terraform providerを書いた

こちらの記事に触発されて terraform planでEventBridgeのcron式を検証するterraform providerを書いた。

github.com

以下のようにデータソースを定義すると

data "cronplan_expr" "every_weekday" {
  expr = "cron(5 0 ? * ? *)"
}

terraform planの時にエラーが表示される。

rate()at()については今のところ無視しているが、そのうち検証するようにしたい。 検証するようにした。

EventBridgeのday-of-weekの奇妙な動作について

EventBridgeのcron式にはいくつかコーナーケースがあって、例えば

  • 0 0 31 * ? *: 31日がない月はどうなるか?
  • 0 0 ? * FRI#5 *: 5週目の金曜日がない月はどうなるか?
  • 0 0 1W 10 ? *: 10/1が土日の場合はどうなるか?

…等々。

一応、EventBridgeのコンソールの出力を正としてそれに合わせるようにしているが、何日、何ヶ月もかけて検証はできないので完全に合っているかはわからない。


そのようなコーナーケースの動作としてday-of-weekのLの動作がある。*1

通常、cron(0 0 ? * 6L *)と書くと*2、毎月の最終の金曜日がスケジュールされる。

# cron(0 0 ? * 6L *)
Fri, 27 Oct 2023 00:00:00
Fri, 24 Nov 2023 00:00:00
Fri, 29 Dec 2023 00:00:00
Fri, 26 Jan 2024 00:00:00
Fri, 23 Feb 2024 00:00:00

しかしLの前に数字や曜日を書かないと、SATと書いたのと同じ動作になる。

# cron(0 0 ? * L *) = cron(0 0 ? * SAT *)
Sat, 07 Oct 2023 00:00:00
Sat, 14 Oct 2023 00:00:00
Sat, 21 Oct 2023 00:00:00
Sat, 28 Oct 2023 00:00:00
Sat, 04 Nov 2023 00:00:00

とても奇妙な仕様なのでL単独で使うのは避けた方がいいと思う。

ちなみに、ウェブを調べていたらJavaQuartz Job Schedulerが同じ仕様だった。

www.quartz-scheduler.org

L (“last”) - ... If used in the day-of-week field by itself, it simply means “7” or “SAT”. ... When using the ‘L’ option, it is important not to specify lists, or ranges of values, as you’ll get confusing/unexpected results.

L ( "last" ) - ... 曜日フィールドで単独で使用される場合は、単に「7」または「SAT」を意味します。... 'L' オプションを使用する場合は、混乱したり予期しない結果が得られるため、リストまたは値の範囲を指定しないことが重要です。

なので、EventBridgeのcron式のパースには秒を無視したQuartzが使われているのではないかと疑っている。

さらに追記

cron式のSUN=0をSUN=1に書き換えた犯人がQuartzではないかと考えているが、ログは見つけられていない…

追記2

※対応しました https://github.com/winebarrel/cronplan/pull/45/files?w=1

*1:https://github.com/winebarrel/cronplan#about-the-behavior-of-l-in-day-of-week

*2:できれば6L→FRILと書いた方がよいと思う