This package provides tracing to Node.js applications for the collection of distributed tracing and performance metrics in Epsagon.
To install Epsagon, simply run:
npm install epsagon
Important: Epsagon is activated and instruments the supported libraries once the module is imported.
The simplest way to get started in some frameworks is to install epsagon-frameworks
:
npm install epsagon-frameworks
epsagon-frameworks
extends the base epsagon
support to more frameworks.
And run your node command:
export EPSAGON_TOKEN=<epsagon-token>
export EPSAGON_APP_NAME=<app-name-stage>
export EPSAGON_METADATA=FALSE
export NODE_OPTIONS='-r epsagon-frameworks'
<node command>
For example:
export EPSAGON_TOKEN=<your-token>
export EPSAGON_APP_NAME=express-prod
export EPSAGON_METADATA=FALSE
export NODE_OPTIONS='-r epsagon-frameworks'
node app.js
When using inside a Dockerfile
, you can use ENV
instead of export
.
You can see the list of auto-tracing supported frameworks
Another simple alternative is to copy the snippet into your code:
const epsagon = require('epsagon-frameworks');
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
metadataOnly: false,
sendBatch: false,
});
To run on your framework please refer to supported frameworks
You can add custom tags to your traces, for easier filtering and aggregations.
Add the following call inside your code:
epsagon.label('key', 'value');
epsagon.label('userId', userId);
You can also use it to ship custom metrics:
epsagon.label('key', 'metric')
epsagon.label('itemsInCart', itemsInCart)
You can also set global labels as part of the Epsagon initialisation:
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
labels: [['key', 'value'], ['userId', userId]],
});
Valid types are string
, boolean
and number
.
In some frameworks tagging can be done in different ways.
You can set a trace as an error (although handled correctly) to get an alert or just follow it on the dashboard.
Add the following call inside your code:
try {
// something bad happens
} catch (err) {
epsagon.setError(err);
}
// or manually specify Error object
epsagon.setError(Error('My custom error'));
This API allows you to flag the trace with a warning and also enables more flexible alerting
Add the following call inside your code:
try {
// something bad happens
} catch (err) {
epsagon.setWarning(err);
}
// Or manually specify Error object
epsagon.setWarning(Error('My custom error'));
In some frameworks custom errors can be declared in different ways.
You can pass a list of sensitive properties and hostnames and they will be filtered out from the traces:
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
metadataOnly: false,
ignoredKeys: ['password', /.*_token$/],
ignoredDBTables: ['users', /.*password$/],
urlPatternsToIgnore: ['example.com', 'auth.com'],
});
The ignoredKeys
property can contain strings (will perform a loose match, so that First Name
also matches first_name
), regular expressions, and predicate functions.
ignoredDBTables
works similary, except will ignore response rows from DB queries.
Also, you can set urlPatternsToIgnore
to ignore HTTP calls to specific domains.
You can ignore certain incoming requests by specifying endpoints:
epsagon.ignoreEndpoints(['/healthcheck'])
You can get the Epsagon dashboard URL for the current trace, using the following:
# Inside some endpoint or function
console.log('Epsagon trace URL:', epsagon.getTraceUrl())
This can be useful to have an easy access the trace from different platforms.
The following frameworks are supported by Epsagon.
Some require installing also epsagon-frameworks
Framework | Supported Version | Epsagon Library | Auto-tracing Supported |
---|---|---|---|
AWS Lambda | All | epsagon |
|
Step Functions | All | epsagon |
|
OpenWhisk Action | All | epsagon |
|
Google Cloud Function | All | epsagon |
|
AWS Batch | All | epsagon |
|
Generic | All | epsagon |
|
Express | >=3.0.0 |
epsagon-frameworks |
|
Hapi | >=17.0.0 |
epsagon-frameworks |
|
Koa | >=1.1.0 |
epsagon-frameworks |
|
WS (Websocket) | >=7.3.1 |
epsagon-frameworks |
|
restify | >=7.0.0 |
epsagon-frameworks |
|
fastify | >=3.0.0 |
epsagon-frameworks |
|
KafkaJS | >=1.2.0 |
epsagon-frameworks |
|
kafka-node | >=3.0.0 |
epsagon-frameworks |
|
PubSub | >=1.1.0 |
epsagon-frameworks |
|
SQS Consumer | >=4.0.0 |
epsagon-frameworks |
|
amqplib | >=0.5.0 |
epsagon-frameworks |
|
bunnybus | >=7.0.0 |
epsagon-frameworks |
|
NATS | >=1.4.0 |
epsagon-frameworks |
Tracing Lambda functions can be done in three methods:
- Auto-tracing through the Epsagon dashboard.
- Using the
serverless-plugin-epsagon
if you're using The Serverless Framework. - Calling the SDK.
Make sure to choose just one of the methods
Calling the SDK is simple:
const epsagon = require('epsagon');
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
metadataOnly: false,
});
// Wrap your entry point
module.exports.handler = epsagon.lambdaWrapper((event, context, callback) => {
// Your code is here
});
// Async functions example
module.exports.handler = epsagon.lambdaWrapper(async (event) => {
// Your code is here
});
Tracing Step Functions is similar to regular Lambda functions, but the wrapper changes from lambdaWrapper
to stepLambdaWrapper
:
const epsagon = require('epsagon');
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
metadataOnly: false,
});
// Wrap your entry point
module.exports.handler = epsagon.stepLambdaWrapper((event, context, callback) => {
// Your code is here
});
// Async functions example
module.exports.handler = epsagon.stepLambdaWrapper(async (event) => {
// Your code is here
});
ECS Step - You should pass Epsagon step_dict id from ECS state input into EPSAGON_STEPS_ID
environment variables of the container, EPSAGON_STEPS_NUM
is the step number of the ECS (default: 0). check the configuration section.
You should pass the Epsagon token to your action as a default parameter, so that you don't have to expose important credentials in your code.
The name of the parameter can be configured using token_param
, in this example we use epsagon-token
:
const epsagon = require('epsagon');
function main(params) {
// Your code is here
}
module.exports.main = epsagon.openWhiskWrapper(
main,
{
token_param: 'epsagon-token', // name of the action parameter to take the token from
appName: 'app-name-stage',
metadataOnly: false
}
);
Tracing Google Cloud Functions by wrapping your entry point with the epsagon.googleCloudFunctionWrapper
:
const epsagon = require('epsagon');
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
metadataOnly: false,
sendBatch: false,
});
// Wrap your entry point
exports.helloWorld = epsagon.googleCloudFunctionWrapper((req, res) => {
res.status(200).send('hello world');
});
Tracing batch jobs running in AWS Batch can be done by calling epsagon.wrapBatchJob()
at the main handler/entrypoint of the code:
const epsagon = require('epsagon');
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
metadataOnly: false,
labels: [["key", "value"]],
traceCollectorURL: "https://eu-central-1.tc.epsagon.com" // default region is us-east-1
});
epsagon.wrapBatchJob();
function process(params) {
try {
// your code here
} catch (error) {
// some other code here
process.exitCode = 1; //exits gracefully
}
}
Tracing Express application can be done in two methods:
- Auto-tracing using the environment variable.
- Calling the SDK.
Calling the SDK is simple, and should be done in your main js
file where the application is being initialized:
const epsagon = require('epsagon-frameworks');
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
metadataOnly: false,
});
Tagging traces or setting custom errors can be by:
app.get('/', (req, res) => {
req.epsagon.label('key', 'value');
req.epsagon.setError(Error('My custom error'));
}
Tracing Hapi application can be done in two methods:
- Auto-tracing using the environment variable.
- Calling the SDK.
Calling the SDK is simple, and should be done in your main js
file where the application is being initialized:
const epsagon = require('epsagon-frameworks');
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
metadataOnly: false,
});
Tagging traces or setting custom errors can be by:
server.route({
method: 'GET',
path:'/',
handler: (request, h) => {
request.epsagon.label('key', 'value');
request.epsagon.setError(Error('My custom error'));
}
});
Tracing Koa application can be done in two methods:
- Auto-tracing using the environment variable.
- Calling the SDK.
Calling the SDK is simple, and should be done in your main js
file where the application is being initialized:
const epsagon = require('epsagon-frameworks');
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
metadataOnly: false,
});
Tagging traces or setting custom errors can be by:
app.use(async ctx => {
ctx.epsagon.label('key', 'value');
ctx.epsagon.setError(Error('My custom error'));
});
Tracing ws
consumers can be done in two methods:
- Auto-tracing using the environment variable.
- Calling the SDK.
Calling the SDK is simple, and should be done in your main js
file where the consumer is being initialized:
const epsagon = require('epsagon-frameworks');
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
metadataOnly: false,
});
Tagging traces or setting custom errors can be by:
socket.on('message', (message) => {
message.epsagon.label('key', 'value');
message.epsagon.setError(Error('My custom error'));
})
Tracing restify application can be done in two methods:
- Auto-tracing using the environment variable.
- Calling the SDK.
Calling the SDK is simple, and should be done in your main js
file where the application is being initialized:
const epsagon = require('epsagon-frameworks');
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
metadataOnly: false,
});
Tagging traces or setting custom errors can be by:
function respond(req, res, next) {
req.epsagon.label('key', 'value');
req.epsagon.setError(Error('My custom error'));
}
Tracing fastify application can be done in two methods:
- Auto-tracing using the environment variable.
- Calling the SDK.
Calling the SDK is simple, and should be done in your main js
file where the application is being initialized:
const epsagon = require('epsagon-frameworks');
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
metadataOnly: false,
});
Tagging traces or setting custom errors can be by:
fastify.get('/', (request, reply) => {
request.epsagon.label('key', 'value');
request.epsagon.setError(Error('My custom error'));
reply.send({ hello: 'world' })
})
Tracing kafkajs
consumers can be done in two methods:
- Auto-tracing using the environment variable.
- Calling the SDK.
Calling the SDK is simple, and should be done in your main js
file where the consumer is being initialized:
const epsagon = require('epsagon-frameworks');
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
metadataOnly: false,
});
Tagging traces or setting custom errors can be by:
await consumer.run({
eachMessage: async ({ topic, partition, message }) => {
message.epsagon.label('key', 'value');
message.epsagon.setError(Error('My custom error'));
},
})
Tracing kafka0node
consumers can be done in two methods:
- Auto-tracing using the environment variable.
- Calling the SDK.
Calling the SDK is simple, and should be done in your main js
file where the consumer is being initialized:
const epsagon = require('epsagon-frameworks');
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
metadataOnly: false,
});
Tagging traces or setting custom errors can be by:
consumer.on('message', function (message) {
message.epsagon.label('key', 'value');
message.epsagon.setError(Error('My custom error'));
})
Tracing @google-cloud/pubsub
consumers can be done in two methods:
- Auto-tracing using the environment variable.
- Calling the SDK.
Calling the SDK is simple, and should be done in your main js
file where the consumer is being initialized:
const epsagon = require('epsagon-frameworks');
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
metadataOnly: false,
});
Tagging traces or setting custom errors can be by:
await consumer.run({
eachMessage: async ({ topic, partition, message }) => {
message.epsagon.label('key', 'value');
message.epsagon.setError(Error('My custom error'));
},
})
Tracing sqs-consumer
consumers can be done in two methods:
- Auto-tracing using the environment variable.
- Calling the SDK.
Calling the SDK is simple, and should be done in your main js
file where the consumer is being initialized:
const epsagon = require('epsagon-frameworks');
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
metadataOnly: false,
});
Tagging traces or setting custom errors can be by:
const messageHandler = message => {
message.epsagon.label('key', 'value');
message.epsagon.setError(Error('My custom error'));
};
Or in batch message handler:
const batchMessageHandler = messages => {
messages[0].epsagon.label('key', 'value');
messages[0].epsagon.setError(Error('My custom error'));
};
Tracing amqplib consumers can be done in two methods:
- Auto-tracing using the environment variable.
- Calling the SDK.
Calling the SDK is simple, and should be done in your main js
file where the consumer is being initialized:
const epsagon = require('epsagon-frameworks');
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
metadataOnly: false,
});
Tagging traces or setting custom errors can be by:
ch.consume(q, function cons(msg) {
if (msg !== null) {
msg.epsagon.label('key', 'value');
msg.epsagon.setError(Error('My custom error'));
ch.ack(msg);
}
});
Tracing bunnybus consumers can be done in two methods:
- Auto-tracing using the environment variable.
- Calling the SDK.
Calling the SDK is simple, and should be done in your main js
file where the consumer is being initialized:
const epsagon = require('epsagon-frameworks');
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
metadataOnly: false,
});
Tagging traces or setting custom errors can be by:
// epsagon is added as an argument to the handler
handler: async ({message, metaData, ack, rej, requeue, epsagon}) => {
epsagon.label('key', 'value');
epsagon.setError(Error('My custom error'));
await ack();
}
Tracing nats
consumers can be done in two methods:
- Auto-tracing using the environment variable.
- Calling the SDK.
Calling the SDK is simple, and should be done in your main js
file where the consumer is being initialized:
const epsagon = require('epsagon-frameworks');
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
metadataOnly: false,
});
For any tracing, you can simply use the generic Epsagon wrapper using the following example:
const epsagon = require('epsagon');
epsagon.init({
token: 'epsagon-token',
appName: 'app-name-stage',
metadataOnly: false,
});
function main(params) {
// Your code is here
}
const wrappedMain = epsagon.nodeWrapper(main);
Epsagon provides out-of-the-box instrumentation (tracing) for many popular frameworks and libraries.
Library | Supported Version |
---|---|
http | Fully supported |
https | Fully supported |
http2 | Fully supported |
dns | Fully supported |
fs | Fully supported |
aws-sdk | >=2.2.0 |
amazon-dax-client | >=1.0.2 |
@google-cloud | >=2.0.0 |
@google-cloud/pubsub | >=1.1.0 |
mysql | >=2 |
mysql2 | >=1 |
pg | >=4 |
mongodb | >=2.2.12 |
kafkajs | >=1.2.0 |
kafka-node | >=3.0.0 |
amqplib | >=0.5.0 |
amqp | >=0.2.0 |
redis | >=0.12.1 |
ioredis | >=4.0.0 |
cassandra-driver | >=3.3.0 |
mqtt | >=2.13.1 |
nats | >=1.4.0 |
openwhisk | >=3.0.0 |
@azure/cosmos | >=3.7.5 |
@azure/storage-blob | >=12.2.0 |
ldapjs | >=2.1.0 |
ws | >=7.3.1 |
pino | >=6.0.0 |
bunyan | >=1.8.0 |
winston | >=2.4.5 |
Advanced options can be configured as a parameter to the init() method or as environment variables.
Parameter | Environment Variable | Type | Default | Description |
---|---|---|---|---|
token | EPSAGON_TOKEN | String | - | Epsagon account token |
appName | EPSAGON_APP_NAME | String | Application |
Application name that will be set for traces |
metadataOnly | EPSAGON_METADATA | Boolean | true |
Whether to send only the metadata (true ) or also the payloads (false ) |
useSSL | EPSAGON_SSL | Boolean | true |
Whether to send the traces over HTTPS SSL or not |
traceCollectorURL | EPSAGON_COLLECTOR_URL | String | - | The address of the trace collector to send trace to |
isEpsagonDisabled | DISABLE_EPSAGON | Boolean | false |
A flag to completely disable Epsagon (can be used for tests or locally) |
ignoredKeys | EPSAGON_IGNORED_KEYS | Array | - | Array of keys names (can be string or regex) to be removed from the trace |
ignoredDBTables | EPSAGON_IGNORED_DB_TABLES | Array | - | Array of DB Table names (can be string or regex) to ignore response from trace. |
removeIgnoredKeys | EPSAGON_REMOVE_IGNORED_KEYS | Boolean | false |
Whether to remove ignored keys instead of masking them |
urlPatternsToIgnore | EPSAGON_URLS_TO_IGNORE | Array | [] |
Array of URL patterns to ignore the calls |
sendTimeout | EPSAGON_SEND_TIMEOUT_SEC | Float | 1.0 |
The timeout duration in seconds to send the traces to the trace collector |
sendBatch | EPSAGON_SEND_BATCH | Boolean | true |
Whether to set the traces in batch mode, effective under high scale (set false for development) |
batchSize | EPSAGON_BATCH_SIZE | Integer | 5 |
The traces' batch size, when batch mode is activated |
decodeHTTP | EPSAGON_DECODE_HTTP | Boolean | true |
Whether to decode and decompress HTTP responses into the payload |
httpErrorStatusCode | EPSAGON_HTTP_ERR_CODE | Integer | 400 |
The minimum number of an HTTP response status code to treat as an error |
- | EPSAGON_PROPAGATE_LAMBDA_ID | Boolean | false |
Insert Lambda request ID into the response payload |
- | DISABLE_EPSAGON_PATCH | Boolean | false |
Disable the library patching (instrumentation) |
- | EPSAGON_DEBUG | Boolean | false |
Enable debug prints for troubleshooting |
- | EPSAGON_PROPAGATE_NATS_ID | Boolean | false |
Whether to propagate a correlation ID in NATS.io calls for distributed tracing |
- | EPSAGON_ADD_NODE_PATH | String | - | List of folders to looks for node_modules when patching libraries. Separated by : |
- | EPSAGON_AUTO_ADD_NODE_PATHS | Boolean | false |
Auto add node_modules sub folders to look when patching libraries. |
- | EPSAGON_DNS_INSTRUMENTATION | Boolean | false |
Whether to capture dns calls into the trace |
- | EPSAGON_FS_INSTRUMENTATION | Boolean | false |
Whether to capture node file system calls into the trace |
- | EPSAGON_LOGGING_TRACING_ENABLED | Boolean | true |
whether to add an Epsagon ID to the logs in order to correlate traces to logs in the dashboard |
- | EPSAGON_STEPS_ID | String | - | The Epsagon step id from the ECS step functions state input |
- | EPSAGON_STEPS_NUM | String | 0 |
The step number of the ECS step functions state |
- | EPSAGON_ALLOW_NO_ROUTE | Boolean | false |
Whether to capture non-matched route requests in Express.js |
- | EPSAGON_LAMBDA_TIMEOUT_THRESHOLD_MS | Integer | 200 |
The threshold in milliseconds to send the trace before a Lambda timeout occurs |
- | EPSAGON_PAYLOADS_TO_IGNORE | Array | - | Array of dictionaries to not instrument. Example: '[{"source": "serverless-plugin-warmup"}]' |
If you have any issue around using the library or the product, please don't hesitate to:
- Use the documentation.
- Use the help widget inside the product.
- Open an issue in GitHub.
If you encounter a bug with the Epsagon library for Node.js, we want to hear about it.
When opening a new issue, please provide as much information about the environment:
- Library version, Node.js runtime version, dependencies, etc.
- Snippet of the usage.
- A reproducible example can really help.
The GitHub issues are intended for bug reports and feature requests. For help and questions about Epsagon, use the help widget inside the product.
Provided under the MIT license. See LICENSE for details.
Copyright 2021, Epsagon