npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@arguslog/sdk-node

v1.0.2

Published

Arguslog Node.js SDK — error tracking for server-side Node apps

Readme

@arguslog/sdk-node

npm version license

Node.js SDK for Arguslog — a multi-tenant error tracking platform. Captures unhandled exceptions, unhandled promise rejections, and manually-reported errors from any Node 18.18+ app, then ships them to the Arguslog ingest endpoint where they're fingerprinted, stored, and surfaced on the dashboard.

Ships ESM only. Built on @arguslog/sdk-core. The only runtime dep is sdk-core itself. Express integration ships under the /express subpath and is a peer-dep — opt in by installing express alongside.

Install

pnpm add @arguslog/sdk-node
# or
npm install @arguslog/sdk-node
# or
yarn add @arguslog/sdk-node

Quick start

Initialize once at the very top of your entry file — before anything else requires a module that might throw on load. The SDK is a no-op until init runs.

import { init } from '@arguslog/sdk-node';

init({
  dsn: 'arguslog://<key>@<host>/api/<projectId>',
  release: process.env.RELEASE ?? 'dev',
  environment: process.env.NODE_ENV,
  integrations: ['processHandlers', 'http'],
  sourcemaps: { enabled: true }, // resolves stack traces against your built .map files
});

After init, process.on('uncaughtException') and process.on('unhandledRejection') are captured automatically (when processHandlers is in integrations). Manual reporting is always available via captureException / captureMessage.

DSN format

arguslog://<publicKey>@<host>/api/<projectId>

Get yours from your Arguslog project settings page. The publicKey is project-scoped — it's intended to be safe to ship in compiled binaries, but on a server you can also load it from process.env like any other secret.

API

init(options): ArguslogClient

Configures and starts the SDK. Re-initializing tears down the previous handlers cleanly, so hot-reload during dev doesn't accumulate stale process listeners.

init({
  dsn: '…',
  release: '1.4.0',
  environment: 'production',
  sampleRate: 1.0,
  maxBreadcrumbs: 50,
  beforeSend: (event) => {
    if (event.message?.includes('SECRET')) return null; // drop
    return event;
  },
  scrubbing: { enabled: true, extraPatterns: [/cust_[a-z0-9]+/g] },
  integrations: ['processHandlers', 'http'],
  processHandlers: { exitOnUncaught: false }, // default keeps Node's "throw" behavior
  sourcemaps: { enabled: true },
});

| Option | Type | Default | Notes | | ----------------- | ------------------------------------------------- | ------------ | ---------------------------------------------------------------------- | | dsn | string | required | See above. | | release | string | none | Free-form version tag stamped on every event. | | environment | string | none | E.g. production, staging, dev. | | sampleRate | number 0–1 | 1.0 | Fraction of events kept. | | maxBreadcrumbs | number | 50 | Per-request ring-buffer size. | | beforeSend | (event) => event \| null \| Promise<...> | identity | Last-mile mutate / drop hook. | | scrubbing | { enabled?: boolean; extraPatterns?: RegExp[] } | enabled | PII redaction in messages and URLs. | | transport | { fetch?: typeof fetch; maxRetries?: number } | global fetch | Inject a custom fetch (testing) or bump retry budget. | | integrations | ('processHandlers' \| 'http')[] | none | See Integrations below. | | processHandlers | { exitOnUncaught?: boolean } | {} | If true, process.exit(1) after capturing an uncaughtException. | | sourcemaps | { enabled?: boolean } | disabled | Calls process.setSourceMapsEnabled(true) so stacks show original TS. | | debug | boolean | false | Logs every send to console — never enable in production. |

captureException(error, hint?)

import { captureException } from '@arguslog/sdk-node';

try {
  await chargeCard(orderId);
} catch (err) {
  captureException(err, { level: 'error', tags: { feature: 'billing' } });
}

Non-Error values are wrapped synthetically. Returns the generated event id, or undefined if the SDK isn't initialized.

captureMessage(message, level?)

captureMessage('Worker idle for 5m', 'warning');

Scope mutation

setUser({ id: 'u-1234', email: '[email protected]' }); // email is auto-scrubbed
setTag('region', 'eu-west');
setContext('order', { id: 42, total_cents: 9900 });
addBreadcrumb({ category: 'queue', message: 'job dequeued', level: 'info', data: { jobId } });

By default, scope is per-request when you use the Express middleware (or runWithRequestScope) — so concurrent requests don't bleed users into each other's events. Outside a request scope, mutations apply to the global fallback scope.

flush()

await flush();

Drains pending sends. Always call before the process exits in short-lived workloads (CLIs, cron jobs, AWS Lambda, Cloud Run requests) — Node will tear down the event loop before background sends complete otherwise.

Integrations

processHandlers

