Wondering what’s next for npm?Check out our public roadmap! »

raygun-apm

0.14.0 • Public • Published

raygun-apm

raygun-apm is a module that can capture and send data about your application's performance to Raygun APM via your local Raygun Agent.

It works by using the V8 profiler API to sample the call stack while the application is running. This is the same approach used by Chrome's dev tools.

raygun-apm also supports request level profiling of web servers. This means that even though Node web applications generally run concurrently on a single thread, raygun-apm will generate traces that only include stack samples from a single request.

Setup

Node Support

The minimum supported Node versions are:

  • v8.12.x
  • v9.6.x
  • v10.x
  • v11.x
  • v12.x
  • v13.x
  • v14.x

Node v8 and v9 are no longer officially supported by the Node.js foundation. We maintain legacy support, but recommend updating to Node 10.x or later.

Additionally, the minimum supported Node versions for profiling worker threads are:

  • v12.17.x
  • v13.13.x
  • v14.x

Building native dependencies (v8-profiler-node8)

Since Raygun uses a native module for v8 profiler bindings, you may need to be able to build native modules to install if a prebuilt binary is not available.

  • Windows: Install the windows-build-tools package (run npm install --global windows-build-tools from an Administrator PowerShell)
  • macOS: Install the Xcode Command Line Tools package (run xcode-select --install) if you haven't already. You may need to install Python (>=v2.7 or >=v3.5) if using macOS 11 (Big Sur) or later.
  • Unix: Ensure Python (>=v2.7 or >=v3.5), make and gcc are installed via your preferred package manager.

For more detailed information on building native modules, please consult the node-gyp documentation.

Please note, when changing Node versions, you may need to run npm rebuild raygun-apm to ensure the correct versions of the native dependencies are installed.

Install package from npm

npm install raygun-apm --save

or

yarn add raygun-apm

Install and run Raygun APM Agent

To send traces to Raygun there must be a Raygun APM Agent installed and running, either locally or on another machine. If you haven't already done so, follow the instructions on the Raygun website to install and run the Agent.

If your application runs on Heroku, you can use the heroku-buildpack-raygun-apm which will run an agent on your web dynos automatically.

Usage

Profiling web server requests

raygun-apm can profile requests to node http and https servers. To enable request level profiling, add this require statement at the start of your main js file.

require('raygun-apm/http');

You can also use import if you are using TypeScript or Babel.

import 'raygun-apm/http';

raygun-apm also ships with a cross platform helper script called with-raygun-apm that will configure Node to load raygun-apm/http at startup. This can be helpful if you're working with a framework that launches your app for you.

On the command line:

node_modules/.bin/with-raygun-apm node index.js

Or in a package.json script:

"scripts"{
  "start": "with-raygun-apm node index.js"
},

The HTTP/HTTPS request profiling support works by wrapping around the node standard library http/https modules, which also means that it works out of the box with express, koa, hapi, sails, adonis, loopback, micro and most node http frameworks.

Here is an example of a simple app that uses express and node-pg:

import 'raygun-apm/http';
 
import express from 'express';
import {Client} from 'pg';
 
const app = express();
 
const client = new Client()
client.connect()
 
app.get('/', (req, res) => {
  client.query("SELECT * FROM test_data", [], (err, pgRes) => {
    res.send(JSON.stringify(pgRes.rows));
  });
});
 
app.listen(3030, 'localhost', () => console.log('listening on 3030'));

Capturing database queries

raygun-apm supports automatically capturing database queries from these adapters:

  • pg
  • mysql
  • mysql2
  • mssql
  • mongodb
  • redis
  • ioredis
  • @elasticsearch/elastic
  • memcached
  • sequelize (when used with a supported adapter)

require-in-the-middle is used to wrap around these libraries when they are imported.

This is necessary to detect when queries start and end, and in some cases to wrap processing of the results of a query in an asynchronous context that's associated with the original request.

When installing raygun-apm, if npm scripts are enabled for packages, raygun-apm will inspect your project's dependencies and warn you if a version of a dependency is known to be incompatible.

Please let us know if there's another database adapter or library you'd like supported.

Performance

raygun-apm introduces a performance overhead to your application, due to the use of v8's CPU profiler and the Node async_hooks module to capture APM information. As such, using raygun-apm in production can cause noticeable slowdown to application code.

This is similar to how a web application behaves when capturing a CPU profile in Chrome. Our current benchmarks suggest this overhead is currently around 30%, although we're constantly endeavouring to reduce the performance impact of raygun-apm.

Limitations

raygun-apm uses v8's CpuProfiler (via v8-profiler-node8) to sample the callstack in order to build traces. This is the same approach used by Chrome's developer tools.

v8's CpuProfiler is a sampling profiler, which means that it captures the callstack at a regular interval. By default, a callstack is captured approximately every 1 millisecond, or a thousand times a second.

