AWS X-Ray SDK for Node.js Core
The `aws-xray-sdk-core` package provides foundational capabilities for instrumenting Node.js applications to integrate with AWS X-Ray, enabling distributed tracing, performance analysis, and service map visualization. Currently at version 3.12.0, the SDK receives regular updates, typically on a monthly or bi-monthly release cadence, focusing on stability, bug fixes, and maintaining compatibility with AWS services. It supports both automatic and manual instrumentation modes; automatic mode, leveraging `cls-hooked` for asynchronous context propagation, is ideal for web frameworks like Express and Restify, as well as AWS Lambda functions, by automatically managing trace segments. Manual mode offers granular control over segment and subsegment creation for custom instrumentation scenarios. Its key differentiators include native integration with AWS services and robust support for Node.js environments.
Common errors
-
Failed to get the current sub/segment. Please ensure the AWS X-Ray SDK is running in automatic mode and that the context is available.
cause Attempting to retrieve the current segment or subsegment via `AWSXRay.getSegment()` or `AWSXRay.getSubsegment()` outside of an active trace context, or when automatic context propagation has failed.fixVerify that `AWSXRay.enableAutomaticMode()` is called early in your application's lifecycle. Ensure the code executing is within a traced context (e.g., an incoming HTTP request handled by X-Ray middleware, or inside `captureAsyncFunc`). All async operations must properly propagate context for automatic mode to work reliably. -
Error: Cannot find module 'cls-hooked'
cause The `cls-hooked` package, a direct dependency required for the SDK's automatic mode context propagation, is not installed or accessible.fixInstall the `cls-hooked` dependency: `npm install cls-hooked` or `yarn add cls-hooked`. Although it's a direct dependency, issues can arise from aggressive dependency pruning or package manager inconsistencies. -
connect ECONNREFUSED 127.0.0.1:2000
cause The AWS X-Ray daemon is not running or is not accessible at the configured address and port (default: `127.0.0.1:2000`).fixEnsure the X-Ray daemon is running and listening on the expected UDP port. Check the `AWS_XRAY_DAEMON_ADDRESS` environment variable or `AWSXRay.setDaemonAddress()` configuration if you've customized it. Verify local firewall rules are not blocking traffic to the daemon. -
Trace ID must be 35 hex characters
cause The `X-Amzn-Trace-Id` HTTP header, which the SDK uses to propagate tracing context, is malformed or does not adhere to the expected format.fixInspect the incoming `X-Amzn-Trace-Id` header to ensure it conforms to the X-Ray trace header specification (`Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1`). This often indicates an issue upstream in the trace propagation chain.
Warnings
- breaking Node.js 14.x or newer is required to use `aws-xray-sdk-core` version 3.x and above. Older Node.js runtimes are not supported.
- gotcha Automatic mode, which is the default, relies on the `cls-hooked` package for asynchronous context propagation. If context is lost during manual asynchronous operations (e.g., raw Promises or callbacks not wrapped by `captureAsyncFunc` or `capturePromise`), calls to `AWSXRay.getSegment()` or `AWSXRay.getSubsegment()` will return null.
- gotcha If utilizing `captureAWS` or `captureAWSClient` to automatically instrument AWS SDK calls, a compatible version of the `aws-sdk` (v2.7.15 or greater) must be installed as a peer dependency in your project.
- gotcha The default behavior for a missing trace context (`AWS_XRAY_CONTEXT_MISSING`) is `LOG_ERROR`. This logs a warning but continues execution, potentially obscuring issues where tracing isn't properly initiated. For development, `RUNTIME_ERROR` can be more useful to immediately identify missing contexts.
Install
-
npm install aws-xray-sdk-core -
yarn add aws-xray-sdk-core -
pnpm add aws-xray-sdk-core
Imports
- AWSXRay
const AWSXRay = require('aws-xray-sdk-core');import AWSXRay from 'aws-xray-sdk-core';
- Segment
import AWSXRay, { Segment } from 'aws-xray-sdk-core';import { Segment } from 'aws-xray-sdk-core'; - Subsegment
import { Subsegment } from 'aws-xray-sdk-core'; - Logger
import type { Logger } from 'aws-xray-sdk-core/lib/types/logger';
Quickstart
import AWSXRay from 'aws-xray-sdk-core';
import { RequestListener, createServer } from 'http';
// Configure X-Ray with a dummy daemon address for local testing if not running daemon
// In a real environment, this would often be picked up from environment variables or default to localhost:2000
AWSXRay.setDaemonAddress('127.0.0.1:2000'); // Default is 127.0.0.1:2000
AWSXRay.setLogger(console); // Enable logging for demonstration
AWSXRay.setSegmentName('MyNodeApp'); // Default segment name for incoming requests
AWSXRay.captureHTTPsGlobal(require('http')); // Capture outgoing HTTP calls globally
AWSXRay.captureHTTPsGlobal(require('https')); // Also for HTTPS
// Enable automatic mode, which is default but good to be explicit for clarity
AWSXRay.enableAutomaticMode(); // This requires 'cls-hooked'
const requestListener: RequestListener = (req, res) => {
// Get the current segment created by automatic mode
const segment = AWSXRay.getSegment();
if (segment) {
segment.addAnnotation('path', req.url || '/');
segment.addMetadata('requestMethod', req.method);
AWSXRay.captureAsyncFunc('myCustomOperation', (subsegment) => {
// Simulate some asynchronous work within a subsegment
return new Promise(resolve => {
setTimeout(() => {
subsegment?.addAnnotation('status', 'success');
subsegment?.close(); // Always close subsegments
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello X-Ray Traced!');
resolve(true);
}, 100);
});
}, segment); // Pass segment explicitly to ensure it's linked
} else {
// Fallback if no segment is found (e.g., direct access without X-Ray context)
console.warn('No active X-Ray segment found for this request.');
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello without X-Ray context!');
}
};
const server = createServer(requestListener);
const port = process.env.PORT || 3000;
server.listen(port, () => {
console.log(`Server running on http://localhost:${port}`);
console.log('Try visiting http://localhost:3000');
});
// For a production setup, ensure the X-Ray daemon is running and accessible.
// Remember to terminate your process cleanly in production, e.g., on SIGTERM.