created: 2024-03-25T06:16:53.307Z

GCP で発生したエラーログをすべて Slack 通知するアラートポリシー

つくりたての GCP プロジェクトとかで、雑でいいのですべてのエラーの発生を簡単に通知してくれる terraform リソースを実装した。 おそらくある程度成熟したプロジェクトだとすごい量のエラーログがでていると思われるので、当然ながらそういう規模に向いたものではない。

すべてのエラーの発生

すべてのエラーの発生

すべて と書いてあるけど、本当はすべてではないし、エラーだけではない。

このような条件で CloudLogging をフィルタしている。

severity=(ERROR OR CRITICAL OR ALERT OR EMERGENCY)
NOT protoPayload.@type="type.googleapis.com/google.cloud.audit.AuditLog"

ログレベルはエラー以上

severity=(ERROR OR CRITICAL OR ALERT OR EMERGENCY)

監査ログは除く

GCP 側が出してくれている「クラウド上でこんな操作がされているよ」というログは省く。

NOT protoPayload.@type="type.googleapis.com/google.cloud.audit.AuditLog"

この条件を入れないと「BigQuery の UI で作業してる時に SQL のシンタックスエラーがありましたよ」みたいなのも通知に乗ってしまうので省いている。

通知してくれるエラーの例

  • Cloud Function で例外が発生した
  • データ不整合か何かで BigQuery のスケジュールクエリが失敗した
  • Firebase がつくってくれた Schedular ジョブの削除漏れが PubSub であったよ

個人レベルのプロジェクトだとだいたいこれでバグをファイルしていけるので、モニタリングをかっちりとやるほどの工数はかけられないけど、という場合に便利。

実装

condition_matched_log をつかっている。

resource "google_monitoring_alert_policy" "ProjectAllErrorCatcher" {
  project      = var.GCP_PROJECT_ID
  enabled      = true
  combiner     = "OR"
  display_name = "Catch all error log"

  notification_channels = [
    google_monitoring_notification_channel.slack_alert.name,
  ]

  conditions {
    display_name = "Catch all error(or higher) log"
    condition_matched_log {
      filter = <<-EOT
        severity=(ERROR OR CRITICAL OR ALERT OR EMERGENCY)
        NOT protoPayload.@type="type.googleapis.com/google.cloud.audit.AuditLog"
      EOT
      label_extractors = {
        insert_id     = "EXTRACT(insertId)"
        log_name      = "EXTRACT(logName)"
        resource_type = "EXTRACT(resource.type)"
        text_payload  = "EXTRACT(textPayload)"
      }
    }
  }

  # https://cloud.google.com/logging/docs/logs-based-metrics/labels?hl=ja#api
  documentation {
    mime_type = "text/markdown"
    content   = <<-EOS
# GCP Project All Error Catcher

エラーが発生しました。以下のクエリで状況を確認できます

\`\`\`

insertId="$${log.extracted_label.insert_id}"
logName="$${log.extracted_label.log_name}"
resource.type="$${log.extracted_label.resource_type}"

\`\`\`

## textPayload

\`\`\`

$$
{log.extracted_label.text_payload}
\`\`\`

* jsonPayload, protoPayload のログは別途確認が必要です

    EOS
  }

  alert_strategy {
    auto_close = "10800s"
    notification_rate_limit {
      period = "1800s"
    }
  }
}

参考

なぜか結果を出す人が勉強以前にやっていること
[ad] なぜか結果を出す人が勉強以前にやっていること
チームドラゴン桜 (単行本)