As a result, there are a few limitations:

  • Functions that take less than 1ms to run might not appear in the trace.
  • The start/end timings for each stack frame are only accurate to ±1ms.
  • As v8's JIT compiler optimizes your code at runtime, traces may appear to lose detail.
  • As a result of all of the above, multiple traces for the same code may contain slightly different details.
  • By default, raygun-apm communicates with the Raygun agent via UDP. As a result, some traces may fail to process due to network conditions.

It's worth noting that all of these limitations apply primarily to code that is executing so fast that it cannot be profiled without introducing a significant overhead. As such, these limitations should have minimal impact when investigating code that takes more than a few millisecond to run.

Configuration

You can set the following environment variables to control the behaviour of the profiler.

RAYGUN_AGENT_HOST

  • defaults to 0.0.0.0

Used to configure the hostname for the Raygun Agent that traces will be sent to.

RAYGUN_AGENT_PORT

  • defaults to 2799

Used to configure the port for the Raygun Agent that traces will be sent to.

RAYGUN_API_KEY

  • not set by default
  • can also be set via Raygun_ApiKey

Used to configure the key the process will use to submit traces to Raygun. This can be used to support multiple apps running on one machine using different keys. If no key is set, the Raygun agent will use the key it has been configured with.

Please note: RAYGUN_API_KEY must be set in order for an application's sampling rules to be applied. Otherwise, the APM agent will use the default sampling settings. This applies to both sampling frequency and any overrides applied via the Raygun website.

RAYGUN_APM_OVERRIDES_PATH

  • not set by default
  • can also be set via PROTON_USER_OVERRIDES_FILE

Used to specify the path to an overrides file. See the Overrides section below for details.

RAYGUN_APM_DISABLE_PROFILING

  • defaults to false

If set to t or true, http servers will no longer be automatically instrumented when raygun-apm/http is loaded, and requiring raygun-apm directly will return a mock makeProfiler that does not capture profiles.

This allows for profiling to be disabled or enabled without requiring any code changes. This is useful when you want to deploy your production application with raygun-apm installed, but only enable it when investigating a performance issue.

Please node that requiring internal profile modules could still activate internal APM logic even when this option is active. As such, requiring internal profiler modules is discouraged.

RAYGUN_APM_SAMPLING_FREQUENCY

  • defaults to 1000 (microseconds)

RAYGUN_APM_SAMPLING_FREQUENCY can be set to change how often stack samples are captured by v8's profiler. Setting a value lower than the default 1000 will include more detail in traces, at the expense of additional overhead. Increasing the value beyond 1000 will causes traces to contain less detail, but will reduce the performance overhead of the v8 profiler.

This variable only supports integer values.

RAYGUN_APM_CONCURRENT_PROFILE_LIMIT

  • defaults to 2

This environment variable can be used to control the number of concurrent profiles that will be capturing and processing at one time. Increasing this number will capture more concurrent profiles at the cost of additional performance overhead.

RAYGUN_APM_FEATURE_LEVEL

  • defaults to stable

If RAYGUN_APM_FEATURE_LEVEL is set to experimental, all feature flags for experimental features will be enabled. If unset or set to anything else, the feature level will default to stable.

RAYGUN_APM_WORKER_PROFILING

  • defaults to true

By default, the worker_threads module will be patched to enable worker thread profiling. When a worker is created by code that is being profiled, or sent a message by code that is being profiled, the worker will be profiled until the main thread profile completes.

If set to f or false this patch will be disabled and workers will operate as normal without profiling support.

There should be no behavioural changes to the Worker class, although there is a small delay (1-2ms) when first starting the profile for the worker, as we ensure the profile is running before allowing the worker to receive the user's message.

The minimum Node versions needed for worker profiling support are:

  • Node v12.17.x
  • Node v13.13x
  • Node v14.x

This is because raygun-apm relies on a Node patch that allows transferring a separate message port on worker initialization, which we use to allow a channel of APM communications that doesn't interfere with end user messages.

RAYGUN_APM_PROFILE_TIMEOUT

  • defaults to 60000 (60 seconds)

This environment variable controls how long a profile will capture for before timing out. This value is in milliseconds, and defaults to 60000, or 60 seconds.

If a profile is timed out, a message will be logged showing which exit points were still pending. This can help to debug long running queries or external resources, but also might be indicative of a bug in raygun-apm's exit point system. If you're unsure, please contact support.

RAYGUN_APM_FILE_TRANSPORT

  • defaults to false

If this environment variable is set to true, the Shared File/Shared Memory transport will be used instead of the default UDP transport. This causes raygun-apm to open a shared file and memory mapping for communication with the agent, which can be useful in environments where it's not viable to connect to the agent over UDP.

In order for traces to be submitted successfully the APM agent also needs to be running in the Shared File/Shared Memory communication mode.

