Giter VIP home page Giter VIP logo

epsagon / epsagon-node Goto Github PK

View Code? Open in Web Editor NEW
57.0 14.0 19.0 3.21 MB

Automated tracing library for Node.js 8.x, 10.x, 12.x, and 14.x ⚡️

Home Page: https://epsagon.com

License: MIT License

JavaScript 95.94% Shell 0.45% PEG.js 3.61%
serverless serverless-functions lambda lambda-functions aws-lambda epsagon monitoring debugging distributed-tracing observability express openwhisk traces instrumentation

epsagon-node's Introduction


Build Status npm version semantic-release

Note: This repository is archived since Epsagon is no longer supported

Epsagon Tracing for Node.js

Trace

This package provides tracing to Node.js applications for the collection of distributed tracing and performance metrics in Epsagon.

Contents

Installation

To install Epsagon, simply run:

npm install epsagon

Usage

Important: Epsagon is activated and instruments the supported libraries once the module is imported.

Auto-tracing

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

Calling the SDK

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

Tagging Traces

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.

Custom Errors

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'));

Custom Warnings

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.

Filter Sensitive Data

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.

Ignore Endpoints

You can ignore certain incoming requests by specifying endpoints:

epsagon.ignoreEndpoints(['/healthcheck'])

Trace URL

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.

Frameworks

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
  • (Through the dashboard only)
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

AWS Lambda

Tracing Lambda functions can be done in three methods:

  1. Auto-tracing through the Epsagon dashboard.
  2. Using the serverless-plugin-epsagon if you're using The Serverless Framework.
  3. 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
});

Step Functions

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.

OpenWhisk Action

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
  }
);

Google Cloud Function

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');
});

AWS Batch

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
  }
}

Express

Tracing Express application can be done in two methods:

  1. Auto-tracing using the environment variable.
  2. 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'));
}

Hapi

Tracing Hapi application can be done in two methods:

  1. Auto-tracing using the environment variable.
  2. 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'));
  }
});

Koa

Tracing Koa application can be done in two methods:

  1. Auto-tracing using the environment variable.
  2. 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'));
});

WS (Websocket)

Tracing ws consumers can be done in two methods:

  1. Auto-tracing using the environment variable.
  2. 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'));
}) 

restify

Tracing restify application can be done in two methods:

  1. Auto-tracing using the environment variable.
  2. 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'));
}

fastify

Tracing fastify application can be done in two methods:

  1. Auto-tracing using the environment variable.
  2. 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' })
})

KafkaJS

Tracing kafkajs consumers can be done in two methods:

  1. Auto-tracing using the environment variable.
  2. 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'));
  },
})

kafka-node

Tracing kafka0node consumers can be done in two methods:

  1. Auto-tracing using the environment variable.
  2. 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'));
})

PubSub

Tracing @google-cloud/pubsub consumers can be done in two methods:

  1. Auto-tracing using the environment variable.
  2. 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'));
  },
})

SQS Consumer

Tracing sqs-consumer consumers can be done in two methods:

  1. Auto-tracing using the environment variable.
  2. 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'));
};

amqplib

Tracing amqplib consumers can be done in two methods:

  1. Auto-tracing using the environment variable.
  2. 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);
  }
});

bunnybus

Tracing bunnybus consumers can be done in two methods:

  1. Auto-tracing using the environment variable.
  2. 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();
}

NATS

Tracing nats consumers can be done in two methods:

  1. Auto-tracing using the environment variable.
  2. 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,
});

Generic

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);

Integrations

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

Configuration

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)
keysToAllow EPSAGON_ALLOWED_KEYS Boolean - Array of keys to automatically label in the trace
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_ALLOW_ERR_MESSAGE_STATUS Boolean true Whether to override http.status_code with a Status Code found in a raised Error's Message
- EPSAGON_PROPAGATE_LAMBDA_ID Boolean false Insert Lambda request ID into the response payload
- DISABLE_EPSAGON_PATCH Boolean false Disable the library patching (instrumentation)
isConsolePatched EPSAGON_PATCH_CONSOLE Boolean false Enable console module patching (instrumentation) for labelling
- 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"}]'

Getting Help

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.

Opening Issues

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.

License

Provided under the MIT license. See LICENSE for details.

Copyright 2021, Epsagon

epsagon-node's People

Contributors

adavidai avatar amitlicht avatar arbiv avatar dependabot[bot] avatar dlcmh avatar enoodle avatar galbash avatar guillaumeduboc avatar haddasbronfman avatar haimrait avatar henperez avatar idonava avatar ilyalibin avatar jcollum avatar liadgo avatar nemoshlag avatar ojongerius avatar osherv avatar ranrib avatar ronnathaniel avatar sagivr2020 avatar trieloff avatar tripodsan avatar tvaintrob avatar ymwjbxxq avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

epsagon-node's Issues

http.get(url, options) not supported

