Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Comprehensive Cloudflare platform skill covering Workers, D1, R2, KV, AI, Durable Objects, and security.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/tail-workers/patterns.md
1# Tail Workers Common Patterns23## Community Libraries45While most tail Worker implementations are custom, these libraries may help:67**Logging/Observability:**8- **Axiom** - `axiom-cloudflare-workers` (npm) - Direct Axiom integration9- **Baselime** - SDK for Baselime observability platform10- **LogFlare** - Structured log aggregation1112**Type Definitions:**13- **@cloudflare/workers-types** - Official TypeScript types (use `TraceItem`)1415**Note:** Most integrations require custom tail handler implementation. See integration examples below.1617## Basic Patterns1819### HTTP Endpoint Logging2021```typescript22export default {23async tail(events, env, ctx) {24const payload = events.map(event => ({25script: event.scriptName,26timestamp: event.eventTimestamp,27outcome: event.outcome,28url: event.event?.request?.url,29status: event.event?.response?.status,30logs: event.logs,31exceptions: event.exceptions,32}));3334ctx.waitUntil(35fetch(env.LOG_ENDPOINT, {36method: "POST",37body: JSON.stringify(payload),38})39);40}41};42```4344### Error Tracking Only4546```typescript47export default {48async tail(events, env, ctx) {49const errors = events.filter(e =>50e.outcome === 'exception' || e.exceptions.length > 051);5253if (errors.length === 0) return;5455ctx.waitUntil(56fetch(env.ERROR_ENDPOINT, {57method: "POST",58body: JSON.stringify(errors),59})60);61}62};63```6465## Storage Integration6667### KV Storage with TTL6869```typescript70export default {71async tail(events, env, ctx) {72ctx.waitUntil(73Promise.all(events.map(event =>74env.LOGS_KV.put(75`log:${event.scriptName}:${event.eventTimestamp}`,76JSON.stringify(event),77{ expirationTtl: 86400 } // 24 hours78)79))80);81}82};83```8485### Analytics Engine Metrics8687```typescript88export default {89async tail(events, env, ctx) {90ctx.waitUntil(91Promise.all(events.map(event =>92env.ANALYTICS.writeDataPoint({93blobs: [event.scriptName, event.outcome],94doubles: [1, event.event?.response?.status ?? 0],95indexes: [event.event?.request?.cf?.colo ?? 'unknown'],96})97))98);99}100};101```102103## Filtering & Routing104105Filter by route, outcome, or other criteria:106107```typescript108export default {109async tail(events, env, ctx) {110// Route filtering111const apiEvents = events.filter(e =>112e.event?.request?.url?.includes('/api/')113);114115// Multi-destination routing116const errors = events.filter(e => e.outcome === 'exception');117const success = events.filter(e => e.outcome === 'ok');118119const tasks = [];120if (errors.length > 0) {121tasks.push(fetch(env.ERROR_ENDPOINT, {122method: "POST",123body: JSON.stringify(errors),124}));125}126if (success.length > 0) {127tasks.push(fetch(env.SUCCESS_ENDPOINT, {128method: "POST",129body: JSON.stringify(success),130}));131}132133ctx.waitUntil(Promise.all(tasks));134}135};136```137138## Sampling139140Reduce costs by processing only a percentage of events:141142```typescript143export default {144async tail(events, env, ctx) {145if (Math.random() > 0.1) return; // 10% sample rate146ctx.waitUntil(fetch(env.LOG_ENDPOINT, {147method: "POST",148body: JSON.stringify(events),149}));150}151};152```153154## Advanced Patterns155156### Batching with Durable Objects157158Accumulate events before sending:159160```typescript161export default {162async tail(events, env, ctx) {163const batch = env.BATCH_DO.get(env.BATCH_DO.idFromName("batch"));164ctx.waitUntil(batch.fetch("https://batch/add", {165method: "POST",166body: JSON.stringify(events),167}));168}169};170```171172See durable-objects skill for full implementation.173174### Workers for Platforms175176Dynamic dispatch sends TWO events per request. Filter by `scriptName` to distinguish dispatch vs user Worker events.177178### Error Handling179180Always wrap external calls. See gotchas.md for fallback storage pattern.181