This mode is automatically enabled when the agent is running on Azure, but can also be explicitly enabled by creating an appsettings.json file in the agent install directory with NetworkTransmissionMode set to File.

{
  "Agent": {
    "NetworkTransmissionMode": "File"
  }
}

RAYGUN_APM_FILE_TRANSPORT_PATH

  • not set by default

If RAYGUN_APM_FILE_TRANSPORT_PATH is enabled, this environment variable can be used to control which directory shared files will be created in. If unset, the path defaults to %ProgramData\Raygun\CommandStream.

RAYGUN_APM_DISABLE_STACK_SIMPLIFICATION

  • defaults to false

If this environment variable is set to true or t, the profiler's stack simplification logic will be disabled.

By default, stack simplification means that consecutive system frames and consecutive frames from the same library are collapsed, which helps to make traces smaller and easier to understand. If you find you need more detail in your traces around system and library behaviour, consider disabling stack simplification.

RAYGUN_APM_INCLUDE_INTERNALS

  • defaults to false

If this environment variable is set to to true or t, internal Node frames, async hooks frame and frames from the profiler itself will be included in traces.

This can add a lot of noise to traces, so it's disabled by default.

RAYGUN_APM_DISABLE_ASYNC_HOOKS

  • defaults to false

In order to separate the execution of multiple parallel requests into distinct traces, raygun-apm uses the async_hooks module from the Node standard library to track the asynchronous contexts used by an application and it's libraries.

async_hooks provides critical information required to implement request level profiling, but that comes at the cost of performance overhead. Depending on your Node version and the type of work an application is performing, this overhead can be significant.

The use of async_hooks can be disabled by setting RAYGUN_APM_DISABLE_ASYNC_HOOKS to true. While this will decrease performance overhead, please note that the following limitations apply:

  • Traces will now contain stack samples from all requests occuring over that time span
  • Database queries, http requests and worker activity may not be correctly attributed to a trace
  • Traces may not be extended by timers and effects
  • Exceptions from raygun4node may not be attached to traces

With that in mind, this setting is not recommended for most users. This setting is primarily useful when evaluating the tradeoff of functionality versus performance overhead that comes from using async_hooks.

Please note that the profiler will continue to use executionAsyncId and triggerAsyncId from async_hooks even when this setting is turned on, as these are populated by Node regardless of whether custom async_hooks logic has been enabled.

DEBUG

  • if set to raygun-apm, detailed debug logging will be printed

Overrides

You can configure the profiler to exclude certain files and functions from the traces that are collected.

You can provide an overrides file to the profiler by setting the PROTON_USER_OVERRIDES_FILE environment variable to a path pointing to an overrides file.

Each line should start with a - or + sign to indicate if the line should be ignored or included. The rest of the line is matched against the start of each file/function name in the trace, using a : to separate the file name and function name.

An overrides file might look like this:

# Ignore an entire directory
-node_modules

# Except for a specific sub-directory
+node_modules/pg

# Ignore a specific function
-app/utils.js:authenticate

# Ignore all but a specific function in a file
-app/middleware.js
+app/middleware.js:loadFile

This means you can provide anything from a partial path to a fully specified filename and function name.

If the path is not absolute, it will be considered to be relative to the current working directory of the process.

You can also ignore or allow Node internals, by prefixing the path with a !.

For example, to remove many of the system frames present in a typical web application, you could add these lines to your overrides file:

-!internal/stream_base_commons.js
-!_stream_readable.js
-!_stream_writeable.js
-!events.js

API

You can profile sections of code directly by using the profiler API.

import { makeProfiler } from 'raygun-apm';

function makeProfiler(host?: string, port?: number): Profiler

Optionally takes a host and a port and returns a Profiler. If the host or port are omitted, they will default to the RAYGUN_AGENT_HOST/RAYGUN_AGENT_PORT environment variables or 0.0.0.0:2799.

Profiler

runProfile(f: (done: () => void) => void): Promise<void>

Takes a function to profile. A done callback is passed to the profile function, which should be called when the profiler should be stopped.

import { makeProfiler } from 'raygun-apm';
 
const profiler = makeProfiler();
 
profiler.runProfile((done) => {
  fetch('google.com').then(() => {
    console.log('Do some work...');
    done();
  });
});

Returns a promise that resolves when the profile has been captured.

stop(): Promise<void>

Stops the profiler. Closes the UDP socket and disables async_hooks.

The profiler will attempt to finish processing any already captured profiles but this is not guaranteed.

Returns a promise that resolves after the profiler has stopped.

Keywords

none

Install

npm i raygun-apm

DownloadsWeekly Downloads

1,011

Version

0.14.0

License

MIT

Unpacked Size

504 kB

Total Files

291

Last publish

Collaborators

  • avatar
  • avatar