> ## Documentation Index
> Fetch the complete documentation index at: https://mw-docs.middleware.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Node.js

> Node.js APM - Setup & Installation Docs | Middleware

<a target="_blank" href="https://www.npmjs.com/package/@middleware.io/node-apm">
  <span
    style={{
    background: "url(https://img.shields.io/npm/v/%40middleware.io%2Fnode-apm) no-repeat",
    width: "125px",
    height: "20px",
    display: "inline-block",
}}
  />
</a>

| Traces | Metrics | App Logs | Custom Logs | Profiling |
| :----: | :-----: | :------: | :---------: | :-------: |
|    ✅   |    ✖️   |    ✖️    |      ✅      |     ✅     |

This guide walks you through setting up Application Performance Monitoring (APM) on a Node.js application. These instructions can also be found on the Installation page in your Middleware Account. View example code [here](https://github.com/middleware-labs/demo-apm/tree/master/nodejs).

# Prerequisites

<Steps>
  <Step title="Infra Agent">
    Infrastructure Agent (Infra Agent). To install the Infra Agent, see our [Installation Guide](https://docs.middleware.io/docs/agent-installation/overview).
  </Step>

  <Step title="Node.js Version">
    `Node.js version 18.17.1` or above. Check your Node.js version with the following command:

    ```javascript bash theme={null}
    node --version
    ```
  </Step>

  <Step title="Python Version">
    `Python version 3.8` or above. Check your Python version with the following command:

    ```javascript bash theme={null}
    python3 --version
    ```
  </Step>
</Steps>

# Install

### Step 1: Install `Node.js` APM Package

Run the following command in your terminal:

```javascript bash theme={null}
npm install @middleware.io/node-apm --save
```

### Step 2:  Initialize Tracker

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.

```javascript Node.js theme={null}
const tracker = require('@middleware.io/node-apm');
tracker.track({
    serviceName: "your-service-name",
    accessToken: "<xxxxxxxxxx>"
});
```

### Step 3: Container Variables

#### 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.

```javascript bash theme={null}
MW_AGENT_SERVICE=<DOCKER_BRIDGE_GATEWAY_ADDRESS>
```

<Note> 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](https://docs.docker.com/network/network-tutorial-standalone/) </Note>

#### Kubernetes

```javascript bash theme={null}
kubectl get service --all-namespaces | grep mw-service
```

Then add the following environment variable to your application deployment YAML file.

```javascript bash theme={null}
MW_AGENT_SERVICE=mw-service.mw-agent-ns.svc.cluster.local
```

### Step 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:

```javascript Node.js theme={null}
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.

```javascript Node.js theme={null}
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.

```javascript Node.js theme={null}
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:

```javascript Node.js theme={null}
const express = require("express");
const app = express();
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: "<your_key_here>",
  // 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>",
});

// Create a tracer, used to create spans.
const tracer = tracker.getTracer();

// Create a meter, used to create custom metrics.
const meter = tracker.getMeter();

// Create a counter metric.
// For a list of other metric types, see the opentelemetry metrics API
// documentation. (https://opentelemetry.io/docs/specs/otel/metrics/api/)
let counter = meter.createCounter("health-check-counter");

/**
 * Generate a random integer between 0 and the range provided.
 * @param {Number} range
 * @returns {Number}
 */
function randInt(range) {
  // Create a span. A span must be closed.
  return tracer.startActiveSpan("randInt", (span) => {
    const randomInt = Math.floor(Math.random() * range);
    // Be sure to end the span
    span.end();
    return randomInt;
  });
}

app.get("/randInt", (req, res) => {
  // Calling the randInt function will generate a span.
  const randomInt = randInt(100);
  res.json({ number: randomInt });
});

app.get("/health", (req, res) => {
  // Increment the health-check-counter by 1.
  counter.add(1);
  res.json({ status: "ok" });
});

app.listen(5051, () => {
  console.log("Server is running on port 5051");
});

```

#### 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.

```javascript Node.js  theme={null}
app.get('/error', function (req, res) {
    try{
        throw new Error('oh error!');
    }catch (e) {
    track.errorRecord(e)
    }
    res.status(500).send("wrong");
}); 
```

# NestJS Framework \[Optional]

### Step 1: Install Node Typescript APM

```javascript Node.js  theme={null}
npm install mw-node-apm-ts
```

### Step 2: Import Package in `main.ts`

Import the following package in your `main.ts` file:

```javascript Node.js theme={null}
import { track } from 'mw-node-apm-ts';

async function bootstrap() {
    track({
      serviceName: 'NestJS Test',
      accessToken: 'your-api-token',
    });

    const app = await NestFactory.create(AppModule, { bufferLogs: true });

    await app.listen(PORT || 3000);
}

bootstrap();
```

### Step 3: Capture Application Data

The following is a sample function that fetches a user's email address and throws an error if the user is not found, while also logging the error using a third-party logging function.

Use the below pattern for any other available methods that are mentioned in [Step 4](/apm-configuration/node-js#step-4-capture-application-data).

```javascript Node.js theme={null}
import { error } from 'mw-node-apm-ts';

async sampleCode(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: {
          email: 'User not found!',
        },
      });
    }
}
```

# Continuous Profiling

Continuous profiling captures real-time performance insights from your application to enable rapid identification of resource allocation, bottlenecks, and more. Navigate to the [Continuous Profiling](https://docs.middleware.io/workflow/profiling#continuous-profiling) section to learn more about using Continuous Profiling with the Node.js APM.

# Troubleshooting

### `node-gyp` Failing/Missing Dependencies

If `node-gyp` fails to build or your infrastructure is missing dependencies, run the following command:

```Shell Shell theme={null}
sudo apt-get build-dep build-essential
sudo apt-get install gcc
sudo apt-get install g++
sudo apt-get install make
```

### Running Apps on Docker

If you are unable to run your Node.js app on Docker, open port `9319` locally to enable proper firewall configurations.

<Note> Need assistance or want to learn more about Middleware? Contact us at support\[at]middleware.io. </Note>
