Cloudflare Logpush セットアップ手順
Workers の構造化ログ (createLogger が出す JSON) を Cloudflare 外の永続ストレージに
ストリーミングするための設定。Workers Observability Dashboard だけでは過去 7 日しか
保管されない ため、本番運用には Logpush が必須。
状況 (2026-04-27): R2 bucket + lifecycle (dev 30d / prod 90d) + Logpush job 配信済み。
- dev job: id=1606777 /
parky-workers-logs-dev→r2://parky-logs-dev/dev/{DATE}/- prod job: id=1606779 /
parky-workers-logs-prod→r2://parky-logs-prod/prod/{DATE}/- lifecycle rules は infra/r2/lifecycle-logs-dev.json / lifecycle-logs-prod.json で管理
推奨構成
| 環境 | Destination | 保持 | 用途 |
|---|---|---|---|
| dev | R2 (parky-logs-dev) |
30 日 | デバッグ・障害分析 |
| prod | R2 (parky-logs-prod) |
90 日 | インシデント・SLO 計測 |
| prod | BigQuery (任意) | 365 日 | 長期分析・ダッシュボード |
R2 を主、BigQuery は将来必要になったら追加 (parky の現フェーズでは R2 だけで十分)。
1. R2 bucket 作成
# dev
wrangler r2 bucket create parky-logs-dev
# prod
wrangler r2 bucket create parky-logs-prod
R2 の lifecycle rule で 30 / 90 日後 auto-delete を設定:
wrangler r2 bucket lifecycle set parky-logs-dev --file infra/r2/lifecycle-logs-dev.json
wrangler r2 bucket lifecycle set parky-logs-prod --file infra/r2/lifecycle-logs-prod.json
JSON 定義は infra/r2/lifecycle-logs-dev.json (30 日) と lifecycle-logs-prod.json (90 日)。
2. Logpush job 作成 (Cloudflare API)
Workers の Logpush は Account 単位 の設定。R2 destination は ownership challenge を経て 作成する 2 ステップフロー。
ACCOUNT_ID=5d8f6201999f8965395396c4674cbe2d
CF_TOKEN=$(op item get fckmphwmq7pccoyg6ye3vf4f34 --vault "PJ|Parky" --fields credential --reveal)
ACCESS_KEY=$(op item get rhxd2jnzp5dqbetn7kiky6aala --vault "PJ|Parky" --fields access_key_id --reveal)
SECRET_KEY=$(op item get rhxd2jnzp5dqbetn7kiky6aala --vault "PJ|Parky" --fields secret_access_key --reveal)
# Step 1: ownership challenge — CF が R2 にチャレンジファイルを書き込む
DEST="r2://parky-logs-dev/dev/{DATE}?account-id=${ACCOUNT_ID}&access-key-id=${ACCESS_KEY}&secret-access-key=${SECRET_KEY}"
CHALLENGE_FILE=$(curl -sS -X POST -H "Authorization: Bearer ${CF_TOKEN}" \
"https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/logpush/ownership" \
--data "{\"destination_conf\":\"${DEST}\"}" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['result']['filename'])")
# Step 2: チャレンジファイルから token を読む
npx wrangler r2 object get "parky-logs-dev/${CHALLENGE_FILE}" --file /tmp/ownership.txt
OWNERSHIP_TOKEN=$(cat /tmp/ownership.txt)
# Step 3: Job 作成 — kind は付けない (workers_trace_events は kind=edge と非対応)
curl -X POST "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/logpush/jobs" \
-H "Authorization: Bearer ${CF_TOKEN}" -H "Content-Type: application/json" \
--data "{
\"name\": \"parky-workers-logs-dev\",
\"destination_conf\": \"${DEST}\",
\"dataset\": \"workers_trace_events\",
\"filter\": \"{\\\"where\\\":{\\\"and\\\":[{\\\"key\\\":\\\"ScriptName\\\",\\\"operator\\\":\\\"startsWith\\\",\\\"value\\\":\\\"parky-\\\"},{\\\"key\\\":\\\"ScriptName\\\",\\\"operator\\\":\\\"contains\\\",\\\"value\\\":\\\"-dev\\\"}]}}\",
\"output_options\": {
\"field_names\": [\"ScriptName\",\"EventType\",\"Outcome\",\"Logs\",\"Exceptions\",\"DispatchNamespace\",\"Event\",\"EventTimestampMs\"],
\"timestamp_format\": \"rfc3339\"
},
\"frequency\": \"high\",
\"enabled\": true,
\"ownership_challenge\": \"${OWNERSHIP_TOKEN}\"
}"
R2 access key は既存の Parky R2 API Token (PJ|Parky vault, item id rhxd2jnzp5dqbetn7kiky6aala) が
account-scoped で全 bucket 書込み可。新規 token 作成不要 (本セットアップで検証済み)。
filter の ScriptName contains -dev / -prod で dev/prod の Worker logs を分離 (例:
parky-api-dev は dev job、parky-api-prod は prod job)。
3. ログのクエリ
R2 に NDJSON 形式で蓄積されるので、解析は以下のいずれか:
- DuckDB ローカル:
r2 cp s3://parky-logs-dev/dev/2026-04-26/ /tmp/ --recursive後duckdb -c "select * from read_ndjson_auto('/tmp/*.json.gz') where Outcome != 'ok'" - Cloudflare R2 SQL (公開待ち): R2 上で直接 SQL クエリ
- BigQuery 連携: 後追いで Logpush job を増やす
クエリ例 (5xx を時系列で):
SELECT
EventTimestampMs,
Logs[0].Message AS log,
Outcome,
Event.RequestUrl AS url
FROM read_ndjson_auto('parky-logs-prod/prod/2026-04-26/*.json.gz')
WHERE Outcome != 'ok'
ORDER BY EventTimestampMs DESC
LIMIT 100
4. Tail Workers (リアルタイム転送)
リアルタイム性が必要な signal (例: 5xx burst の即時 Slack 通知) は Logpush では
遅すぎるため、別途 Tail Worker を作って wrangler.toml の tail_consumers で
配線する。本書の対象外 (B12 の DLQ monitor と統合する別タスク)。
5. PII / GDPR 注意
RequestHeadersフィールドにはAuthorization/Cookieヘッダが含まれうる。 Logpush の filter で除外する:"logpull_options": "fields=...&exclude=RequestHeaders.Authorization,RequestHeaders.Cookie"- structured log の
error.messageに email / phone が混入しないよう、lib/logger.ts側で redact する責務 (S7 / 別タスク)。
6. SLO / Alert 連携
Logpush の R2 dump を Workers Cron で 5 分毎に集計して analytics.error_reports に書き
戻す案がある (P1 / project_parky_log_aggregation)。実装は本書の対象外。
7. コスト目安
- Logpush: $0.05 / 1M log lines (Workers Paid Plan に含まれる)
- R2 storage: 30 日 × 1GB/day × $0.015/GB = $0.45/月
- R2 egress: 0 (Cloudflare 内なら 0、外部 destination で発生)
関連
- parky/api/wrangler.toml —
[observability] head_sampling_rate - parky/api/src/lib/logger.ts — JSON ログスキーマ
- parky/docs/ops/logging.md — 構造化ログ仕様 (level/scope/resource)
- parky/docs/ops/sentry-setup.md — Sentry (Issue / Alert) 連携