BugsRadar

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

Terminal
npm install bugsradar

Create the client

Create one client for the whole process:

bugsradar.js
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:

orders.js
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:

app.js
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:

logger.js
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:

logger.js
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:

job.js
await bugsRadar.flush(); // waits up to shutdownTimeout

How events travel

Configuration

OptionDefaultMeaning
apiKey—Project API key from app.bugsradar.com. Required.
environment—Environment name for events (Production, Staging).
hostos.hostname()Host for events.
appVersion—Version of your application. Not used for grouping.
captureUncaughttrueReport uncaught exceptions and unhandled rejections.
repeatInterval5000 msRepeats within this interval travel as one request.
queueCapacity1000Queued events beyond this are dropped with a warning.
shutdownTimeout5000 msHow long flush() and an uncaught exception wait for the queue.
requestTimeout15000 msOne request to the server.
apiUrlapi.bugsradar.comChange 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.