CtrlK
BlogDocsLog inGet started
Tessl Logo

kopai/otel-instrumentation

Instrument applications with the OpenTelemetry SDK and prove the telemetry is good by validating it against a local Kopai backend. Use when setting up observability, adding tracing/logging/metrics, deciding what to instrument or which attributes to add, retrofitting OTel into an existing codebase, threading context through call chains, configuring sampling, or when traces/logs/metrics aren't appearing after setup. Also use when users say things like "my traces aren't showing up", "I don't see any data", or "how do I add observability to my app". Do NOT use to investigate existing telemetry for a root cause (use root-cause-analysis), to build dashboards (use create-dashboard), or to instrument LLM and agent calls (use otel-genai-instrumentation).

Quality

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Low

Low-risk findings worth noting

Overview
Quality
Evals
Security
Files

lang-nodejs.mdreferences/

titleimpacttags
Node.js InstrumentationHIGHlang, nodejs, javascript, traces, logs, metrics

Node.js Instrumentation

Set up OpenTelemetry SDK for Node.js applications with automatic instrumentation.

Install

npm install @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node @opentelemetry/api

npm shown — install with the project's own package manager (pnpm add / yarn add), detected per the package-picking rule in SKILL.md.

Configuration

Environment Variables:

VariableDescription
OTEL_EXPORTER_OTLP_ENDPOINTOTLP endpoint (e.g., http://localhost:4318)
OTEL_SERVICE_NAMEService name shown in observability backend

Instrumentation File (instrumentation.mjs)

Create a separate instrumentation file that loads before your application:

import { NodeSDK } from "@opentelemetry/sdk-node";
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";

const sdk = new NodeSDK({
  instrumentations: [getNodeAutoInstrumentations()],
});

sdk.start();

// Graceful shutdown
process.on("SIGTERM", () => {
  sdk
    .shutdown()
    .then(() => console.log("Tracing terminated"))
    .catch((error) => console.log("Error terminating tracing", error))
    .finally(() => process.exit(0));
});

Run with Instrumentation

# Load instrumentation before your app
node --import ./instrumentation.mjs server.mjs

Or in package.json:

{
  "type": "module",
  "scripts": {
    "start": "node --import ./instrumentation.mjs server.mjs"
  }
}

In a "type": "module" app this patches CommonJS dependencies (they still load through the require hook). A dependency published as native ESM bypasses that hook and additionally needs OTel's experimental loader hook:

node --experimental-loader=@opentelemetry/instrumentation/hook.mjs \
  --import ./instrumentation.mjs server.mjs

What Gets Instrumented

The auto-instrumentation automatically captures:

  • Traces: HTTP requests, Express routes, database queries
  • Logs: Console output (with additional config)
  • Metrics: HTTP request metrics (with additional config)

The SDK auto-detects OTEL_EXPORTER_OTLP_ENDPOINT and exports via OTLP HTTP.

Framework coverage

getNodeAutoInstrumentations() covers Express, Koa, Hapi, and most HTTP/DB clients. It does not cover Fastify — that instrumentation moved to the Fastify team (@fastify/otel) and the deprecated contrib package was removed from the bundle in March 2026. Fastify app → lang-fastify.md, which registers a plugin instead of relying on module interception.

Example

See the complete working example: kopai-integration-examples/node-js

Reference

OpenTelemetry JavaScript

Next

SDK setup is step 3 of six. It gets bytes flowing; it does not make the telemetry good.

  1. Decide what earns a span — instrument-spans.md
  2. Add the context that makes spans answerable — instrument-attributes.md
  3. Instrument the error paths — instrument-errors.md
  4. Drive traffic yourself — drive-traffic.md
  5. Assert on what arrived — validate-traces.md

Confirm before moving on: the SDK starts before any application code that could create a span, and shutdown flushes on SIGTERM (validate-shutdown.md). Both fail silently.

references

_sections.md

architectural-patterns.md

attributes.md

cli-reference.md

context-propagation.md

custom-instrumentation.md

drive-traffic.md

instrument-attributes.md

instrument-errors.md

instrument-spans.md

lang-cpp.md

lang-dotnet.md

lang-erlang.md

lang-fastify.md

lang-go.md

lang-java.md

lang-nextjs.md

lang-nodejs.md

lang-php.md

lang-python.md

lang-ruby.md

lang-rust.md

layered-telemetry.md

nextjs-examples.md

otel-docs.md

sampling.md

setup-backend.md

setup-environment.md

troubleshoot-missing-attrs.md

troubleshoot-missing-spans.md

troubleshoot-no-data.md

troubleshoot-wrong-port.md

validate-logs.md

validate-metrics.md

validate-shutdown.md

validate-traces.md

CHANGELOG.md

SKILL.md

tile.json