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:
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:
- Global Error Handlers - Unhandled exceptions and promise rejections
- Error Boundaries - React component errors via
error.tsxandglobal-error.tsx - 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.)
Breadcrumb Types¶
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.sendBeaconfor 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:
Verify Integration¶
Check the browser console for:
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' },
});