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

@22hbg/sentinel-node

v0.4.2

Published

Sentinel observability SDK for Node.js — traces, metrics and logs over OTLP/HTTP, powered by OpenTelemetry.

Readme

@22hbg/sentinel-node

Sentinel observability SDK for Node.js — a thin, opinionated wrapper over the OpenTelemetry Node SDK that ships traces, metrics and logs to a Sentinel server over OTLP/HTTP.

  • One-line setup, sensible defaults, zero-code --import mode
  • Automatic instrumentation (HTTP, Express, pg, Redis, …) with the noisy ones off
  • Structured logger with automatic trace correlation
  • captureException, custom spans, metric helpers
  • Never crashes your app: init/telemetry failures degrade to a warning + no-op

Requires Node.js >= 20. ESM-only.

Install

npm install @22hbg/sentinel-node        # or: pnpm add @22hbg/sentinel-node

Inside this monorepo:

pnpm add @22hbg/sentinel-node --filter <your-app>   # resolves via workspace:*

Quickstart

import { startSentinel, logger, withSpan, metrics } from "@22hbg/sentinel-node";

startSentinel({
  token: "sat_...",                          // or env SENTINEL_TOKEN
  endpoint: "https://sentinel.example.com",  // or env SENTINEL_ENDPOINT
  service: "checkout-api",                   // or env SENTINEL_SERVICE
  environment: "production",                 // optional
  version: "1.4.2",                          // optional
});

logger.info("order placed", { orderId: 42 });

Call startSentinel() as early as possible (before importing the frameworks you want auto-instrumented) — or use the zero-code form below.

CommonJS

The package is dual (ESM and CommonJS), so require() works too:

const { startSentinel, logger } = require("@22hbg/sentinel-node");
startSentinel({ service: "checkout-api" }); // reads SENTINEL_TOKEN / SENTINEL_ENDPOINT
logger.info("order placed", { orderId: 42 });

The one exception is the zero-code preload @22hbg/sentinel-node/register, which is ESM-only (it uses an ESM loader hook). It still works for a CommonJS app — the preload runs in ESM and your CJS code require()s the logger normally; both share the same provider:

SENTINEL_TOKEN=sat_… SENTINEL_ENDPOINT=https://sentinel.example.com \
SENTINEL_SERVICE=checkout-api node --import @22hbg/sentinel-node/register app.cjs

Zero-code setup

No source changes required — bootstrap via Node's --import flag:

SENTINEL_TOKEN=sat_... \
SENTINEL_ENDPOINT=https://sentinel.example.com \
SENTINEL_SERVICE=checkout-api \
node --import @22hbg/sentinel-node/register app.js

Configuration

Precedence: explicit startSentinel() options > SENTINEL_* env vars > standard OTEL_* env vars > defaults.

| Env var | Option | Default | Description | | --- | --- | --- | --- | | SENTINEL_TOKEN | token | — | Agent token (sat_...). Optional when exporting to a local host agent; otherwise a warning is logged if missing. | | SENTINEL_ENDPOINT | endpoint | http://localhost:4318 | Base URL of the Sentinel server or host agent. The SDK appends /v1/traces, /v1/metrics, /v1/logs. Falls back to OTEL_EXPORTER_OTLP_ENDPOINT. | | SENTINEL_SERVICE | service | unknown_service:node | Service name (service.name). Falls back to OTEL_SERVICE_NAME. | | SENTINEL_ENVIRONMENT | environment | — | Deployment environment (deployment.environment), e.g. production. | | SENTINEL_VERSION | version | — | Service version (service.version). | | — | instrumentations | "auto" | "auto" (full auto-instrumentation, fs/dns/net disabled), "http-only", or an array of your own instrumentations ([] disables). | | SENTINEL_STARTUP_LOG | startupLog | true | Emit an INFO log the moment the SDK connects (flushed immediately) so the service's monitor shows activity right away. Set to false to disable. | | SENTINEL_DEBUG | debug | false | Verbose SDK diagnostics on the console. Export errors (e.g. a rejected token → 401 Invalid or unauthorized agent token) are printed regardless, so you can tell whether telemetry reaches the API. |

Metrics are exported every 15 seconds; traces and logs are batched.

Just connected but the monitor shows no logs? That's expected until your app calls logger.* — auto-instrumentation only produces traces. On startup the SDK emits one Sentinel SDK connected … log so you can confirm the pipeline immediately; if you don't even see that, check the console for a [sentinel] … line and any 401/export error (usually a wrong token or endpoint).

Logs

import { logger } from "@22hbg/sentinel-node";

logger.debug("cache miss", { key: "user:42" });
logger.info("order placed", { orderId: 42 });
logger.warn("retrying payment", { attempt: 2 });
logger.error("checkout failed", { err });   // Error values are expanded to
                                            // err.message / err.stack attributes

Log records emitted inside a span are automatically correlated with the active trace (trace/span IDs are attached).

Exceptions

import { captureException } from "@22hbg/sentinel-node";

try {
  await chargeCard(order);
} catch (err) {
  captureException(err, { orderId: order.id });
  throw err;
}

Emits an ERROR log with exception.type / exception.message / exception.stacktrace, and — when inside an active span — records the exception on the span and marks it as errored.

Custom spans

import { withSpan } from "@22hbg/sentinel-node";

const receipt = await withSpan("charge-card", async (span) => {
  span.setAttribute("payment.provider", "stripe");
  return chargeCard(order);
}, { orderId: order.id });

The span is ended automatically; thrown errors are recorded and re-thrown with the span status set to ERROR. Works with sync and async functions.

Metrics

import { metrics } from "@22hbg/sentinel-node";

const orders = metrics.counter("orders_placed");
orders.add(1, { plan: "pro" });

const latency = metrics.histogram("checkout_duration_ms", { unit: "ms" });
latency.record(183);

const queue = metrics.gauge("queue_depth");
queue.record(7);

The helpers return standard OpenTelemetry instruments. Create them after startSentinel() so they bind to the initialized meter provider.

Shutdown

import { shutdownSentinel } from "@22hbg/sentinel-node";

await shutdownSentinel(); // flush all pending telemetry

The SDK also hooks SIGTERM / SIGINT / beforeExit to flush automatically (it never calls process.exit itself). Call shutdownSentinel() manually before an explicit process.exit().

Where to point it

Through the Sentinel host agent (recommended on monitored hosts). The agent runs a local OTLP receiver — no token needed:

SENTINEL_ENDPOINT=http://localhost:4318 node --import @22hbg/sentinel-node/register app.js

Directly to the Sentinel server. Use your Sentinel URL and an agent token (Sentinel UI → Infrastructure → hostAgent token):

SENTINEL_ENDPOINT=https://sentinel.example.com \
SENTINEL_TOKEN=sat_... \
node --import @22hbg/sentinel-node/register app.js

Example

See examples/basic.mjs:

pnpm --filter @22hbg/sentinel-node build
SENTINEL_ENDPOINT=http://localhost:4318 node clients/sdk-node/examples/basic.mjs

License

MIT