コンテンツにスキップ

可観測性

ログ

全 Lambda は @aws-lambda-powertools/logger で構造化 JSON ログを出力する (Issue #78)。 標準 attribute:

attribute 由来 用途
level logger INFO / WARN / ERROR
message logger 人間向け文字列 (検索 key 兼用)
service logger Lambda 名 (deliver / webhook-backlog 等)
function_request_id logger.addContext Lambda 1 実行を一意に識別
cold_start logger.addContext Cold start invocation か
tenant withLogContext 配信スコープ内のテナント slug
issueKey withLogContext Backlog 課題 key (deliver / webhook-backlog)
error.name / error.message / error.stack toLogError(err) 失敗ログに必ず付与
種類 内容 保管
アプリログ 構造化 JSON(INFO/WARN/ERROR) CloudWatch Logs 30 日
監査ログ 状態遷移 / 外部 API 呼び出し / シークレット参照 DB 12 ヶ月以上
配信ログ DeliveryRun, リトライ, 通数 DB 12 ヶ月以上
クリックログ リダイレクタ受信ログ DB 12 ヶ月以上

ログレベル

POWERTOOLS_LOG_LEVEL 環境変数で上書き可能 (default INFO)。LOG_LEVEL は fallback。

CloudWatch Logs Insights クエリ集

CloudWatch コンソール → Logs Insights で実行する。Log group は /aws/lambda/automedia-<service>。 複数 Lambda 横断は Logs Insights 画面で対象 log group を複数選択する。

配信 1 件のフルトレース (issueKey)

fields @timestamp, service, level, message, error.message
| filter issueKey = "BATO-15"
| sort @timestamp asc

webhook-backlog → deliver の流れが時系列で並ぶ。X-Ray と突合する場合は function_request_id_X_AMZN_TRACE_ID (= xray_trace_id attribute) を控える。

tenant 別の配信エラー集計 (直近 24h)

fields @timestamp, service, message, error.message
| filter level = "ERROR" and service = "deliver"
| stats count() by tenant

tenantwithDeliveryScope で全 deliver ログに付与される。

失敗種別 (message) 集計

filter level = "ERROR"
| stats count() by service, message
| sort count desc

messagelogger.error('...') の固定文字列なので失敗カテゴリの分類 key として使える。

配信スキップ (lock 取得失敗 / channel disabled / dry_run) の件数

fields @timestamp, tenant, issueKey, message
| filter service = "deliver" and (message = "lock not acquired — skip" or message like /skip/)
| stats count() by tenant

スキップは正常動作だが、同一 tenant で頻発する場合は二重 invoke (Schedule 重複 / scan 救済) を疑う。

AI 生成 fallback の頻度 (deliver)

fields @timestamp, tenant, issueKey, error.message
| filter message = "AI generation failed — fallback to dumb content"
| sort @timestamp desc
| limit 50

Claude API 障害 / workspace 設定ミス / token 切れの早期発見用。

Cold start ratio

filter @type = "REPORT" or (level = "INFO" and message = "deliver invoked")
| stats sum(cold_start) as cold, count() as total by service
| display service, cold, total, cold * 100 / total as cold_pct

cold_start が異常に高い場合は memory_size / provisioned concurrency を検討する。

Backlog status 遷移失敗 (Issue #109 / #142)

fields @timestamp, tenant, issueKey, statusName, error.message
| filter message like /status update failed/ or message like /resolveStatusId/
| sort @timestamp desc

automedia実行済み / automediaエラー への自動遷移ができていないケースを検出する。発生時は project の status 名が運用と乖離していないか確認する (available_names attribute を見る)。

Defensive invalidate の頻度 (webhook-backlog, Issue #128)

fields @timestamp, tenant, issueKey
| filter message like /invalidating defensively/
| stats count() by tenant, bin(1h)

InvalidateDefensive Custom Metric (Alarm) と併用。短時間に集中するなら Backlog payload 仕様変更を疑う。

Secrets 鮮度 watch (secret-watch)

fields @timestamp, message
| filter service = "secret-watch" and level >= "WARN"
| sort @timestamp desc
| limit 100

secrets expiring critical (<= 7d) / secrets stale critical (>= 120d since update) 等の WARN/ERROR を直近で確認する。

1 配信の所要時間 (deliver invoke から配信完了まで)

fields @timestamp, message
| filter service = "deliver" and (message = "deliver invoked" or message = "content built" or message like /status updated/)
| sort @timestamp asc

content built (AI / template 確定) と status updated (configured 完了) の差分が配信 latency の主要部分。

配信失敗の自動リトライ (Issue #77)

deliver Lambda が SQS で 3 連続失敗すると deliver-dlq に到達する。deliver-retry Lambda が DLQ を event source として消費し、時間差で再度 deliver-queue に SendMessage する。

SQS:deliver-queue → deliver Lambda
                      ↓ 3 SQS 受信失敗
                    SQS:deliver-dlq
                      ↓ event source (batch=1)
                    deliver-retry Lambda
                      ├─ dispatched marker 有り → drop (dedup)
                      ├─ status == automediaエラー → drop (人手 review 待ち)
                      ├─ retry_count < N → EventBridge Schedule at(now+delay) →
                      │                     SQS:deliver-queue SendMessage
                      └─ retry_count == N → SNS publish (最終失敗通知)
retry delay (default) 環境変数で上書き可
0 → 1 10 分 RETRY_DELAYS_SEC=600,3600,21600
1 → 2 1 時間
2 → 3 6 時間
3 以降 最終失敗 → SNS

最終失敗時の SNS 通知

  • topic: automedia-alarms (統合)
  • MessageAttributes: type=deliver_final_failure, severity=high, tenant, issueKey
  • Message body は JSON (tenant / issueKey / retry_count / first_failed_at / backlog_url / log_search_url)
  • Backlog にも「自動リトライ後も失敗しました。手動で status を automedia承認 に戻すことで再配信できます」コメントを残す

運営者の手介入 (最終失敗時)

  1. SNS / Backlog コメントで通知を受ける
  2. log_search_url または Logs Insights で原因を調査
  3. 原因修正後、Backlog 課題の status を automedia承認 に戻すと webhook-backlog 経由で再配信される

Logs Insights クエリ: retry 集計

fields @timestamp, tenant, issueKey, message, retry_count, max_retries
| filter service = "deliver-retry"
| sort @timestamp desc
| limit 50

短期間に retry が集中する場合は upstream API (Backlog / LINE / HubSpot / Claude) 側の障害を疑う。

X-Ray (分散トレース)

全 Lambda は tracing_config { mode = "Active" } で X-Ray active tracing を有効化 (Issue #78 Phase 3, aws/tofu/lambda.tf)。AWSXRayDaemonWriteAccessfor_each で全 role に attach 済み。

subsegment 構成 (deliver, Issue #78 Phase 4)

aws/lambdas/deliver/src/xray.tscaptureClient / captureAsync で以下を subsegment 化する。X-Ray service map から各依存先が独立ノードとして見える。

subsegment 名 対象 計装方法
DynamoDB acquireDeliverLock / releaseDeliverLock SDK v3 middleware (captureAWSv3Client)
SecretsManager getProviderSecret SDK v3 middleware
S3 loadProjectConfig / loadOptionalTemplate SDK v3 middleware
Backlog.getIssue / Backlog.postComment / Backlog.fetchProjectStatuses / Backlog.patchIssueStatus Backlog API 手動 (captureAsync)
Claude.messages.create Claude Platform on AWS 手動 (captureAsync)
LINE.broadcast LINE Messaging API 手動 (captureAsync)
HubSpot.createBlogPost HubSpot CMS Blog API 手動 (captureAsync)

annotation (X-Ray 検索 key)

subsegment に addAnnotation 済みのため、X-Ray コンソールから filter expression で絞り込める:

  • annotation.issueKey = "BATO-15" — 課題 1 件のトレース全件
  • annotation.tenant = "acme" — tenant 別
  • annotation.model = "claude-sonnet-4-6" — モデル別
  • annotation.projectKey = "BATO" — Backlog project 別

CloudWatch Logs ↔ X-Ray の突合

powertools logger は xray_trace_id attribute を全ログ行に付与する (active tracing 有効時は自動)。

  • X-Ray コンソール: xray_trace_id の値を「Trace ID」検索に入れる
  • Logs Insights: filter xray_trace_id = "1-xxx-xxx" で同 trace の全 log を抽出

fetch ベース API が手動 capture な理由

Node 組み込み fetch (Node 20) は undici を使い node:https を経由しない。そのため captureHTTPsGlobal では自動補足できず、Backlog / LINE / HubSpot / Claude の各 API call は captureAsync('<service>.<op>', async (sub) => {...}) で個別にラップしている。

メトリクス

  • 配信成功率(プロジェクト × チャネル × 1h)
  • 配信遅延(schedule から send までの差分)
  • API エラーレート(チャネル別)
  • Queue 長 / 滞留時間
  • GitHub テンプレ取得時間 / キャッシュヒット率
  • automedia/WebhookBacklog::InvalidateDefensive (Issue #128)
  • automedia/Sync::ProjectConfigInvalid (Issue #113)
  • automedia/SecretWatch::SecretExpiringCritical / SecretStale* (Issue #79 / #114)

アラート

トリガ 重要度
配信失敗連続 N 件 High
トークン期限 7 日以内 Medium
Queue 滞留 5 分超 High
Scheduler 遅延 2 分超 Medium
クリック計測 200/min 超(不正アクセスの疑い) Low

通知先

  • 高重要: PagerDuty / Slack #alerts-automedia
  • 中低: メール / Backlog コメント

運用ダッシュボード

  • 当日の配信予定一覧
  • 直近 24 時間の配信結果
  • 失敗中の課題一覧
  • トークン期限近接の一覧