Node.js
Traces | Metrics | App Logs | Custom Logs | Profiling |
---|---|---|---|---|
✅ | ✅ | ✅ | ✅ | ✅ |
This guide provides instructions to set up Application Performance Monitoring (APM) in a Node.js application. You can also find these instructions on the installation page in your Middleware account. For example code, view here.
Prerequisites
- Node.js 18.17.1+: Verify with
node --version
- Python Version 3.8+ Verify with
python3 --version
Installation
1 Install Node.js
APM Package
Run the following command in your terminal:
shell
npm install @middleware.io/node-apm --save
2 Setup Options
Host based APM requires the Middleware Agent which can be installed using the relevant OS based instructions. here.
Method 1: Direct Code Initialization
Add the following lines to the beginning of your application code base. The access token is your account key, which can be found on the Installation page.
index.js
const tracker = require('@middleware.io/node-apm'); tracker.track({ serviceName: "your-service-name", accessToken: "<MW_API_KEY>", }); // must come before importing any other module. // At the very top of the entrypoint const express = require('express'); // other dependencies
If you want to track APM data across different deployments of your application. You can pass along the app.version
,
For Example, If your deployment version is 1.2.0
the config should look something like this.
index.js
const tracker = require('@middleware.io/node-apm'); tracker.track({ serviceName: "your-service-name", accessToken: "<MW_API_KEY>", customResourceAttributes: { "app.version": "1.2.0", } });
Method 2: Add the tracker with command line arguments
Create a file named instrument.js or instrument.ts
in your project root:
instrument.js
// instrument.js const tracker = require('@middleware.io/node-apm'); tracker.track({ serviceName: "your-service-name", accessToken: "<MW_API_KEY>", customResourceAttributes: { "app.version": "1.2.0", } });
To ensure the tracker is initialized before any other code runs, use the --require
flag when starting your Node.js application:
Shell
node --require ./instrument.js your-main-app.js
Method 1: Direct Code Initialization
Add the following lines to the beginning of your application code base. The access token is your account key, which can be found on the Installation page.
index.js
const tracker = require('@middleware.io/node-apm'); tracker.track({ serviceName: "your-service-name", accessToken: "<MW_API_KEY>", target: "https://<MW_UID>.middleware.io:443", }); // must come before importing any other module. // At the very top of the entrypoint const express = require('express'); // other dependencies
If you want to track APM data across different deployments of your application. You can pass along the app.version
,
For Example, If your deployment version is 1.2.0
the config should look something like this.
index.js
const tracker = require('@middleware.io/node-apm'); tracker.track({ serviceName: "your-service-name", accessToken: "<MW_API_KEY>", target: "https://<MW_UID>.middleware.io:443", customResourceAttributes: { "app.version": "1.2.0", } });
Method 2: Add the tracker with command line arguments
Create a file named instrument.js or instrument.ts
in your project root:
instrument.js
// instrument.js const tracker = require('@middleware.io/node-apm'); tracker.track({ serviceName: "your-service-name", accessToken: "<MW_API_KEY>", target: "https://<MW_UID>.middleware.io:443", customResourceAttributes: { "app.version": "1.2.0", } });
To ensure the tracker is initialized before any other code runs, use the --require
flag when starting your Node.js application:
Shell
node --require ./instrument.js your-main-app.js
3 Container Variables
No Container Variables Required in case of serverless mode
Docker
Applications running in a container require an additional environment variable. If your application is not running in a container, move to Step 4.
For Docker containers, add the following environment variable to your application.
Bash
MW_AGENT_SERVICE=<DOCKER_BRIDGE_GATEWAY_ADDRESS>
The DOCKER_BRIDGE_GATEWAY_ADDRESS
is the IP address of the gateway between the Docker host and bridge network. This is 172.17.0.1
by default. Learn more about Docker bridge networking here
Kubernetes
Bash
kubectl get service --all-namespaces | grep mw-service
Then add the following environment variable to your application deployment YAML file.
Bash
MW_AGENT_SERVICE=mw-service.mw-agent-ns.svc.cluster.local
4 Capture Application Data
Traces
Distributed tracing is automatically enabled upon completion of Step 2.
Span Attributes
For any automatically instrumented endpoints, add the following code snippet:
router.post("/email/send", async (req, res) => { const email = req.body.email; tracker.setAttribute("email", email); res.json({ status: "email sent" }); });
Custom Logs
To ingest custom logs into Middleware, utilize the following functions inside your logging method based on desired log severity levels.
index.js
tracker.info('Info sample'); tracker.warn('Warning sample'); tracker.debug('Debugging Sample'); tracker.error('Error Sample');
To add stack traces along with the error log, use the following error tracking function.
index.js
tracker.error(new Error('Error sample with stack trace'));
Custom Metrics and Spans
Create custom instruments and spans by exposing the meter and tracer with the following pattern:
index.js
const tracker = require("@middleware.io/node-apm"); // Initialize the tracker tracker.track({ // Service name differentiates your applications in the APM section of the Middleware platform. serviceName: "<your_service_name_here>", // You can find your access token in the Middleware platform by going to the installation page. accessToken: "<MW_API_KEY>", // The target is your Middleware platform URL. // When you login to the Middleware platform, you can find your target URL in the URL bar. target: "<your_mw_url_here>",
Profiling
Application Profiling is auto-configured upon completing Step 2.
Stack Traces
Use the errorRecord
method to record a stack trace when an error occurs. See an example of this method below.
index.js
app.get('/error', function (req, res) { try{ throw new Error('oh error!'); }catch (e) { track.errorRecord(e) } res.status(500).send("wrong"); });
Continuous Profiling
Continuous profiling captures real-time performance insights. Access this feature under the APM > Continuous Profiling section in the Middleware platform.
Environment Variables
The following environment variables can be used to configure the Middleware APM tracker:
Variable | Description | Possible Values |
---|---|---|
MW_TARGET | Sets the target URL | Your Middleware URL |
MW_API_KEY | Sets the access token | Your Middleware API key |
MW_PROJECT_NAME | Sets the project name | Any string |
MW_SERVICE_NAME | Sets the service name | Any string |
MW_APM_TRACES_ENABLED | Enables/disables trace collection | "true" or "false" |
MW_APM_METRICS_ENABLED | Enables/disables metric collection | "true" or "false" |
MW_CONSOLE_EXPORTER | Enables/disables console exporter | "true" or "false" |
MW_AGENT_SERVICE | Sets the host for the APM service when using MW Agent | Valid hostname or IP address |
OTEL_NODE_RESOURCE_DETECTORS | Specifies which resource detectors to use | Comma-separated list (see below) |
MW_NODE_DISABLED_INSTRUMENTATIONS | Specifies which instrumentations to disable | Comma-separated list (see below) |
Customizing Resource Detection with OTEL_NODE_RESOURCE_DETECTORS
Specifies which resource detectors to use. Each detector provides specific information about the application's environment.
Default: env, process, host, os, container, serviceinstance
Possible values: env, process, serviceinstance, os, host, container, aws, azure, gcp, none, all
Example: OTEL_NODE_RESOURCE_DETECTORS=env,process,host,aws
Disabling Specific Instrumentations with MW_NODE_DISABLED_INSTRUMENTATIONS
Disables specific instrumentations to exclude certain types of data collection.
Note: File System (fs) instrumentation is permanently disabled due to performance issues.
Possible values: dns, net
Example: MW_NODE_DISABLED_INSTRUMENTATIONS=dns,net
Available instrumentations may vary depending on your Middleware APM version and configuration.
Configuration Options
In addition to using environment variables, you can configure the Middleware APM tracker directly through the tracker.track()
call. Here are the configuration options you can use: (env variables have higher priority)
Option | Type | Default | Description |
---|---|---|---|
target | string | N/A | Sets the target URL for the APM service |
accessToken | string | N/A | Sets the access token for authentication |
projectName | string | N/A | Sets the project name |
serviceName | string | N/A | Sets the service name |
pauseTraces | boolean | false | Disables trace collection |
pauseMetrics | boolean | false | Disables metric collection |
consoleExporter | boolean | false | Enables console exporter |
customResourceAttributes | object | N/A | Sets custom resource attributes |
disabledInstrumentations | string | N/A | Specifies which instrumentations to disable (comma-separated) |
consoleLog | boolean | false | Enables consoleLog logs collection |
consoleError | boolean | false | Enables consoleError logs collection |
enableSelfInstrumentation | boolean | false | Enables self-instrumentation for the profiling traces |
enableProfiling | boolean | true | Enables profiling functionality for performance analysis |
Usage Example
index.js
const tracker = require('@middleware.io/node-apm'); tracker.track({ serviceName: "my-service", accessToken: "your-access-token", projectName: "my-project", pauseTraces: false, pauseMetrics: false, consoleExporter: true, customResourceAttributes: {
Framework-Specific Configuration
If any of the following Nodejs web frameworks are used in your application, configuration steps as per framework is given below.
NestJS
Step 1: Import the Package
In your main.ts
, import and configure the tracker:
import * as tracker from "@middleware.io/node-apm"; async function bootstrap() { tracker.track({ serviceName: "your-service-name", accessToken: "<MW_API_KEY>", target: "https://<MW_UID>.middleware.io:443" }); const app = await NestFactory.create(AppModule, { bufferLogs: true });
Step 2: Capture Data
An example of handling errors and logging them:
import * as tracker from "@middleware.io/node-apm"; async sampleFunction(data: userDto): Promise<IResponse> { const user = await this.userService.getUserByEmail(loginDto.email); if (!user) { error('User not found'); throw new UnprocessableEntityException({ status: HttpStatus.UNPROCESSABLE_ENTITY, errors: {
Graceful Shutdown (Optional)
The Middleware APM tracker provides a sdkShutdown
function for graceful shutdown. This ensures all pending telemetry data is sent before your application exits. Call tracker.sdkShutdown()
when your application is about to exit to ensure all data is properly flushed.
Usage
const tracker = require('@middleware.io/node-apm'); // Initialize the tracker tracker.track({ // Your configuration options }); // Handle application shutdown process.on('SIGINT', async () => { console.log('SIGINT signal received. Shutting down gracefully');
Basic Troubleshooting Guidelines
If you're experiencing issues with the Middleware APM tracker or not seeing the expected data, try the following steps:
Enable Debug Logging: Set the DEBUG flag to true in your configuration or use the environment variable to get more detailed logs:
tracker.track({ // other options... DEBUG: true });
Check Configuration: Ensure all required fields (like
serviceName
,accessToken
,target
andaccessToken
) are correctly set.Initialize Tracking Function: Make sure your tracker.track() is initialized at the very top of the main server file.
Instrumentation Issues: If specific instrumentations aren't working, check if they're accidentally disabled in your configuration.
Resource Detection: If you're not seeing expected resource attributes, verify your
OTEL_NODE_RESOURCE_DETECTORS
setting.Restart Your Application: Sometimes, a simple restart after configuration changes can resolve issues.
Agent Health Check: If you're using the Middleware Agent, the SDK performs a health check at startup. If you see a warning message about the health check failing, it could be due to:
- Incorrect value of
MW_AGENT_SERVICE
If the problem persists, verify your agent configuration and ensure it's running correctly.
- Incorrect value of
OpenTelemetry Dependency Conflicts: If you're using OpenTelemetry in your application code alongside the Middleware Node SDK, ensure that the versions are compatible. Conflicting versions can lead to unexpected behavior. Check the OpenTelemetry version used by the Middleware SDK (you can find this in the SDK's
package.json
) and make sure your application's OpenTelemetry dependencies match or are compatible with this version.
If problems persist after trying these steps, please contact Middleware support with your debug logs and configuration details (with sensitive information redacted).
Frequently Asked Questions (FAQ)
node-gyp Failing or Missing Dependencies
If node-gyp
fails or dependencies are missing, run the following commands:
sudo apt-get build-dep build-essential sudo apt-get install gcc g++ make
Running Apps on Docker
If you're unable to run your Node.js app on Docker, ensure port 9319
is open to allow proper firewall configurations.
Installation successful but no data appears / Existing OpenTelemetry dependency older version issue
If you're seeing the following error, especially when DEBUG: true
:
Error: @opentelemetry/api: Registration of version vx.x.x for trace does not match previously registered API vy.y.y
This error occurs due to a version conflict in OpenTelemetry dependencies:
- Your project (or one of its dependencies) is using OpenTelemetry API older version
- Our package requires OpenTelemetry API vx.x.x
This version mismatch prevents proper registration of the OpenTelemetry API, which blocks data collection.
Override the older OpenTelemetry API version by explicitly installing vx.x.x:
npm i @opentelemetry/[email protected] --save
Docker Image Failing
If your Docker image build is failing, it might be due to missing build dependencies. Add the following lines to your Dockerfile:
RUN apk --no-cache add build-base RUN apk add --update --no-cache python3 && ln -sf python3 /usr/bin/python
These commands install necessary build tools and Python, which are often required for compiling native addons.
ESM Modules Auto-instrumentation not working
If your JavaScript or TypeScript code ( compiled to ES6 Modules (ESM)) and auto-instrumentation isn't working for few libraries.
- Install the required package
npm i @opentelemetry/[email protected] // or any other new version
- Use this startup command:
node --experimental-loader=@opentelemetry/instrumentation/hook.mjs --import instrument.js app.js
Pyroscope profiling is not available
This warning appears because Pyroscope is an optional dependency that requires system-level build tools. It may fail if:
- Required system dependencies are missing
node-gyp
build fails- Running in Docker without build essentials
- Not supported for few machines
Solution For local development, install build dependencies:
sudo apt-get build-dep build-essential python3 sudo apt-get install gcc g++ make
For Docker, add build tools in your Dockerfile:
RUN apk --no-cache add build-base RUN apk add --update --no-cache python3 && ln -sf python3 /usr/bin/python
Need assistance or want to learn more about Middleware? Contact our support team in Slack.