Node.js
Instrument Node.js applications with OpenTelemetry for comprehensive tracing and observability
Use OpenTelemetry to instrument your Node.js application and send telemetry data to Last9. This integration provides automatic instrumentation for HTTP requests, database operations, file system access, and external API calls in your Node.js applications.
You can either run OpenTelemetry Collector as a separate service or send telemetry directly from your application to Last9.
Prerequisites
Before setting up Node.js monitoring, ensure you have:
- Node.js 16.0 or higher installed
- Node.js application to instrument
- Last9 account with integration credentials
- npm or yarn package manager available
-
Install OpenTelemetry Packages
Install the required OpenTelemetry packages for comprehensive Node.js instrumentation:
npm install \@opentelemetry/api@1.9.0 \@opentelemetry/auto-instrumentations-node@0.59.0 \@opentelemetry/exporter-trace-otlp-grpc@0.201.1 \@opentelemetry/exporter-trace-otlp-http@0.201.1 \@opentelemetry/instrumentation@0.201.1 \@opentelemetry/resources@2.0.1 \@opentelemetry/sdk-node@0.201.1 \@opentelemetry/sdk-trace-base@2.0.1 \@opentelemetry/sdk-trace-node@2.0.1 \@opentelemetry/semantic-conventions@1.34.0These packages provide:
- Core APIs: Base OpenTelemetry functionality
- Auto-instrumentation: Automatic tracing for popular libraries
- OTLP Exporters: Direct export to Last9
- Node.js SDK: Optimized for Node.js runtime
-
Set Environment Variables
Configure OpenTelemetry environment variables for your Node.js application:
export OTEL_SERVICE_NAME="<your_service_name>"export OTEL_EXPORTER_OTLP_ENDPOINT=$last9_otlp_endpointexport OTEL_EXPORTER_OTLP_HEADERS="Authorization=$last9_otlp_auth_header"export OTEL_TRACES_SAMPLER="always_on"export OTEL_RESOURCE_ATTRIBUTES="deployment.environment=production"export OTEL_LOG_LEVEL=errorReplace
<your_service_name>with a descriptive name for your Node.js service (e.g.,api-server,user-service,payment-processor). -
Create Instrumentation File
Create an instrumentation file that sets up OpenTelemetry for your Node.js application. Choose the appropriate version based on your project setup:
Create a file named
instrumentation.tsin your project root:import {NodeTracerProvider,TracerConfig,} from "@opentelemetry/sdk-trace-node";import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";import { registerInstrumentations } from "@opentelemetry/instrumentation";import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";import {ATTR_SERVICE_NAME,ATTR_DEPLOYMENT_ENVIRONMENT,} from "@opentelemetry/semantic-conventions";import { resourceFromAttributes } from "@opentelemetry/resources";const providerConfig: TracerConfig = {resource: resourceFromAttributes({[ATTR_SERVICE_NAME]: process.env.OTEL_SERVICE_NAME,[ATTR_DEPLOYMENT_ENVIRONMENT]: process.env.NODE_ENV,}),};// Initialize and register the tracer providerconst provider = new NodeTracerProvider(providerConfig);const otlp = new OTLPTraceExporter({url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT + "/v1/traces",headers: {Authorization:process.env.OTEL_EXPORTER_OTLP_HEADERS?.replace("Authorization=","",) || "",},});provider.addSpanProcessor(new BatchSpanProcessor(otlp));provider.register();// Automatically instrument the Node.js applicationregisterInstrumentations({instrumentations: [getNodeAutoInstrumentations({// Disable noisy file system instrumentation"@opentelemetry/instrumentation-fs": {enabled: false,},}),],});Create a file named
instrumentation.jsin your project root:// instrumentation.jsconst opentelemetry = require("@opentelemetry/sdk-node");const {getNodeAutoInstrumentations,} = require("@opentelemetry/auto-instrumentations-node");const {OTLPTraceExporter,} = require("@opentelemetry/exporter-trace-otlp-http");const { resourceFromAttributes } = require("@opentelemetry/resources");const {ATTR_SERVICE_NAME,ATTR_DEPLOYMENT_ENVIRONMENT,} = require("@opentelemetry/semantic-conventions");// Simple logging utilityconst logger = {info: (message) => console.log(`[OpenTelemetry] ${message}`),error: (message, error) =>console.error(`[OpenTelemetry Error] ${message}`, error || ""),};logger.info(`Initializing OpenTelemetry for service: ${process.env.OTEL_SERVICE_NAME}`,);// Create and configure SDKconst sdk = new opentelemetry.NodeSDK({resource: resourceFromAttributes({[ATTR_SERVICE_NAME]: process.env.OTEL_SERVICE_NAME,[ATTR_DEPLOYMENT_ENVIRONMENT]: process.env.NODE_ENV,}),traceExporter: new OTLPTraceExporter({url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT + "/v1/traces",headers: {Authorization:process.env.OTEL_EXPORTER_OTLP_HEADERS?.replace("Authorization=","",) || "",},}),instrumentations: [getNodeAutoInstrumentations({"@opentelemetry/instrumentation-fs": { enabled: false },}),],});// Initialize the SDK and register with the OpenTelemetry APItry {sdk.start();logger.info("Tracing initialized successfully");} catch (error) {logger.error("Failed to initialize tracing", error);}// Gracefully shut down the SDK on process exitprocess.on("SIGTERM", () => {logger.info("Application shutting down, finalizing traces");sdk.shutdown().then(() => logger.info("Trace provider shut down successfully")).catch((error) =>logger.error("Error shutting down trace provider", error),).finally(() => process.exit(0));});process.on("SIGINT", () => {logger.info("Application shutting down (SIGINT), finalizing traces");sdk.shutdown().then(() => logger.info("Trace provider shut down successfully")).catch((error) =>logger.error("Error shutting down trace provider", error),).finally(() => process.exit(0));});logger.info("OpenTelemetry instrumentation setup complete"); -
Import Instrumentation in Your Application
Import the instrumentation file at the very top of your main application file, before any other imports. This is crucial for proper instrumentation setup.
If your main file is
server.tsorapp.ts, import the instrumentation at the top:import "./instrumentation";import express from "express";import { createServer } from "http";// ... other importsconst app = express();// ... rest of your application codeIf your main file is
server.jsorapp.js, require the instrumentation at the top:require("./instrumentation");const express = require("express");const http = require("http");// ... other requiresconst app = express();// ... rest of your application codeImportant: Make sure to import/require the instrumentation script before any other modules to ensure proper auto-instrumentation.
-
Run Your Node.js Application
Start your Node.js application normally. The OpenTelemetry instrumentation will automatically begin collecting and sending telemetry data to Last9:
# For developmentnpm start# Or with nodemon for developmentnodemon server.js# For production with PM2pm2 start server.js --name "my-api"# Direct node executionnode server.js
Understanding Node.js Instrumentation
The instrumentation setup performs the following steps:
- Service Configuration: Sets up trace provider with your application’s name as service name
- OTLP Export: Configures direct export to Last9 endpoint with authentication
- Auto-Instrumentation: Registers automatic tracing for popular Node.js libraries
- Performance Optimization: Uses batch processing and efficient span management
What Gets Instrumented
When you use automatic instrumentation with Node.js, OpenTelemetry automatically captures:
HTTP Operations
- Incoming Requests: HTTP server requests with method, URL, headers, and response codes
- Outgoing Requests: HTTP client requests using
http,https,axios,fetch, etc. - Request/Response Bodies: Configurable body capture for debugging
- Request Timing: Complete request lifecycle timing
Database Operations
- SQL Databases: MySQL, PostgreSQL, SQLite queries and connection pooling
- NoSQL Databases: MongoDB, Redis operations and commands
- ORMs: Sequelize, TypeORM, Prisma database operations
- Connection Management: Database connection lifecycle and health
File System Operations
- File I/O: File read/write operations (disabled by default to reduce noise)
- Directory Operations: Directory listing and manipulation
- Stream Operations: File streaming and processing
External Services
- API Calls: External HTTP API interactions
- Message Queues: RabbitMQ, Kafka, Redis pub/sub operations
- Cache Operations: Redis, Memcached interactions
- Cloud Services: AWS SDK, Google Cloud, Azure SDK operations
Advanced Configuration
Custom Service Metadata
Enhance your service metadata with additional resource attributes:
const providerConfig: TracerConfig = { resource: resourceFromAttributes({ [ATTR_SERVICE_NAME]: process.env.OTEL_SERVICE_NAME, [ATTR_SERVICE_VERSION]: "2.1.0", [ATTR_DEPLOYMENT_ENVIRONMENT]: process.env.NODE_ENV, "service.instance.id": "api-server-1", team: "backend", }),};Custom Spans and Attributes
Add custom spans and attributes to track business-specific operations:
import { trace } from "@opentelemetry/api";
const tracer = trace.getTracer("my-app");
async function processUserData(userId: string) { const span = tracer.startSpan("process_user_data");
try { span.setAttributes({ "user.id": userId, "operation.type": "user_processing", "operation.priority": "high", });
// Your business logic here const userData = await fetchUserData(userId); const processedData = await processData(userData);
span.setStatus({ code: trace.SpanStatusCode.OK }); return processedData; } catch (error) { span.setStatus({ code: trace.SpanStatusCode.ERROR, message: error.message, }); span.recordException(error); throw error; } finally { span.end(); }}Performance Monitoring
Monitor Node.js specific metrics:
import { metrics } from "@opentelemetry/api";
const meter = metrics.getMeter("my-app");
// Create custom metricsconst requestCounter = meter.createCounter("http_requests_total", { description: "Total number of HTTP requests",});
const memoryGauge = meter.createObservableGauge("nodejs_memory_usage_bytes", { description: "Node.js memory usage",});
// Record memory usagememoryGauge.addCallback((result) => { const memUsage = process.memoryUsage(); result.observe(memUsage.heapUsed, { type: "heap_used" }); result.observe(memUsage.heapTotal, { type: "heap_total" }); result.observe(memUsage.rss, { type: "rss" });});Verification
-
Check Application Startup
When you start your Node.js application, you should see OpenTelemetry initialization messages in the console.
-
Generate Test Traffic
Make some requests to your Node.js application to generate telemetry data:
curl http://localhost:3000/curl http://localhost:3000/healthcurl http://localhost:3000/api/users -
Test Database Operations
If your app uses databases, perform some database operations to generate database spans.
-
Verify Traces in Last9
Log into your Last9 account and check that traces are being received in the Traces dashboard.
Look for:
- HTTP request traces with timing information
- Database operation spans
- External API call traces
- Error traces for failed operations
Troubleshooting
Common Issues
Instrumentation Not Working
Ensure the instrumentation file is imported before any other modules:
// ✅ Correct orderrequire("./instrumentation");const express = require("express");
// ❌ Incorrect orderconst express = require("express");require("./instrumentation");Missing Traces for Specific Libraries
Check if the library has specific instrumentation available:
npm list | grep @opentelemetry/instrumentationEnvironment Variables Not Set
Verify your environment variables are properly configured:
env | grep OTEL_Network Connection Issues
Test connectivity to Last9:
curl -v -H "Authorization: $last9_otlp_auth_header" $last9_otlp_endpointPerformance Considerations
- Sampling: Use sampling in production to control trace volume
- Batch Processing: BatchSpanProcessor is enabled by default for performance
- Memory Usage: Monitor memory usage impact of instrumentation
- File System: Keep file system instrumentation disabled in production to reduce noise
Best Practices
- Import Order: Always import instrumentation first
- Service Naming: Use descriptive, consistent service names
- Environment Configuration: Use different service names per environment
- Custom Spans: Add spans for critical business operations
- Error Handling: Implement proper error handling with span status updates
- Graceful Shutdown: Handle application shutdown to flush remaining traces
Supported Libraries
OpenTelemetry automatically instruments many popular Node.js libraries:
- HTTP Libraries:
http,https,axios,node-fetch,request - Web Frameworks:
express,koa,fastify,hapi - Databases:
mysql,mysql2,pg,mongodb,ioredis - ORMs:
sequelize,typeorm,prisma - Message Queues:
amqplib(RabbitMQ),kafkajs - Cloud Services:
aws-sdk,@google-cloud/*,@azure/*
For a complete list of supported libraries, visit the OpenTelemetry Node.js documentation.
Need Help?
If you encounter any issues or have questions:
- Join our Discord community for real-time support
- Contact our support team at support@last9.io