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.
1---2name: observability3description: 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.4---5# Observability67Use this skill for logging, metrics, traces, and incident debugging in Cloudflare applications.89## Observability stance1011- Edge systems are ephemeral; design logs and metrics as the primary debugging evidence.12- Add correlation IDs at the Worker boundary and pass them through bindings, queues, workflows, and external calls.13- Log structured events, not unparseable strings.14- Redact secrets and minimize PII.15- Observe every asynchronous boundary: `waitUntil`, Queues, Workflows, Durable Objects, AI calls, and container calls.1617## Request ID middleware pattern1819```ts20export function getRequestId(request: Request) {21 return request.headers.get("cf-ray")22 ?? request.headers.get("x-request-id")23 ?? crypto.randomUUID();24}2526export function log(event: string, fields: Record<string, unknown>) {27 console.log(JSON.stringify({ event, ...fields }));28}29```3031## Worker handler pattern3233```ts34export default {35 async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {36 const requestId = getRequestId(request);37 const started = Date.now();3839 try {40 const response = await route(request, env, ctx, requestId);41 log("request.complete", {42 requestId,43 status: response.status,44 durationMs: Date.now() - started45 });46 return response;47 } catch (error) {48 log("request.error", {49 requestId,50 durationMs: Date.now() - started,51 error: error instanceof Error ? error.message : String(error)52 });53 return Response.json({ error: "internal_error", requestId }, { status: 500 });54 }55 }56} satisfies ExportedHandler<Env>;57```5859## What to log by primitive6061- Workers: route, status, duration, request ID, tenant ID, user ID hash, cache outcome.62- Durable Objects: object key, method, queue length/backpressure signal, storage operation summary, WebSocket counts.63- D1: query class/name, row counts, duration, not raw user data.64- R2: key prefix/category, operation, bytes, duration.65- KV: key namespace/category, hit/miss, TTL class.66- Queues: queue name, message ID/job ID, retry count, ack/retry/failure.67- Workflows: instance ID, step name, retry count, status.68- AI: model, prompt class, tokens where available, duration, fallback, refusal/abstention.6970## Error response rules7172- Include request ID in user-visible errors.73- Never expose stack traces or secrets.74- Map validation/auth errors to 4xx; unknown application failures to 500.75- Use safe error messages and log detailed internal messages.7677## Incident checklist7879- Can you identify affected tenants/users?80- Can you follow one request through Worker -> DO/Queue/Workflow -> storage/AI?81- Are retries amplifying the incident?82- Is there a hot Durable Object or hot D1 query?83- Are external APIs failing or slow?84- Is an AI model/provider unavailable or returning malformed output?8586## Anti-patterns8788- Logs only say `failed` without request/job IDs.89- Logging full prompts, secrets, tokens, or uploaded file contents.90- No visibility into background work after the initial HTTP 202.91- Treating local debugging as enough for production edge behavior.