The get function of the NodeJS http module can be called with options or with url, [options]. The wrapper was built only for the optionscase, and assumes that the first argument is always an object, when it can be an object, a string, or aURL` object.

When http.get is used with a URL as in https://github.com/adobe/helix-resolve-git-ref/blob/233400fb22d69c79153d7ff126d8ca85c0210ce2/src/index.js#L44 it results in traces to HTTP requests being recorded as pointing to http://localhost/. This is due to the assumption that options will always be an object here:

const hostname = (
options.hostname ||
options.host ||
(options.uri && options.uri.hostname) ||
'localhost'
);

serverless-plugin-epsagon leads to Internal Server error

When I use the serverless-plugin-epsagon with my lambda function, it stops working.

Reproduction:

  • Create basic function template with serverless framework
  • Add HTTP handler
  • install epsagon and plugin
  • Supply token to epsagon config in serverless.yml
  • Deploy function

Call HTTP:
{"message": "Internal server error"}

  • Comment out the epsagon plugin
  • Deploy function

Call HTTP:
{ "message": "Hello World!" }

Openhwisk patcher doesn't work when final action is bundled

The problem is the:

const actions = tryRequire('openwhisk/lib/actions.js');

which hides the dependency from webpack. so in the final bundle, it cannot find the source.

replacing it with an explicit require works:

let actions;
try {
    // eslint-disable-next-line global-require,import/no-unresolved
    actions = require('openwhisk/lib/actions.js');
} catch (e) {
    // ignore
}

Does Epsagon wrapper support async/await style of lambdas?

Hello Guys!
Just a quick question for confirmation.
Lambda function with Node 8.10 runtime supports async/await style of coding. What about Epsagon?
Will code below work as expected?

const epsagon = require('epsagon');

const handler = async event => {
  try {
    // do something
    return result;
  } catch (err) {
    // do something
    throw err;
  }
}

epsagon.init({
  token: 'my-token',
  appName: 'my-app-name',
  metadataOnly: true, // or false
});

exports.handler = epsagon.lambdaWrapper(handler);

Thanks!

Webpack WARN: Critical dependency: require function is used in a way in which dependencies cannot be statically extracted

Dependency versions

epsagon: ^1.109.0
serverless-plugin-epsagon: ^1.11.0
serverless-webpack: ^5.4.1
webpack: ^5.35.0
fork-ts-checker-webpack-plugin: ^6.2.6

Full warning trace shown during webpack bundling with stats.errorDetails: true:

 WARNING in ../node_modules/epsagon/dist/bundle.js 1:70355-70362
Critical dependency: require function is used in a way in which dependencies cannot be statically extracted
at CommonJsRequireContextDependency.getWarnings (/Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/lib/dependencies/ContextDependency.js:82:18)
at Compilation.reportDependencyErrorsAndWarnings (/Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/lib/Compilation.js:2535:24)
at /Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/lib/Compilation.js:2163:10
at _next2 (eval at create (/Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:34:1)
at eval (eval at create (/Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:62:1)
at /Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/lib/FlagDependencyExportsPlugin.js:375:11
at /Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/neo-async/async.js:2830:7
at Object.each (/Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/neo-async/async.js:2850:39)
at /Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/lib/FlagDependencyExportsPlugin.js:354:18
at /Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/neo-async/async.js:2830:7
at Object.each (/Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/neo-async/async.js:2850:39)
at /Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/lib/FlagDependencyExportsPlugin.js:48:16
at Hook.eval [as callAsync] (eval at create (/Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:58:1)
at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (/Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/node_modules/tapable/lib/Hook.js:18:14)
at Compilation.finish (/Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/lib/Compilation.js:2155:28)
at /Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/lib/Compiler.js:1075:19
at processTicksAndRejections (internal/process/task_queues.js:76:11)
@ ./epsagon_handlers/fieldGroupEditorHandler-epsagon.ts 23:29-47


WARNING in ../node_modules/epsagon/dist/bundle.js 1:70476-70483
Critical dependency: require function is used in a way in which dependencies cannot be statically extracted
at CommonJsRequireContextDependency.getWarnings (/Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/lib/dependencies/ContextDependency.js:82:18)
at Compilation.reportDependencyErrorsAndWarnings (/Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/lib/Compilation.js:2535:24)
at /Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/lib/Compilation.js:2163:10
at _next2 (eval at create (/Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:34:1)
at eval (eval at create (/Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:62:1)
at /Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/lib/FlagDependencyExportsPlugin.js:375:11
at /Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/neo-async/async.js:2830:7
at Object.each (/Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/neo-async/async.js:2850:39)
at /Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/lib/FlagDependencyExportsPlugin.js:354:18
at /Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/neo-async/async.js:2830:7
at Object.each (/Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/neo-async/async.js:2850:39)
at /Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/lib/FlagDependencyExportsPlugin.js:48:16
at Hook.eval [as callAsync] (eval at create (/Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:58:1)
at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (/Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/node_modules/tapable/lib/Hook.js:18:14)
at Compilation.finish (/Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/lib/Compilation.js:2155:28)
at /Users/usivaguru/Documents/remotes/servicerocket/scaf-cloud/node_modules/webpack/lib/Compiler.js:1075:19
at processTicksAndRejections (internal/process/task_queues.js:76:11)
@ ./epsagon_handlers/fieldGroupEditorHandler-epsagon.ts 23:29-47

epsagon_handlers/fieldGroupEditorHandler-epsagon.ts (automatically generated by serverless-plugin-epsagon)

import * as epsagon from 'epsagon';
import * as epsagonHandler from '../handler';



  if (!process.env.EPSAGON_IGNORED_KEYS) {
    process.env.EPSAGON_IGNORED_KEYS = "";
  }

  if (!process.env.EPSAGON_URLS_TO_IGNORE) {
    process.env.EPSAGON_URLS_TO_IGNORE = "";
  }

epsagon.init({
    token: 'redacted',
    appName: 'scaff-cloud-ucchishta',
    traceCollectorURL: undefined,
    metadataOnly: Boolean(0),
    labels: [],
});

export const fieldGroupEditor = epsagon.lambdaWrapper(epsagonHandler.fieldGroupEditor);

no traces are sent when JSON.stringify throws

When sending a trace in sendCurrentTrace(traceSender), a traceJson is assembled and later its size checked by JSON.stringifying it:

    if (JSON.stringify(traceJson).length >= consts.MAX_TRACE_SIZE_BYTES) {
        // ...
    }

JSON.stringify can throw when the JSON has issues, such as a circular reference:

TypeError: Converting circular structure to JSON
    at JSON.stringify (<anonymous>)
    at Object.<anonymous> (<anonymous>:1:27)
    at sendCurrentTrace (/code/dist/getAllChannels/index.js:37495:5)
    at Promise.all.then (/code/dist/getAllChannels/index.js:37653:16)
    at process._tickCallback (internal/process/next_tick.js:68:7)

Probably this error should be caught and logged :D and other traces allowed to be sent.

Use TransactionId for tracing in OpenWhisk

Currently tracing using __ACTIVATION_ID as id for tracing in OpenWhisk which works well for seeing calls made from withing single activation.

Recently in OpenWhisk we also enabled exposing the transactionId (apache/openwhisk#4585) i.e. __TRANSACTION_ID which may be better suited as tracing id (in place of activationId) as it enables tracing requests made within a sequence or composition also.

The transactionId is also exposed as X-Request-Id and hence exposed to end users (apache/openwhisk#3199).

Further note that support for this feature is new. So the library may want to have a fallback to activationId if transactionId is not present

ECONNREFUSED and timeout when load testing

Hi guys!

I'm load testing an API Gateway endpoint. The lambda behind is instrumented with epsagon (I'm using the serverless plugin but I don't think it is related).
I'm sending 2000 requests, one every 10ms.
It works until a point, and then I see a Error: ECONNREFUSED, Connection refused and then the handler does not even get called (I don't see any logs, but I can see that the lambda has been invoked). The lambda also timeout, which is weird because I don't see any logs:
image

I've tried to disable epsagon and the issue does not replicate:

epsagon:
  disable: true

I kind of expect some lambda not to work, but I would prefer at least to exit so I don't pay until timeout.

Could this be linked to the wrapper?

Best

kafka send: Maximum call stack size exceeded

version: epagon-node 1.63.1

When using kafkajs#send espagon produces an uncaught "Maximum call stack size exceeded" error that breaks our openwhisk action sending the event.

Downgrading to version 1.62.3 fixeds the issue which was probably introduced via #277

v1.62.3...v1.63.1

There seems to be circularity between:

        const patchedSend = messages => kafkaSendMiddleware(messages, producer);
        ...
        response = producer.originalSend(messages);

in https://github.com/epsagon/epsagon-node/blob/master/src/events/kafkajs.js

Above two lines are featured in the stack:

RangeError: Maximum call stack size exceeded
    at Object.addException (/code/dist/action/index.js:43842:15)
    at Object.setException (/code/dist/action/index.js:43493:16)
    at kafkaSendMiddleware (/code/dist/action/index.js:57588:19)
    at Object.patchedSend (/code/dist/action/index.js:57702:41)
    at kafkaSendMiddleware (/code/dist/action/index.js:57585:29)
    at Object.patchedSend (/code/dist/action/index.js:57702:41)
    at kafkaSendMiddleware (/code/dist/action/index.js:57585:29)
    at Object.patchedSend (/code/dist/action/index.js:57702:41)
    at kafkaSendMiddleware (/code/dist/action/index.js:57585:29)
    at Object.patchedSend (/code/dist/action/index.js:57702:41)
    at kafkaSendMiddleware (/code/dist/action/index.js:57585:29)
    at Object.patchedSend (/code/dist/action/index.js:57702:41)
    at kafkaSendMiddleware (/code/dist/action/index.js:57585:29)
    at Object.patchedSend (/code/dist/action/index.js:57702:41)
    at kafkaSendMiddleware (/code/dist/action/index.js:57585:29)
    at Object.patchedSend (/code/dist/action/index.js:57702:41)
    at kafkaSendMiddleware (/code/dist/action/index.js:57585:29)
    at Object.patchedSend (/code/dist/action/index.js:57702:41)
    at kafkaSendMiddleware (/code/dist/action/index.js:57585:29)
    at Object.patchedSend (/code/dist/action/index.js:57702:41)
    at kafkaSendMiddleware (/code/dist/action/index.js:57585:29)
    at Object.patchedSend (/code/dist/action/index.js:57702:41)

/cc @ekremney @ranrib @idonava

Add ability to control if filtered properties should be removed or redacted.

In version 1.89.0 the way how filtered properties are handled changed: #375
it now masks the filtered keys instead of suppressing them. It would be good, if we could have an option to remove the keys completely.

a least it should be possible to have an option to disable redacting and removing the ignored keys.
even better would be to have the possibility to define the individual keys that should remain but redacted.

Connect AWS API Gateway directly to SNS using a service integration

Hello,

from the ServiceMap I can tell you that APIGW is not present.

I have this configuration:
APIGW -> SNS -> 2 SQS -> 2 Lambda

I can see all from: SNS -> 2 SQS -> 2 Lambda

Would be nice and very important to get the support for the APIGW because there you can be throttled and would be nice to get notified.

The logs for the APIGW are

Extended Request Id: xxxx=
Method request path: {}
Method request query string: {}
Method request headers: {Content-type=application/json, Accept=*/*, x-api-key=xxxxx, User-Agent=python-requests/2.9.1, X-Forwarded-Proto=https, X-Forwarded-For=81.210.128.100, Host=xxxxx, Accept-Encoding=gzip, deflate, X-Forwarded-Port=443, X-Amzn-Trace-Id=Root=xxxxx}
Method request body before transformations: {
    "prop1": "value"
}
 
Endpoint request URI: https://sns.region.amazonaws.com//
Endpoint request headers: {Authorization=xxxx, X-Amz-Date=20210221T210502Z, x-amzn-apigateway-api-id=xxxxx, Accept=application/json, User-Agent=AmazonAPIGateway_xxxxx, X-Amz-Security-Token=xxxxxxx [TRUNCATED]
 
Endpoint request body after transformations: Action=Publish&Message=xxxxxx&TopicArn=arn:sns-topic
Endpoint response headers: {x-amzn-RequestId=xxxxx, X-Amzn-Trace-Id=Root=xxxxx;Parent=xxxxxx;Sampled=1, Content-Type=application/json, Content-Length=184, Date=Sun, 21 Feb 2021 21:05:02 GMT}
Endpoint response body before transformations: {
    "PublishResponse": {
        "PublishResult": {
            "MessageId": "xxxxx",
            "SequenceNumber": null
        },
        "ResponseMetadata": {
            "RequestId": "xxxxx"
        }
    }
}
Method response body after transformations: {
    "status": "OK"
}

so in theory you have all the information to connect the dots.

Thanks

Dealing with OpenWhisk sequences

OpenWhisk supports action sequences

When invoking a sequence, epsagon only records the activation-id of that sequences and it's not possible to consolidate the executed actions of that sequences with the invocation chain. when invoking the action via a http request, the reponse header only contain the activation-id of the sequence.

however, it is possible to fetch the activation afterwards, eg:

$ wsk activation  get c56f8cf4c78a46d6af8cf4c78a36d6b2
ok: got activation c56f8cf4c78a46d6af8cf4c78a36d6b2
{
    "namespace": "helix",
    "name": "word2md@v1",
    "version": "0.0.200",
    "subject": "helix",
    "activationId": "c56f8cf4c78a46d6af8cf4c78a36d6b2",
    "start": 1585016256171,
    "end": 1585016262961,
    "duration": 6779,
    "statusCode": 0,
    "response": {
        "status": "success",
        "statusCode": 0,
        "success": true,
        "result": {
            "body": "...",
            "headers": {
                "Cache-Control": "no-store, private, must-revalidate",
                "Content-Length": 4413,
                "Content-Type": "text/plain",
                "X-Source-Location": "..."
            },
            "statusCode": 200
        }
    },
    "logs": [
        "853430d28a894e30b430d28a89be3091"
    ],
    "annotations": [
        {
            "key": "topmost",
            "value": true
        },
        {
            "key": "path",
            "value": "helix/helix-services/word2md@v1"
        },
        {
            "key": "kind",
            "value": "sequence"
        },
        {
            "key": "limits",
            "value": {
                "concurrency": 200,
                "logs": 10,
                "memory": 256,
                "timeout": 60000
            }
        }
    ],
    "publish": false
}

The activation response contains a logs property, which are the activations executed in that sequence.

Approach 1

Epsagon fetches the activation of sequence actions in order to construct the graph of the invocations. this is rather expensive and requires the wsk token of the respective namespace.

Approach 2

A best effort approach could be to return a x-last-activation-id header in the action that is executed last in the sequence. for most of our actions, that would be enough.

Tracing AWS EventBridge Target Step Functions state machines

Hello,

I have a lambda function that add an event into EventBridge to execute a Stepfunction.
Your ServiceMap does not trace this connection.
I can see:

  • Lambda to EventBridge (putEvents)
  • The first Lambda of the StepFunction completely separated and without the state machine icon as well

This is how I put the event that you trace (putEvents)
const eventRequest: PutEventsRequest = { Entries: [{ EventBusName: process.env.myBus, Source: "mySource", Detail: JSON.stringify(message), DetailType: "myType" }] }; const response = await this.eventBridge.putEvents(eventRequest).promise();

Would be nice to have the connection between the services

Use with Step Function

Hi I've been using epsagon with AWS lambda's but wanted to know how to get tracing working with step functions triggered by a cloudwatch schedule. Based on the examples you can:

module.exports.hello = epsagon.stepLambdaWrapper((event, context, callback) => {
   // Your code is here
});

But as my step function is triggered by cloud watch would each step(Lambda) need to be wrapped in the stepLambdaWrapper ?

Should OpenWhisk web actions that return an error HTTP status code be treated as errors?

I'm unsure if this is a bug, or what the desired behavior should be:

I have a function that will return a HTTP status code 404 if it can't find a particular file, e.g. by calling https://adobeioruntime.net/api/v1/web/helix/helix-services/static@ci109?owner=trieloff&repo=helix-demo&ref=master&entry=/index.js&plain=true and it returns 200 when everything is ok: http "https://adobeioruntime.net/api/v1/web/helix/helix-services/static@ci109?owner=trieloff&repo=helix-demo&ref=master&entry=/index.js&plain=true&root=/htdocs"

Both kinds of behavior are expected by the action developer, but not necessarily by the user of the action.

For HTTP requests made by the function, Epsagon treats everything >=400 as an error. Should the same rule apply to HTTP responses returned by the action?

I could also see that only HTTP status codes >=500 should be treated as an error in the action, and 4xx status code indicate an error only from the perspective of the caller, i.e. if it's called externally, then it's not an error, but if observed through #122 then it should be reported as an error, similar to a failed HTTP request.

TypeScript type definitions

This is something I'm using internally in our TypeScript project. It'd be great if epsagon included index.d.ts inside of itself.

// epsagon.d.ts
declare module 'epsagon' {
  import 'aws-lambda'

  export function init(options: {
    token: string
    appName: string
    metadataOnly?: boolean
  }): void
  export function label(key: string, value: string): void
  export function setError(error: Error): void

  type Wrapper<T extends AWSLambda.Handler> = (f: T) => T

  export function lambdaWrapper<T extends AWSLambda.Handler>(f: T): T
  export function stepLambdaWrapper<T extends AWSLambda.Handler>(f: T): T
  export function nodeWrapper<T extends Function>(f: T): T
  export function wrapBatchJob<T extends Function>(f: T): T
}

http response handling changes of epsagon 1.56.1 still produce runtime errors

even with the recent fixes of #244, we're still seeing errors with epsagon enabled, that are otherwise not a problem:

RangeError: Resource length mismatch (possibly incomplete body)
    at throwLengthMismatch (./node_modules/fetch-h2/dist/lib/body.js:17:11)
    at StreamResponse.validateIntegrity (./node_modules/fetch-h2/dist/lib/body.js:167:13)
    at awaitBuffer.then.already_1.tap.buffer 

could be caused by epsagon, consuming the chunks of the response.

Improve key filtering

Currently, it is only possible to filter for key names out of the context of the rest of the resource.
e.g. it is not possible to filter key names based on target host or request method.
For example, I would like to remove the request_body for all POST requests to *.okta.com.

A even better mechanism would be the ability to filter the values, eg redact the value of a token header.

Service Integrations with AWS Step Functions

Hello,

it seems that the service integrations like (at least the one that I could test):

  1. SQS
  2. Batch

are not traced or caught.

For example SQS:
TaskScheduled:

{
  "resourceType": "sqs",
  "resource": "sendMessage.waitForTaskToken",
  "region": "eu-central-1",
  "parameters": {
    "MessageBody": [
      {
        "Input": "msg"
      },
      {
        "TaskToken": "token"
      }
    ],
    "MessageGroupId": "$.contentId",
    "QueueUrl": "https://sqs.region.amazonaws.com/xxxxxxxx/queue(.could be also fifo)"
  },
  "timeoutInSeconds": 86400,
  "heartbeatInSeconds": null
}

TaskStarted:

{
  "resourceType": "sqs",
  "resource": "sendMessage.waitForTaskToken"
}

TaskSubmitted:

{
  "resourceType": "sqs",
  "resource": "sendMessage.waitForTaskToken",
  "output": {
    "MD5OfMessageBody": ".....",
    "MessageId": "d1968f1e-594d-454c-8a25-8ab3997b1c52",
    "SdkHttpMetadata": {
      "AllHttpHeaders": {
        "x-amzn-RequestId": [
          "cac232d9-ed4b-4982-a725-36aa4ae3d13f"
        ],
        "Content-Length": [
          "431"
        ],
        "Date": [
          "Mon, 22 Feb 2021 04:31:56 GMT"
        ],
        "Content-Type": [
          "text/xml"
        ]
      },
      "HttpHeaders": {
        "Content-Length": "431",
        "Content-Type": "text/xml",
        "Date": "Mon, 22 Feb 2021 04:31:56 GMT",
        "x-amzn-RequestId": "cac232d9-ed4b-4982-a725-36aa4ae3d13f"
      },
      "HttpStatusCode": 200
    },
    "SdkResponseMetadata": {
      "RequestId": "cac232d9-ed4b-4982-a725-36aa4ae3d13f"
    },
    "SequenceNumber": "18859919962822895872"
  },
  "outputDetails": {
    "truncated": false
  }
}

TaskFailed:

{
  "resourceType": "sqs",
  "resource": "sendMessage.waitForTaskToken",
  "error": "boom",
  "cause": "manual"
}

For example BATCH:
TaskScheduled:

{
  "resourceType": "batch",
  "resource": "submitJob.sync",
  "region": "regione",
  "parameters": {
    "JobQueue": "myJobQueue",
    "JobName": "myJobName",
    "ContainerOverrides": {
      "Environment": [
        {
          "Name": "MANAGED_BY_AWS",
          "Value": "STARTED_BY_STEP_FUNCTIONS"
        },
        {
          "Name": "EPSAGON_TOKEN",
          "Value": "token"
        },
        {
          "Name": "DISABLE_EPSAGON",
          "Value": "false"
        }
      ]
    },
    "JobDefinition": "myJobDefinition"
  },
  "timeoutInSeconds": 21600,
  "heartbeatInSeconds": null
}

TaskStarted:

{
  "resourceType": "batch",
  "resource": "submitJob.sync"
}

TaskSubmitted:

{
  "resourceType": "batch",
  "resource": "submitJob.sync",
  "output": {
    "JobArn": "myJobArn",
    "JobId": "fa13d348-fb58-4364-9cf3-50b49a28f595",
    "JobName": "myJobId",
    "SdkHttpMetadata": {
      "AllHttpHeaders": {
        "x-amz-apigw-id": [
          "bHR_cGIyFiAFvPA="
        ],
        "Connection": [
          "keep-alive"
        ],
        "x-amzn-RequestId": [
          "6ec57cc5-3e54-488c-bd75-d418140c3406"
        ],
        "Content-Length": [
          "238"
        ],
        "Date": [
          "Sun, 21 Feb 2021 21:00:44 GMT"
        ],
        "X-Amzn-Trace-Id": [
          "Root=1-6032c9f8-969a5b7103ec6cf43fcb21f8"
        ],
        "Content-Type": [
          "application/json"
        ]
      },
      "HttpHeaders": {
        "Connection": "keep-alive",
        "Content-Length": "238",
        "Content-Type": "application/json",
        "Date": "Sun, 21 Feb 2021 21:00:44 GMT",
        "x-amz-apigw-id": "bHR_cGIyFiAFvPA=",
        "x-amzn-RequestId": "6ec57cc5-3e54-488c-bd75-d418140c3406",
        "X-Amzn-Trace-Id": "Root=1-6032c9f8-969a5b7103ec6cf43fcb21f8"
      },
      "HttpStatusCode": 200
    },
    "SdkResponseMetadata": {
      "RequestId": "6ec57cc5-3e54-488c-bd75-d418140c3406"
    }
  },
  "outputDetails": {
    "truncated": false
  }
}

TaskFailed:

{
  "resourceType": "batch",
  "resource": "submitJob.sync",
  "error": "States.TaskFailed",
  "cause": {
    "Attempts": [
      {
        "Container": {
          "ContainerInstanceArn": "myContainerInstanceArn",
          "LogStreamName": "myLogStreamName",
          "NetworkInterfaces": [],
          "TaskArn": "myTaskArn"
        },
        "StatusReason": "Terminated by user via console",
        "StoppedAt": 1613941358899
      }
    ],
    "Container": {
      "Command": [],
      "ContainerInstanceArn": "myContainerInstanceArn",
      "Environment": [
        {
          "Name": "MANAGED_BY_AWS",
          "Value": "STARTED_BY_STEP_FUNCTIONS"
        },
        {
          "Name": "DISABLE_EPSAGON",
          "Value": "false"
        },
        {
          "Name": "EPSAGON_TOKEN",
          "Value": "token"
        }
      ],
      "Image": "myImage",
      "JobRoleArn": "myJobRoleArn,
      "LogStreamName": "myLogStreamName",
      "Memory": 2048
    },
    "CreatedAt": 1613941244461,
    "DependsOn": [],
    "JobArn": myJobArn,
    "JobDefinition": "myJobDefinition",
    "JobId": "fa13d348-fb58-4364-9cf3-50b49a28f595",
    "JobName": "myJobName",
    "JobQueue": "myJobQueue",
    "Parameters": {},
    "PlatformCapabilities": [],
    "PropagateTags": false,
    "RetryStrategy": {
      "Attempts": 10,
      "EvaluateOnExit": []
    },
    "Status": "FAILED",
    "StatusReason": "Terminated by user via console",
    "StoppedAt": 1613941358899,
  }
}

I cannot see two things over here:

  1. the state machine with status FAILED it is always SUCCESS
  2. the call or trace to the SQS at least the reference
  3. the call or trace to the BATCH at least the reference

Thanks,

http response handling changes of epsagon 1.56.1 produce runtime errors

How to reproduce:

$ cd http-example
$ npm install
$ node index.js
buffer.js:480
      throw new ERR_INVALID_ARG_TYPE(
      ^

TypeError [ERR_INVALID_ARG_TYPE]: The "list[0]" argument must be one of type Array, Buffer, or Uint8Array. Received type string
    at Function.concat (buffer.js:480:13)
    at IncomingMessage.r.on (~/codez/epsagon-testing/http-example/node_modules/epsagon/dist/bundle.js:1:58912)
    at IncomingMessage.emit (events.js:203:15)
    at endReadableNT (_stream_readable.js:1143:12)
    at process._tickCallback (internal/process/next_tick.js:63:19)

Question: Epsagon Lambda Wrapper. How to create errors responses?

Hello guys.

I have a question related with Epsagon lambda wrapper. When I wrap a lambda I'm loosing the possibility to correctly handle the error and create the correct error response at the moment. What is the best solution for this problem?

E.g.: I want to be able to throw a custom error such as NotFound('product x not found') and create the appropriate APIGateway response:

 statusCode: 404 
 message: product x not found

Thank you

Node support

Hello,

epsagon-node support 8.x, 10.x, 12.x, and 14.x where

8.x has been deprecated since a while
10.x will be deprecated end of April 2021
https://endoflife.date/nodejs

Do you have plans to fork the current version for 8 and 10?

If you do that you will have advantages to keep the "active" version up to date with dependencies, currently because the compatibility to 8.x you cannot update pretty much anything without breaking your CI.

Thanks,
Dan

Patched functions add events even if not wrapped

Once epsagon is required, it patches the event handlers, e.g. for http.request etc.
Now, if requests are made before the tracer is restarted, it will add events to the tracer, which can lead to a high memory consumption.

a solution could be to set the __epsagonCallback for all requests that should not be traced, but this looks like an implementation detail.

ideally, the API would export some way to disable the tracer until tracer.restart is called.

AWS Batch wrapper cannot execute function

Your documentation report this
https://docs.epsagon.com/docs/nodejs-aws-batch

I am using TypeScript and I have tried multiple things but I am getting always the same error.

try number 1:
`export const startExecution: any = epsagon.wrapBatchJob(doit);

