Skip to content

Cloudflare Analytics Engine 연동 구현 가이드

목적: Control Plane Worker에서 writeDataPoint()로 테넌트별 API 사용량·프로비저닝 결과를 수집하여, Cloudflare 기반 모니터링(§16) 및 대시보드·알림의 입력으로 사용.
참조: cloudflare-based-monitoring-plan.md, api-control-plane-implementation-plan.md §16.


1. Wrangler 설정

prego-control-plane/wrangler.toml에 Analytics Engine 데이터셋 바인딩 추가:

[[analytics_engine_datasets]]
binding = "ANALYTICS_ENGINE"
dataset = "prego_metrics"
  • dataset: 최초 writeDataPoint() 호출 시 자동 생성됨.
  • 제한: Worker 호출당 최대 250 data points, data point당 index 1개·blobs 최대 20·doubles 최대 20, 보존 기간 3개월.

2. 데이터 포인트 스키마

Cloudflare Analytics Engine은 index(샘플링/그룹 키) 1개, blobs(문자열 차원), doubles(숫자) 배열을 사용.

2.1 이벤트 타입별 스키마

이벤트indexblobs (차원)doubles (값)용도
api_requestapi_requestpath, tenant_id, plan, status_bucket1, duration_ms테넌트별 요청 수·지연·에러율. status_bucket: “2xx”,“4xx”,“5xx”.
job_createdjob_createdtenant_id, plan_tier, region1프로비저닝 요청 발생 수.
provision_completeprovision_completetenant_id, status (Completed/Failed)1, duration_sec설치 성공률·소요 시간. duration_sec는 job 생성→완료까지(선택).
  • tenant_id: 없으면 "anonymous" 또는 "-".
  • path: 예 POST /v1/tenants, GET /v1/jobs/:id, POST /internal/provision-complete.
  • duration_ms: 요청 처리 시간(ms). 선택.

2.2 쿼리 시 활용

  • SQL(Cloudflare Analytics 쿼리 API) 또는 대시보드에서: index = api_request, blobs[0]=path, blobs[1]=tenant_id, blobs[2]=status_bucket, doubles[0]=count, doubles[1]=duration_ms.
  • 테넌트별 RPS·에러율: tenant_id로 그룹, sum(doubles[0]), count where status_bucket=‘5xx’.
  • 프로비저닝 성공률: index = provision_complete, status로 그룹.

3. 호출 위치 (Control Plane Worker)

위치이벤트시점
index.tsapi_requestPOST /v1/tenants, GET /v1/jobs/:id, /internal/*, /health 처리 직후. status_code, path, duration_ms, tenant_id(있으면).
index.tsjob_createdenqueueProvisionJob 성공 후. tenant_id, plan_tier, region.
internal.tsprovision_completehandleProvisionComplete 성공 후. tenant_id, status(Completed/Failed). (duration_sec는 D1에서 job created_at과 비교해 계산 가능·선택)
  • writeDataPoint()non-blocking. await 하지 않아도 되며, 실패해도 요청 응답에는 영향 없음.
  • ANALYTICS_ENGINE 바인딩이 없으면 no-op(호출 생략 또는 stub).

4. 구현 체크리스트

  • wrangler.toml에 [[analytics_engine_datasets]] 추가.
  • Env 타입에 ANALYTICS_ENGINE?: AnalyticsEngineDataset 추가.
  • src/analytics.ts: writeApiRequest, writeJobCreated, writeProvisionComplete 헬퍼 구현(바인딩 없으면 return).
  • index.ts: 각 라우트 처리 후 경로·상태코드·duration_ms·tenant_id(가능 시)로 writeApiRequest 호출; enqueueProvisionJob 성공 시 writeJobCreated 호출.
  • internal.ts: handleProvisionComplete 성공 후 writeProvisionComplete 호출.
  • (선택) Stripe webhook: job_created는 이미 API 경로에서 발생하므로 중복 방지. webhook 자체는 api_request로만 집계 가능(path = POST /webhooks/stripe).

5. Phase 2: Analytics Engine SQL 쿼리 (대시보드 Row 3)

대시보드 Edge Performance 행에 테넌트별 RPS·에러율·지연을 넣으려면 Worker에서 Analytics Engine을 쿼리해야 함.

5.1 HTTP SQL API

  • 엔드포인트: POST https://api.cloudflare.com/client/v4/accounts/<account_id>/analytics_engine/sql
  • 인증: Authorization: Bearer <API_TOKEN> — Cloudflare 대시보드에서 Custom Token 생성, 권한 Account | Account Analytics | Read.
  • 요청: POST body에 SQL 문자열. 응답 형식은 쿼리 끝에 FORMAT JSON 등으로 지정.

5.2 테이블 구조 (prego_metrics)

컬럼설명
dataset데이터셋 이름
timestamp이벤트 시각
_sample_interval샘플링 시 행당 가중치 (집계 시 SUM(_sample_interval) 등 사용)
index1이벤트 타입 (api_request, job_created, provision_complete)
blob1..blob4path, tenant_id, plan, status_bucket
double1, double2count(1), duration_ms

5.3 예시 쿼리 (최근 1시간 API 요청 집계)

SELECT
SUM(_sample_interval) AS requests,
SUM(_sample_interval * double2) / NULLIF(SUM(_sample_interval), 0) AS avg_duration_ms,
SUM(CASE WHEN blob4 = '5xx' THEN _sample_interval * double1 ELSE 0 END) AS errors_5xx
FROM prego_metrics
WHERE index1 = 'api_request' AND timestamp > NOW() - INTERVAL '1' HOUR
FORMAT JSON

5.4 Worker에서 호출

  • Secrets: CF_ANALYTICS_READ_TOKEN (Account Analytics Read 토큰), CF_ACCOUNT_ID (32자 계정 ID).
  • 위치: handleMetricsSummary 내부에서 두 값이 있으면 위 쿼리로 fetch() 호출. 실패 또는 미설정 시 edge: null 반환.
  • 응답 병합: GET /internal/metrics/summary JSON에 edge: { requests_1h, avg_duration_ms_1h, errors_5xx_1h } 추가. 대시보드 Row 3에서 표시.

6. 관련 문서

Help