@22hbg/sentinel-node
v0.4.2
Published
Sentinel observability SDK for Node.js — traces, metrics and logs over OTLP/HTTP, powered by OpenTelemetry.
Maintainers
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
--importmode - 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-nodeInside 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.cjsZero-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.jsConfiguration
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 oneSentinel 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 any401/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 attributesLog 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 telemetryThe 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.jsDirectly to the Sentinel server. Use your Sentinel URL and an agent token (Sentinel UI → Infrastructure → host → Agent token):
SENTINEL_ENDPOINT=https://sentinel.example.com \
SENTINEL_TOKEN=sat_... \
node --import @22hbg/sentinel-node/register app.jsExample
See examples/basic.mjs:
pnpm --filter @22hbg/sentinel-node build
SENTINEL_ENDPOINT=http://localhost:4318 node clients/sdk-node/examples/basic.mjsLicense
MIT
