cloudflareloggingtutorial

How to Monitor Logs in Cloudflare Workers

Cloudflare Workers gives you a powerful serverless runtime at the edge, but console.log output disappears after the request ends. Here’s how to build a real log monitoring system that persists, queries, and alerts on your logs.

Why console.log isn’t enough

When debugging locally, wrangler dev shows console output inline. In production, Workers logs are available in the Cloudflare dashboard for a limited window — but you can’t search them, set up alerts, or correlate them across requests.

For any app beyond a prototype, you need:

Option 1: Use ScryWatch (5 minutes)

ScryWatch runs on the same Cloudflare infrastructure as your Workers. Send logs with a single fetch:

async function log(env, level, message, fields = {}) {
  await fetch('https://ingest.scrywatch.com/v1/logs', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${env.SCRYWATCH_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      level,
      message,
      service: 'my-worker',
      ...fields,
    }),
  });
}

Then in your Worker handler:

export default {
  async fetch(request, env, ctx) {
    ctx.waitUntil(log(env, 'info', 'Request received', {
      path: new URL(request.url).pathname,
      method: request.method,
    }));

    // your handler logic...
  }
};

ctx.waitUntil ensures the log is sent without blocking the response.

Option 2: Use Cloudflare Logpush (complex)

Cloudflare Logpush can forward Worker logs to S3, R2, or a SIEM. It requires:

This works well at scale but takes days to set up correctly.

Structured logging best practices

Regardless of which approach you use:

  1. Always use JSON{ level: 'error', message: '...', userId: '...' } not plain strings
  2. Add a service field — makes it easy to filter by microservice
  3. Log at request boundaries — start, end, and any errors
  4. Use ctx.waitUntil — never await log calls in the critical path

Summary

← All posts