# Tail Workers Common Patterns

## Community Libraries

While most tail Worker implementations are custom, these libraries may help:

**Logging/Observability:**

- **Axiom** - `axiom-cloudflare-workers` (npm) - Direct Axiom integration
- **Baselime** - SDK for Baselime observability platform
- **LogFlare** - Structured log aggregation

**Type Definitions:**

- **@cloudflare/workers-types** - Official TypeScript types (use `TraceItem`)

**Note:** Most integrations require custom tail handler implementation. See integration examples below.

## Basic Patterns

### HTTP Endpoint Logging

```typescript
export default {
  async tail(events, env, ctx) {
    const payload = events.map(event => ({
      script: event.scriptName,
      timestamp: event.eventTimestamp,
      outcome: event.outcome,
      url: event.event?.request?.url,
      status: event.event?.response?.status,
      logs: event.logs,
      exceptions: event.exceptions,
    }));

    ctx.waitUntil(
      fetch(env.LOG_ENDPOINT, {
        method: "POST",
        body: JSON.stringify(payload),
      })
    );
  },
};
```

### Error Tracking Only

```typescript
export default {
  async tail(events, env, ctx) {
    const errors = events.filter(e => e.outcome === "exception" || e.exceptions.length > 0);

    if (errors.length === 0) return;

    ctx.waitUntil(
      fetch(env.ERROR_ENDPOINT, {
        method: "POST",
        body: JSON.stringify(errors),
      })
    );
  },
};
```

## Storage Integration

### KV Storage with TTL

```typescript
export default {
  async tail(events, env, ctx) {
    ctx.waitUntil(
      Promise.all(
        events.map(event =>
          env.LOGS_KV.put(
            `log:${event.scriptName}:${event.eventTimestamp}`,
            JSON.stringify(event),
            { expirationTtl: 86400 } // 24 hours
          )
        )
      )
    );
  },
};
```

### Analytics Engine Metrics

```typescript
export default {
  async tail(events, env, ctx) {
    ctx.waitUntil(
      Promise.all(
        events.map(event =>
          env.ANALYTICS.writeDataPoint({
            blobs: [event.scriptName, event.outcome],
            doubles: [1, event.event?.response?.status ?? 0],
            indexes: [event.event?.request?.cf?.colo ?? "unknown"],
          })
        )
      )
    );
  },
};
```

## Filtering & Routing

Filter by route, outcome, or other criteria:

```typescript
export default {
  async tail(events, env, ctx) {
    // Route filtering
    const apiEvents = events.filter(e => e.event?.request?.url?.includes("/api/"));

    // Multi-destination routing
    const errors = events.filter(e => e.outcome === "exception");
    const success = events.filter(e => e.outcome === "ok");

    const tasks = [];
    if (errors.length > 0) {
      tasks.push(
        fetch(env.ERROR_ENDPOINT, {
          method: "POST",
          body: JSON.stringify(errors),
        })
      );
    }
    if (success.length > 0) {
      tasks.push(
        fetch(env.SUCCESS_ENDPOINT, {
          method: "POST",
          body: JSON.stringify(success),
        })
      );
    }

    ctx.waitUntil(Promise.all(tasks));
  },
};
```

## Sampling

Reduce costs by processing only a percentage of events:

```typescript
export default {
  async tail(events, env, ctx) {
    if (Math.random() > 0.1) return; // 10% sample rate
    ctx.waitUntil(
      fetch(env.LOG_ENDPOINT, {
        method: "POST",
        body: JSON.stringify(events),
      })
    );
  },
};
```

## Advanced Patterns

### Batching with Durable Objects

Accumulate events before sending:

```typescript
export default {
  async tail(events, env, ctx) {
    const batch = env.BATCH_DO.get(env.BATCH_DO.idFromName("batch"));
    ctx.waitUntil(
      batch.fetch("https://batch/add", {
        method: "POST",
        body: JSON.stringify(events),
      })
    );
  },
};
```

See durable-objects skill for full implementation.

### Workers for Platforms

Dynamic dispatch sends TWO events per request. Filter by `scriptName` to distinguish dispatch vs user Worker events.

### Error Handling

Always wrap external calls. See gotchas.md for fallback storage pattern.
