Instrument a Node.js service with OpenTelemetry
Start with automatic coverage, give the service a stable identity, and add custom spans only where the application needs a better name for the work.
A Node.js service rarely needs dozens of custom spans on day one. Most teams get more value by making the standard runtime visible first: incoming requests, outgoing HTTP calls, database work, queues, errors, and the service identity that ties those signals together.
OpenTelemetry is a good fit because the instrumentation can stay independent of the observability backend. Telemio accepts OTLP, so an existing OpenTelemetry setup can usually keep its SDKs and exporters.
Map the service before changing it
Find the real entry point. It might be an Express server, a Fastify app, a worker that consumes a queue, a scheduled process, or several of those in one repository. Check for existing OpenTelemetry initialization before installing another SDK. Two telemetry bootstraps in the same process can create confusing duplicate spans.
Then identify the dependencies that matter in production. HTTP clients, SQL or document databases, Redis, queues, cloud SDKs, and background jobs are common places where automatic instrumentation saves time.
Give the process a stable name
service.name should describe the logical service, not the machine that happens to run it. A name such as checkout-api should survive a deployment from one container to another. Add environment and release information from the deployment system so a trace can be tied back to the code that produced it.
This identity is more important than an early custom dashboard. If every process reports under a changing or generic name, the rest of the telemetry becomes harder to use.
Use automatic spans for protocol work
An HTTP client span already knows the remote host, method, timing, and status. A database span already knows the operation and duration. Recreating those spans by hand adds code without adding much meaning.
Manual spans are worth the maintenance when they name a business operation that crosses several technical calls. Checkout creation is a good example. It might perform a database read, call a payment provider, publish a job, and update an order. A single parent span called checkout.create makes the trace easier to scan.
import { createTelemio } from "@telemio/sdk"
const telemio = createTelemio({
apiKey: process.env.TELEMIO_API_KEY,
serviceName: "checkout-api",
environment: process.env.NODE_ENV,
release: process.env.APP_VERSION
})
await telemio.tracer.withSpan("checkout.create", async (span) => {
span.setAttribute("checkout.provider", "stripe")
await createCheckout()
})
Correlate logs instead of duplicating them
Logs are still useful for details that do not belong on every span. Keep trace and request correlation available so a log record can lead back to the operation that emitted it. Avoid putting large request bodies or secrets into log attributes just because the logger makes it easy.
Metrics answer a different class of question. Counters and timings are useful for rates, capacity, and trends. Traces help explain individual work. A healthy setup uses each signal for what it does well.
Keep configuration outside the source
Exporter endpoints, API keys, deployment environment, and release identifiers should come from the same environment or secret configuration the service already uses. Server API keys do not belong in browser bundles or committed configuration.
If the repository already has OpenTelemetry environment variables, keep them. Point the OTLP exporter at https://otlp.telemio.sh and preserve the normal OpenTelemetry configuration surface where possible.
Verify before calling it done
Run the service's tests and type checks. Start the service locally if that is part of the normal workflow. Confirm that the process starts with instrumentation enabled and that failed dependencies do not crash the application because telemetry export is unavailable.
Then look at a real request end to end. You should see the service span, important dependencies, errors, and the release identity you expect. Add custom spans only after you can point to a specific gap in that trace.
A quick setup path
The Telemio CLI can inspect a repository and help configure the OpenTelemetry path: npm i -g telemio, then telemio setup otel. For manual JavaScript or TypeScript context, install npm i @telemio/sdk. The agent-readable setup guide lives at /agent/setup.md.