BugsRadar for Node.js
One npm package for servers, workers and command-line tools on Node.js 18 and later: uncaught errors, direct calls, Express, winston and pino. ESM and CommonJS, with TypeScript types.
You need a BugsRadar project with a channel and the project's API key first: see Get started.
The API key is secret: this package is for Node.js on your servers. Never put the key in browser code — React, Angular, Vue, Next.js client components — in an Electron app you ship to others, or in a public repository: anyone can take the key out of them. For browser apps, public keys are on the way. Where the key may go
Install the package
npm install bugsradar
Create the client
Create one client for the whole process:
import { BugsRadar } from 'bugsradar';
export const bugsRadar = new BugsRadar({
apiKey: process.env.BUGSRADAR_KEY,
environment: process.env.NODE_ENV, // optional
});
With CommonJS: const { BugsRadar } = require('bugsradar');. Keep the key out of the source, for example in an environment variable. The key is required: an empty one throws when the client is created.
Uncaught errors
The client reports uncaught exceptions by itself. Unhandled promise rejections become uncaught exceptions in Node.js 15 and later, so they are reported the same way. BugsRadar waits up to shutdownTimeout for the report to leave, then the process exits with code 1, as it would without BugsRadar. If your application has its own uncaughtException handler, the exit is left to it.
To turn this off, pass captureUncaught: false.
Direct calls
Report exceptions or your own events:
import { bugsRadar } from './bugsradar.js';
try {
await createOrder(orderId);
} catch (error) {
bugsRadar.sendException(error, { module: 'Orders' });
// or the full event
bugsRadar.send({
exception: error,
messageTemplate: 'Order {orderId} failed',
message: `Order ${orderId} failed`,
properties: { orderId },
module: 'Orders',
});
}
send and sendException queue the event and return at once, so reporting an error never adds network time to your own code. Nothing throws: delivery problems are written to the console as warnings.
BugsRadar groups repeats of an error by the exception type and the top frames of the stack, or by the message template. To group by your own key, set fingerprint on the event.
Express
Add the error handler after your routes:
import express from 'express';
import { expressErrorHandler } from 'bugsradar/express';
import { bugsRadar } from './bugsradar.js';
const app = express();
// ... your routes
app.use(expressErrorHandler(bugsRadar));
It reports the error with the method and the path of the request, then passes it on with next(error), so your own error handler still answers the request. Errors with a status below 500, such as a 404 from http-errors, are passed on without a report.
winston
Add the transport next to the ones you already have:
import winston from 'winston';
import { BugsRadarTransport } from 'bugsradar/winston';
import { bugsRadar } from './bugsradar.js';
export const logger = winston.createLogger({
transports: [
new winston.transports.Console(),
new BugsRadarTransport({ client: bugsRadar, level: 'error' }),
],
});
logger.error('Order failed', { orderId, error });
The transport takes error and above. An Error in the error or err field travels as the exception, with its stack; the other fields become the event's properties.
pino
pino runs transports in a worker thread, so this one gets the key in its options rather than the client:
import pino from 'pino';
export const logger = pino({
transport: {
targets: [
{ target: 'pino/file', options: { destination: 1 } },
{ target: 'bugsradar/pino', level: 'error', options: { apiKey: process.env.BUGSRADAR_KEY } },
],
},
});
logger.error({ err: error, orderId }, 'Order failed');
The transport sends error and fatal entries; to send warnings too, add level: 'warn' to its options. The error in err travels as the exception, with its stack; the other fields become the event's properties.
Before the process exits
Command-line tools, scheduled jobs and serverless functions often exit right after their work. Wait for the queued reports first:
await bugsRadar.flush(); // waits up to shutdownTimeout
How events travel
- Events go to an in-process queue and are sent in the background; your code never waits for the network.
- Repeats of the same error within
repeatInterval(5 seconds) are folded into one request with a count. A crash loop costs one request every few seconds, not thousands per second. - The same
Errorobject seen twice — by Express and by winston, say — is sent once. - On
429the client waits as long as the server asks; on5xxand network failures it retries three times.
Configuration
| Option | Default | Meaning |
|---|---|---|
apiKey | — | Project API key from app.bugsradar.com. Required. |
environment | — | Environment name for events (Production, Staging). |
host | os.hostname() | Host for events. |
appVersion | — | Version of your application. Not used for grouping. |
captureUncaught | true | Report uncaught exceptions and unhandled rejections. |
repeatInterval | 5000 ms | Repeats within this interval travel as one request. |
queueCapacity | 1000 | Queued events beyond this are dropped with a warning. |
shutdownTimeout | 5000 ms | How long flush() and an uncaught exception wait for the queue. |
requestTimeout | 15000 ms | One request to the server. |
apiUrl | api.bugsradar.com | Change it only for a self-hosted BugsRadar. |
Browser apps
This package is for Node.js. Code that runs in the browser — React, Angular, Vue — is public, and so would be a key inside it: anyone could take it and fill your channels. Browser apps need a key that is safe to publish: public keys are on the way.
Something doesn't arrive? Write to support@bistriy.com and include the warnings the package wrote to the console.