Features

Exceptions

Errors your app runs into, with stack traces and your source lines, grouped into issues and linked to the request they happened in.

PeekInside records the errors your app runs into, next to the requests. Each exception has its stack trace (with the source lines of your own code), its cause chain, the request it happened in and details of the process. Exceptions with the same type and the same top frames of your code are grouped into one issue, so a fix that moves a line doesn't split it.

What is recorded automatically#

Where Recorded Handled?
Express 4 and 5 Errors thrown by handlers, passed to next(err), or (Express 5) rejected by async handlers Yes when an error middleware (err, req, res, next) receives it; no when it reaches Express's default handler, which answers 500
Koa Errors thrown by middleware after PeekInside's No: Koa's default handler answers them (attach PeekInside before your own error-handling middleware)
Fastify Errors from route handlers and hooks (onError) Yes when the app set its own error handler with setErrorHandler()
Crashes Uncaught exceptions and unhandled promise rejections No

Errors with a 4xx status, such as createError(404) or Koa's ctx.throw(400), are how apps answer bad requests, so they aren't recorded automatically. Nothing about how your app answers changes: same status codes, same bodies, same logging.

Crashes#

An uncaught exception or unhandled rejection still crashes your app exactly as before, with the same output and exit code: PeekInside only watches (with Node's uncaughtExceptionMonitor) and never handles them. It doesn't add an unhandledRejection listener either, since that alone would stop Node from crashing; when your app adds its own, PeekInside records the rejections your app now survives.

A crashing process can't wait for the next batch, so the crash, and the request it happened in, are saved before the process exits. With the local dashboard they are written to ~/.peekinside/spool, which the dashboard picks up within a second, or when it next starts. With PeekInside Cloud they are encrypted and sent right away (the process waits up to 3 seconds); if PeekInside Cloud can't be reached, the encrypted batch is saved and sent when the app starts again.

Reporting errors yourself#

try {
  await chargeCard(order);
} catch (error) {
  PeekInside.report(error, { tags: { provider: 'stripe' }, extra: { orderId: order.id } });
  return res.status(502).json({ error: 'payment_failed' });
}

peekInside.report(error, options) records any error (or thrown value) and returns its id, or null when nothing was recorded. PeekInside.report() does the same with the instance that tracks the current request (or the most recently created one). Options:

Option Default Description
request the current request The request the error relates to
tags {} Up to 32 short labels, such as { provider: 'stripe' }
extra none Any JSON-safe data; past 16 KB only a preview is kept
handled true Whether your app handled the error

Linked to requests#

During a request, PeekInside knows which request your code runs for, through timers, promises and callbacks (with AsyncLocalStorage). Every exception carries the id of its request and a snapshot of it (method, URL, headers, query, the first 8 KB of the body), and every request lists the exceptions that happened while it was handled. Exceptions thrown outside requests (at startup, in background jobs) are recorded without one.

Source context and privacy#

For the top five frames of your own code (files in your project folder, outside node_modules), the line and the five lines on each side are read from disk and included. Turn this off with sourceContext: false; turn automatic recording off with captureExceptions: false (report() keeps working).

With PeekInside Cloud, exceptions are encrypted like requests: messages, stack traces, source lines, request snapshots, tags and extra are sealed with your project's public key, and PeekInside Cloud only sees when an exception happened, its environment, whether it was handled or fatal, and the id of its request. Crashes saved to disk while PeekInside Cloud is unreachable are saved encrypted.

At most 50 exceptions a second are recorded (bursts of 100), so an app in trouble can't fill its memory with them; crashes are always recorded.