Node.js Application Performance Monitoring

The Atatus Node.js Agent helps you in troubleshooting your Node.js application problems and also identifies performance issues before it becomes apparent to your users. It also captures unhandled exceptions and HTTP failures in production to determine which part of your Node.js application is slower or producing lots of errors.

Create a free account to start monitoring your Node.js apps.

Installation & Setup

1. Install atatus-node using npm:

npm install --save atatus-node

2. Require atatus-node in your node.js app:

var atatus = require("atatus-node");

3. Start the atatus agent with your API key:

atatus.start({ apiKey: "YOUR_API_KEY" });

See below for additional configuration options.

Configuration options

The atatus.start can accept other options along with API Key. The options can be a combination of any of the following:

Version tracking

If you use an appVersion to identify releases of your app you can send it to Atatus. It is highly recommended to set App Version.

// From your app Package.json
atatus.start({ apiKey: "YOUR_API_KEY", appVersion: require('./package.json').version });
// (OR) You can also directly assign it
atatus.start({ apiKey: "YOUR_API_KEY", appVersion: "1.0.0" });
Release Stage

By default, Atatus looks at the NODE_ENV environment variable to see what releaseStage the script is running in. If that is not set, Atatus assumes you are running in production. If you want to override this behavior, you can set the releaseStage option:

atatus.start({ apiKey: "YOUR_API_KEY", releaseStage: "development" });
Project Root

Atatus can highlight stacktrace lines that are in your project, and automatically hides stacktrace lines from external libraries. If Atatus is not hiding external stacktrace lines, it is likely that the projectRoot is being incorrectly calculated. You can set projectRoot as part of the start call:

atatus.start({ apiKey: "YOUR_API_KEY", projectRoot: "/path/to/root" });
Adding tags

It is often very useful to send some extra info along with errors and performance metrics, so that you can filter them in the Atatus dashboard. To do this, you can set the tags:

atatus.start({ apiKey: "YOUR_API_KEY", tags: ['new-user', 'signup'] });
Custom data

To debug error effectively, you can also send some meta data along with errors. To do this, you can set the customData:

atatus.start({ apiKey: "YOUR_API_KEY", customData: { foo: 'bar', name: "John Doe" }});
Proxy

You can use a proxy server by configuring a proxy url when starting with atatus.

atatus.start({ apiKey: "YOUR_API_KEY", proxy: "http://localhost:8080" });
Hostname

By default we'll fetch the hostname using Node's os.hostname(), but you can override this as follows:

atatus.start({ apiKey: "YOUR_API_KEY", hostname: "web1.example.com" });
Before error send callback

If you want to modify error reports just before they are sent to Atatus, or prevent them from being sent, you can add before notify callback:

atatus.start({
  apiKey: "YOUR_API_KEY",
  beforeErrorSend: function (payload) {

    var errorMessage = payload.exceptions[0].message;

    // Dont send Not found message
    if (errorMessage.indexOf('Not Found') === 0) {
        return false;
    }

    return true;
  }
});
Send code

If you want to send code snippets for each frame of the stacktrace you can enable sendCode. This asynchronously loads any file from the stacktrace, which is within the scope of the project, and sends 3 lines either side of the erroneous line of code to Atatus.

This works almost the same as how Atatus JavaScript projects handle source maps - however loading the code is done on the local machine and sent over the internet with the error data. By default, this option is enabled. If you don't want, you can disable it.

atatus.start({ apiKey: "YOUR_API_KEY", sendCode: false });
Grouping key

If you need programmatical control over how the errors are grouped within atatus, you can send a groupingKey to the notify call. This will ensure that atatus groups all errors with the same groupingKey together.

atatus.start({ apiKey: "YOUR_API_KEY", groupingKey: function(payload) {
    // You can generate grouping based on error payload details
    // or send static grouping key for all errors
    return "auth/create";
  }
});
Send custom exceptions

Atatus automatically captures all unhandled exceptions and HTTP errors from your Node.js app. If you want to send error manually, you can do it by atatus.notifyError function. The accepts an error as either a string or an Error object as the first argument, as well as options object as its second parameter. The second parameter may contain tags, custom data and user id.

atatus.notifyError(new Error("Something went badly wrong"), {
  tags: ['new-user', 'signup'],
  customData: { name: 'John Doe', country: 'US' }
});
User tracking

A unique identifier for a user affected by this error. This could be any distinct identifier that makes sense for your application. This is automatically set to the ip address of the current request.

atatus.notifyError(new Error("Something went badly wrong"), { userId: "someone@example.com" });

Exclude URL

You can exclude particular transaction with excludeURL function.
Lets say you want to exclude URL starts with /v1/internal/, then you can do it as follows

var atatus = require("atatus-node");
atatus.excludeURL("/v1/internal");

The argument of the excludeURL function is a Regex pattern string. The URL that is matching the pattern will not be monitored.

Custom Instrumentation

Atatus APM automatically instruments all web requests. In case you want to instrument web sockets calls, background jobs, and unsupported databases, you need to use custom instrumentation as follows

//Example 1:
var atatus = require("atatus-node");
var txn = atatus.startTransaction("custom transaction name", function() {
    atatus.createLayer("custom layer name", function () {
        // Your code here.
        atatus.endTransaction();
    })();
});
txn();
//Example 2:
var atatus = require("atatus-node");
socket.on("message", atatus.startTransaction("new:chat-message", function (data) {
    addMessageToFirebase(data, function () {
      socket.emit("got the message");
      atatus.endTransaction();
    })
}));

Transaction timing consists of layers. Every transaction must have at-least one layer. Any database calls will be added automatically as layer to the transaction.

If you want to instrument an asynchronous function, you need to wrap the asynchronous function with createLayer().

queue.add(atatus.createLayer("add:notifications:channels", function (err, result) {
  if (err) {
    next(err);
  }
  res.json({ success: true, data: result });
}));
Document Sections