diff --git a/.gitignore b/.gitignore index ce45b111..9013f8e6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules *.log docs +package-lock.json diff --git a/.travis.yml b/.travis.yml index 3f05b943..c31dd301 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,16 @@ notifications: on_success: never on_failure: always +matrix: + include: + - node_js: "8" + env: TEST_ASYNC=test-async + - node_js: "10" + env: TEST_ASYNC=test-async + - node_js: "12" + env: TEST_ASYNC=test-async + script: - lerna bootstrap --hoist - lerna run test + - "if [[ $TEST_ASYNC == 'test-async' ]]; then lerna run $TEST_ASYNC || exit 0; fi" diff --git a/packages/core/README.md b/packages/core/README.md index b9ebefeb..8a6073b1 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -9,8 +9,8 @@ The AWS X-Ray SDK (the SDK) automatically records information for incoming and o requests and responses (via middleware). It also automatically records local data such as function calls, time, variables (via metadata and annotations), and Amazon EC2 instance data (via plugins). Currently, only Express -applications are supported for automatic capturing. See the [aws-xray-sdk-express] -(https://github.com/aws/aws-xray-sdk-node/tree/master/packages/express) package for additional information. +applications are supported for automatic capturing. See the +[aws-xray-sdk-express](https://github.com/aws/aws-xray-sdk-node/tree/master/packages/express) package for additional information. The SDK exposes the Segment and Subsegment objects so you can create your own capturing mechanisms, but a few are supplied. @@ -302,7 +302,7 @@ the X-Ray SDK provides helper functions under `AWSXRay.middleware`. See the [aws-xray-sdk-express](https://github.com/aws/aws-xray-sdk-node/tree/master/packages/express) module for more information. For additional information about and examples for using the CLS namespace to create -a new context, see: https://github.com/othiym23/node-continuation-local-storage. +a new context, see: https://github.com/jeff-lewis/cls-hooked. ### Capture subsegmenets within chained native Promise using automatic mode diff --git a/packages/core/lib/aws-xray.js b/packages/core/lib/aws-xray.js index f7cad54d..1254d2ca 100644 --- a/packages/core/lib/aws-xray.js +++ b/packages/core/lib/aws-xray.js @@ -286,8 +286,8 @@ var AWSXRay = { isAutomaticMode: contextUtils.isAutomaticMode, /** - * Enables automatic mode. Automatic mode uses 'continuation-local-storage'. - * @see https://github.com/othiym23/node-continuation-local-storage + * Enables automatic mode. Automatic mode uses 'cls-hooked'. + * @see https://github.com/jeff-lewis/cls-hooked * @memberof AWSXRay * @function * @see module:context_utils.enableAutomaticMode diff --git a/packages/core/lib/context_utils.js b/packages/core/lib/context_utils.js index 7b12152e..436111b4 100644 --- a/packages/core/lib/context_utils.js +++ b/packages/core/lib/context_utils.js @@ -2,7 +2,7 @@ * @module context_utils */ -var cls = require('continuation-local-storage'); +var cls = require('cls-hooked'); var logger = require('./logger'); var Segment = require('./segments/segment'); @@ -127,8 +127,8 @@ var contextUtils = { }, /** - * Enables automatic mode. Automatic mode uses 'continuation-local-storage'. - * @see https://github.com/othiym23/node-continuation-local-storage + * Enables automatic mode. Automatic mode uses 'cls-hooked'. + * @see https://github.com/jeff-lewis/cls-hooked * @alias module:context_utils.enableAutomaticMode */ diff --git a/packages/core/package.json b/packages/core/package.json index 41d94a90..25abea86 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -18,7 +18,7 @@ "@types/continuation-local-storage": "*", "atomic-batcher": "^1.0.2", "aws-sdk": "^2.304.0", - "continuation-local-storage": "^3.2.0", + "cls-hooked": "^4.2.2", "date-fns": "^1.29.0", "pkginfo": "^0.4.0", "semver": "^5.3.0" @@ -38,7 +38,8 @@ }, "scripts": { "test": "mocha --recursive ./test/ -R spec && tsd", - "test-d": "tsd" + "test-d": "tsd", + "test-async": "./node_modules/.bin/mocha --recursive ./test_async/ -R spec" }, "keywords": [ "amazon", diff --git a/packages/core/test_async/integration/segment_maintained_across_awaited.test.js b/packages/core/test_async/integration/segment_maintained_across_awaited.test.js new file mode 100644 index 00000000..479ffab8 --- /dev/null +++ b/packages/core/test_async/integration/segment_maintained_across_awaited.test.js @@ -0,0 +1,85 @@ +var assert = require('chai').assert; +var http = require('http'); +var AWSXRay = require('../../'); +var Segment = AWSXRay.Segment; + +AWSXRay.enableAutomaticMode(); + +describe('Integration', function() { + describe('#async', function() { + it('should maintain segment in async functions', function(done) { + var sharedPromise = null; + + var requestCount = 0; + var server = http + .createServer(function(req, res) { + var ns = AWSXRay.getNamespace(); + ns.bindEmitter(req); + ns.bindEmitter(res); + + ns.run(function () { + var segment = new Segment('root'); + + AWSXRay.setSegment(segment); + + if (!sharedPromise) { + sharedPromise = Promise.resolve(); + } + + // execute an async task + sharedPromise.then(async () => { + + await sleep(0); + + var retrievedSegment = AWSXRay.getSegment(); + res.end(); + + // setTimeout so the assertion isn't caught by the promise + setTimeout(function() { + assert.equal(segment.id, retrievedSegment.id); + if (++requestCount === 2){ + done(); + } + }); + }); + }); + }).listen(8080, '0.0.0.0', function() { + + var address = server.address(); + + var count = 0; + function cb(err) { + if (err) { + throw err; + } + + if (++count === 2) { + server.close(); + } + } + sendRequest(address, cb); + sendRequest(address, cb); + }); + }) + }); +}); + +function sendRequest(address, cb) { + http + .request({ + hostname: address.address, + port: address.port, + path: '/' + }) + .on('response', function(res) { + res.on('end', cb).resume(); + }) + .on('error', cb) + .end(); +} + +function sleep(ms) { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); +} \ No newline at end of file