function doit() {
console.log("sfsdffdsf")
}`

ERROR:
TypeError: handler_1.startExecution is not a function

try number 2:
export const startExecution: any = epsagon.wrapBatchJob((): any => { console.log("sfsdffdsf") });

ERROR:
TypeError: handler_1.startExecution is not a function

try number 3:
`export const startExecution: any = epsagon.wrapBatchJob(async (): Promise => {
await runBatch();
});

export const runBatch = async (): Promise => {
// code here
};`

ERROR:
TypeError: handler_1.startExecution is not a function

It is interesting to note that the unit tests are all passing if you replace wrapBatchJob with lambdaWrapper and both of them have the same definition:
`
export function lambdaWrapper(f: T): T

export function wrapBatchJob(f: T): T
`

Thanks

Error when using a Winston logger in Epsagon instrumented code during Mocha test

Working (no error) version of function:

async function buildPayload(err, res, event) {
    if (err) {
        console.log({
            level: 'ERROR',
            message: 'Failed to query for data.',
            function: 'buildPayload',
            filename: __filename,
            error: err.toString()
        });
        return Promise.reject(err);
    }
...
}

Failing version:

const {version, name}  = require ('../package.json');
const logger = winston.createLogger({
    level: process.env.LOG_LEVEL || 'warn',
    defaultMeta: {service: name, filename: __filename, version},
    transports: [
        new winston.transports.Console({
            format: winston.format.json()
        })
    ]
});
... 

async function buildPayload(err, res, event) {
    logger.debug("buildPayload starting"); 
...
}

In case it isn't clear, ... means I left code out. Doesn't matter, if I put in the Winston logger in the epsagon-instrumented code it fails on the first line. Stack trace:

TypeError: Cannot read property 'node' of undefined
    at Object.e.exports.createTracer (/Users/justin.collum/work/read-account-lambda/node_modules/epsagon/dist/bundle.js:1:28127)
    at Object.trace_object_get [as getTrace] (/Users/justin.collum/work/read-account-lambda/node_modules/epsagon/dist/bundle.js:1:37578)
    at Object.e.exports.getTraceId (/Users/justin.collum/work/read-account-lambda/node_modules/epsagon/dist/bundle.js:1:36832)
    at /Users/justin.collum/work/read-account-lambda/node_modules/epsagon/dist/bundle.js:1:151398
    at DerivedLogger.<anonymous> (/Users/justin.collum/work/read-account-lambda/node_modules/epsagon/dist/bundle.js:1:151416)
    at DerivedLogger.<computed> [as debug] (/Users/justin.collum/work/read-account-lambda/node_modules/winston/lib/winston/create-logger.js:81:14)
    at buildPayload (/Users/justin.collum/work/read-account-lambda/lib/read-account-lambda.js:89:16)
    at Context.<anonymous> (/Users/justin.collum/work/read-account-lambda/test/read-account-lambda-test.js:109:20)
    at callFn (/Users/justin.collum/work/read-account-lambda/node_modules/mocha/lib/runnable.js:387:21)
    at Test.Runnable.run (/Users/justin.collum/work/read-account-lambda/node_modules/mocha/lib/runnable.js:379:7)
    at Runner.runTest (/Users/justin.collum/work/read-account-lambda/node_modules/mocha/lib/runner.js:535:10)
    at /Users/justin.collum/work/read-account-lambda/node_modules/mocha/lib/runner.js:653:12
    at next (/Users/justin.collum/work/read-account-lambda/node_modules/mocha/lib/runner.js:447:14)
    at /Users/justin.collum/work/read-account-lambda/node_modules/mocha/lib/runner.js:457:7
    at next (/Users/justin.collum/work/read-account-lambda/node_modules/mocha/lib/runner.js:362:14)
    at /Users/justin.collum/work/read-account-lambda/node_modules/mocha/lib/runner.js:420:7
    at done (/Users/justin.collum/work/read-account-lambda/node_modules/mocha/lib/runnable.js:334:5)
    at callFn (/Users/justin.collum/work/read-account-lambda/node_modules/mocha/lib/runnable.js:410:7)
    at Hook.Runnable.run (/Users/justin.collum/work/read-account-lambda/node_modules/mocha/lib/runnable.js:379:7)
    at next (/Users/justin.collum/work/read-account-lambda/node_modules/mocha/lib/runner.js:384:10)
    at Immediate._onImmediate (/Users/justin.collum/work/read-account-lambda/node_modules/mocha/lib/runner.js:425:5)
    at processImmediate (internal/timers.js:456:21)
    at process.topLevelDomainCallback (domain.js:137:15)

Relevant sections of package-lock:

    "epsagon": {
      "version": "1.94.0",
      "resolved": "https://registry.npmjs.org/epsagon/-/epsagon-1.94.0.tgz",
      "integrity": "sha512-hObfsn1eYJRc+WJvbgOla8kma8oaxKDSjmb8rOkjqpGoLeUsuM/jhcdtnHFDlwl4DNumWxe3bAqaYIJHNTAEvw==",
      "requires": {
        "axios": "^0.19.0",
        "google-protobuf": "^3.5.0",
        "json.sortify": "^2.2.2",
        "md5": "^2.2.1",
        "require-in-the-middle": "^5.0.3",
        "shimmer": "^1.2.1",
        "uuid-parse": "^1.1.0",
        "uuid4": "^1.0.0"
      }
    },
 "winston": {
      "version": "3.3.3",
      "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz",
      "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==",
      "requires": {
        "@dabh/diagnostics": "^2.0.2",
        "async": "^3.1.0",
        "is-stream": "^2.0.0",
        "logform": "^2.2.0",
        "one-time": "^1.0.0",
        "readable-stream": "^3.4.0",
        "stack-trace": "0.0.x",
        "triple-beam": "^1.3.0",
        "winston-transport": "^4.4.0"
      },
      "dependencies": {
        "async": {
          "version": "3.2.0",
          "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz",
          "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw=="
        }
      }
    },

package deps:

"devDependencies": {
    "ajv": "^5.5.2",
    "aws-sdk-mock": "^5.0.0",
    "chai": "^4.2.0",
    "eslint": "^6.6.0",
    "mocha": "^6.2.2",
    "nyc": "^14.1.1",
    "rewire": "^4.0.1",
    "sinon": "^9.0.2"
  },
  "dependencies": { 
    "aws-sdk": "^2.784.0",
    "epsagon": "^1.94.0",
    "lodash": "^4.17.20",
    "winston": "~3.3.3"
  },

Env:

Node v12.16.1
NPM 6.14.10

I'm running Mocha via IntelliJ IDEA usually but it also fails in the same way when running from command line.

AWS AppConfig support

Would be nice to add a special icon for AWS AppConfig especially the integration with Lambda function
https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-integration-lambda-extensions.html

When you integrate AppConfig you will have:

  • Lambda layer (arn:aws:lambda:{REGION}:066940009817:layer:AWS-AppConfig-Extension:{version}
  • Environment variable (configurable)
Environment variable Default value
AWS_APPCONFIG_EXTENSION_POLL_INTERVAL_SECONDS 45
AWS_APPCONFIG_EXTENSION_POLL_TIMEOUT_MILLIS 3000
AWS_APPCONFIG_EXTENSION_HTTP_PORT 2772

At the moment is the serviceMap you see it as http calls.

I think you should catch somehow the environment variable or the lambda layer and when there is an http call to "http//locahost:{AWS_APPCONFIG_EXTENSION_HTTP_PORT}/applications/" based on the env variables you do your magic creating the connection (already there but http type)

Lambda example:
`const AWS = require('aws-sdk');
const appconfig = new AWS.AppConfig();
const http = require('http');

