| name | observability |
| description | Add production observability to Cloudflare Workers apps with structured logs, request IDs, metrics, traces, Durable Object/Queue/Workflow visibility, error handling, and incident debugging. Use before deploying or debugging Cloudflare applications.
|
| compatibility | Cloudflare Workers TypeScript projects using Wrangler; verify current Cloudflare APIs, limits, and pricing before production use. |
| metadata | {"source":"Architecting on Cloudflare plus official Cloudflare Developer Platform docs","generated":"2026-04-28"} |
Observability
Use this skill for logging, metrics, traces, and incident debugging in Cloudflare applications.
Observability stance
- Edge systems are ephemeral; design logs and metrics as the primary debugging evidence.
- Add correlation IDs at the Worker boundary and pass them through bindings, queues, workflows, and external calls.
- Log structured events, not unparseable strings.
- Redact secrets and minimize PII.
- Observe every asynchronous boundary:
waitUntil, Queues, Workflows, Durable Objects, AI calls, and container calls.
Request ID middleware pattern
export function getRequestId(request: Request) {
return request.headers.get("cf-ray")
?? request.headers.get("x-request-id")
?? crypto.randomUUID();
}
export function log(event: string, fields: Record<string, unknown>) {
console.log(JSON.stringify({ event, ...fields }));
}
Worker handler pattern
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const requestId = getRequestId(request);
const started = Date.now();
try {
const response = await route(request, env, ctx, requestId);
log("request.complete", {
requestId,
status: response.status,
durationMs: Date.now() - started
});
return response;
} catch (error) {
log("request.error", {
requestId,
durationMs: Date.now() - started,
error: error instanceof Error ? error.message : String(error)
});
return Response.json({ error: "internal_error", requestId }, { status: 500 });
}
}
} satisfies ExportedHandler<Env>;
What to log by primitive
- Workers: route, status, duration, request ID, tenant ID, user ID hash, cache outcome.
- Durable Objects: object key, method, queue length/backpressure signal, storage operation summary, WebSocket counts.
- D1: query class/name, row counts, duration, not raw user data.
- R2: key prefix/category, operation, bytes, duration.
- KV: key namespace/category, hit/miss, TTL class.
- Queues: queue name, message ID/job ID, retry count, ack/retry/failure.
- Workflows: instance ID, step name, retry count, status.
- AI: model, prompt class, tokens where available, duration, fallback, refusal/abstention.
Error response rules
- Include request ID in user-visible errors.
- Never expose stack traces or secrets.
- Map validation/auth errors to 4xx; unknown application failures to 500.
- Use safe error messages and log detailed internal messages.
Incident checklist
- Can you identify affected tenants/users?
- Can you follow one request through Worker -> DO/Queue/Workflow -> storage/AI?
- Are retries amplifying the incident?
- Is there a hot Durable Object or hot D1 query?
- Are external APIs failing or slow?
- Is an AI model/provider unavailable or returning malformed output?
Anti-patterns
- Logs only say
failed without request/job IDs.
- Logging full prompts, secrets, tokens, or uploaded file contents.
- No visibility into background work after the initial HTTP 202.
- Treating local debugging as enough for production edge behavior.