Skip to content

Producer Portal Logging & Error Tracking

This guide covers the Sentry error tracking integration in the Producer Portal application deployed to Cloudflare Workers.

Overview

The Producer Portal uses a custom SDK-free Sentry implementation designed for Cloudflare Workers edge runtime compatibility. The official Sentry SDK is not compatible with Cloudflare Workers, so we use the Sentry Envelope API directly.

This implementation mirrors the approach used in the Frontend application.

Architecture

┌─────────────────────────────────────────────────────────────┐
│                    Producer Portal                          │
├─────────────────────────────────────────────────────────────┤
│  Browser (Client-side)          │  Server (Edge Runtime)    │
│  ─────────────────────          │  ────────────────────     │
│  • SentryInitializer            │  • instrumentation.ts     │
│  • Global error handlers        │  • Server-side capture    │
│  • Breadcrumb capture           │  • Edge-compatible fetch  │
│  • Console interception         │                           │
└─────────────────────────────────┴───────────────────────────┘
              ┌─────────────────┐
              │  Sentry Ingest  │
              │  (Envelope API) │
              └─────────────────┘

Configuration

Environment Variables

Variable Description Required
NEXT_PUBLIC_SENTRY_DSN Sentry Data Source Name Yes
NEXT_PUBLIC_SENTRY_ENABLED Enable/disable Sentry (true/false) No (default: true)
NEXT_PUBLIC_SENTRY_ENVIRONMENT Environment name (production/staging/development) No
NEXT_PUBLIC_SENTRY_SAMPLE_RATE Error sampling rate (0.0 - 1.0) No (default: 1.0)
NEXT_PUBLIC_APP_VERSION Application version for release tracking No

Wrangler Configuration

Add Sentry variables to wrangler.jsonc:

{
  "vars": {
    "NEXT_PUBLIC_SENTRY_ENVIRONMENT": "production",
    "NEXT_PUBLIC_SENTRY_ENABLED": "true"
  }
}

Secret Management

The NEXT_PUBLIC_SENTRY_DSN should be set as a Cloudflare secret, not in wrangler.jsonc:

wrangler secret put NEXT_PUBLIC_SENTRY_DSN

Local Development

Create a .env.local file:

NEXT_PUBLIC_SENTRY_DSN=https://your-key@your-org.ingest.sentry.io/your-project-id
NEXT_PUBLIC_SENTRY_ENVIRONMENT=development
NEXT_PUBLIC_SENTRY_ENABLED=true
NEXT_PUBLIC_SENTRY_SAMPLE_RATE=1.0

Usage

Automatic Error Capture

Errors are automatically captured in several ways:

  1. Global Error Handlers - Unhandled exceptions and promise rejections
  2. Error Boundaries - React component errors via error.tsx and global-error.tsx
  3. Console Interception - console.error() calls are captured as breadcrumbs

Manual Error Capture

import { captureException, captureMessage } from '@/lib/sentry';

// Capture an exception with context
try {
  await riskyOperation();
} catch (error) {
  captureException(error, {
    tags: { component: 'checkout', action: 'payment' },
    extra: { userId: user.id, orderId: order.id },
  });
}

// Capture a message
captureMessage('User completed checkout', 'info', {
  tags: { flow: 'checkout' },
});

Server-Side Error Capture

For server components and API routes:

import { captureServerException } from '@/lib/sentry/server';

export async function GET(request: Request) {
  try {
    const data = await fetchData();
    return Response.json(data);
  } catch (error) {
    await captureServerException(error, {
      tags: { route: '/api/data' },
    });
    return Response.json({ error: 'Internal error' }, { status: 500 });
  }
}

Adding Custom Breadcrumbs

import { addBreadcrumb } from '@/lib/sentry';

// Add a navigation breadcrumb
addBreadcrumb({
  category: 'navigation',
  message: 'User navigated to dashboard',
  level: 'info',
  data: { from: '/home', to: '/dashboard' },
});

// Add a user action breadcrumb
addBreadcrumb({
  category: 'user',
  message: 'User clicked submit button',
  level: 'info',
});

Error Boundaries

Route-Level Error Boundary

Each route can have its own error.tsx file:

'use client';

import { useEffect } from 'react';

export default function RouteError({ error, reset }: {
  error: Error;
  reset: () => void;
}) {
  useEffect(() => {
    import('@/lib/sentry').then(({ captureException }) => {
      captureException(error, {
        tags: { component: 'route-name' },
      });
    });
  }, [error]);

  return (
    <div>
      <h2>Something went wrong!</h2>
      <button onClick={() => reset()}>Try again</button>
    </div>
  );
}

Dashboard Error Components

The dashboard uses parallel routes with individual error boundaries:

Route Error Component Sentry Tag
@bar_stats error.tsx dashboard-bar-stats
@pie_stats error.tsx dashboard-pie-stats
@area_stats error.tsx dashboard-area-stats
@sales error.tsx dashboard-sales
overview error.tsx dashboard-overview

Library Structure

src/lib/sentry/
├── index.ts              # Public API exports
├── types.ts              # TypeScript interfaces
├── utils.ts              # Utility functions
├── envelope.ts           # Sentry Envelope format builder
├── serialize.ts          # Error serialization & stack traces
├── scrub.ts              # PII scrubbing utilities
├── breadcrumbs.ts        # Breadcrumb capture
├── transport.ts          # HTTP transport with retry
├── client.ts             # Browser-side client
├── server.ts             # Server-side client (Edge compatible)
└── integrations/
    └── globalHandlers.ts # Global error handlers

Features

PII Scrubbing

Sensitive data is automatically scrubbed from error reports:

  • Passwords and secrets
  • Credit card numbers
  • API keys and tokens
  • Authorization headers
  • Common sensitive field names (SSN, DOB, etc.)

The following breadcrumbs are automatically captured:

Type Description
console Console log/warn/error calls
fetch HTTP request/response info
navigation URL changes and page navigations
click User click events (with element info)
error JavaScript errors

Transport Features

  • Retry Logic: Failed requests are retried with exponential backoff
  • Queue Management: Events are queued when offline
  • Beacon API: Uses navigator.sendBeacon for reliable delivery on page unload

Content Security Policy

The CSP headers in next.config.js include Sentry domains:

const cspHeader = `
  connect-src 'self' ... https://*.ingest.sentry.io https://*.ingest.us.sentry.io;
`;

Debugging

Enable Debug Mode

In development, debug logging is enabled automatically. For production debugging:

initSentry({
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
  debug: true, // Enable debug logging
});

Verify Integration

Check the browser console for:

[Sentry] Client initialized with config: {...}
[Sentry] Global handlers registered

Common Issues

Issue Solution
Events not appearing in Sentry Check DSN is correct and SENTRY_ENABLED is true
CSP errors in console Verify Sentry domains are in CSP connect-src
Server errors not captured Ensure instrumentation.ts is in src/ root
Missing breadcrumbs Check initGlobalHandlers() is called

Testing Error Capture

To test that errors are being captured:

// In a component or page
<button onClick={() => {
  throw new Error('Test Sentry error');
}}>
  Test Error
</button>

// Or programmatically
import { captureException } from '@/lib/sentry';
captureException(new Error('Manual test error'), {
  tags: { test: 'manual' },
});