exports.handler = async (event) => {
const result = await new Promise((resolve, reject) => {
http.get("http://localhost:2772/applications/applicationTest/environments/ myTestEnvironment/configurations/myConfigurationProfile", resolve);
});

const configData = await new Promise((resolve, reject) => {
let data = '';
result.on('data', chunk => data += chunk);
result.on('error', err => reject(err));
result.on('end', () => resolve(data));
});

console.log(configData);
return JSON.parse(configData);
}; `

Thanks

epsagon 1.58.5 hangs after 2 consecutive http requests

It is a bit hard to reproduce, but it seems that with 2 consecutive https requests, which both return a 404 but with content, sending the trace will fail.

this only happens when using helix-fetch

see https://github.com/tripodsan/epsagon-testing/tree/master/action-with-fetch

running the example shows:

$ npm run test:fetch

> [email protected] test:fetch ~/codez/helix/epsagon-testing/action-with-fetch
> node test/run.js fetch

Patching http2 module
instrumenting epsagon.
using fetch to download content.
404
404
Could not parse JSON response_body in http
Sending trace async
.....
(process hangs)

SSRF vulnerability reported via Axios in 1.104.4

Fresh install of Epsagon today in an old project:

  npm i --save epsagon
  npm audit
✗ cat package.json | grep epsa
    "epsagon": "^1.104.4",

Result:

│ High          │ Server-Side Request Forgery                                  │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ axios                                                        │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ >=0.21.1                                                     │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ epsagon                                                      │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ epsagon > axios                                              │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://npmjs.com/advisories/1594                            │

openwhisk: Pending events are not cleared

my tests show that traces are sent over and over again, with each invocation of an openwhisk action.
I assume that the pendingEvents map is not properly cleared or the eventList in the Trace.

this is certainly a problem, if sending one of the traces fails, but it seems also to occur if the traces are sent successfully.

you can also see this in the traces UI:

image

where the same request is shown multiple times, although this action only issued 1 request.

Doesn't work with `got`

epsagon version: 1.61.5
got version: 11.0.2

Recently added got to my project and received the following error when calling got.get(url, options) with Epsagon enabled

TypeError: i is not a function
      at ClientRequest.patchedCallback (webpack:///../node_modules/epsagon/dist/bundle.js?:1:63790)
      at Object.onceWrapper (events.js:428:26)
      at ClientRequest.emit (events.js:333:22)
      at ClientRequest.EventEmitter.emit (domain.js:485:12)
      at ClientRequest.origin.emit (webpack:///../node_modules/got/node_modules/@szmarczak/http-timer/dist/source/index.js?:39:20)
      at HTTPParser.parserOnIncomingClient [as onIncoming] (_http_client.js:602:27)
      at HTTPParser.parserOnHeadersComplete (_http_common.js:116:17)
      at TLSSocket.socketOnData (_http_client.js:471:22)
      at TLSSocket.emit (events.js:321:20)
      at TLSSocket.EventEmitter.emit (domain.js:485:12)
      at addChunk (_stream_readable.js:297:12)
      at readableAddChunk (_stream_readable.js:273:9)
      at TLSSocket.Readable.push (_stream_readable.js:214:10)
      at TLSWrap.onStreamRead (internal/stream_base_commons.js:186:23)

The error is thrown by the following line https://github.com/epsagon/epsagon-node/blob/master/src/events/http.js#L273 because callback is an object and not a function.
image

Provide Option to Mask Sensitive Data

When functions carry sensitive data such as API tokens, E-Mail addresses, etc. it is desirable to keep them away from logging infrastructure.

Therefore, I propose the addition of two new parameters for options: mask_fields and mask_values that specifies each a list of strings or regular expressions that will be applied to traces in sendCurrentTrace.

epsagon.init({
  // the usual stuff omitted
  mask_fields: ['EPSAGON_TOKEN', 'Authorization'], // mask well-known field and header names
  mask_values: [/[0-9a-zA-Z/+]{40}/, /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/] // mask AWS Secret Keys and E-Mail addresses 
});

Initially, I'd just mask things with --------------, but I could imagine a more advanced hash-based masking that would enable search in the Epsagon UI (by applying the same hash to the search term).

AWS Batch wrapper does not trace error

AWS Batch wrapper does not report job failures...

Inside the log we should see:

[EPSAGON] [http] filtered ignored hostname eu-central-1.tc.epsagon.com
[EPSAGON] Trace posted!

instead this is missing.

The batch wrapper
https://github.com/epsagon/epsagon-node/blob/master/src/wrappers/batch.js

has this:

process.on('uncaughtException', (err) => {
            eventInterface.setException(runner, err);
        });
process.once('beforeExit', () => {
            tracer.sendTrace(runnerSendUpdateHandler);
        });


in my PoC you can see the following result:

node process.js 
do something
inside catch Error: boom
    at wrapBatchJob (/Users/fra0005d/git/epsagon-node/src/wrappers/process.js:8:11)
    at Object.<anonymous> (/Users/fra0005d/git/epsagon-node/src/wrappers/process.js:2:1)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
    at internal/main/run_main_module.js:17:47
Process will exit with code: 0
Process exited with code: 0

if you remove the the try catch instead you have:

node process.js 
do something
/Users/fra0005d/git/epsagon-node/src/wrappers/process.js:7
    throw new Error("boom")
    ^

Error: boom
    at wrapBatchJob (/Users/fra0005d/git/epsagon-node/src/wrappers/process.js:7:11)
    at Object.<anonymous> (/Users/fra0005d/git/epsagon-node/src/wrappers/process.js:2:1)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
    at internal/main/run_main_module.js:17:47

so uncaughtException is never called.

wrapBatchJob();

function wrapBatchJob() {
  try {
    console.log("do something");
    throw new Error("boom")
  } catch (error) {
    console.log("inside catch", error)
    // process.exit(1) will skip process handling
  }
}

process.on('beforeExit', code => {
  // Can make asynchronous calls
  setTimeout(() => {
    console.log(`Process will exit with code: ${code}`)
    process.exit(code)
  }, 100)
})

process.on('exit', code => {
  // Only synchronous calls
  console.log(`Process exited with code: ${code}`)
})

// never called
process.on('uncaughtException', err => {
  console.log(`Uncaught Exception: ${err.message}`)
  process.exit(1)
})

considering a realistic code inside the batch where you have to catch the error to do some "cleanup" the error process.exit(1) cannot be use to mark the batch as failed

try {
    doSomerhing();
  } catch (error) {
     epsagon.setError(error);
     doSomethingBecauseTheError();
    // process.exit(1) will skip process handling
  }

and so you have 2 big problems here:

  1. You cannot use anymore the batch re-try built-in system
  2. The batch is not marked as failed in the aws console but only in your dashboard

POSSIBLE SOLUTION:

in your trace you have

[EPSAGON] trace: {
"resource":{
   "error_code": 2,
   "exception": {
      "type": "Error",
      "message": "boom",

You are looking for this in the beforeExit and if it is present exiting with process.exit(1)

Thanks,
Dan

OpenWhisk Wrapper with token_param fails when called without parameters

See this commit: adobe/helix-dispatch@4a94c00 and this test result: https://circleci.com/gh/adobe/helix-experimental-dispatch/102

Cannot read property 'EPSAGON_TOKEN' of undefined
TypeError: Cannot read property 'EPSAGON_TOKEN' of undefined
    at r (node_modules/epsagon/dist/bundle.js:1:37704)
    at Context.it (test/index.test.js:51:26)

the wrapper function doesn't like it too much when params is empty, which leads to a bad failure. This can never happen in production, but it would make sense to guard against it for test cases. PR incoming.

epsagon.lambdaWrapper is not async

This post https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/ shows how to use async function properly. Here is what I am doing:

let AWS = require('aws-sdk');
let lambda = new AWS.Lambda();

exports.handler = async (event) => {
    return await lambda.getAccountSettings().promise() ;
};

Then I can test this file as:

. . .
let result = await app.handler(event);
. . .

This works, it will wait for app.handler to finish before continuing with execution. BUT I can not do this with Epsagon, if I change the program as you suggest:

let AWS = require('aws-sdk');
let lambda = new AWS.Lambda();
const epsagon = require('epsagon');

const handler = async event => {
  return await lambda.getAccountSettings().promise() ;
}

epsagon.init({
  token: 'my-token',
  appName: 'my-app-name',
  metadataOnly: true, // or false
});

exports.handler = epsagon.lambdaWrapper(handler);

This does not work, it does not await in the test, it returns immediately with a undefined and continues. This tells me that lambdaWrapper is not Async. Can you please make it async?

http response handling changes of epsagon 1.58.3 still produce runtime errors when webpacked

with #249 fixed, the tests now work locally, but when bundling with webpack, they still fail:

RangeError: Resource length mismatch (possibly incomplete body)
    at throwLengthMismatch (/Users/tripod/codez/helix/epsagon-testing/action-with-fetch/dist/default/[email protected]:4726:11)
    at StreamResponse.validateIntegrity (/Users/tripod/codez/helix/epsagon-testing/action-with-fetch/dist/default/[email protected]:4876:13)
    at awaitBuffer.then.already_1.tap.buffer (/Users/tripod/codez/helix/epsagon-testing/action-with-fetch/dist/default/[email protected]:4790:52)
    at /Users/tripod/codez/helix/epsagon-testing/action-with-fetch/dist/default/[email protected]:1571:15
    at process._tickCallback (internal/process/next_tick.js:68:7)

when running the test locally, I see that the arguments passed into the internalHttpWrapper are:

http arguments [Arguments] {
  '0':
   { createConnection: [Function: createConnection],
     agent: false,
     hostname: 'adobeioruntime.net',
     method: 'GET',
     path:
      '/api/v1/web/helix/helix-services/word2md@v1...',
     port: 443,
     protocol: 'https:',
     headers: { connection: 'keep-alive' },
     epsagonSkipResponseData: true } }

but when running in the bundle, i get:

http arguments [Arguments] {
  '0':
   { createConnection: [Function: createConnection],
     agent: false,
     hostname: 'adobeioruntime.net',
     method: 'GET',
     path:
      '/api/v1/web/helix/helix-services/word2md@v1...,
     port: 443,
     protocol: 'https:',
     headers: { connection: 'keep-alive' } } }

It seems that the shimmer can't patch the method when it's bundled.

Unable to import module 'epsagon_handlers/run-epsagon'

This is probably my fault, but I'm getting this error when I try to wrap a function. I am using Typescript, so maybe that has something to do with it. Anyways, I have a lambda in my state machine that looks something like the following:

const epsagon = require('epsagon');
epsagon.init({
  token: '...',
  appName: 'Ingestion',
  metadataOnly: false, // Optional, send more trace data
});


let upsertFile: Handler = async (
  event: UpsertFileEvent,
  _: Context,
  callback: Callback,
) => {
 //...
}
upsertFile = epsagon.lambdaWrapper(upsertFile);
export { upsertFile };

And I am seeing this error occur in my run function, which is responsible for executing the state machine, where upsertFile lives.

Unable to import module 'epsagon_handlers/run-epsagon': Error
at Function.Module._resolveFilename (module.js:547:15)
at Function.Module._load (module.js:474:25)
at Module.require (module.js:596:17)
at require (internal/module.js:11:18)
at Object.<anonymous> (/var/task/epsagon_handlers/run-epsagon.js:3:15)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)

Any pointers on what I might be doing wrong here?

Thanks!

process.env.EPSAGON_SEND_TIMEOUT_SEC is used globally

process.env.EPSAGON_SEND_TIMEOUT_SEC is used globally:

const timeoutEnv = (process.env.EPSAGON_SEND_TIMEOUT_SEC || 0) * 1000.0;
const timeoutGraceTimeMs = 200;
const sendTimeoutMilliseconds = timeoutEnv || timeoutGraceTimeMs;

which requires it be be set before the epsagon module is imported. this is not very practical.
it would be better if it was evaluated each time it's needed.

Feature Request: ignoredHosts

Similar to the ignoredKeys setting, I'd like to propose an ignoredHosts setting that allows specifying a black list of host names (or expressions). Any outgoing request made to a host on the blacklist won't get traced.

In our use case, we see a lot of logging requests sent to Coralogix, which is great the first time (when you want to confirm it's working) and annoying any time after.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.