New Relic offers several tools to help obtain the information needed to provide useful metrics about your Node.js application. These include:
Reading the route names (if used) from the Express and Restify routers
Using the API to name the current request, either with simple names or groups of controllers with actions
Support rules that are stored in your agent's configuration that can mark requests to be renamed or ignored based on regular expressions matched against the request's raw URLs (also available as API calls)
The number of names that New Relic tracks needs to be small enough so that the user experience is robust. It also needs to be large enough to provide the right amount of information (without overwhelming you with data) so that you can identify problem spots in your applications more easily.
The Node.js agent captures the HTTP method along with a potentially parameterized path (such as /user/:id) or a regular expression (such as /^/user/([-0-9a-f]+)$/). These pieces of information become part of the request name.
If you have support for slow transaction traces and have added 'request.parameters.*' to attributes.include in your config file, the transaction trace will also have the request's parameters and their values attached. If you don't like the request names that the Node.js agent uses, you can use API calls to create more descriptive names.
Tip
If grouping your requests under the generic name, then /* is sufficient, and you do not need to customize your configuration file or API calls.
Requirements
New Relic uses request names to group requests for many charts and tables. The value of these visualizations will drop as the number of different request names increases.
For example, do not include potentially dynamic data like GUIDs, numerical IDs, or timestamps in the request names you create. If your request is slow enough to generate a transaction trace, that trace will contain the original URL. If you enable parameter capture, the parameters will also be attached to the trace.
Tip
Avoid having more than 50 different transaction names. For example, if you have more than a couple hundred different request names, rethink your naming strategy.
Avoid metric grouping issues
The request naming API helps New Relic avoid problems with trying to handle too many metrics, which sometimes is referred to as "metric explosion." New Relic has several strategies to deal with these issues; the most severe is simply to add offending applications to your deny list.
The main reason for you to be careful in using these request-naming tools is to prevent that from happening to your applications. For more information, see Metric grouping issues.
Guidelines
Define your configuration rules from the most specific to the most general. The first rules listed in your config file or added with the Node.js transaction naming API will be applied first and should be narrowly targeted. More general "fall-through" rules should be added toward the end of the list, because they will be evaluated in the order they were configured or added using the Node.js transaction naming API.
With these rules, the retailer would create three transaction names:
/user/customers/:customer
/user/customers/all
/user/customers/all/prospects
If the retailer reversed the order, the rules would catch all transactions in :customer, which would not be as useful.
Load the request naming API
Make sure that loading the New Relic module is the first thing your application does, as it needs to bootstrap itself before the rest of your application loads:
const newrelic =require('newrelic');
This returns the request naming API. You can safely require the module from multiple modules in your application, as it only initializes itself once.
Request API calls
Here is a summary of the Request API calls for New Relic's Node.js agent.
newrelic.setTransactionName(name)
Name the current request, following the request naming requirements. You can call this function anywhere within the context of an HTTP request handler, at any time after handling of the request has started, but before the request has finished. In general, if the request and response objects are in scope, you can set the name.
Explicitly calling newrelic.setTransactionName() will override any names set by Express or Restify routes. Also, calls to newrelic.setTransactionName() and newrelic.setControllerName() will overwrite each other. The last one to run before the request ends wins.
newrelic.setControllerName(name,[action])
Name the current request using a controller-style pattern, optionally including the current controller action. If the action is omitted, New Relic will include the HTTP method (GET, POST, etc.) as the action. The rules for when you can call newrelic.setControllerName() are the same as they are for newrelic.setTransactionName(), including the request naming requirements.
Explicitly calling newrelic.setControllerName() will override any names set by Express or Restify routes. Also, calls to newrelic.setTransactionName() and newrelic.setControllerName() will overwrite each other. The last one to run before the request ends wins.
Sets an instrumentation callback for a specific module.
The provided onRequire callback will be fired when the given module is loaded with require. The moduleName parameter should be the string that will be passed to require; for example, 'express' or 'amqplib/callback_api'. The optional onError callback is called if the onRequire parameters throws an error. This is useful for debugging your instrumentation.
Use this method to:
Add instrumentation for modules not currently instrumented by New Relic.
Instrument your own code.
Replace the Node.js agent's built-in instrumentation with your own.
This method is not supported or necessary in ES module applications, as agent bootstrapping in ES module applications is different than CommonJS applications.
In ES module applications, the agent is able to compensate for the issue this method solves for CommonJS applications.
The instrumentLoadedModule method allows you to add stock instrumentation to specific modules in situations where it's impossible to have require('newrelic'); as the first line of your app's main module.
// load the agent
const newrelic =require('newrelic');
// module loaded before newrelic
const expressModule =require('express');
// instrument express after the agent has been loaded
newrelic.instrumentLoadedModule(
'express',// the module's name, as a string
expressModule // the module instance
);
Important
This method cannot instrument any arbitrary module. Its purpose is to add modules that were missed because the agent was not loaded as the first thing in your program. The instrumentLoadedModule method can only instrument modules the agent would normally instrument. You can see a list of these modules in the agent's lib/instrumentations module.
Instrument the specified web transaction. Using this API call, you can instrument transactions that New Relic does not automatically detect.
The url defines the transaction name and needs to be static. Do not include variable data such as user ID.
The handle defines the function you want to instrument.
New Relic will capture any metrics that would be captured by auto-instrumentation, as well as manual instrumentation via startSegment().
You must handle custom transactions manually by calling newrelic.getTransaction() at the start of your transaction, and then call transaction.end() when you are finished. New Relic begins timing the transaction when newrelic.startWebTransaction() is called and ends the transaction when transaction.end() is called.
You can also return a promise to indicate the end of the transaction. Please note that if this promise rejects, it does not automatically hook into New Relic's error tracking. This needs to be done manually with noticeError().
The name defines the transaction name and needs to be static. Do not include variable data such as user ID.
The group is optional, and it allows you to group similar jobs together via the transaction type in the user interface. Like name, the group needs to be static.
The handle defines a function that includes the entire background job you want to instrument.
New Relic will capture any metrics that would be captured by auto-instrumentation, as well as manual instrumentation via startSegment().
You must handle custom transactions manually by calling newrelic.getTransaction() at the start of your transaction, and then call transaction.end() when you are finished. New Relic begins timing the transaction when newrelic.startBackgroundTransaction() is called and ends the transaction when transaction.end() is called.
You can also return a promise to indicate the end of the transaction. Please note that if this promise rejects, it does not automatically hook into New Relic’s error tracking. This needs to be done manually with noticeError().
newrelic.getTransaction()
Returns a handle on the currently executing transaction. This handle can then be used to interact with a given transaction safely from any context. It is best used with newrelic.startWebTransaction() and newrelic.startBackgroundTransaction().
End the current web or background custom transaction. This method requires being in the correct transaction context when called. This API call takes no arguments.
The name defines a name for the segment. This name will be visible in transaction traces and as a new metric in the New Relic UI.
The record flag defines whether the segment should be recorded as a metric.
The handler is the function you want to track as a segment.
The optional callback is a function passed to the handler to fire after its work is done.
The agent begins timing the segment when startSegment is called. The segment is ended when either the handler finishes executing, or callback is fired, if it is provided.
Use recordMetric to record an event-based metric, usually associated with a particular duration. The name must be a string following standard metric naming rules. The value will usually be a number, but it can also be an object.
When value is a numeric value, it should represent the magnitude of a measurement associated with an event; for example, the duration for a particular method call.
When value is an object, it must contain count, total, min, max, and sumOfSquares keys, all with number values. This form is useful to aggregate metrics on your own and report them periodically; for example, from a setInterval. These values will be aggregated with any previously collected values for the same metric. The names of these keys match the names of the keys used by the platform API.
newrelic.incrementMetric(name,[amount])
Use incrementMetric to update a metric that acts as a simple counter. The count of the selected metric will be incremented by the specified amount, defaulting to 1.
Custom events API calls
Use these API calls to record additional events:
newrelic.recordCustomEvent(eventType, attributes)
Use recordCustomEvent to record an event-based metric, usually associated with a particular duration.
The eventType must be an alphanumeric string less than 255 characters.
The attributes must be an object of key and value pairs. The keys must be shorter than 255 characters, and the values must be string, number, or boolean.
The following example demonstrates recording a custom event with multiple attributes.
Use recordLogEvent to record a log event, in case that automatic logging instrumentation is insufficient for your logging framework. Consult the auto-generated documentation for the details of the parameter types accepted.
The following example demonstrates recording a log event associated to an error.
transactionHandle.insertDistributedTraceHeaders is used to implement distributed tracing. It modifies the headers map that is passed in by adding W3C Trace Context headers and New Relic Distributed Trace headers. The New Relic headers can be disabled with distributed_tracing.exclude_newrelic_header: true in the config. This method replaces the deprecated createDistributedTracePayload method, which only creates New Relic Distributed Trace payloads.
In the following example, by calling insertDistributedTraceHeaders with an empty object, the appropriate Distributed Trace headers and W3C Trace Context headers will be generated for the transaction.
// Call newrelic.getTransaction to retrieve a handle on the current transaction.
transactionHandle.acceptDistributedTraceHeaders is used to instrument the called service for inclusion in a distributed trace. It links the spans in a trace by accepting a payload generated by insertDistributedTraceHeaders or generated by some other W3C Trace Context compliant tracer. This method accepts the headers of an incoming request, looks for W3C Trace Context headers, and if not found, falls back to New Relic distributed trace headers. This method replaces the deprecated (and now removed as of version 7.0.0) acceptDistributedTracePayload method, which only handles New Relic distributed trace payloads.
transportType should be one of the following strings:
AMQP
HTTP
HTTPS
IronMQ
JMS
Kafka
Other
Queue
Unknown
headers should be an object containing all the headers in the incoming request. The keys must be lowercase.
The following example demonstrates adding distributed trace headers retrieved from a Kafka message. In this example, we assume that the incoming Kafka message has Distributed Trace headers inserted.
// incoming Kafka message headers
const headersObject = message.headers;
// Call newrelic.getTransaction to retrieve a handle on the current transaction.
This call is used to implement distributed tracing. It generates a payload that is read by the receiving application with acceptDistributedTracePayload.
Important
Note: In order to maintain proper ordering of spans in a trace, you must generate the payload in the context of the span that sends it.
The DistributedTracePayload object has two available methods used for generating the payload in different formats:
DistributedTracePayload#text: returns a JSON representation of the payload.
// Call newrelic.getTransaction to retrieve a handle on the current transaction.
var transactionHandle = newrelic.getTransaction();
var payload = transactionHandle.createDistributedTracePayload();
transactionHandle.acceptDistributedTracePayload is used to instrument the called service for inclusion in a distributed trace. It links the spans in a trace by accepting the payload generated by createDistributedTracePayload.
transactionHandle.isSampled()
Returns whether this trace is being sampled.
Other API calls
New Relic's Node.js agent includes additional API calls.
newrelic.addCustomAttribute(name, value)
Set a custom attribute value to be displayed along with the transaction trace in the New Relic UI. This must be called within the context of a transaction so it has a place to set the custom attributes. Custom attributes will appear in APM's transaction trace detail view and in errors for the transaction.
If you want to use your custom attributes, avoid using any of the reserved terms used by NRQL when naming them.
newrelic.addCustomAttributes(attributes)
Set multiple custom attribute values to be displayed along with the transaction trace in the New Relic UI. The attributes should be passed as a single object. This must be called within the context of a transaction so it has a place to set the custom attributes. Custom attributes will appear in the transaction trace detail view and in errors for the transaction.
const attributes ={
attribute1:'value1',
attribute2:2
};
newrelic.addCustomAttributes(attributes);
Caution
If you want to use your custom attributes, avoid using any of the reserved terms used by NRQL when naming them.
newrelic.addCustomSpanAttribute(name, value)
Set a custom span attribute value to be displayed along with a transaction trace span in the New Relic UI. This must be called within the context of an active segment/span so it has a place to set the custom span attributes. Custom span attributes will appear in the Attributes section of the span detail view.
If you want to use your custom span attributes, avoid using any of the reserved terms used by NRQL when naming them.
newrelic.addCustomSpanAttributes(attributes)
Set multiple custom span attribute values to be displayed along with the transaction trace spans in the New Relic UI. The attributes should be passed as a single object. This must be called within the context of an active segment/span so it has a place to set the custom span attributes. Custom span attributes will appear in the Attributes section of the span detail view.
If you want to use your custom span attributes, avoid using any of the reserved terms used by NRQL when naming them.
newrelic.getBrowserTimingHeader()
Returns the HTML snippet to be inserted into the header of HTML pages to enable browser monitoring. The HTML will instruct the browser to fetch a small JavaScript file and start the page timer.
Use this call if your app is doing its own error handling with domains or try/catch clauses, but you want all of the information about how many errors are coming out of the app to be centrally managed. Unlike other Node.js calls, this can be used outside of route handlers, but it will have additional context if called from within transaction scope.
error should be an Error or one of its subtypes, but the API will handle strings and objects that have an attached .message or .stack property.
customAttributes is an optional object of any custom attributes to be displayed in the New Relic UI.
expected is an optional boolean to classify the error as an error you expect. If an error collected with noticeError is expected, it will be collected and reported, but will not affect Apdex or error rate metrics. By default, expected is false.
{extraInformation:"error already handled in the application"},
true
);
}
Caution
Errors recorded using this method do not obey the ignore_status_codes configuration value.
newrelic.setErrorGroupCallback(callback)
This method lets you define a custom callback to generate error group names, which will be used by errors inbox to group similar errors together via the error.group.name agent attribute.
Provided functions must return a string, and receive an object as an argument. The object contains information related to the error that occurred, and has the following format:
Tell the module whether or not to ignore a given request. This allows you to explicitly filter long-polling, irrelevant routes or requests you know will be time-consuming. This also allows you to gather metrics for requests that otherwise would be ignored.
To ignore the transaction, set the parameter to true: this will ignore the transaction.
To prevent a transaction from being ignored with this function, pass the parameter false.
Passing null or undefined will not change whether the transaction is ignored.
newrelic.setUserID(string)
This method gives you a way to associate a unique identifier with a transaction event, transaction trace and errors within transaction. A new property, enduser.id, will be added to the error and reported to errors inbox.
Use this method to gracefully shut down the agent, both parameters are optional. Here's an overview table showing the parameters:
Parameter
Type
Attributes
Description
options
object
Optional
Object with shut down options
callback
function
Optional
Callback function that runs when agent stops
Here is a detail table showing the object shutdown options:
Option name
Type
Attributes
Default
Description
collectPendingData
boolean
Optional
false
Tell the agent whether to send any pending data to the New Relic collector before shutting down.
timeout
number
Optional
0
The default time before forcing a shutdown. When collectPendingData is true, the agent will wait for a connection before shutting down. This timeout is useful for short lived processes, like AWS Lambda, in order to keep the process from staying open too long, while trying to connect.
waitForIdle
boolean
Optional
false
If true, the agent will not shut down until there are no active transactions.
If you do not want to put calls to the New Relic module directly into your application code, you can use pattern-based rules to name requests. There are two sets of rules: one for renaming requests, and one to mark requests to be ignored by New Relic's instrumentation.
Here is the structure for rules in New Relic's Node.js agent.
A list of rules of the format {pattern : "pattern", name : "name"} for matching incoming request URLs to pattern and naming the matching New Relic transaction's name. This acts as a regex replace, where you can set the pattern either as a string, or as a JavaScript regular expression literal, and both pattern and name are required.
When passing a regex as a string, escape backslashes, as the agent does not keep them when given as a string in a pattern. Define your configuration rules from the most specific to the most general, as the patterns will be evaluated in order and are terminal in nature. For more information, see the naming guidelines.
This can also be set with the environment variable NEW_RELIC_NAMING_RULES, with multiple rules passed in as a list of comma-delimited JSON object literals:
When set to true (default), no further rules will be evaluated if this rule is a match. Setting this to false is useful when multiple rules should be used together. For example, one rule could be replacing a common pattern in many different URLs, while subsequent rule(s) would be more specific.
replace_all
Default: false
When set to true, all matches of the pattern will be replaced. Otherwise, only the first match will be replaced. Using the g flag with regular expression literal will have the same effect. For example:
pattern: '[0-9]+',
replace_all: true
This has the same effect as pattern: /[0-9]+/g.
precedence
By default the rules are evaluated in order, from first to last. If you prefer to have complete control over the order, you can give each rule a precedence attribute. The precedence is an integer number, and rules are evaluated in ascending order. If precedence is not explicitly defined, it will be set to 500 by default.
Additional attributes are ignored.
Testing your naming rules
The Node.js agent comes with a command-line tool for testing naming rules. For more information, run the following command in terminal window in a directory where your app is installed:
bash
$
node node_modules/.bin/newrelic-naming-rules
Naming rule examples [#examples-rules]
Here are some examples of naming rules and the results.
pattern: "^/items/[0-9]+$",
name: "/items/:id"
will result in:
/items/123 => /items/:id
/orders/123 => /orders/123 (not replaced since the rule is a full match)
pattern: "[0-9]+",
name: ":id"
will result in:
/orders/123 => /orders/:id
/items/123 => /items/:id
/orders/123/items/123 => /orders/:id/items/123
pattern: "[0-9]+",
name: ":id",
replace_all: true
will result in:
/orders/123/items/123 => /orders/:id/items/:id
Using regular expression match group references:
pattern: '^/(items|orders)/[0-9]+$',
name: '/\\1/:id'
will result in:
/orders/123 => /orders/:id
/items/123 => /items/:id
This can also be set via the environment variable NEW_RELIC_IGNORING_RULES, with multiple rules passed in as a list of comma-delimited patterns. Currently there is no way to escape commas in patterns.
If you are using socket.io, you will have a use case for ignoring rules right out of the box. To keep socket.io long-polling from dominating your response-time metrics and affecting the Apdex metrics for your application, add a rule such as:
// newrelic.js
exports.config={
// other configuration
rules:{
ignore:[
'^\/socket\.io\/.*\/xhr-polling'
]
}
};
API calls for rules
Here are the API calls for naming and ignoring rules with New Relic's Node.js agent.
Programmatic version of rules.name. Once naming rules are added, they cannot be removed until the Node.js process is restarted. They can also be added via the Node.js agent's configuration. Both parameters are required.
Programmatic version of rules.ignore. Once ignoring rules are added, they cannot be removed until the Node.js process is restarted. They can also be added via the Node.js agent's configuration. This parameter is required.