Next.js SDK Logging
Full-stack TypeScript logging for Next.js applications with App Router and Pages Router support.
Last updated: 27 Oct 2026
Full-stack TypeScript logging for Next.js applications with App Router and Pages Router support.
Installation#
Add the Abrova registry to .npmrc, then install (see Next.js SDK):
# .npmrc @abrova-trace:registry=https://center.abrova.ir/api/packages/abrova/npm/
npm install @abrova-trace/nextjs-sdk
Initialize Logger#
Create lib/logger.ts:
import { LogService } from '@abrova-trace/nextjs-sdk';
export const logger = new LogService({
apiKey: process.env.ABROVA_TRACE_API_KEY!,
sourceId: 'nextjs-app',
sourceName: 'My Next.js App',
platform: 'nextjs',
environment: process.env.NODE_ENV,
});App Router (Next.js 13+)#
// app/api/users/route.ts
import { NextResponse } from 'next/server';
import { logger } from '@/lib/logger';
export async function GET(request: Request) {
logger.log('Fetching users', 'info');
try {
const users = await db.users.findMany();
logger.log('Users fetched', 'info', { count: users.length });
return NextResponse.json(users);
} catch (error) {
logger.log('Failed to fetch users', 'error', {
error: error instanceof Error ? error.message : 'Unknown',
});
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
}
}Pages Router (API Routes)#
// pages/api/orders.ts
import { logger } from '@/lib/logger';
export default async function handler(req, res) {
logger.log('Order request received', 'info', {
method: req.method,
path: req.url,
});
try {
const order = await createOrder(req.body);
logger.log('Order created', 'info', { orderId: order.id });
res.json(order);
} catch (error) {
logger.log('Order creation failed', 'error', {
error: error.message,
});
res.status(500).json({ error: 'Failed to create order' });
}
}Log Levels#
// LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'
logger.log('Detailed trace info', 'trace');
logger.log('Debug information', 'debug');
logger.log('User action completed', 'info');
logger.log('Approaching rate limit', 'warn');
logger.log('Failed to save data', 'error');
logger.log('App crashed unexpectedly', 'fatal');Middleware Integration#
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { logger } from '@/lib/logger';
export function middleware(request: NextRequest) {
const start = Date.now();
logger.log('Request received', 'info', {
method: request.method,
path: request.nextUrl.pathname,
});
const response = NextResponse.next();
const duration = Date.now() - start;
logger.log('Request processed', 'info', {
path: request.nextUrl.pathname,
duration,
});
return response;
}
export const config = { matcher: '/api/:path*' };Client-Side Logging#
Two options. In the browser you can log straight through the SDK instance you already initialized, e.g.
AbrovaTrace.getInstance()?.info('Button clicked', { buttonId: 'submit-form' }). If you would rather validate or filter client logs on your own server first, send them through an API route as below. Logs are buffered (sent after 50 logs or 30 seconds by default) and are not sent automatically when the page closes, so call AbrovaTrace.getInstance()?.flushLogs() when a log must go out right away.Create a proxy route:
// app/api/log/route.ts
import { NextResponse } from 'next/server';
import { logger } from '@/lib/logger';
export async function POST(request: Request) {
const { message, level, metadata } = await request.json();
const validLevels = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];
const safeLevel = validLevels.includes(level) ? level : 'info';
logger.log(message, safeLevel, { ...metadata, source: 'client' });
return NextResponse.json({ success: true });
}Client component:
'use client';
async function logToServer(message: string, level: string, metadata?: object) {
await fetch('/api/log', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message, level, metadata }),
});
}
// Usage
logToServer('Button clicked', 'info', { buttonId: 'submit-form' });Configuration#
| Option | Type | Required | Description |
|---|---|---|---|
| apiKey | string | Yes | Your project API key |
| sourceId | string | No | Log source identifier. With it, logs are sent in batches (/api/logs/ingest/batch); without it, each buffered log is sent in its own request |
| sourceName | string | No | Display name for this source |
| platform | string | Yes | Platform identifier, e.g. "nextjs" (no default) |
| environment | string | Yes | Environment name, e.g. "production" (no default) |
| release | string | No | App version attached to each log |
| batchSize | number | No | Flush at this buffer size (default: 50) |
| flushIntervalMs | number | No | Max ms before flush (default: 30000) |
| maxBufferSize | number | No | Drop oldest when exceeded (default: 1000) |
| debug | boolean | No | Print SDK debug output to the console (default: false) |
| apiUrl | string | No | Base URL of the Trace API (default: "https://trace.abrova.ir"). Set it only for self-hosted |
Best Practices#
Centralize Logger
Create a single logger instance in lib/logger.ts and import it everywhere
Filter Client Logs
Use a proxy route when you want to validate or filter client logs before they reach Abrova Trace
Log API Routes
Add logging to all API routes for full request visibility
Add Request Context
Include method, path, and duration in request logs
Validate Client Logs
Sanitize and validate log level/message from client-side proxy
Use Middleware
Add middleware for automatic request/response logging on API routes
Was this page helpful?
Report a problem