@julianm-lrj/node-instrumentation
v0.5.0
Published
Production-focused OpenTelemetry instrumentation helpers for Node, Express, and h3.
Readme
@julianm-lrj/node-instrumentation
Production-focused OpenTelemetry instrumentation helpers for Node services.
Features
- Node
>=20.6.0policy-aligned configuration. - Traces, metrics, and logs with OTLP exporters.
- Express middleware with request/response telemetry capture.
- h3 handler wrapper with equivalent telemetry behavior.
- Capture-all-except-denylist headers, content-type body filtering, recursive redaction, and truncation markers.
- Environment-driven sampling and capture controls.
service.versiondefaults to the nearestpackage.jsonversion (or env overrides).
Install
npm install @julianm-lrj/node-instrumentationRuntime Support
- Minimum supported Node.js version:
20.6.0 - Continuously validated in CI on Node
20.xand24.x
Quality Gates
npm run lintnpm run typechecknpm testnpm run test:coverage(fullsrc/**/*.tscoverage; fails below90%lines/statements,80%branches,95%functions, and writescoverage/lcov.info)
Start OpenTelemetry
import { startTelemetry } from "@julianm-lrj/node-instrumentation";
const telemetry = startTelemetry({
serviceName: "payments-api",
deploymentEnvironment: "production",
requireOtlpTls: true
});
// Optional explicit shutdown if your process manager does not send signals.
await telemetry.shutdown();startTelemetry Config Type
startTelemetry accepts overrides?: Partial<InstrumentationConfig>.
All fields are optional. Resolution order is: explicit overrides -> environment variables -> built-in defaults.
type StartTelemetryConfig = Partial<{
serviceName: string;
serviceVersion: string;
deploymentEnvironment: string;
captureHeaders: boolean;
captureRequestBody: boolean;
captureResponseBody: boolean;
allowedBodyTypes: string[];
deniedHeaders: string[];
redactionPatterns: RegExp[];
maxUrlBytes: number;
maxHeaderValueBytes: number;
maxRequestBodyBytes: number;
maxResponseBodyBytes: number;
traceSamplingRate: number;
excludedPaths: string[];
otlpEndpoint: string | undefined;
otlpTracesEndpoint: string | undefined;
otlpMetricsEndpoint: string | undefined;
otlpLogsEndpoint: string | undefined;
otlpHeaders: Record<string, string>;
otlpTimeoutMillis: number;
metricExportIntervalMillis: number;
requireOtlpTls: boolean;
installSignalHandlers: boolean;
}>;Practical requirement: set serviceName for clear service identity in observability backends.
Express Usage
import express from "express";
import {
createExpressInstrumentationMiddleware,
startTelemetry
} from "@julianm-lrj/node-instrumentation";
startTelemetry({ serviceName: "express-api" });
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(createExpressInstrumentationMiddleware());h3 Usage
import { createApp, createRouter, eventHandler, readBody, toNodeListener } from "h3";
import { instrumentH3Handler, startTelemetry } from "@julianm-lrj/node-instrumentation";
startTelemetry({ serviceName: "h3-api" });
const app = createApp();
const router = createRouter();
router.post(
"/orders/:id",
instrumentH3Handler(async (event) => {
const body = await readBody(event);
return { ok: true, body };
})
);
app.use(router);Environment Variables
OTEL_SERVICE_NAME(defaultnode-instrumentation)OTEL_SERVICE_VERSION(defaultnpm_package_version; then nearestpackage.jsonversion; then0.0.0)OTEL_DEPLOYMENT_ENVIRONMENT(defaultNODE_ENV; thenproduction)INSTRUMENTATION_CAPTURE_HEADERS(true|false, defaulttrue)INSTRUMENTATION_CAPTURE_REQUEST_BODY(true|false, defaulttrue)INSTRUMENTATION_CAPTURE_RESPONSE_BODY(true|false, defaultfalse)INSTRUMENTATION_ALLOWED_BODY_TYPES(CSV, defaultapplication/json,application/x-www-form-urlencoded)INSTRUMENTATION_DENIED_HEADERS(CSV, defaultauthorization,proxy-authorization,cookie,set-cookie,x-api-key,x-auth-token,x-access-token,x-session-id,*token*,*secret*,*password*)INSTRUMENTATION_REDACTION_PATTERNS(CSV regex/literals, default built-in sensitive key patterns)INSTRUMENTATION_MAX_URL_BYTES(default2048, min128)INSTRUMENTATION_MAX_HEADER_VALUE_BYTES(default1024, min64)INSTRUMENTATION_MAX_REQUEST_BODY_BYTES(default8192, min256)INSTRUMENTATION_MAX_RESPONSE_BODY_BYTES(default4096, min256)INSTRUMENTATION_TRACE_SAMPLING_RATE(0.0-1.0, default1.0)INSTRUMENTATION_EXCLUDED_PATHS(CSV, default/health,/ready,/metrics)INSTRUMENTATION_REQUIRE_OTLP_TLS(true|false, defaulttrue)INSTRUMENTATION_ALLOW_INSECURE_OTLP(true|false, defaultfalse)OTEL_EXPORTER_OTLP_ENDPOINTOTEL_EXPORTER_OTLP_TRACES_ENDPOINTOTEL_EXPORTER_OTLP_METRICS_ENDPOINTOTEL_EXPORTER_OTLP_LOGS_ENDPOINTOTEL_EXPORTER_OTLP_HEADERS(CSVkey=valuepairs, default empty)OTEL_EXPORTER_OTLP_TIMEOUT(milliseconds, default10000, min1000)INSTRUMENTATION_METRIC_EXPORT_INTERVAL_MS(milliseconds, default10000, min1000)INSTRUMENTATION_INSTALL_SIGNAL_HANDLERS(true|false, defaulttrue)
OTLP TLS Flag
- Automatic disable: if a trace/metric/log OTLP URL is missing (or rejected by TLS policy), export for that signal is skipped automatically.
- Per-signal behavior: you can configure only
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,OTEL_EXPORTER_OTLP_METRICS_ENDPOINT, orOTEL_EXPORTER_OTLP_LOGS_ENDPOINT; unconfigured signals remain disabled. - Secure by default: TLS is enforced unless explicitly disabled.
- Runtime flag: start with
--allow-insecure-otlpto allowhttp://OTLP exporter URLs. - Programmatic override:
startTelemetry({ requireOtlpTls: false }).
