Monitoring nextjs
Skill PIXARTSeu/Synapse/packages/codegraph/data/skill/monitoring-nextjs
Self-improving AI brain for Claude Code & Desktop — 28 MCP tools, 253 skills, collective memory, project tracking, work logs. One server, all your sessions share the same knowledge. Deploy on Coolify in 2 minutes.
npx -y skills add PIXARTSeu/Synapse --skill monitoring-nextjsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 8 stars8 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Monitoring and observability for Next.js — Sentry error tracking, structured logging with Pino, OpenTelemetry tracing, health checks, uptime monitoring, alerting. Use when adding error tracking, logging, performance monitoring, or alerting to a Next.js project.
SKILL.md
10.4 KB, as published. Nobody here has run it
Monitoring & Observability — Next.js
1. Sentry Setup
pnpm add @sentry/nextjs
npx @sentry/wizard@latest -i nextjs
// sentry.client.config.ts
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0,
replaysSessionSampleRate: 0.01, // 1% of sessions
replaysOnErrorSampleRate: 1.0, // 100% of errored sessions
integrations: [
Sentry.replayIntegration(),
Sentry.feedbackIntegration({ colorScheme: 'system' }),
],
})
// sentry.server.config.ts
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampleRate: 0.1,
profilesSampleRate: 0.1,
})
// sentry.edge.config.ts
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampleRate: 0.1,
})
// next.config.ts
import { withSentryConfig } from '@sentry/nextjs'
const config = { /* your config */ }
export default withSentryConfig(config, {
org: process.env.SENTRY_ORG,
project: process.env.SENTRY_PROJECT,
authToken: process.env.SENTRY_AUTH_TOKEN,
silent: true,
hideSourceMaps: true,
widenClientFileUpload: true,
tunnelRoute: '/monitoring', // proxy to bypass ad-blockers
})
Custom Error Boundary
// app/global-error.tsx
'use client'
import * as Sentry from '@sentry/nextjs'
import { useEffect } from 'react'
export default function GlobalError({ error, reset }: { error: Error; reset: () => void }) {
useEffect(() => {
Sentry.captureException(error)
}, [error])
return (
<html><body>
<div className="flex min-h-screen items-center justify-center">
<div className="text-center">
<h2 className="text-2xl font-bold">Something went wrong</h2>
<button onClick={reset} className="mt-4 rounded bg-primary px-4 py-2 text-primary-foreground">
Try again
</button>
</div>
</div>
</body></html>
)
}
Track User & Custom Events
// After login
import * as Sentry from '@sentry/nextjs'
Sentry.setUser({ id: user.id, email: user.email, username: user.name })
// Custom event with context
Sentry.captureMessage('User upgraded plan', {
level: 'info',
tags: { plan: 'pro' },
extra: { previousPlan: 'free' },
})
// Performance span
const transaction = Sentry.startSpan({ name: 'process-payment' }, () => {
// your logic
})
2. Structured Logging with Pino
pnpm add pino pino-pretty
// lib/logger.ts
import pino from 'pino'
const isDev = process.env.NODE_ENV === 'development'
export const logger = pino({
level: process.env.LOG_LEVEL || (isDev ? 'debug' : 'info'),
...(isDev && {
transport: {
target: 'pino-pretty',
options: { colorize: true, translateTime: 'HH:MM:ss', ignore: 'pid,hostname' },
},
}),
formatters: {
level: (label) => ({ level: label }),
},
base: {
env: process.env.NODE_ENV,
service: 'my-app',
},
})
// Child loggers for modules
export const dbLogger = logger.child({ module: 'database' })
export const authLogger = logger.child({ module: 'auth' })
export const apiLogger = logger.child({ module: 'api' })
Request Logging Middleware
// middleware.ts (or in API routes)
import { logger } from '@/lib/logger'
import { NextRequest, NextResponse } from 'next/server'
import { nanoid } from 'nanoid'
export function middleware(req: NextRequest) {
const requestId = nanoid(12)
const start = Date.now()
// Add request ID to response headers
const response = NextResponse.next()
response.headers.set('X-Request-Id', requestId)
// Log request
logger.info({
requestId,
method: req.method,
path: req.nextUrl.pathname,
userAgent: req.headers.get('user-agent'),
ip: req.headers.get('x-forwarded-for'),
}, 'Incoming request')
return response
}
Log Shipping to Axiom/Logtail
pnpm add @axiomhq/pino
// lib/logger.ts (production)
import pino from 'pino'
export const logger = pino({
level: 'info',
transport: process.env.NODE_ENV === 'production'
? {
target: '@axiomhq/pino',
options: {
dataset: process.env.AXIOM_DATASET,
token: process.env.AXIOM_TOKEN,
},
}
: {
target: 'pino-pretty',
options: { colorize: true },
},
})
3. OpenTelemetry
pnpm add @vercel/otel @opentelemetry/api
// instrumentation.ts (Next.js 15+ — root of project)
// This file is auto-loaded by Next.js via the instrumentation hook.
// Requires: pnpm add @vercel/otel @opentelemetry/api
import { registerOTel } from '@vercel/otel'
export function register() {
registerOTel({
serviceName: 'my-app',
// Optional: export to Honeycomb, Jaeger, etc.
// traceExporter: new OTLPTraceExporter({ url: '...' }),
})
}
// Custom spans
import { trace } from '@opentelemetry/api'
const tracer = trace.getTracer('my-app')
export async function processOrder(orderId: string) {
return tracer.startActiveSpan('process-order', async (span) => {
span.setAttribute('order.id', orderId)
try {
await validateOrder(orderId)
await chargePayment(orderId)
await sendConfirmation(orderId)
span.setStatus({ code: 1 }) // OK
} catch (error) {
span.setStatus({ code: 2, message: String(error) }) // ERROR
throw error
} finally {
span.end()
}
})
}
4. Health Checks
// app/api/health/route.ts (Liveness)
export async function GET() {
return Response.json({
status: 'ok',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
version: process.env.APP_VERSION || 'unknown',
})
}
// app/api/ready/route.ts (Readiness)
export async function GET() {
const checks: Record<string, 'ok' | 'fail'> = {}
// Check database
try {
await db.$queryRaw`SELECT 1`
checks.database = 'ok'
} catch {
checks.database = 'fail'
}
// Check Redis
try {
await redis.ping()
checks.redis = 'ok'
} catch {
checks.redis = 'fail'
}
// Check external API
try {
const res = await fetch('https://api.stripe.com/v1', {
method: 'HEAD',
signal: AbortSignal.timeout(3000),
})
checks.stripe = res.ok ? 'ok' : 'fail'
} catch {
checks.stripe = 'fail'
}
const allHealthy = Object.values(checks).every((v) => v === 'ok')
return Response.json(
{ status: allHealthy ? 'ready' : 'degraded', checks },
{ status: allHealthy ? 200 : 503 },
)
}
# Docker HEALTHCHECK
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD curl -f http://localhost:3000/api/health || exit 1
5. Error Handling Architecture
// lib/errors.ts — application error classes
export class AppError extends Error {
constructor(
message: string,
public code: string,
public statusCode: number = 500,
public isOperational = true,
) {
super(message)
this.name = 'AppError'
}
}
export class NotFoundError extends AppError {
constructor(resource: string, id: string) {
super(`${resource} not found: ${id}`, 'NOT_FOUND', 404)
}
}
export class ValidationError extends AppError {
constructor(message: string) {
super(message, 'VALIDATION_ERROR', 400)
}
}
// lib/api-handler.ts — error middleware for API routes
import { logger } from '@/lib/logger'
import * as Sentry from '@sentry/nextjs'
import { AppError } from '@/lib/errors'
import { NextResponse } from 'next/server'
export function withErrorHandler(
handler: (req: Request, ctx: any) => Promise<Response>
) {
return async (req: Request, ctx: any) => {
try {
return await handler(req, ctx)
} catch (error) {
// Known operational errors
if (error instanceof AppError && error.isOperational) {
logger.warn({ err: error, code: error.code }, error.message)
return NextResponse.json(
{ error: error.message, code: error.code },
{ status: error.statusCode },
)
}
// Unknown/programmer errors — log + report
logger.error({ err: error }, 'Unhandled error')
Sentry.captureException(error)
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 },
)
}
}
}
// Usage
export const GET = withErrorHandler(async (req) => {
const data = await fetchData()
if (!data) throw new NotFoundError('Data', 'latest')
return NextResponse.json(data)
})
6. Alerting
Slack Webhook for Critical Errors
// lib/alerts.ts
export async function alertSlack(message: string, level: 'warn' | 'error' | 'critical') {
const emoji = { warn: '⚠️', error: '🔴', critical: '🚨' }
await fetch(process.env.SLACK_WEBHOOK_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: `${emoji[level]} *[${level.toUpperCase()}]* ${message}`,
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `${emoji[level]} *[${level.toUpperCase()}]* ${message}\n\n*Service:* ${process.env.APP_NAME}\n*Environment:* ${process.env.NODE_ENV}\n*Time:* ${new Date().toISOString()}`,
},
},
],
}),
})
}
Sentry Alert Rules
Recommended alert rules in Sentry dashboard:
1. Spike detection — alert when error count > 2x normal in 5 min
2. New issue — alert on first occurrence of any new error
3. Regression — alert when resolved issue reappears
4. Performance — alert when p95 response time > 2s
5. Error budget — alert when error rate > 1% in 1 hour
Quick Setup Checklist
□ Sentry: install, configure client/server/edge, enable source maps
□ Logger: Pino with structured output, ship to Axiom/Logtail in prod
□ Health: /api/health (liveness) + /api/ready (readiness with DB check)
□ Error classes: AppError hierarchy for operational vs programmer errors
□ Error handler: withErrorHandler wrapper for all API routes
□ Alerting: Slack webhook for critical, Sentry for everything
□ OpenTelemetry: instrumentation.ts for tracing
□ Docker: HEALTHCHECK directive