Loading...
Loading...
This skill should be used when adding error tracking and performance monitoring with Sentry and OpenTelemetry tracing to Next.js applications. Apply when setting up error monitoring, configuring tracing for Server Actions and routes, implementing logging wrappers, adding performance instrumentation, or establishing observability for debugging production issues.
npx skill4agent add hopeoverture/worldbuilding-app-skills sentry-and-otel-setupnpm install @sentry/nextjsnpx @sentry/wizard@latest -i nextjssentry.client.config.tssentry.server.config.tssentry.edge.config.tsinstrumentation.tsnext.config.js.env.localSENTRY_DSN=https://your-dsn@sentry.io/project-id
SENTRY_ORG=your-org
SENTRY_PROJECT=your-project
NEXT_PUBLIC_SENTRY_DSN=https://your-dsn@sentry.io/project-idsentry.server.config.tsassets/sentry-server-config.tssentry.client.config.tsassets/sentry-client-config.tsinstrumentation.tsassets/instrumentation.tsexperimental.instrumentationHooknext.config.jslib/logger.tsassets/logger.tsconsole.logimport { logger } from '@/lib/logger';
logger.info('User logged in', { userId: user.id });
logger.error('Failed to save data', { error, userId });components/error-boundary.tsxassets/error-boundary.tsximport { ErrorBoundary } from '@/components/error-boundary';
export default function Layout({ children }) {
return (
<ErrorBoundary>
{children}
</ErrorBoundary>
);
}app/error.tsxassets/error-page.tsxapp/global-error.tsxassets/global-error.tsx'use server';
import { logger } from '@/lib/logger';
import * as Sentry from '@sentry/nextjs';
export async function createPost(formData: FormData) {
return await Sentry.startSpan(
{ name: 'createPost', op: 'server.action' },
async () => {
try {
const title = formData.get('title') as string;
logger.info('Creating post', { title });
// Your logic here
const post = await prisma.post.create({
data: { title, content: '...' },
});
logger.info('Post created', { postId: post.id });
return { success: true, post };
} catch (error) {
logger.error('Failed to create post', { error });
Sentry.captureException(error);
throw error;
}
}
);
}import * as Sentry from '@sentry/nextjs';
import { getCurrentUser } from '@/lib/auth/utils';
export async function setUserContext() {
const user = await getCurrentUser();
if (user) {
Sentry.setUser({
id: user.id,
email: user.email,
});
}
}Sentry.setTag('feature', 'worldbuilding');
Sentry.setTag('entity_type', 'character');
// Now errors are tagged and filterable in Sentry dashboardSentry.addBreadcrumb({
category: 'user_action',
message: 'User clicked create entity',
level: 'info',
data: {
entityType: 'character',
worldId: 'world-123',
},
});import * as Sentry from '@sentry/nextjs';
export async function complexOperation() {
const transaction = Sentry.startTransaction({
name: 'Complex World Generation',
op: 'task',
});
// Step 1
const span1 = transaction.startChild({
op: 'generate.terrain',
description: 'Generate terrain data',
});
await generateTerrain();
span1.finish();
// Step 2
const span2 = transaction.startChild({
op: 'generate.biomes',
description: 'Generate biome data',
});
await generateBiomes();
span2.finish();
transaction.finish();
}// Queries are automatically traced if OTel is configured
const users = await prisma.user.findMany();
// Shows up in Sentry as a database span// sentry.server.config.ts
Sentry.init({
dsn: process.env.SENTRY_DSN,
// Percentage of errors to capture (1.0 = 100%)
sampleRate: 1.0,
// Percentage of transactions to trace
tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0,
// Percentage of sessions to replay
replaysSessionSampleRate: 0.1,
// Percentage of error sessions to replay
replaysOnErrorSampleRate: 1.0,
});Sentry.init({
environment: process.env.NODE_ENV,
enabled: process.env.NODE_ENV !== 'development', // Disable in dev
beforeSend(event, hint) {
// Filter out specific errors
if (event.exception?.values?.[0]?.value?.includes('ResizeObserver')) {
return null; // Don't send to Sentry
}
return event;
},
});// next.config.js (added by Sentry wizard)
const { withSentryConfig } = require('@sentry/nextjs');
module.exports = withSentryConfig(
nextConfig,
{
silent: true,
org: process.env.SENTRY_ORG,
project: process.env.SENTRY_PROJECT,
},
{
hideSourceMaps: true,
widenClientFileUpload: true,
}
);instrumentation.tsregister()beforeSendtracesSampleRateinstrumentation.tsNEXT_PUBLIC_SENTRY_DSNsentry-best-practices.mdotel-integration.mdsentry-server-config.tssentry-client-config.tsinstrumentation.tslogger.tserror-boundary.tsxerror-page.tsxglobal-error.tsx