Captures uncaughtException and unhandledRejection. By default the SDK lets Node's normal "fatal exception → exit" behavior continue once the event is queued; set processHandlers.exitOnUncaught: false if you have a process supervisor that will restart you and you'd rather not double-emit.

init({
  dsn,
  integrations: ['processHandlers'],
  processHandlers: { exitOnUncaught: true },
});

http

Auto-instruments outbound http/https requests, dropping a breadcrumb per request with method, URL, and status code. Useful for "what was this service talking to right before it crashed?" debugging.

init({ dsn, integrations: ['http'] });

The integration patches http.request / https.request — there's no async-hooks wizardry and no work done if the integration isn't enabled.

Source maps

init({ dsn, sourcemaps: { enabled: true } });

Calls process.setSourceMapsEnabled(true) so Error.stack reports your original TypeScript filenames + line numbers instead of the bundled .js ones. Pair with uploading the maps to Arguslog so the dashboard can deminify production traces — see the @arguslog/cli README for the upload flow:

npx @arguslog/cli releases new "$VERSION" --project 42
npx @arguslog/cli sourcemaps upload dist/server.js.map \
  --project 42 --release "$RELEASE_ID" --name dist/server.js

Express

The Express middleware lives at @arguslog/sdk-node/express. It uses AsyncLocalStorage for per-request scope isolation, so concurrent requests don't bleed users into each other's breadcrumbs/tags.

import express from 'express';
import { init } from '@arguslog/sdk-node';
import { requestHandler, errorHandler } from '@arguslog/sdk-node/express';

init({
  dsn: process.env.ARGUSLOG_DSN!,
  integrations: ['processHandlers', 'http'],
  release: process.env.RELEASE,
});

const app = express();

// First — opens an isolated scope for every request.
app.use(requestHandler());

app.use(express.json());
app.use('/api', apiRoutes);

// Last — captures anything that propagates out of a route or middleware.
app.use(errorHandler());

app.listen(3000);

Inside a route, scope mutations are request-scoped:

app.get('/users/:id', async (req, res) => {
  setUser({ id: req.params.id }); // visible only on this request's events
  setTag('endpoint', 'GET /users/:id');
  res.json(await loadUser(req.params.id));
});

requestHandler() also drops a breadcrumb per request with method + path so failed requests carry the route they came from.

Custom request scopes (queues, gRPC, …)

For non-Express workloads, wrap each unit of work in runWithRequestScope:

import { runWithRequestScope, setTag, captureException } from '@arguslog/sdk-node';

queue.process(async (job) => {
  await runWithRequestScope(async () => {
    setTag('job', job.name);
    setTag('jobId', String(job.id));
    try {
      await job.run();
    } catch (err) {
      captureException(err);
      throw err;
    }
  });
});

Each invocation gets its own forked scope; tags from one job don't leak into the next.

AWS Lambda / serverless

The recipe is the same except flush() becomes mandatory — Lambda freezes the runtime the moment your handler returns, which strands any in-flight sends.

import { init, captureException, flush } from '@arguslog/sdk-node';

init({ dsn: process.env.ARGUSLOG_DSN!, release: process.env.AWS_LAMBDA_FUNCTION_VERSION });

export const handler = async (event) => {
  try {
    return await businessLogic(event);
  } catch (err) {
    captureException(err);
    throw err;
  } finally {
    await flush(); // critical
  }
};

Configuration tips

  • Capture early. Call init at the very top of your entry file. Errors thrown during module evaluation of files imported before init won't be captured.
  • One init per process. Re-initializing is safe (handlers are torn down and re-installed) but you generally don't need to.
  • debug: true is for development only. It logs every event to the console; in production it doubles your stderr volume.
  • Long-lived servers don't need flush() — the transport's background queue drains during normal request idleness. Short-lived processes do.

Troubleshooting

Events not appearing on the dashboard. Check release matches what you uploaded sourcemaps under — the dashboard groups by exact match. Also check that the DSN's host is reachable from your server (not just your laptop) — a corporate proxy or NAT can strand HTTPS to the ingest endpoint.

Cannot find module '@arguslog/sdk-node/express'. Express is a peer dep — install it: pnpm add express. Then make sure your bundler/runner supports the exports map in package.json (Node 18+ does natively).

Concurrent requests show each other's user/tags. You're mutating scope outside requestHandler(). Mount it as the first middleware in your Express stack, or wrap the work in runWithRequestScope.

Stack traces show bundled .js paths instead of .ts. You forgot sourcemaps: { enabled: true }, or your build isn't emitting .map files, or you're running a transpiled-on-startup loader (tsx/ts-node) that doesn't surface maps to V8. Switch to a build step that emits maps + init with sourcemaps.enabled.

Source

The full implementation lives in the arguslog monorepo at packages/sdk-node/. Issues and PRs welcome.