dd-trace
Advanced tools
Comparing version 0.6.0-beta.2 to 0.6.0
@@ -7,3 +7,3 @@ 'use strict' | ||
Benchmark.options.maxTime = 0.5 | ||
Benchmark.options.maxTime = 0.1 | ||
Benchmark.options.minSamples = 5 | ||
@@ -10,0 +10,0 @@ |
@@ -31,3 +31,2 @@ 'use strict' | ||
let sampler | ||
let queue | ||
@@ -81,17 +80,2 @@ const traceStub = require('./stubs/trace') | ||
}) | ||
.add('Writer#flush (1000 items)', { | ||
onStart () { | ||
writer = new Writer({}, 1001) | ||
for (let i = 0; i < 1000; i++) { | ||
writer.append(spanStub) | ||
} | ||
queue = writer._queue | ||
}, | ||
fn () { | ||
writer._queue = queue | ||
writer.flush() | ||
} | ||
}) | ||
.add('Sampler#isSampled', { | ||
@@ -98,0 +82,0 @@ onStart () { |
'use strict' | ||
const benchmark = require('../benchmark') | ||
const Buffer = require('safe-buffer').Buffer | ||
const platform = require('../../src/platform') | ||
@@ -12,4 +11,2 @@ const node = require('../../src/platform/node') | ||
let data | ||
const traceStub = require('../stubs/trace') | ||
@@ -28,22 +25,2 @@ | ||
}) | ||
.add('request', { | ||
onStart () { | ||
data = Buffer.alloc(1000000) | ||
}, | ||
fn () { | ||
platform | ||
.request({ | ||
protocol: 'http:', | ||
hostname: 'test', | ||
port: '8080', | ||
path: '/v0.4/traces', | ||
method: 'PUT', | ||
headers: { | ||
'Content-Type': 'application/msgpack' | ||
}, | ||
data | ||
}) | ||
.catch(() => {}) | ||
} | ||
}) | ||
.add('msgpack#prefix', { | ||
@@ -50,0 +27,0 @@ fn () { |
@@ -184,2 +184,21 @@ <h1 id="home">Datadog JavaScript Tracer API</h1> | ||
<h3 id="hapi">hapi</h3> | ||
<h5 id="hapi-tags">Tags</h5> | ||
| Tag | Description | | ||
|------------------|-----------------------------------------------------------| | ||
| http.url | The complete URL of the request. | | ||
| http.method | The HTTP method of the request. | | ||
| http.status_code | The HTTP status code of the response. | | ||
| http.headers.* | A recorded HTTP header. | | ||
<h5 id="hapi-config">Configuration Options</h5> | ||
| Option | Default | Description | | ||
|------------------|---------------------------|----------------------------------------| | ||
| service | *Service name of the app* | The service name for this integration. | | ||
| validateStatus | `code => code < 500` | Callback function to determine if there was an error. It should take a status code as its only parameter and return `true` for success or `false` for errors. | | ||
| headers | `[]` | An array of headers to include in the span metadata. | | ||
<h3 id="http">http / https</h3> | ||
@@ -202,2 +221,53 @@ | ||
<h3 id="ioredis">ioredis</h3> | ||
<h5 id="ioredis-tags">Tags</h5> | ||
| Tag | Description | | ||
|------------------|-----------------------------------------------------------| | ||
| db.name | The index of the queried database. | | ||
| out.host | The host of the Redis server. | | ||
| out.port | The port of the Redis server. | | ||
<h5 id="ioredis-config">Configuration Options</h5> | ||
| Option | Default | Description | | ||
|------------------|------------------|----------------------------------------| | ||
| service | redis | The service name for this integration. | | ||
<h3 id="koa">koa</h3> | ||
<h5 id="koa-tags">Tags</h5> | ||
| Tag | Description | | ||
|------------------|-----------------------------------------------------------| | ||
| http.url | The complete URL of the request. | | ||
| http.method | The HTTP method of the request. | | ||
| http.status_code | The HTTP status code of the response. | | ||
| http.headers.* | A recorded HTTP header. | | ||
<h5 id="koa-config">Configuration Options</h5> | ||
| Option | Default | Description | | ||
|------------------|---------------------------|----------------------------------------| | ||
| service | *Service name of the app* | The service name for this integration. | | ||
| validateStatus | `code => code < 500` | Callback function to determine if there was an error. It should take a status code as its only parameter and return `true` for success or `false` for errors. | | ||
| headers | `[]` | An array of headers to include in the span metadata. | | ||
<h3 id="memcached">memcached</h3> | ||
<h5 id="memcached-tags">Tags</h5> | ||
| Tag | Description | | ||
|------------------|-----------------------------------------------------------| | ||
| memcached.query | The query sent to the server. | | ||
| out.host | The host of the Memcached server. | | ||
| out.port | The port of the Memcached server. | | ||
<h5 id="memcached-config">Configuration Options</h5> | ||
| Option | Default | Description | | ||
|------------------|------------------|----------------------------------------| | ||
| service | memcached | The service name for this integration. | | ||
<h3 id="mongodb-core">mongodb-core</h3> | ||
@@ -287,2 +357,22 @@ | ||
<h3 id="restify">restify</h3> | ||
<h5 id="restify-tags">Tags</h5> | ||
| Tag | Description | | ||
|------------------|-----------------------------------------------------------| | ||
| http.url | The complete URL of the request. | | ||
| http.method | The HTTP method of the request. | | ||
| http.status_code | The HTTP status code of the response. | | ||
| http.headers.* | A recorded HTTP header. | | ||
<h5 id="restify-config">Configuration Options</h5> | ||
| Option | Default | Description | | ||
|------------------|---------------------------|----------------------------------------| | ||
| service | *Service name of the app* | The service name for this integration. | | ||
| validateStatus | `code => code < 500` | Callback function to determine if there was an error. It should take a status code as its only parameter and return `true` for success or `false` for errors. | | ||
| headers | `[]` | An array of headers to include in the span metadata. | | ||
<h2 id="advanced-configuration">Advanced Configuration</h2> | ||
@@ -289,0 +379,0 @@ |
'use strict' | ||
module.exports = { | ||
// Common | ||
SERVICE_NAME: 'service.name', | ||
RESOURCE_NAME: 'resource.name', | ||
SPAN_TYPE: 'span.type', | ||
SAMPLING_PRIORITY: 'sampling.priority' | ||
SPAN_KIND: 'span.kind', | ||
SAMPLING_PRIORITY: 'sampling.priority', | ||
ERROR: 'error', | ||
// HTTP | ||
HTTP_URL: 'http.url', | ||
HTTP_METHOD: 'http.method', | ||
HTTP_STATUS_CODE: 'http.status_code', | ||
HTTP_HEADERS: 'http.headers' | ||
} |
@@ -1,1 +0,1 @@ | ||
module.exports = '0.6.0-beta.2' | ||
module.exports = '0.6.0' |
{ | ||
"name": "dd-trace", | ||
"version": "0.6.0-beta.2", | ||
"version": "0.6.0", | ||
"description": "Datadog APM tracing client for JavaScript", | ||
@@ -13,3 +13,3 @@ "main": "index.js", | ||
"test": "node ./scripts/install_plugin_modules && nyc --reporter text --reporter lcov mocha 'test/**/*.spec.js'", | ||
"leak": "node --no-warnings ./node_modules/.bin/tape 'test/leak/**/*.js'" | ||
"leak": "(cd test/leak && yarn) && NODE_PATH=./test/leak/node_modules node --no-warnings ./node_modules/.bin/tape 'test/leak/{,!(node_modules)/**/}/*.js'" | ||
}, | ||
@@ -78,2 +78,3 @@ "repository": { | ||
"jsdoc": "^3.5.5", | ||
"memcached": "^2.2.2", | ||
"mocha": "^5.2.0", | ||
@@ -90,9 +91,7 @@ "mongodb-core": "^3.0.7", | ||
"retry": "^0.10.1", | ||
"selfsigned": "^1.10.3", | ||
"sinon": "^4.2.1", | ||
"sinon-chai": "^2.14.0", | ||
"tape": "^4.9.1" | ||
}, | ||
"optionalDependencies": { | ||
"@airbnb/node-memwatch": "^1.0.2" | ||
} | ||
} |
@@ -9,5 +9,5 @@ 'use strict' | ||
const filePath = path.join(__dirname, '..', '/LICENSE-3rdparty.csv') | ||
const deps = Object.keys(pkg.dependencies) | ||
.concat(Object.keys(pkg.devDependencies)) | ||
.concat(Object.keys(pkg.optionalDependencies)) | ||
const deps = Object.keys(pkg.dependencies || {}) | ||
.concat(Object.keys(pkg.devDependencies || {})) | ||
.concat(Object.keys(pkg.optionalDependencies || {})) | ||
.sort() | ||
@@ -14,0 +14,0 @@ |
@@ -10,2 +10,3 @@ 'use strict' | ||
const plugins = requireDir('../src/plugins') | ||
const externals = require('../test/plugins/externals') | ||
@@ -23,10 +24,13 @@ const workspaces = new Set() | ||
function assertVersions () { | ||
Object.keys(plugins).filter(key => key !== 'index').forEach(key => { | ||
[].concat(plugins[key]).forEach(instrumentation => { | ||
[].concat(instrumentation.versions).forEach(version => { | ||
if (version) { | ||
assertModules(instrumentation.name, version) | ||
assertModules(instrumentation.name, semver.coerce(version).version) | ||
} | ||
}) | ||
const internals = Object.keys(plugins) | ||
.filter(key => key !== 'index') | ||
.map(key => plugins[key]) | ||
.reduce((prev, next) => prev.concat(next), []) | ||
internals.concat(externals).forEach(instrumentation => { | ||
[].concat(instrumentation.versions).forEach(version => { | ||
if (version) { | ||
assertModules(instrumentation.name, version) | ||
assertModules(instrumentation.name, semver.coerce(version).version) | ||
} | ||
}) | ||
@@ -33,0 +37,0 @@ }) |
'use strict' | ||
const Uint64BE = require('int64-buffer').Uint64BE | ||
const Int64BE = require('int64-buffer').Int64BE | ||
const DatadogSpanContext = require('../span_context') | ||
@@ -15,4 +14,4 @@ | ||
inject (spanContext, carrier) { | ||
carrier[traceKey] = new Int64BE(spanContext.traceId.toBuffer()).toString() | ||
carrier[spanKey] = new Int64BE(spanContext.spanId.toBuffer()).toString() | ||
carrier[traceKey] = spanContext.traceId.toString() | ||
carrier[spanKey] = spanContext.spanId.toString() | ||
@@ -19,0 +18,0 @@ this._injectSamplingPriority(spanContext, carrier) |
'use strict' | ||
const Buffer = require('safe-buffer').Buffer | ||
const Uint64BE = require('int64-buffer').Uint64BE | ||
const randomBytes = require('crypto').randomBytes | ||
module.exports = () => new Uint64BE(randomBytes(8)) | ||
// Cryptographically secure local seeds to mitigate Math.random() seed reuse. | ||
const hiSeed = randomBytes(4).readUInt32BE() | ||
const loSeed = randomBytes(4).readUInt32BE() | ||
// Simple pseudo-random 64-bit ID generator. | ||
function pseudoRandom () { | ||
const buffer = Buffer.allocUnsafe(8) | ||
const hi = randomUInt32(hiSeed) & 0x7FFFFFFF // only positive int64 | ||
const lo = randomUInt32(loSeed) | ||
writeUInt32BE(buffer, hi, 0) | ||
writeUInt32BE(buffer, lo, 4) | ||
return buffer | ||
} | ||
// Generate a random unsigned 32-bit integer. | ||
function randomUInt32 (seed) { | ||
return seed ^ Math.floor(Math.random() * (0xFFFFFFFF + 1)) | ||
} | ||
// Write unsigned integer bytes to a buffer. Faster than Buffer.writeUInt32BE(). | ||
function writeUInt32BE (buffer, value, offset) { | ||
buffer[3 + offset] = value & 255 | ||
value = value >> 8 | ||
buffer[2 + offset] = value & 255 | ||
value = value >> 8 | ||
buffer[1 + offset] = value & 255 | ||
value = value >> 8 | ||
buffer[0 + offset] = value & 255 | ||
} | ||
module.exports = () => new Uint64BE(pseudoRandom()) |
'use strict' | ||
const opentracing = require('opentracing') | ||
const Tags = opentracing.Tags | ||
const FORMAT_HTTP_HEADERS = opentracing.FORMAT_HTTP_HEADERS | ||
const METHODS = require('methods').concat('use', 'route', 'param', 'all') | ||
const pathToRegExp = require('path-to-regexp') | ||
const log = require('../log') | ||
const web = require('./util/web') | ||
const OPERATION_NAME = 'express.request' | ||
function createWrapMethod (tracer, config) { | ||
const headersToRecord = getHeadersToRecord(config) | ||
const validateStatus = getStatusValidator(config) | ||
config = web.normalizeConfig(config) | ||
function ddTrace (req, res, next) { | ||
if (req._datadog.span) return next() | ||
if (web.active(req)) return next() | ||
const url = `${req.protocol}://${req.get('host')}${req.originalUrl}` | ||
const childOf = tracer.extract(FORMAT_HTTP_HEADERS, req.headers) | ||
web.instrument(tracer, config, req, res, 'express.request') | ||
const span = tracer.startSpan(OPERATION_NAME, { | ||
childOf, | ||
tags: { | ||
[Tags.SPAN_KIND]: Tags.SPAN_KIND_RPC_SERVER, | ||
[Tags.HTTP_URL]: url, | ||
[Tags.HTTP_METHOD]: req.method | ||
} | ||
}) | ||
const originalEnd = res.end | ||
res.end = function () { | ||
if (req._datadog.finished) return originalEnd.apply(this, arguments) | ||
const returned = originalEnd.apply(this, arguments) | ||
const path = req._datadog.paths.join('') | ||
const resource = [req.method].concat(path).filter(val => val).join(' ') | ||
span.setTag('resource.name', resource) | ||
span.setTag('service.name', config.service || tracer._service) | ||
span.setTag('span.type', 'http') | ||
span.setTag(Tags.HTTP_STATUS_CODE, res.statusCode) | ||
if (!validateStatus(res.statusCode)) { | ||
span.setTag(Tags.ERROR, true) | ||
} | ||
headersToRecord.forEach(key => { | ||
const value = req.headers[key] | ||
if (value) { | ||
span.setTag(`http.headers.${key}`, value) | ||
} | ||
}) | ||
span.finish() | ||
req._datadog.scope && req._datadog.scope.close() | ||
req._datadog.finished = true | ||
return returned | ||
} | ||
req._datadog.span = span | ||
next() | ||
@@ -83,7 +32,3 @@ } | ||
return function handleWithTracer (req) { | ||
if (!req._datadog) { | ||
Object.defineProperty(req, '_datadog', { | ||
value: { paths: [] } | ||
}) | ||
} | ||
web.patch(req) | ||
@@ -106,3 +51,3 @@ return handle.apply(this, arguments) | ||
if (matchers[i].test(layer.path)) { | ||
req._datadog.paths.push(matchers[i].path) | ||
web.enterRoute(req, matchers[i].path) | ||
@@ -148,3 +93,3 @@ break | ||
function wrapNext (tracer, layer, req, next) { | ||
if (!req._datadog.span) { | ||
if (!web.active(req)) { | ||
return next | ||
@@ -155,8 +100,7 @@ } | ||
req._datadog.scope && req._datadog.scope.close() | ||
req._datadog.scope = tracer.scopeManager().activate(req._datadog.span) | ||
web.reactivate(req) | ||
return function (error) { | ||
if (!error && layer.path && !isFastStar(layer)) { | ||
req._datadog.paths.pop() | ||
web.exitRoute(req) | ||
} | ||
@@ -170,24 +114,2 @@ | ||
function getHeadersToRecord (config) { | ||
if (Array.isArray(config.headers)) { | ||
try { | ||
return config.headers.map(key => key.toLowerCase()) | ||
} catch (err) { | ||
log.error(err) | ||
} | ||
} else if (config.hasOwnProperty('headers')) { | ||
log.error('Expected `headers` to be an array of strings.') | ||
} | ||
return [] | ||
} | ||
function getStatusValidator (config) { | ||
if (typeof config.validateStatus === 'function') { | ||
return config.validateStatus | ||
} else if (config.hasOwnProperty('validateStatus')) { | ||
log.error('Expected `validateStatus` to be a function.') | ||
} | ||
return code => code < 500 | ||
} | ||
function extractMatchers (fn) { | ||
@@ -194,0 +116,0 @@ const arg = flatten([].concat(fn)) |
@@ -5,2 +5,3 @@ 'use strict' | ||
const opentracing = require('opentracing') | ||
const semver = require('semver') | ||
@@ -10,17 +11,17 @@ const Tags = opentracing.Tags | ||
function patch (http, tracer, config) { | ||
this.wrap(http, 'request', request => makeRequestTrace(request)) | ||
this.wrap(http, 'get', get => makeRequestTrace(get)) | ||
function patch (http, methodName, tracer, config) { | ||
this.wrap(http, methodName, fn => makeRequestTrace(fn)) | ||
function makeRequestTrace (request) { | ||
return function requestTrace (options, callback) { | ||
const uri = extractUrl(options) | ||
const method = (options.method || 'GET').toUpperCase() | ||
return function requestTrace () { | ||
const args = normalizeArgs.apply(null, arguments) | ||
const uri = args.uri | ||
const options = args.options | ||
const callback = args.callback | ||
if (uri === `${tracer._url.href}/v0.4/traces`) { | ||
return request.apply(this, [options, callback]) | ||
return request.call(this, options, callback) | ||
} | ||
options = typeof options === 'string' ? url.parse(uri) : Object.assign({}, options) | ||
options.headers = options.headers || {} | ||
const method = (options.method || 'GET').toUpperCase() | ||
@@ -85,2 +86,14 @@ const parentScope = tracer.scopeManager().active() | ||
} | ||
function normalizeArgs (inputURL, inputOptions, callback) { | ||
let options = typeof inputURL === 'string' ? url.parse(inputURL) : Object.assign({}, inputURL) | ||
options.headers = options.headers || {} | ||
if (typeof inputOptions === 'function') { | ||
callback = inputOptions | ||
} else if (typeof inputOptions === 'object') { | ||
options = Object.assign(options, inputOptions) | ||
} | ||
const uri = extractUrl(options) | ||
return { uri, options, callback } | ||
} | ||
} | ||
@@ -144,3 +157,12 @@ | ||
name: 'http', | ||
patch, | ||
patch: function (http, tracer, config) { | ||
patch.call(this, http, 'request', tracer, config) | ||
if (semver.satisfies(process.version, '>=8')) { | ||
/** | ||
* In newer Node versions references internal to modules, such as `http(s).get` calling `http(s).request`, do | ||
* not use externally patched versions, which is why we need to also patch `get` here separately. | ||
*/ | ||
patch.call(this, http, 'get', tracer, config) | ||
} | ||
}, | ||
unpatch | ||
@@ -150,5 +172,16 @@ }, | ||
name: 'https', | ||
patch, | ||
patch: function (http, tracer, config) { | ||
if (semver.satisfies(process.version, '>=9')) { | ||
patch.call(this, http, 'request', tracer, config) | ||
patch.call(this, http, 'get', tracer, config) | ||
} else { | ||
/** | ||
* Below Node v9 the `https` module invokes `http.request`, which would end up counting requests twice. | ||
* So rather then patch the `https` module, we ensure the `http` module is patched and we count only there. | ||
*/ | ||
require('http') | ||
} | ||
}, | ||
unpatch | ||
} | ||
] |
@@ -9,3 +9,7 @@ 'use strict' | ||
'graphql': require('./graphql'), | ||
'hapi': require('./hapi'), | ||
'http': require('./http'), | ||
'ioredis': require('./ioredis'), | ||
'koa': require('./koa'), | ||
'memcached': require('./memcached'), | ||
'mongodb-core': require('./mongodb-core'), | ||
@@ -15,3 +19,4 @@ 'mysql': require('./mysql'), | ||
'pg': require('./pg'), | ||
'redis': require('./redis') | ||
'redis': require('./redis'), | ||
'restify': require('./restify') | ||
} |
@@ -17,3 +17,3 @@ 'use strict' | ||
'x-datadog-trace-id': '123', | ||
'x-datadog-parent-id': '-456', | ||
'x-datadog-parent-id': '18446744073709551160', // -456 casted to uint64 | ||
'ot-baggage-foo': 'bar' | ||
@@ -38,3 +38,3 @@ } | ||
expect(carrier).to.have.property('x-datadog-trace-id', '123') | ||
expect(carrier).to.have.property('x-datadog-parent-id', '-456') | ||
expect(carrier).to.have.property('x-datadog-parent-id', '18446744073709551160') // -456 casted to uint64 | ||
expect(carrier).to.have.property('ot-baggage-foo', 'bar') | ||
@@ -41,0 +41,0 @@ }) |
@@ -65,3 +65,10 @@ 'use strict' | ||
beforeEach(() => { | ||
randomBytes = sinon.stub() | ||
const seed = Buffer.alloc(4) | ||
seed.writeUInt32BE(0xFF000000) | ||
randomBytes = sinon.stub().returns(seed) | ||
sinon.stub(Math, 'random') | ||
id = proxyquire('../src/platform/node/id', { | ||
@@ -72,10 +79,10 @@ 'crypto': { randomBytes } | ||
it('should return a random 64bit ID', () => { | ||
const buffer = Buffer.alloc(8) | ||
buffer.writeUInt32BE(0x12345678) | ||
buffer.writeUInt32BE(0x87654321, 4) | ||
afterEach(() => { | ||
Math.random.restore() | ||
}) | ||
randomBytes.returns(buffer) | ||
it('should return a random 63bit ID', () => { | ||
Math.random.returns(0x0000FF00 / (0xFFFFFFFF + 1)) | ||
expect(id().toString('16')).to.equal('1234567887654321') | ||
expect(id().toBuffer().toString('hex')).to.equal('7f00ff00ff00ff00') | ||
}) | ||
@@ -82,0 +89,0 @@ }) |
@@ -11,10 +11,10 @@ 'use strict' | ||
const handlers = new Set() | ||
let agent = null | ||
let server = null | ||
let listener = null | ||
let tracer = null | ||
let handlers = [] | ||
let promise | ||
let skip = [] | ||
module.exports = { | ||
// Load the plugin on the tracer with an optional config and start a mock agent. | ||
load (plugin, pluginName, config) { | ||
@@ -32,10 +32,3 @@ tracer = require('../..') | ||
res.status(200).send('OK') | ||
if (skip[0]) { | ||
skip[0].resolve() | ||
skip.shift() | ||
} else if (handlers[0]) { | ||
handlers[0](req.body) | ||
handlers.shift() | ||
} | ||
handlers.forEach(handler => handler(req.body)) | ||
}) | ||
@@ -45,3 +38,3 @@ | ||
return new Promise((resolve, reject) => { | ||
const server = http.createServer(agent) | ||
server = http.createServer(agent) | ||
@@ -67,35 +60,58 @@ listener = server.listen(port, 'localhost', resolve) | ||
use (callback, count) { | ||
count = count || 1 | ||
promise = Promise.reject(new Error('No request was expected.')) | ||
// Register a callback with expectations to be run on every agent call. | ||
use (callback) { | ||
const deferred = {} | ||
const promise = new Promise((resolve, reject) => { | ||
deferred.resolve = resolve | ||
deferred.reject = reject | ||
}) | ||
for (let i = 0; i < count; i++) { | ||
promise = promise.catch(() => new Promise((resolve, reject) => { | ||
handlers.push(function () { | ||
try { | ||
callback.apply(null, arguments) | ||
resolve() | ||
} catch (e) { | ||
reject(e) | ||
} | ||
}) | ||
})) | ||
const timeout = setTimeout(() => { | ||
if (error) { | ||
deferred.reject(error) | ||
} | ||
}, 1000) | ||
let error | ||
const handler = function () { | ||
try { | ||
callback.apply(null, arguments) | ||
handlers.delete(handler) | ||
clearTimeout(timeout) | ||
deferred.resolve() | ||
} catch (e) { | ||
error = error || e | ||
} | ||
} | ||
handler.promise = promise | ||
handlers.add(handler) | ||
return promise | ||
}, | ||
skip (count) { | ||
for (let i = 0; i < count; i++) { | ||
const defer = {} | ||
// Return a promise that will resolve when all expectations have run. | ||
promise () { | ||
const promises = Array.from(handlers) | ||
.map(handler => handler.promise.catch(e => e)) | ||
defer.promise = new Promise((resolve, reject) => { | ||
defer.resolve = resolve | ||
defer.reject = reject | ||
}) | ||
return Promise.all(promises) | ||
.then(results => results.find(e => e instanceof Error)) | ||
}, | ||
skip.push(defer) | ||
// Unregister any outstanding expectation callbacks. | ||
reset () { | ||
handlers.clear() | ||
}, | ||
// Wrap a callback so it will only be called when all expectations have run. | ||
wrap (callback) { | ||
return error => { | ||
this.promise() | ||
.then(err => callback(error || err)) | ||
} | ||
}, | ||
// Return the current active span. | ||
currentSpan () { | ||
@@ -106,19 +122,22 @@ const scope = tracer.scopeManager().active() | ||
// Stop the mock agent, reset all expectations and wipe the require cache. | ||
close () { | ||
const timeout = setTimeout(() => { | ||
skip.forEach(defer => defer.resolve()) | ||
}, 1000) | ||
this.wipe() | ||
return Promise.all(skip.map(defer => defer.promise)) | ||
.then(() => { | ||
clearTimeout(timeout) | ||
listener.close() | ||
listener = null | ||
agent = null | ||
handlers = [] | ||
skip = [] | ||
delete require.cache[require.resolve('../..')] | ||
listener.close() | ||
listener = null | ||
agent = null | ||
handlers.clear() | ||
delete require.cache[require.resolve('../..')] | ||
return new Promise((resolve, reject) => { | ||
server.on('close', () => { | ||
server = null | ||
resolve() | ||
}) | ||
}) | ||
}, | ||
// Wipe the require cache. | ||
wipe () { | ||
@@ -125,0 +144,0 @@ const basedir = path.join(__dirname, 'versions') |
@@ -21,26 +21,28 @@ 'use strict' | ||
connection.close() | ||
agent.close() | ||
agent.wipe() | ||
}) | ||
describe('without configuration', () => { | ||
before(() => { | ||
return agent.load(plugin, 'amqplib') | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
describe('when using a callback', () => { | ||
beforeEach(done => { | ||
agent.load(plugin, 'amqplib') | ||
.then(() => { | ||
require(`./versions/amqplib@${version}`).get('amqplib/callback_api') | ||
.connect((err, conn) => { | ||
connection = conn | ||
require(`./versions/amqplib@${version}`).get('amqplib/callback_api') | ||
.connect((err, conn) => { | ||
connection = conn | ||
if (err != null) { | ||
return done(err) | ||
} | ||
if (err != null) { | ||
return done(err) | ||
} | ||
conn.createChannel((err, ch) => { | ||
channel = ch | ||
done(err) | ||
}) | ||
}) | ||
conn.createChannel((err, ch) => { | ||
channel = ch | ||
done(err) | ||
}) | ||
}) | ||
.catch(done) | ||
}) | ||
@@ -219,4 +221,3 @@ | ||
beforeEach(() => { | ||
return agent.load(plugin, 'amqplib') | ||
.then(() => require(`./versions/amqplib@${version}`).get().connect()) | ||
return require(`./versions/amqplib@${version}`).get().connect() | ||
.then(conn => (connection = conn)) | ||
@@ -241,20 +242,24 @@ .then(conn => conn.createChannel()) | ||
describe('with configuration', () => { | ||
before(() => { | ||
return agent.load(plugin, 'amqplib', { service: 'test' }) | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
beforeEach(done => { | ||
agent.load(plugin, 'amqplib', { service: 'test' }) | ||
.then(() => { | ||
require(`./versions/amqplib@${version}`).get('amqplib/callback_api') | ||
.connect((err, conn) => { | ||
connection = conn | ||
require(`./versions/amqplib@${version}`).get('amqplib/callback_api') | ||
.connect((err, conn) => { | ||
connection = conn | ||
if (err !== null) { | ||
return done(err) | ||
} | ||
if (err !== null) { | ||
return done(err) | ||
} | ||
conn.createChannel((err, ch) => { | ||
channel = ch | ||
done(err) | ||
}) | ||
}) | ||
conn.createChannel((err, ch) => { | ||
channel = ch | ||
done(err) | ||
}) | ||
}) | ||
.catch(done) | ||
}) | ||
@@ -261,0 +266,0 @@ |
@@ -18,20 +18,20 @@ 'use strict' | ||
afterEach(() => { | ||
agent.close() | ||
agent.wipe() | ||
}) | ||
describe('without configuration', () => { | ||
let client | ||
beforeEach(() => { | ||
before(() => { | ||
return agent.load(plugin, 'elasticsearch') | ||
.then(() => { | ||
elasticsearch = require(`./versions/elasticsearch@${version}`).get() | ||
client = new elasticsearch.Client({ | ||
host: 'localhost:9200' | ||
}) | ||
}) | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
beforeEach(() => { | ||
elasticsearch = require(`./versions/elasticsearch@${version}`).get() | ||
client = new elasticsearch.Client({ | ||
host: 'localhost:9200' | ||
}) | ||
}) | ||
it('should sanitize the resource name', done => { | ||
@@ -226,12 +226,17 @@ agent | ||
beforeEach(() => { | ||
before(() => { | ||
return agent.load(plugin, 'elasticsearch', { service: 'test' }) | ||
.then(() => { | ||
elasticsearch = require(`./versions/elasticsearch@${version}`).get() | ||
client = new elasticsearch.Client({ | ||
host: 'localhost:9200' | ||
}) | ||
}) | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
beforeEach(() => { | ||
elasticsearch = require(`./versions/elasticsearch@${version}`).get() | ||
client = new elasticsearch.Client({ | ||
host: 'localhost:9200' | ||
}) | ||
}) | ||
it('should be configured with the correct values', done => { | ||
@@ -238,0 +243,0 @@ agent |
@@ -22,3 +22,2 @@ 'use strict' | ||
afterEach(() => { | ||
agent.close() | ||
appListener.close() | ||
@@ -28,9 +27,14 @@ }) | ||
describe('without configuration', () => { | ||
beforeEach(() => { | ||
before(() => { | ||
return agent.load(plugin, 'express') | ||
.then(() => { | ||
express = require(`./versions/express@${version}`).get() | ||
}) | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
beforeEach(() => { | ||
express = require(`./versions/express@${version}`).get() | ||
}) | ||
it('should do automatic instrumentation on app routes', done => { | ||
@@ -481,7 +485,2 @@ const app = express() | ||
axios.get(`http://localhost:${port}/app/user/123`) | ||
.then(res => { | ||
expect(res.status).to.equal(200) | ||
expect(res.data).to.be.empty | ||
done() | ||
}) | ||
.catch(done) | ||
@@ -553,17 +552,18 @@ }) | ||
describe('with configuration', () => { | ||
let config | ||
beforeEach(() => { | ||
config = { | ||
before(() => { | ||
return agent.load(plugin, 'express', { | ||
service: 'custom', | ||
validateStatus: code => code < 400, | ||
headers: ['User-Agent'] | ||
} | ||
}) | ||
}) | ||
return agent.load(plugin, 'express', config) | ||
.then(() => { | ||
express = require(`./versions/express@${version}`).get() | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
beforeEach(() => { | ||
express = require(`./versions/express@${version}`).get() | ||
}) | ||
it('should be configured with the correct service name', done => { | ||
@@ -570,0 +570,0 @@ const app = express() |
@@ -143,15 +143,10 @@ 'use strict' | ||
withVersions(plugin, 'graphql', version => { | ||
beforeEach(() => { | ||
tracer = require('../..') | ||
before(() => { | ||
sort = spans => spans.sort((a, b) => a.start.toString() >= b.start.toString() ? 1 : -1) | ||
}) | ||
afterEach(() => { | ||
agent.close() | ||
agent.wipe() | ||
}) | ||
describe('without configuration', () => { | ||
before(() => { | ||
tracer = require('../..') | ||
describe('without configuration', () => { | ||
beforeEach(() => { | ||
return agent.load(plugin, 'graphql') | ||
@@ -164,2 +159,6 @@ .then(() => { | ||
after(() => { | ||
return agent.close() | ||
}) | ||
it('should instrument operations', done => { | ||
@@ -477,5 +476,4 @@ const source = `query MyQuery { hello(name: "world") }` | ||
expect(result.data.human.pets[0].owner.name).to.equal('test') | ||
done() | ||
}) | ||
.then(done) | ||
.catch(done) | ||
@@ -782,12 +780,20 @@ }) | ||
describe('with configuration', () => { | ||
beforeEach(() => { | ||
before(() => { | ||
tracer = require('../..') | ||
return agent.load(plugin, 'graphql', { | ||
service: 'test', | ||
variables: variables => Object.assign({}, variables, { who: 'REDACTED' }) | ||
}).then(() => { | ||
graphql = require(`./versions/graphql@${version}`).get() | ||
buildSchema() | ||
}) | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
beforeEach(() => { | ||
graphql = require(`./versions/graphql@${version}`).get() | ||
buildSchema() | ||
}) | ||
it('should be configured with the correct values', done => { | ||
@@ -831,10 +837,17 @@ const source = `{ hello(name: "world") }` | ||
describe('with a depth of 0', () => { | ||
beforeEach(() => { | ||
before(() => { | ||
tracer = require('../..') | ||
return agent.load(plugin, 'graphql', { depth: 0 }) | ||
.then(() => { | ||
graphql = require(`./versions/graphql@${version}`).get() | ||
buildSchema() | ||
}) | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
beforeEach(() => { | ||
graphql = require(`./versions/graphql@${version}`).get() | ||
buildSchema() | ||
}) | ||
it('should only instrument the operation', done => { | ||
@@ -871,10 +884,17 @@ const source = ` | ||
describe('with a depth >=1', () => { | ||
beforeEach(() => { | ||
before(() => { | ||
tracer = require('../..') | ||
return agent.load(plugin, 'graphql', { depth: 2 }) | ||
.then(() => { | ||
graphql = require(`./versions/graphql@${version}`).get() | ||
buildSchema() | ||
}) | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
beforeEach(() => { | ||
graphql = require(`./versions/graphql@${version}`).get() | ||
buildSchema() | ||
}) | ||
it('should only instrument up to the specified depth', done => { | ||
@@ -881,0 +901,0 @@ const source = ` |
@@ -5,2 +5,3 @@ 'use strict' | ||
const agent = require('./agent') | ||
const semver = require('semver') | ||
@@ -15,445 +16,583 @@ wrapIt() | ||
let tracer | ||
let pems | ||
describe('http', () => { | ||
beforeEach(() => { | ||
plugin = require('../../src/plugins/http') | ||
tracer = require('../..') | ||
}) | ||
['http', 'https'].forEach(protocol => { | ||
describe(protocol, () => { | ||
function server (app, port, listener) { | ||
let server | ||
if (protocol === 'https') { | ||
if (!pems) { | ||
// Generate self-signed cert | ||
pems = require('selfsigned').generate([{ name: 'commonName', value: 'datadoghq.com' }], { days: 365 }) | ||
// We're fine with self-signed certs for this test | ||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' | ||
} | ||
server = require('https').createServer({ key: pems.private, cert: pems.cert }, app) | ||
} else { | ||
server = require('http').createServer(app) | ||
} | ||
server.listen(port, 'localhost', listener) | ||
return server | ||
} | ||
afterEach(() => { | ||
appListener.close() | ||
return agent.close() | ||
}) | ||
describe('without configuration', () => { | ||
beforeEach(() => { | ||
return agent.load(plugin, 'http') | ||
.then(() => { | ||
http = require('http') | ||
express = require('express') | ||
}) | ||
plugin = require('../../src/plugins/http') | ||
tracer = require('../..') | ||
appListener = null | ||
}) | ||
it('should do automatic instrumentation', done => { | ||
const app = express() | ||
afterEach(() => { | ||
if (appListener) { | ||
appListener.close() | ||
} | ||
return agent.close() | ||
}) | ||
app.get('/user', (req, res) => { | ||
res.status(200).send() | ||
describe('without configuration', () => { | ||
beforeEach(() => { | ||
return agent.load(plugin, 'http') | ||
.then(() => { | ||
http = require(protocol) | ||
express = require('express') | ||
}) | ||
}) | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
expect(traces[0][0]).to.have.property('service', 'test-http-client') | ||
expect(traces[0][0]).to.have.property('type', 'web') | ||
expect(traces[0][0]).to.have.property('resource', 'GET') | ||
expect(traces[0][0].meta).to.have.property('span.kind', 'client') | ||
expect(traces[0][0].meta).to.have.property('http.url', `http://localhost:${port}/user`) | ||
expect(traces[0][0].meta).to.have.property('http.method', 'GET') | ||
expect(traces[0][0].meta).to.have.property('http.status_code', '200') | ||
}) | ||
.then(done) | ||
.catch(done) | ||
it('should do automatic instrumentation', done => { | ||
const app = express() | ||
appListener = app.listen(port, 'localhost', () => { | ||
const req = http.request(`http://localhost:${port}/user`, res => { | ||
res.on('data', () => {}) | ||
app.get('/user', (req, res) => { | ||
res.status(200).send() | ||
}) | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
expect(traces[0][0]).to.have.property('service', 'test-http-client') | ||
expect(traces[0][0]).to.have.property('type', 'web') | ||
expect(traces[0][0]).to.have.property('resource', 'GET') | ||
expect(traces[0][0].meta).to.have.property('span.kind', 'client') | ||
expect(traces[0][0].meta).to.have.property('http.url', `${protocol}://localhost:${port}/user`) | ||
expect(traces[0][0].meta).to.have.property('http.method', 'GET') | ||
expect(traces[0][0].meta).to.have.property('http.status_code', '200') | ||
}) | ||
.then(done) | ||
.catch(done) | ||
appListener = server(app, port, () => { | ||
const req = http.request(`${protocol}://localhost:${port}/user`, res => { | ||
res.on('data', () => {}) | ||
}) | ||
req.end() | ||
}) | ||
req.end() | ||
}) | ||
}) | ||
}) | ||
it('should also support http.get', done => { | ||
const app = express() | ||
it(`should also support get()`, done => { | ||
const app = express() | ||
app.get('/user', (req, res) => { | ||
res.status(200).send() | ||
}) | ||
app.get('/user', (req, res) => { | ||
res.status(200).send() | ||
}) | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
expect(traces[0][0]).to.not.be.undefined | ||
}) | ||
.then(done) | ||
.catch(done) | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
expect(traces[0][0]).to.not.be.undefined | ||
}) | ||
.then(done) | ||
.catch(done) | ||
appListener = app.listen(port, 'localhost', () => { | ||
const req = http.get(`http://localhost:${port}/user`, res => { | ||
res.on('data', () => {}) | ||
appListener = server(app, port, () => { | ||
const req = http.get(`${protocol}://localhost:${port}/user`, res => { | ||
res.on('data', () => {}) | ||
}) | ||
req.end() | ||
}) | ||
req.end() | ||
}) | ||
}) | ||
}) | ||
it('should support configuration as an URL object', done => { | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
expect(traces[0][0].meta).to.have.property('http.url', `http://localhost:${port}/user`) | ||
}) | ||
.then(done) | ||
.catch(done) | ||
it('should support configuration as an URL object', done => { | ||
const app = express() | ||
const uri = { | ||
hostname: 'localhost', | ||
port, | ||
pathname: '/user' | ||
} | ||
app.get('/user', (req, res) => { | ||
res.status(200).send() | ||
}) | ||
const req = http.request(uri) | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
expect(traces[0][0].meta).to.have.property('http.url', `${protocol}://localhost:${port}/user`) | ||
}) | ||
.then(done) | ||
.catch(done) | ||
req.end() | ||
const uri = { | ||
protocol: `${protocol}:`, | ||
hostname: 'localhost', | ||
port, | ||
pathname: '/user' | ||
} | ||
appListener = server(app, port, () => { | ||
const req = http.request(uri) | ||
req.end() | ||
}) | ||
}) | ||
}) | ||
}) | ||
it('should use the correct defaults when not specified', done => { | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
expect(traces[0][0].meta).to.have.property('http.url', `http://localhost:${port}/`) | ||
if (semver.satisfies(process.version, '>=10')) { | ||
it('should support a string URL and an options object, which merges and takes precedence', done => { | ||
const app = express() | ||
app.get('/user', (req, res) => { | ||
res.status(200).send() | ||
}) | ||
.then(done) | ||
.catch(done) | ||
const req = http.request({ | ||
port | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
expect(traces[0][0].meta).to.have.property('http.url', `${protocol}://localhost:${port}/user`) | ||
}) | ||
.then(done) | ||
.catch(done) | ||
appListener = server(app, port, () => { | ||
const req = http.request(`${protocol}://localhost:${port}/another-path`, { path: '/user' }) | ||
req.end() | ||
}) | ||
}) | ||
}) | ||
req.end() | ||
}) | ||
}) | ||
it('should support a URL object and an options object, which merges and takes precedence', done => { | ||
const app = express() | ||
it('should not require consuming the data', done => { | ||
const app = express() | ||
app.get('/user', (req, res) => { | ||
res.status(200).send() | ||
}) | ||
app.get('/user', (req, res) => { | ||
res.status(200).send() | ||
}) | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
expect(traces[0][0].meta).to.have.property('http.url', `${protocol}://localhost:${port}/user`) | ||
}) | ||
.then(done) | ||
.catch(done) | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
expect(traces[0][0]).to.not.be.undefined | ||
const uri = { | ||
protocol: `${protocol}:`, | ||
hostname: 'localhost', | ||
port, | ||
pathname: '/another-path' | ||
} | ||
appListener = server(app, port, () => { | ||
const req = http.request(uri, { path: '/user' }) | ||
req.end() | ||
}) | ||
}) | ||
.then(done) | ||
.catch(done) | ||
}) | ||
} | ||
appListener = app.listen(port, 'localhost', () => { | ||
const req = http.request(`http://localhost:${port}/user`) | ||
it('should use the correct defaults when not specified', done => { | ||
const app = express() | ||
req.end() | ||
app.get('/user', (req, res) => { | ||
res.status(200).send() | ||
}) | ||
}) | ||
}) | ||
it('should wait for other listeners before resuming the response stream', done => { | ||
const app = express() | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
expect(traces[0][0].meta).to.have.property('http.url', `${protocol}://localhost:${port}/`) | ||
}) | ||
.then(done) | ||
.catch(done) | ||
app.get('/user', (req, res) => { | ||
res.status(200).send('OK') | ||
}) | ||
appListener = server(app, port, () => { | ||
const req = http.request({ | ||
protocol: `${protocol}:`, | ||
port | ||
}) | ||
getPort().then(port => { | ||
appListener = app.listen(port, 'localhost', () => { | ||
const req = http.request(`http://localhost:${port}/user`, res => { | ||
setTimeout(() => { | ||
res.on('data', () => done()) | ||
}) | ||
req.end() | ||
}) | ||
req.end() | ||
}) | ||
}) | ||
}) | ||
it('should inject its parent span in the headers', done => { | ||
const app = express() | ||
it('should not require consuming the data', done => { | ||
const app = express() | ||
app.get('/user', (req, res) => { | ||
expect(req.get('x-datadog-trace-id')).to.be.a('string') | ||
expect(req.get('x-datadog-parent-id')).to.be.a('string') | ||
app.get('/user', (req, res) => { | ||
res.status(200).send() | ||
}) | ||
res.status(200).send() | ||
}) | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
expect(traces[0][0]).to.not.be.undefined | ||
}) | ||
.then(done) | ||
.catch(done) | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
expect(traces[0][0].meta).to.have.property('http.status_code', '200') | ||
appListener = server(app, port, () => { | ||
const req = http.request(`${protocol}://localhost:${port}/user`) | ||
req.end() | ||
}) | ||
.then(done) | ||
.catch(done) | ||
}) | ||
}) | ||
appListener = app.listen(port, 'localhost', () => { | ||
const req = http.request(`http://localhost:${port}/user`) | ||
it('should wait for other listeners before resuming the response stream', done => { | ||
const app = express() | ||
req.end() | ||
app.get('/user', (req, res) => { | ||
res.status(200).send('OK') | ||
}) | ||
getPort().then(port => { | ||
appListener = server(app, port, () => { | ||
const req = http.request(`${protocol}://localhost:${port}/user`, res => { | ||
setTimeout(() => { | ||
res.on('data', () => done()) | ||
}) | ||
}) | ||
req.end() | ||
}) | ||
}) | ||
}) | ||
}) | ||
it('should skip injecting if the Authorization header contains an AWS signature', done => { | ||
const app = express() | ||
it('should inject its parent span in the headers', done => { | ||
const app = express() | ||
app.get('/', (req, res) => { | ||
try { | ||
expect(req.get('x-datadog-trace-id')).to.be.undefined | ||
expect(req.get('x-datadog-parent-id')).to.be.undefined | ||
app.get('/user', (req, res) => { | ||
expect(req.get('x-datadog-trace-id')).to.be.a('string') | ||
expect(req.get('x-datadog-parent-id')).to.be.a('string') | ||
res.status(200).send() | ||
}) | ||
done() | ||
} catch (e) { | ||
done(e) | ||
} | ||
}) | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
expect(traces[0][0].meta).to.have.property('http.status_code', '200') | ||
}) | ||
.then(done) | ||
.catch(done) | ||
getPort().then(port => { | ||
appListener = app.listen(port, 'localhost', () => { | ||
const req = http.request({ | ||
port, | ||
headers: { | ||
Authorization: 'AWS4-HMAC-SHA256 ...' | ||
} | ||
appListener = server(app, port, () => { | ||
const req = http.request(`${protocol}://localhost:${port}/user`) | ||
req.end() | ||
}) | ||
req.end() | ||
}) | ||
}) | ||
}) | ||
it('should skip injecting if one of the Authorization headers contains an AWS signature', done => { | ||
const app = express() | ||
it('should skip injecting if the Authorization header contains an AWS signature', done => { | ||
const app = express() | ||
app.get('/', (req, res) => { | ||
try { | ||
expect(req.get('x-datadog-trace-id')).to.be.undefined | ||
expect(req.get('x-datadog-parent-id')).to.be.undefined | ||
app.get('/', (req, res) => { | ||
try { | ||
expect(req.get('x-datadog-trace-id')).to.be.undefined | ||
expect(req.get('x-datadog-parent-id')).to.be.undefined | ||
res.status(200).send() | ||
res.status(200).send() | ||
done() | ||
} catch (e) { | ||
done(e) | ||
} | ||
}) | ||
done() | ||
} catch (e) { | ||
done(e) | ||
} | ||
}) | ||
getPort().then(port => { | ||
appListener = app.listen(port, 'localhost', () => { | ||
const req = http.request({ | ||
port, | ||
headers: { | ||
Authorization: ['AWS4-HMAC-SHA256 ...'] | ||
} | ||
getPort().then(port => { | ||
appListener = server(app, port, () => { | ||
const req = http.request({ | ||
port, | ||
headers: { | ||
Authorization: 'AWS4-HMAC-SHA256 ...' | ||
} | ||
}) | ||
req.end() | ||
}) | ||
req.end() | ||
}) | ||
}) | ||
}) | ||
it('should skip injecting if the X-Amz-Signature header is set', done => { | ||
const app = express() | ||
it('should skip injecting if one of the Authorization headers contains an AWS signature', done => { | ||
const app = express() | ||
app.get('/', (req, res) => { | ||
try { | ||
expect(req.get('x-datadog-trace-id')).to.be.undefined | ||
expect(req.get('x-datadog-parent-id')).to.be.undefined | ||
app.get('/', (req, res) => { | ||
try { | ||
expect(req.get('x-datadog-trace-id')).to.be.undefined | ||
expect(req.get('x-datadog-parent-id')).to.be.undefined | ||
res.status(200).send() | ||
res.status(200).send() | ||
done() | ||
} catch (e) { | ||
done(e) | ||
} | ||
}) | ||
done() | ||
} catch (e) { | ||
done(e) | ||
} | ||
}) | ||
getPort().then(port => { | ||
appListener = app.listen(port, 'localhost', () => { | ||
const req = http.request({ | ||
port, | ||
headers: { | ||
'X-Amz-Signature': 'abc123' | ||
} | ||
getPort().then(port => { | ||
appListener = server(app, port, () => { | ||
const req = http.request({ | ||
port, | ||
headers: { | ||
Authorization: ['AWS4-HMAC-SHA256 ...'] | ||
} | ||
}) | ||
req.end() | ||
}) | ||
req.end() | ||
}) | ||
}) | ||
}) | ||
it('should skip injecting if the X-Amz-Signature query param is set', done => { | ||
const app = express() | ||
it('should skip injecting if the X-Amz-Signature header is set', done => { | ||
const app = express() | ||
app.get('/', (req, res) => { | ||
try { | ||
expect(req.get('x-datadog-trace-id')).to.be.undefined | ||
expect(req.get('x-datadog-parent-id')).to.be.undefined | ||
app.get('/', (req, res) => { | ||
try { | ||
expect(req.get('x-datadog-trace-id')).to.be.undefined | ||
expect(req.get('x-datadog-parent-id')).to.be.undefined | ||
res.status(200).send() | ||
res.status(200).send() | ||
done() | ||
} catch (e) { | ||
done(e) | ||
} | ||
}) | ||
done() | ||
} catch (e) { | ||
done(e) | ||
} | ||
}) | ||
getPort().then(port => { | ||
appListener = app.listen(port, 'localhost', () => { | ||
const req = http.request({ | ||
port, | ||
path: '/?X-Amz-Signature=abc123' | ||
getPort().then(port => { | ||
appListener = server(app, port, () => { | ||
const req = http.request({ | ||
port, | ||
headers: { | ||
'X-Amz-Signature': 'abc123' | ||
} | ||
}) | ||
req.end() | ||
}) | ||
req.end() | ||
}) | ||
}) | ||
}) | ||
it('should run the callback in the parent context', done => { | ||
if (process.env.DD_CONTEXT_PROPAGATION === 'false') return done() | ||
it('should skip injecting if the X-Amz-Signature query param is set', done => { | ||
const app = express() | ||
const app = express() | ||
app.get('/', (req, res) => { | ||
try { | ||
expect(req.get('x-datadog-trace-id')).to.be.undefined | ||
expect(req.get('x-datadog-parent-id')).to.be.undefined | ||
app.get('/user', (req, res) => { | ||
res.status(200).send('OK') | ||
}) | ||
res.status(200).send() | ||
getPort().then(port => { | ||
appListener = app.listen(port, 'localhost', () => { | ||
const req = http.request(`http://localhost:${port}/user`, res => { | ||
expect(tracer.scopeManager().active()).to.be.null | ||
done() | ||
} catch (e) { | ||
done(e) | ||
} | ||
}) | ||
getPort().then(port => { | ||
appListener = server(app, port, () => { | ||
const req = http.request({ | ||
port, | ||
path: '/?X-Amz-Signature=abc123' | ||
}) | ||
req.end() | ||
}) | ||
req.end() | ||
}) | ||
}) | ||
}) | ||
it('should run the event listeners in the parent context', done => { | ||
if (process.env.DD_CONTEXT_PROPAGATION === 'false') return done() | ||
it('should run the callback in the parent context', done => { | ||
if (process.env.DD_CONTEXT_PROPAGATION === 'false') return done() | ||
const app = express() | ||
const app = express() | ||
app.get('/user', (req, res) => { | ||
res.status(200).send('OK') | ||
}) | ||
app.get('/user', (req, res) => { | ||
res.status(200).send('OK') | ||
}) | ||
getPort().then(port => { | ||
appListener = app.listen(port, 'localhost', () => { | ||
const req = http.request(`http://localhost:${port}/user`, res => { | ||
res.on('data', () => {}) | ||
res.on('end', () => { | ||
getPort().then(port => { | ||
appListener = server(app, port, () => { | ||
const req = http.request(`${protocol}://localhost:${port}/user`, res => { | ||
expect(tracer.scopeManager().active()).to.be.null | ||
done() | ||
}) | ||
req.end() | ||
}) | ||
req.end() | ||
}) | ||
}) | ||
}) | ||
it('should handle errors', done => { | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
expect(traces[0][0].meta).to.have.property('error.type', 'Error') | ||
expect(traces[0][0].meta).to.have.property('error.msg', `connect ECONNREFUSED 127.0.0.1:${port}`) | ||
expect(traces[0][0].meta).to.have.property('error.stack') | ||
it('should run the event listeners in the parent context', done => { | ||
if (process.env.DD_CONTEXT_PROPAGATION === 'false') return done() | ||
const app = express() | ||
app.get('/user', (req, res) => { | ||
res.status(200).send('OK') | ||
}) | ||
getPort().then(port => { | ||
appListener = server(app, port, () => { | ||
const req = http.request(`${protocol}://localhost:${port}/user`, res => { | ||
res.on('data', () => {}) | ||
res.on('end', () => { | ||
expect(tracer.scopeManager().active()).to.be.null | ||
done() | ||
}) | ||
}) | ||
req.end() | ||
}) | ||
.then(done) | ||
.catch(done) | ||
}) | ||
}) | ||
const req = http.request(`http://localhost:${port}/user`) | ||
it('should handle errors', done => { | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
expect(traces[0][0].meta).to.have.property('error.type', 'Error') | ||
expect(traces[0][0].meta).to.have.property('error.msg', `connect ECONNREFUSED 127.0.0.1:${port}`) | ||
expect(traces[0][0].meta).to.have.property('error.stack') | ||
}) | ||
.then(done) | ||
.catch(done) | ||
req.end() | ||
const req = http.request(`${protocol}://localhost:${port}/user`) | ||
req.end() | ||
}) | ||
}) | ||
}) | ||
}) | ||
describe('with service configuration', () => { | ||
let config | ||
it('should only record a request once', done => { | ||
// Make sure both plugins are loaded, which could cause double-counting. | ||
require('http') | ||
require('https') | ||
beforeEach(() => { | ||
config = { | ||
service: 'custom' | ||
} | ||
const app = express() | ||
return agent.load(plugin, 'http', config) | ||
.then(() => { | ||
http = require('http') | ||
express = require('express') | ||
app.get('/user', (req, res) => { | ||
res.status(200).send() | ||
}) | ||
}) | ||
it('should be configured with the correct values', done => { | ||
const app = express() | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
const spans = traces[0] | ||
expect(spans.length).to.equal(3) | ||
}) | ||
.then(done) | ||
.catch(done) | ||
app.get('/user', (req, res) => { | ||
res.status(200).send() | ||
}) | ||
appListener = server(app, port, () => { | ||
// Activate a new parent span so we capture any double counting that may happen, otherwise double-counts | ||
// would be siblings and our test would only capture 1 as a false positive. | ||
const span = tracer.startSpan('http-test') | ||
tracer.scopeManager().activate(span) | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
expect(traces[0][0]).to.have.property('service', 'custom') | ||
}) | ||
.then(done) | ||
.catch(done) | ||
// Test `http(s).request | ||
const req = http.request(`${protocol}://localhost:${port}/user?test=request`, res => { | ||
res.on('data', () => {}) | ||
}) | ||
req.end() | ||
appListener = app.listen(port, 'localhost', () => { | ||
const req = http.request(`http://localhost:${port}/user`, res => { | ||
res.on('data', () => {}) | ||
// Test `http(s).get` | ||
http.get(`${protocol}://localhost:${port}/user?test=get`, res => { | ||
res.on('data', () => {}) | ||
}) | ||
span.finish() | ||
}) | ||
req.end() | ||
}) | ||
}) | ||
}) | ||
}) | ||
describe('with splitByDomain configuration', () => { | ||
let config | ||
describe('with service configuration', () => { | ||
let config | ||
beforeEach(() => { | ||
config = { | ||
splitByDomain: true | ||
} | ||
beforeEach(() => { | ||
config = { | ||
service: 'custom' | ||
} | ||
return agent.load(plugin, 'http', config) | ||
.then(() => { | ||
http = require('http') | ||
express = require('express') | ||
return agent.load(plugin, 'http', config) | ||
.then(() => { | ||
http = require(protocol) | ||
express = require('express') | ||
}) | ||
}) | ||
it('should be configured with the correct values', done => { | ||
const app = express() | ||
app.get('/user', (req, res) => { | ||
res.status(200).send() | ||
}) | ||
}) | ||
it('should use the remote endpoint as the service name', done => { | ||
const app = express() | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
expect(traces[0][0]).to.have.property('service', 'custom') | ||
}) | ||
.then(done) | ||
.catch(done) | ||
app.get('/user', (req, res) => { | ||
res.status(200).send() | ||
}) | ||
appListener = server(app, port, () => { | ||
const req = http.request(`${protocol}://localhost:${port}/user`, res => { | ||
res.on('data', () => {}) | ||
}) | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
expect(traces[0][0]).to.have.property('service', `localhost:${port}`) | ||
req.end() | ||
}) | ||
.then(done) | ||
.catch(done) | ||
}) | ||
}) | ||
}) | ||
appListener = app.listen(port, 'localhost', () => { | ||
const req = http.request(`http://localhost:${port}/user`, res => { | ||
res.on('data', () => {}) | ||
describe('with splitByDomain configuration', () => { | ||
let config | ||
beforeEach(() => { | ||
config = { | ||
splitByDomain: true | ||
} | ||
return agent.load(plugin, 'http', config) | ||
.then(() => { | ||
http = require(protocol) | ||
express = require('express') | ||
}) | ||
}) | ||
req.end() | ||
it('should use the remote endpoint as the service name', done => { | ||
const app = express() | ||
app.get('/user', (req, res) => { | ||
res.status(200).send() | ||
}) | ||
getPort().then(port => { | ||
agent | ||
.use(traces => { | ||
expect(traces[0][0]).to.have.property('service', `localhost:${port}`) | ||
}) | ||
.then(done) | ||
.catch(done) | ||
appListener = server(app, port, () => { | ||
const req = http.request(`${protocol}://localhost:${port}/user`, res => { | ||
res.on('data', () => {}) | ||
}) | ||
req.end() | ||
}) | ||
}) | ||
}) | ||
@@ -460,0 +599,0 @@ }) |
@@ -26,3 +26,2 @@ 'use strict' | ||
afterEach(() => { | ||
agent.close() | ||
server.destroy() | ||
@@ -32,19 +31,23 @@ }) | ||
describe('without configuration', () => { | ||
before(() => { | ||
return agent.load(plugin, 'mongodb-core') | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
beforeEach(done => { | ||
agent.load(plugin, 'mongodb-core') | ||
.then(() => { | ||
mongo = require(`./versions/mongodb-core@${version}`).get() | ||
mongo = require(`./versions/mongodb-core@${version}`).get() | ||
server = new mongo.Server({ | ||
host: 'localhost', | ||
port: 27017, | ||
reconnect: false | ||
}) | ||
server = new mongo.Server({ | ||
host: 'localhost', | ||
port: 27017, | ||
reconnect: false | ||
}) | ||
server.on('connect', () => done()) | ||
server.on('error', done) | ||
server.on('connect', () => done()) | ||
server.on('error', done) | ||
server.connect() | ||
}) | ||
.catch(done) | ||
server.connect() | ||
}) | ||
@@ -290,25 +293,23 @@ | ||
describe('with configuration', () => { | ||
let config | ||
before(() => { | ||
return agent.load(plugin, 'mongodb-core', { service: 'custom' }) | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
beforeEach(done => { | ||
config = { | ||
service: 'custom' | ||
} | ||
mongo = require(`./versions/mongodb-core@${version}`).get() | ||
agent.load(plugin, 'mongodb-core', config) | ||
.then(() => { | ||
mongo = require(`./versions/mongodb-core@${version}`).get() | ||
server = new mongo.Server({ | ||
host: 'localhost', | ||
port: 27017, | ||
reconnect: false | ||
}) | ||
server = new mongo.Server({ | ||
host: 'localhost', | ||
port: 27017, | ||
reconnect: false | ||
}) | ||
server.on('connect', () => done()) | ||
server.on('error', done) | ||
server.on('connect', () => done()) | ||
server.on('error', done) | ||
server.connect() | ||
}) | ||
.catch(done) | ||
server.connect() | ||
}) | ||
@@ -315,0 +316,0 @@ |
@@ -18,23 +18,23 @@ 'use strict' | ||
afterEach(() => { | ||
agent.close() | ||
agent.wipe() | ||
}) | ||
describe('without configuration', () => { | ||
let connection | ||
beforeEach(() => { | ||
before(() => { | ||
return agent.load(plugin, 'mysql') | ||
.then(() => { | ||
mysql = require(`./versions/mysql@${version}`).get() | ||
}) | ||
connection = mysql.createConnection({ | ||
host: 'localhost', | ||
user: 'root', | ||
database: 'db' | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
connection.connect() | ||
}) | ||
beforeEach(() => { | ||
mysql = require(`./versions/mysql@${version}`).get() | ||
connection = mysql.createConnection({ | ||
host: 'localhost', | ||
user: 'root', | ||
database: 'db' | ||
}) | ||
connection.connect() | ||
}) | ||
@@ -126,21 +126,21 @@ | ||
let connection | ||
let config | ||
before(() => { | ||
return agent.load(plugin, 'mysql', { service: 'custom' }) | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
beforeEach(() => { | ||
config = { | ||
service: 'custom' | ||
} | ||
mysql = require(`./versions/mysql@${version}`).get() | ||
return agent.load(plugin, 'mysql', config) | ||
.then(() => { | ||
mysql = require(`./versions/mysql@${version}`).get() | ||
connection = mysql.createConnection({ | ||
host: 'localhost', | ||
user: 'root', | ||
database: 'db' | ||
}) | ||
connection = mysql.createConnection({ | ||
host: 'localhost', | ||
user: 'root', | ||
database: 'db' | ||
}) | ||
connection.connect() | ||
}) | ||
connection.connect() | ||
}) | ||
@@ -165,16 +165,21 @@ | ||
beforeEach(() => { | ||
before(() => { | ||
return agent.load(plugin, 'mysql') | ||
.then(() => { | ||
mysql = require(`./versions/mysql@${version}`).get() | ||
}) | ||
pool = mysql.createPool({ | ||
connectionLimit: 10, | ||
host: 'localhost', | ||
user: 'root', | ||
database: 'db' | ||
}) | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
beforeEach(() => { | ||
mysql = require(`./versions/mysql@${version}`).get() | ||
pool = mysql.createPool({ | ||
connectionLimit: 10, | ||
host: 'localhost', | ||
user: 'root', | ||
database: 'db' | ||
}) | ||
}) | ||
afterEach(done => { | ||
@@ -181,0 +186,0 @@ pool.end(done) |
@@ -18,23 +18,23 @@ 'use strict' | ||
afterEach(() => { | ||
agent.close() | ||
agent.wipe() | ||
}) | ||
describe('without configuration', () => { | ||
let connection | ||
beforeEach(() => { | ||
before(() => { | ||
return agent.load(plugin, 'mysql2') | ||
.then(() => { | ||
mysql2 = require(`./versions/mysql2@${version}`).get() | ||
}) | ||
connection = mysql2.createConnection({ | ||
host: 'localhost', | ||
user: 'root', | ||
database: 'db' | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
connection.connect() | ||
}) | ||
beforeEach(() => { | ||
mysql2 = require(`./versions/mysql2@${version}`).get() | ||
connection = mysql2.createConnection({ | ||
host: 'localhost', | ||
user: 'root', | ||
database: 'db' | ||
}) | ||
connection.connect() | ||
}) | ||
@@ -129,21 +129,21 @@ | ||
let connection | ||
let config | ||
before(() => { | ||
return agent.load(plugin, 'mysql2', { service: 'custom' }) | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
beforeEach(() => { | ||
config = { | ||
service: 'custom' | ||
} | ||
mysql2 = require(`./versions/mysql2@${version}`).get() | ||
return agent.load(plugin, 'mysql2', config) | ||
.then(() => { | ||
mysql2 = require(`./versions/mysql2@${version}`).get() | ||
connection = mysql2.createConnection({ | ||
host: 'localhost', | ||
user: 'root', | ||
database: 'db' | ||
}) | ||
connection = mysql2.createConnection({ | ||
host: 'localhost', | ||
user: 'root', | ||
database: 'db' | ||
}) | ||
connection.connect() | ||
}) | ||
connection.connect() | ||
}) | ||
@@ -170,15 +170,20 @@ | ||
beforeEach(() => { | ||
before(() => { | ||
return agent.load(plugin, 'mysql2') | ||
.then(() => { | ||
mysql2 = require(`./versions/mysql2@${version}`).get() | ||
}) | ||
pool = mysql2.createPool({ | ||
connectionLimit: 10, | ||
host: 'localhost', | ||
user: 'root' | ||
}) | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
beforeEach(() => { | ||
mysql2 = require(`./versions/mysql2@${version}`).get() | ||
pool = mysql2.createPool({ | ||
connectionLimit: 10, | ||
host: 'localhost', | ||
user: 'root' | ||
}) | ||
}) | ||
afterEach(done => { | ||
@@ -185,0 +190,0 @@ pool.end(done) |
@@ -19,22 +19,22 @@ 'use strict' | ||
afterEach(() => { | ||
agent.close() | ||
}) | ||
describe('when using a client', () => { | ||
before(() => { | ||
return agent.load(plugin, 'pg') | ||
}) | ||
describe('when using a client', () => { | ||
after(() => { | ||
return agent.close() | ||
}) | ||
beforeEach(done => { | ||
agent.load(plugin, 'pg') | ||
.then(() => { | ||
pg = require(`./versions/pg@${version}`).get() | ||
pg = require(`./versions/pg@${version}`).get() | ||
client = new pg.Client({ | ||
user: 'postgres', | ||
password: 'postgres', | ||
database: 'postgres', | ||
application_name: 'test' | ||
}) | ||
client = new pg.Client({ | ||
user: 'postgres', | ||
password: 'postgres', | ||
database: 'postgres', | ||
application_name: 'test' | ||
}) | ||
client.connect(err => done(err)) | ||
}) | ||
.catch(done) | ||
client.connect(err => done(err)) | ||
}) | ||
@@ -121,20 +121,24 @@ | ||
before(() => { | ||
return agent.load(plugin, 'pg') | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
beforeEach(done => { | ||
agent.load(plugin, 'pg') | ||
.then(() => { | ||
pg = require('pg') | ||
pg = require('pg') | ||
pool = new pg.Pool({ | ||
user: 'postgres', | ||
password: 'postgres', | ||
database: 'postgres', | ||
application_name: 'test' | ||
}) | ||
pool = new pg.Pool({ | ||
user: 'postgres', | ||
password: 'postgres', | ||
database: 'postgres', | ||
application_name: 'test' | ||
}) | ||
pool.connect((err, c) => { | ||
client = c | ||
done(err) | ||
}) | ||
}) | ||
.catch(done) | ||
pool.connect((err, c) => { | ||
client = c | ||
done(err) | ||
}) | ||
}) | ||
@@ -165,22 +169,20 @@ | ||
describe('with configuration', () => { | ||
let config | ||
before(() => { | ||
return agent.load(plugin, 'pg', { service: 'custom' }) | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
beforeEach(done => { | ||
config = { | ||
service: 'custom' | ||
} | ||
pg = require('pg') | ||
agent.load(plugin, 'pg', config) | ||
.then(() => { | ||
pg = require('pg') | ||
client = new pg.Client({ | ||
user: 'postgres', | ||
password: 'postgres', | ||
database: 'postgres' | ||
}) | ||
client = new pg.Client({ | ||
user: 'postgres', | ||
password: 'postgres', | ||
database: 'postgres' | ||
}) | ||
client.connect(err => done(err)) | ||
}) | ||
.catch(done) | ||
client.connect(err => done(err)) | ||
}) | ||
@@ -187,0 +189,0 @@ |
@@ -21,14 +21,18 @@ 'use strict' | ||
client.quit() | ||
agent.close() | ||
}) | ||
describe('without configuration', () => { | ||
beforeEach(() => { | ||
before(() => { | ||
return agent.load(plugin, 'redis') | ||
.then(() => { | ||
redis = require(`./versions/redis@${version}`).get() | ||
client = redis.createClient() | ||
}) | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
beforeEach(() => { | ||
redis = require(`./versions/redis@${version}`).get() | ||
client = redis.createClient() | ||
}) | ||
it('should do automatic instrumentation when using callbacks', done => { | ||
@@ -112,14 +116,13 @@ client.on('error', done) | ||
describe('with configuration', () => { | ||
let config | ||
before(() => { | ||
return agent.load(plugin, 'redis', { service: 'custom' }) | ||
}) | ||
after(() => { | ||
return agent.close() | ||
}) | ||
beforeEach(() => { | ||
config = { | ||
service: 'custom' | ||
} | ||
return agent.load(plugin, 'redis', config) | ||
.then(() => { | ||
redis = require(`./versions/redis@${version}`).get() | ||
client = redis.createClient() | ||
}) | ||
redis = require(`./versions/redis@${version}`).get() | ||
client = redis.createClient() | ||
}) | ||
@@ -126,0 +129,0 @@ |
@@ -15,5 +15,6 @@ 'use strict' | ||
const mongo = require('mongodb-core') | ||
const elasticsearch = require('elasticsearch') | ||
const axios = require('axios') | ||
const amqplib = require('amqplib/callback_api') | ||
const amqp = require('amqp10') | ||
const Memcached = require('memcached') | ||
const platform = require('../src/platform') | ||
@@ -23,2 +24,3 @@ const node = require('../src/platform/node') | ||
const agent = require('./plugins/agent') | ||
const externals = require('./plugins/externals.json') | ||
@@ -50,2 +52,6 @@ const scopeManager = new ScopeManager() | ||
afterEach(() => { | ||
agent.reset() | ||
}) | ||
waitForServices() | ||
@@ -65,3 +71,4 @@ .then(run) | ||
waitForRabbitMQ(), | ||
waitForQpid() | ||
waitForQpid(), | ||
waitForMemcached() | ||
]) | ||
@@ -176,12 +183,9 @@ } | ||
operation.attempt(currentAttempt => { | ||
const client = new elasticsearch.Client({ | ||
host: 'localhost:9200' | ||
}) | ||
client.ping((err) => { | ||
if (retryOperation(operation, err)) return | ||
if (err) return reject(err) | ||
resolve() | ||
}) | ||
// Not using ES client because it's buggy for initial connection. | ||
axios.get('http://localhost:9200/_cluster/health?wait_for_status=green&local=true&timeout=100ms') | ||
.then(() => resolve()) | ||
.catch(err => { | ||
if (retryOperation(operation, err)) return | ||
reject(err) | ||
}) | ||
}) | ||
@@ -227,2 +231,20 @@ }) | ||
function waitForMemcached () { | ||
return new Promise((resolve, reject) => { | ||
const operation = createOperation('memcached') | ||
operation.attempt(currentAttempt => { | ||
const memcached = new Memcached('localhost:11211', { retries: 0 }) | ||
memcached.version((err, version) => { | ||
if (retryOperation(operation, err)) return | ||
if (err) return reject(err) | ||
memcached.end() | ||
resolve() | ||
}) | ||
}) | ||
}) | ||
} | ||
function withoutScope (fn) { | ||
@@ -250,3 +272,3 @@ return function () { | ||
return it.call(this, title, function (done) { | ||
arguments[0] = withoutScope(done) | ||
arguments[0] = withoutScope(agent.wrap(done)) | ||
@@ -263,5 +285,7 @@ return fn.apply(this, arguments) | ||
.catch(withoutScope(err => Promise.reject(err))) | ||
.then(() => agent.promise()) | ||
} | ||
return result | ||
return agent.promise() | ||
.then(() => result) | ||
}) | ||
@@ -273,3 +297,3 @@ } | ||
function withVersions (plugin, moduleName, range, cb) { | ||
const instrumentations = [].concat(plugin) | ||
const instrumentations = [].concat(plugin, externals) | ||
const testVersions = new Map() | ||
@@ -287,6 +311,4 @@ | ||
.forEach(version => { | ||
const min = semver.coerce(version).version | ||
const max = require(`./plugins/versions/${moduleName}@${version}`).version() | ||
try { | ||
const min = semver.coerce(version).version | ||
require(`./plugins/versions/${moduleName}@${min}`).get() | ||
@@ -298,3 +320,6 @@ testVersions.set(min, { range: version, test: min }) | ||
agent.wipe() | ||
try { | ||
const max = require(`./plugins/versions/${moduleName}@${version}`).version() | ||
require(`./plugins/versions/${moduleName}@${version}`).get() | ||
@@ -305,2 +330,4 @@ testVersions.set(max, { range: version, test: version }) | ||
} | ||
agent.wipe() | ||
}) | ||
@@ -307,0 +334,0 @@ }) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
412460
18
168
11437
37
88
11