Next.js Supabase V3 (#463)
Version 3 of the kit: - Radix UI replaced with Base UI (using the Shadcn UI patterns) - next-intl replaces react-i18next - enhanceAction deprecated; usage moved to next-safe-action - main layout now wrapped with [locale] path segment - Teams only mode - Layout updates - Zod v4 - Next.js 16.2 - Typescript 6 - All other dependencies updated - Removed deprecated Edge CSRF - Dynamic Github Action runner
This commit is contained in:
committed by
GitHub
parent
4912e402a3
commit
7ebff31475
347
docs/monitoring/overview.mdoc
Normal file
347
docs/monitoring/overview.mdoc
Normal file
@@ -0,0 +1,347 @@
|
||||
---
|
||||
title: "Monitoring and Error Tracking in Makerkit"
|
||||
status: "published"
|
||||
label: "How Monitoring Works"
|
||||
order: 0
|
||||
description: "Set up error tracking and performance monitoring in your Next.js Supabase SaaS app with Sentry, PostHog, or SigNoz."
|
||||
---
|
||||
|
||||
{% sequence title="Steps to configure monitoring" description="Learn how to configure monitoring in the Next.js Supabase Starter Kit." %}
|
||||
|
||||
[Understanding the monitoring architecture](#understanding-the-monitoring-architecture)
|
||||
|
||||
[Supported monitoring providers](#supported-monitoring-providers)
|
||||
|
||||
[Configuring your monitoring provider](#configuring-your-monitoring-provider)
|
||||
|
||||
[What gets monitored automatically](#what-gets-monitored-automatically)
|
||||
|
||||
[Manually capturing exceptions](#manually-capturing-exceptions)
|
||||
|
||||
[Identifying users in error reports](#identifying-users-in-error-reports)
|
||||
|
||||
{% /sequence %}
|
||||
|
||||
## Understanding the Monitoring Architecture
|
||||
|
||||
Makerkit's monitoring system uses a **provider-based architecture** that lets you swap monitoring services without changing your application code. The system lives in the `@kit/monitoring` package and handles:
|
||||
|
||||
- **Error tracking**: Capture client-side and server-side exceptions
|
||||
- **Performance monitoring**: Track server response times via OpenTelemetry instrumentation
|
||||
- **User identification**: Associate errors with specific users for debugging
|
||||
|
||||
The architecture follows a registry pattern. When you set `NEXT_PUBLIC_MONITORING_PROVIDER`, Makerkit loads the appropriate service implementation at runtime:
|
||||
|
||||
```
|
||||
MonitoringProvider (React context)
|
||||
│
|
||||
▼
|
||||
Registry lookup
|
||||
│
|
||||
▼
|
||||
┌───────┴───────┐
|
||||
│ sentry │
|
||||
│ posthog │
|
||||
│ signoz │
|
||||
└───────────────┘
|
||||
```
|
||||
|
||||
This means your components interact with a consistent `MonitoringService` interface regardless of which provider you choose.
|
||||
|
||||
## Supported Monitoring Providers
|
||||
|
||||
Makerkit provides first-class support for these monitoring providers:
|
||||
|
||||
| Provider | Error Tracking | Performance | Self-Hostable | Notes |
|
||||
|----------|---------------|-------------|---------------|-------|
|
||||
| [Sentry](/docs/next-supabase-turbo/monitoring/sentry) | Yes | Yes | Yes | Built-in, recommended for most apps |
|
||||
| [PostHog](/docs/next-supabase-turbo/monitoring/posthog) | Yes | No | Yes | Plugin, doubles as analytics |
|
||||
| [SigNoz](/docs/next-supabase-turbo/monitoring/signoz) | Yes | Yes | Yes | Plugin, OpenTelemetry-native |
|
||||
|
||||
**Sentry** is included out of the box. PostHog and SigNoz require installing plugins via the Makerkit CLI.
|
||||
|
||||
{% alert type="default" title="Custom providers" %}
|
||||
You can add support for any monitoring service by implementing the `MonitoringService` interface and registering it in the provider registry. See [Adding a custom monitoring provider](#adding-a-custom-monitoring-provider) below.
|
||||
{% /alert %}
|
||||
|
||||
## Configuring Your Monitoring Provider
|
||||
|
||||
Set these environment variables to enable monitoring:
|
||||
|
||||
```bash title=".env.local"
|
||||
# Required: Choose your provider (sentry, posthog, or signoz)
|
||||
NEXT_PUBLIC_MONITORING_PROVIDER=sentry
|
||||
|
||||
# Provider-specific configuration
|
||||
# See the individual provider docs for required variables
|
||||
```
|
||||
|
||||
The `NEXT_PUBLIC_MONITORING_PROVIDER` variable determines which service handles your errors. Leave it empty to disable monitoring entirely (errors still log to console in development).
|
||||
|
||||
## What Gets Monitored Automatically
|
||||
|
||||
Once configured, Makerkit captures errors without additional code:
|
||||
|
||||
### Client-side exceptions
|
||||
|
||||
The `MonitoringProvider` component wraps your app and captures uncaught exceptions in React components. This includes:
|
||||
|
||||
- Runtime errors in components
|
||||
- Unhandled promise rejections
|
||||
- Errors thrown during rendering
|
||||
|
||||
### Server-side exceptions
|
||||
|
||||
Next.js 15+ includes an instrumentation hook that captures server errors automatically. Makerkit hooks into this via `instrumentation.ts`:
|
||||
|
||||
```typescript title="apps/web/instrumentation.ts"
|
||||
import { type Instrumentation } from 'next';
|
||||
|
||||
export const onRequestError: Instrumentation.onRequestError = async (
|
||||
err,
|
||||
request,
|
||||
context,
|
||||
) => {
|
||||
const { getServerMonitoringService } = await import('@kit/monitoring/server');
|
||||
|
||||
const service = await getServerMonitoringService();
|
||||
await service.ready();
|
||||
|
||||
await service.captureException(
|
||||
err as Error,
|
||||
{},
|
||||
{
|
||||
path: request.path,
|
||||
headers: request.headers,
|
||||
method: request.method,
|
||||
routePath: context.routePath,
|
||||
},
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
This captures errors from Server Components, Server Actions, Route Handlers, and Middleware.
|
||||
|
||||
## Manually Capturing Exceptions
|
||||
|
||||
For expected errors (like validation failures or API errors), capture them explicitly:
|
||||
|
||||
### In Server Actions or Route Handlers
|
||||
|
||||
```typescript
|
||||
import { getServerMonitoringService } from '@kit/monitoring/server';
|
||||
|
||||
export async function createProject(data: FormData) {
|
||||
try {
|
||||
// ... your logic
|
||||
} catch (error) {
|
||||
const monitoring = await getServerMonitoringService();
|
||||
await monitoring.ready();
|
||||
|
||||
monitoring.captureException(error, {
|
||||
action: 'createProject',
|
||||
userId: user.id,
|
||||
});
|
||||
|
||||
throw error; // Re-throw or handle as needed
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### In React Components
|
||||
|
||||
Use the `useMonitoring` hook for client-side error capture:
|
||||
|
||||
```tsx
|
||||
'use client';
|
||||
|
||||
import { useMonitoring } from '@kit/monitoring/hooks';
|
||||
|
||||
export function DataLoader() {
|
||||
const monitoring = useMonitoring();
|
||||
|
||||
async function loadData() {
|
||||
try {
|
||||
const response = await fetch('/api/data');
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load data: ${response.status}`);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
} catch (error) {
|
||||
monitoring.captureException(error, {
|
||||
component: 'DataLoader',
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### The `useCaptureException` Hook
|
||||
|
||||
For error boundaries or components that receive errors as props:
|
||||
|
||||
```tsx
|
||||
'use client';
|
||||
|
||||
import { useCaptureException } from '@kit/monitoring/hooks';
|
||||
|
||||
export function ErrorDisplay({ error }: { error: Error }) {
|
||||
// Automatically captures the error when the component mounts
|
||||
useCaptureException(error);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>Something went wrong</h2>
|
||||
<p>{error.message}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Identifying Users in Error Reports
|
||||
|
||||
Associate errors with users to debug issues faster. Makerkit's monitoring providers support user identification:
|
||||
|
||||
```typescript
|
||||
const monitoring = useMonitoring();
|
||||
|
||||
// After user signs in
|
||||
monitoring.identifyUser({
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
// Additional fields depend on your provider
|
||||
});
|
||||
```
|
||||
|
||||
Makerkit automatically identifies users when they sign in if you've configured the analytics/events system. The `user.signedIn` event triggers user identification in both analytics and monitoring.
|
||||
|
||||
## Adding a Custom Monitoring Provider
|
||||
|
||||
To add a provider not included in Makerkit:
|
||||
|
||||
### 1. Implement the MonitoringService interface
|
||||
|
||||
```typescript title="packages/monitoring/my-provider/src/my-provider.service.ts"
|
||||
import { MonitoringService } from '@kit/monitoring-core';
|
||||
|
||||
export class MyProviderMonitoringService implements MonitoringService {
|
||||
private readyPromise: Promise<void>;
|
||||
private readyResolver?: () => void;
|
||||
|
||||
constructor() {
|
||||
this.readyPromise = new Promise((resolve) => {
|
||||
this.readyResolver = resolve;
|
||||
});
|
||||
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
async ready() {
|
||||
return this.readyPromise;
|
||||
}
|
||||
|
||||
captureException(error: Error, extra?: Record<string, unknown>) {
|
||||
// Send to your monitoring service
|
||||
myProviderSDK.captureException(error, { extra });
|
||||
}
|
||||
|
||||
captureEvent(event: string, extra?: Record<string, unknown>) {
|
||||
myProviderSDK.captureEvent(event, extra);
|
||||
}
|
||||
|
||||
identifyUser(user: { id: string }) {
|
||||
myProviderSDK.setUser(user);
|
||||
}
|
||||
|
||||
private initialize() {
|
||||
// Initialize your SDK
|
||||
myProviderSDK.init({ dsn: process.env.MY_PROVIDER_DSN });
|
||||
this.readyResolver?.();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Register the provider
|
||||
|
||||
Add your provider to the monitoring registries:
|
||||
|
||||
```typescript title="packages/monitoring/api/src/get-monitoring-provider.ts"
|
||||
const MONITORING_PROVIDERS = [
|
||||
'sentry',
|
||||
'my-provider', // Add your provider
|
||||
'',
|
||||
] as const;
|
||||
```
|
||||
|
||||
```typescript title="packages/monitoring/api/src/services/get-server-monitoring-service.ts"
|
||||
serverMonitoringRegistry.register('my-provider', async () => {
|
||||
const { MyProviderMonitoringService } = await import('@kit/my-provider');
|
||||
return new MyProviderMonitoringService();
|
||||
});
|
||||
```
|
||||
|
||||
```typescript title="packages/monitoring/api/src/components/provider.tsx"
|
||||
monitoringProviderRegistry.register('my-provider', async () => {
|
||||
const { MyProviderProvider } = await import('@kit/my-provider/provider');
|
||||
|
||||
return {
|
||||
default: function MyProviderWrapper({ children }: React.PropsWithChildren) {
|
||||
return <MyProviderProvider>{children}</MyProviderProvider>;
|
||||
},
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
{% alert type="default" title="Telegram notifications" %}
|
||||
We wrote a tutorial showing how to add Telegram notifications for error monitoring: [Send SaaS errors to Telegram](/blog/tutorials/telegram-saas-error-monitoring).
|
||||
{% /alert %}
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Do capture context with errors
|
||||
|
||||
```typescript
|
||||
// Good: Includes debugging context
|
||||
monitoring.captureException(error, {
|
||||
userId: user.id,
|
||||
accountId: account.id,
|
||||
action: 'updateBillingPlan',
|
||||
planId: newPlanId,
|
||||
});
|
||||
|
||||
// Less useful: No context
|
||||
monitoring.captureException(error);
|
||||
```
|
||||
|
||||
### Don't capture expected validation errors
|
||||
|
||||
```typescript
|
||||
// Avoid: This clutters your error dashboard
|
||||
if (!isValidEmail(email)) {
|
||||
monitoring.captureException(new Error('Invalid email'));
|
||||
return { error: 'Invalid email' };
|
||||
}
|
||||
|
||||
// Better: Only capture unexpected failures
|
||||
try {
|
||||
await sendEmail(email);
|
||||
} catch (error) {
|
||||
monitoring.captureException(error, {
|
||||
extra: { email: maskEmail(email) },
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
Choose a monitoring provider and follow its setup guide:
|
||||
|
||||
- [Configure Sentry](/docs/next-supabase-turbo/monitoring/sentry) (recommended for most apps)
|
||||
- [Configure PostHog](/docs/next-supabase-turbo/monitoring/posthog) (if you already use PostHog for analytics)
|
||||
- [Configure SigNoz](/docs/next-supabase-turbo/monitoring/signoz) (self-hosted, OpenTelemetry-native)
|
||||
Reference in New Issue
Block a user