Node.js SDK
Server-side error tracking for Node.js applications with Express middleware, breadcrumbs, scoped context, and TypeScript support.
Comprehensive error monitoring for Node.js applications
Catches uncaught exceptions and unhandled promise rejections
Built-in middleware for Express.js request/error handling
Track events leading up to an error for better context
Temporarily set context for a block of code with withScope
Associate errors with user information
Filter and modify events with beforeSend, ignoredExceptions and ignoredPaths
Full TypeScript definitions included
Installation#
Packages come from Abrova Center. Two steps:
1. Add the Abrova registry to .npmrc in your project root (npm, yarn and pnpm all read it):
# .npmrc @abrova-trace:registry=https://center.abrova.ir/api/packages/abrova/npm/
2. Install the package:
npm install @abrova-trace/nodejs-sdk # or yarn add @abrova-trace/nodejs-sdk # or pnpm add @abrova-trace/nodejs-sdk
Quick Start#
const AbrovaTrace = require('@abrova-trace/nodejs-sdk');
// Initialize AbrovaTrace
AbrovaTrace.init({
apiKey: 'ab_live_your_api_key', // project API key
serverSecret: process.env.ABROVA_SERVER_SECRET, // ab_srv_... (required)
environment: 'production',
release: '1.0.0'
});
// Capture exceptions
try {
throw new Error('Something went wrong!');
} catch (error) {
AbrovaTrace.captureException(error);
}
// Capture messages
AbrovaTrace.captureMessage('User completed checkout');Capture Errors#
Capture Exceptions
AbrovaTrace.captureException(error, {
extra: {
userId: 123,
feature: 'checkout'
}
});Capture Messages
AbrovaTrace.captureMessage('Something happened', {
level: 'warning', // 'debug' | 'info' (default) | 'warning' | 'error'
extra: { context: 'additional info' },
tags: { feature: 'checkout' }
});Messages appear in the Console under Abrova Trace → Messages, with their level, platform, extra data and breadcrumbs. They never create an issue. 'warn' is sent as warning, 'fatal' as error and 'trace' as debug; anything else as info. Use messages for things your app reports on purpose ("checkout started", "sync finished"); for high-volume diagnostics use Logs.
Breadcrumbs#
Breadcrumbs track events leading up to an error, helping you understand what happened before the error occurred.
Manual Breadcrumbs
AbrovaTrace.addBreadcrumb({
message: 'User clicked checkout',
category: 'user-action',
level: 'info',
data: { cartTotal: 99.99 }
});Breadcrumb Helpers
const { Breadcrumb } = require('@abrova-trace/nodejs-sdk');
// HTTP request breadcrumb
AbrovaTrace.addBreadcrumb(Breadcrumb.http('POST', '/api/order', 200, 150));
// Database query breadcrumb
AbrovaTrace.addBreadcrumb(Breadcrumb.database('SELECT * FROM users', 25));
// User action breadcrumb
AbrovaTrace.addBreadcrumb(Breadcrumb.user('clicked_button', { buttonId: 'submit' }));User Context#
AbrovaTrace.setUser({
id: 123,
email: 'user@example.com',
username: 'john_doe'
});Scoped Context#
Use scoped context to set a user and extra values for one synchronous block of code. The user and extra values are restored when the callback returns; breadcrumbs added inside the block are kept.
AbrovaTrace.withScope((scope) => {
scope.setUser({ id: 456 });
scope.setExtra('operation', 'bulk_import');
scope.addBreadcrumb({ message: 'Starting import' });
// Errors captured here include this context
AbrovaTrace.captureException(new Error('Import failed'));
});
// Context is restored after the blockExpress.js Integration#
Built-in middleware for automatic request tracking and error handling in Express.js applications.
const express = require('express');
const AbrovaTrace = require('@abrova-trace/nodejs-sdk');
const app = express();
// Initialize
AbrovaTrace.init({
apiKey: 'ab_live_your_api_key',
serverSecret: process.env.ABROVA_SERVER_SECRET,
environment: process.env.NODE_ENV
});
// Add middleware
const middleware = AbrovaTrace.expressMiddleware();
app.use(middleware.requestHandler());
// Your routes
app.get('/api/users/:id', async (req, res) => {
// Your route logic
});
// Error handler (must be last)
app.use(middleware.errorHandler());
app.listen(3000);The error handler middleware must be added after all routes. Express requires error-handling middleware to be defined last. Call AbrovaTrace.init() before AbrovaTrace.expressMiddleware(): middleware created before init() does nothing.
Errors reported by errorHandler() include the request method, URL, path, matched route (for example /api/users/:id), query and route parameters, user agent, IP address and the response status (err.status / err.statusCode when it is 4xx or 5xx, otherwise 500). Request headers and the request body are never sent. Query and route parameters whose name looks sensitive (password, token, secret, auth, API key, session, cookie, signature, OTP, code) are sent as [REDACTED]. The same applies to the request address sent with errors and breadcrumbs: the values of sensitive query parameters in it are replaced with [REDACTED] (for example /reset?token=[REDACTED]&page=2), while parameter names and other values are kept (since 0.2.3).
Database Query Tracking#
const AbrovaTrace = require('@abrova-trace/nodejs-sdk');
async function executeQuery(sql, params) {
const startTime = Date.now();
try {
AbrovaTrace.addBreadcrumb({
message: 'Executing query',
category: 'database',
data: { sql: sql.substring(0, 100) }
});
const results = await db.query(sql, params);
AbrovaTrace.addBreadcrumb({
message: 'Query completed',
category: 'database',
data: { duration_ms: Date.now() - startTime }
});
return results;
} catch (error) {
AbrovaTrace.captureException(error, {
extra: { sql, duration_ms: Date.now() - startTime }
});
throw error;
}
}Error Filtering#
Use the beforeSend hook to filter or modify events before they are sent to AbrovaTrace. It runs for exceptions and for captureMessage() events; return null to drop one. To skip whole exception classes or request paths, use the ignoredExceptions and ignoredPaths options instead.
AbrovaTrace.init({
apiKey: 'ab_live_your_api_key',
serverSecret: process.env.ABROVA_SERVER_SECRET,
beforeSend(event) {
// Don't send network errors
if (event.message.includes('ECONNREFUSED')) {
return null;
}
// Add custom data (errors are AbrovaTraceError objects; messages from
// captureMessage() arrive as plain objects without setExtra)
if (typeof event.setExtra === 'function') {
event.setExtra('server_id', process.env.SERVER_ID);
}
return event;
}
});Graceful Shutdown#
Errors, messages, logs and performance spans are sent in the background. flush() sends everything that is still waiting, so call it before the process exits: before process.exit(), at the end of a serverless handler, and in your shutdown handlers.
process.on('SIGTERM', async () => {
console.log('Shutting down...');
const sent = await AbrovaTrace.flush(2000); // false if 2 seconds pass before everything is sent
await AbrovaTrace.close(); // Sends buffered logs and performance spans, then resets the SDK
process.exit(0);
});flush(timeout) takes a timeout in milliseconds (default: 5000) and returns a Promise<boolean>: true when sending finished within the timeout, false when the timeout passed first. It never rejects. close() also returns a Promise; it sends buffered logs and performance spans but does not wait for errors and messages that are still being sent, so call flush() first. After close(), call init() again before you use the SDK.
In a serverless function, flush before the handler returns:
exports.handler = async (event) => {
try {
return await processEvent(event);
} catch (error) {
AbrovaTrace.captureException(error);
throw error;
} finally {
await AbrovaTrace.flush();
}
};Source Maps#
If you're using TypeScript, bundlers (webpack, esbuild), or Babel, enable source maps for accurate stack traces:
node --enable-source-maps app.js
Or programmatically in your app:
process.setSourceMapsEnabled(true);
Logging#
Structured server-side logging, batched with exponential backoff and zero dependencies. Logs go to Abrova Trace → Logs and are separate from captureMessage() (Messages). After init(), enable logging once and log from anywhere:
AbrovaTrace.enableLogging({ sourceId: 'api-server' });
AbrovaTrace.info('Server started on port 3000');
AbrovaTrace.warn('Database connection slow', { latency: 2500 });
AbrovaTrace.logError('Failed to process payment', { orderId: '12345' });See Node.js SDK Logging for the full pipeline — log levels, Express integration, batching, and graceful shutdown.
Configuration Options#
AbrovaTrace.init({
apiKey: 'ab_live_your_api_key', // Required
serverSecret: 'ab_srv_your_secret', // Required
environment: 'production', // Default: NODE_ENV or 'development'
release: '1.0.0', // Default: npm_package_version or '1.0.0'
enabled: true, // Default: true
debug: false, // Default: false
timeout: 5000, // Default: 5000ms
captureUncaughtExceptions: true, // Default: true
captureUnhandledRejections: true, // Default: true
maxBreadcrumbs: 50, // Default: 50 (max 100)
sampleRate: 1.0, // Default: 1.0 (captureException and captureMessage)
ignoredExceptions: ['ValidationError'], // Error class, error.name, or RegExp
ignoredPaths: ['/health*'], // Express paths not reported
beforeSend: (event) => event, // Filter/modify events
});| Option | Type | Required | Description |
|---|---|---|---|
| apiKey | string | Yes | Your project API key (ab_live_xxx) |
| serverSecret | string | Yes | Your server secret (ab_srv_xxx); keep it on the server |
| environment | string | No | Environment name (default: NODE_ENV or "development") |
| release | string | No | App version (default: npm_package_version or "1.0.0") |
| enabled | boolean | No | Enable/disable tracking (default: true) |
| debug | boolean | No | Enable debug logging (default: false) |
| timeout | number | No | HTTP timeout in milliseconds, 1000-30000 (default: 5000) |
| captureUncaughtExceptions | boolean | No | Auto-capture uncaught exceptions (default: true) |
| captureUnhandledRejections | boolean | No | Auto-capture unhandled rejections (default: true) |
| maxBreadcrumbs | number | No | Max breadcrumbs to keep, up to 100 (default: 50). The 10 most recent are sent with each event |
| sampleRate | number | No | Fraction of captureException() and captureMessage() events sent, 0.0-1.0 (default: 1.0) |
| ignoredExceptions | array | No | Exceptions that captureException() and the Express error handler do not report: an error class (matched with instanceof), a string equal to error.name, or a RegExp tested against error.name. Uncaught exceptions and unhandled rejections are always reported |
| ignoredPaths | array | No | Request paths the Express middleware skips: glob, exact path, or RegExp |
| beforeSend | function | No | Hook to filter/modify errors and messages before sending; return null to drop |
SDK Stats#
const stats = AbrovaTrace.getStats();
console.log(stats);
// {
// isEnabled: true,
// breadcrumbCount: 5,
// rateLimiter: { totalErrorsInWindow: 3, uniqueErrorsInWindow: 2, totalLimit: 100, errorLimit: 10, windowMs: 60000 },
// config: { environment: 'production', release: '1.0.0', apiKey: 'ab_live_abc1234...' }
// }TypeScript Support#
The SDK includes full TypeScript definitions. Import types as needed:
import AbrovaTrace, {
AbrovaTraceInitOptions,
AbrovaTraceError,
Breadcrumb,
BreadcrumbOptions,
UserContext
} from '@abrova-trace/nodejs-sdk';Requirements#
- Node.js — >= 14.0.0
- Express (optional) — >= 4.0.0
API Reference#
AbrovaTrace
init(config)— Initialize SDKcaptureException(error, options?)— Capture an errorcaptureMessage(message, options?)— Send a message to Abrova Trace → Messages (options:level,extra,tags)addBreadcrumb(breadcrumb)— Add a breadcrumbsetUser(user)— Set user contextsetRequestContext(context)— Set request context attached to captured eventswithScope(callback)— Run code with isolated scopeexpressMiddleware()— Get Express.js middlewareflush(timeout?)— Send pending errors, messages, logs and performance spans;timeoutin milliseconds (default: 5000). ReturnsPromise<boolean>:falseif the timeout passes firstclose()— Flush logs and performance spans, then clean up (returns a Promise)getStats()— Get SDK statisticsenableLogging(options?),log(),trace(),logDebug(),info(),warn(),logError(),fatal(),flushLogs()— Logging (see Node.js SDK Logging)trackOperation(name, fn, options?),reportPerformanceSpan(span),reportPerformanceSpanBatch(spans),flushPerformance()— Performance spans
Breadcrumb Helpers
Breadcrumb.http(method, url, status?, duration?)— HTTP request breadcrumbBreadcrumb.database(query, duration, error?)— Database query breadcrumbBreadcrumb.user(action, data?)— User action breadcrumbBreadcrumb.console(level, message, ...args)— Console output breadcrumbBreadcrumb.navigation(from, to, method?)— Navigation breadcrumbBreadcrumb.custom(message, category, data?)— Breadcrumb with your own category
Express Middleware
requestHandler()— Returns request tracking middlewareerrorHandler()— Returns error handling middlewareuserMiddleware()— Sets user context fromreq.user(id, email, username)transactionMiddleware(name)— Adds start and completion breadcrumbs (duration, status) for a named route
Complete Example#
const express = require('express');
const AbrovaTrace = require('@abrova-trace/nodejs-sdk');
const { Breadcrumb } = require('@abrova-trace/nodejs-sdk');
// Initialize AbrovaTrace
AbrovaTrace.init({
apiKey: 'ab_live_your_api_key',
serverSecret: process.env.ABROVA_SERVER_SECRET,
environment: process.env.NODE_ENV || 'development',
release: '1.0.0',
captureUncaughtExceptions: true,
captureUnhandledRejections: true,
maxBreadcrumbs: 50,
debug: process.env.NODE_ENV === 'development',
});
const app = express();
// Add AbrovaTrace middleware
const middleware = AbrovaTrace.expressMiddleware();
app.use(middleware.requestHandler());
app.use(express.json());
// Set user context from auth
app.use((req, res, next) => {
if (req.user) {
AbrovaTrace.setUser({
id: req.user.id,
email: req.user.email,
});
}
next();
});
app.get('/api/users/:id', async (req, res) => {
AbrovaTrace.addBreadcrumb(Breadcrumb.user('view_user', {
userId: req.params.id,
}));
try {
const user = await db.query('SELECT * FROM users WHERE id = ?', [req.params.id]);
AbrovaTrace.addBreadcrumb(Breadcrumb.database('SELECT * FROM users', 15));
res.json(user);
} catch (error) {
AbrovaTrace.captureException(error, {
extra: { userId: req.params.id },
});
res.status(500).json({ error: 'Internal Server Error' });
}
});
// Error handler (must be last)
app.use(middleware.errorHandler());
// Graceful shutdown
process.on('SIGTERM', async () => {
await AbrovaTrace.flush(2000);
await AbrovaTrace.close();
process.exit(0);
});
app.listen(3000, () => console.log('Server running on port 3000'));Best Practices#
Initialize AbrovaTrace at the top of your application entry point to catch all errors
Add the request handler first and error handler last for comprehensive Express.js tracking
Associate errors with user information for easier debugging
Use withScope to set temporary context for a synchronous block; the SDK context is process-wide, so it is restored when the callback returns
Track important operations (DB queries, HTTP calls, user actions) as breadcrumbs
Await flush() and close() on SIGTERM/SIGINT so pending errors, logs and spans are sent
Use --enable-source-maps for accurate stack traces in TypeScript/bundled apps
Filter out noisy errors and enrich error data with custom context