Comparing version 5.21.0 to 5.22.0
{ | ||
"name": "dd-trace", | ||
"version": "5.21.0", | ||
"version": "5.22.0", | ||
"description": "Datadog APM tracing client for JavaScript", | ||
@@ -75,3 +75,3 @@ "main": "index.js", | ||
"dependencies": { | ||
"@datadog/native-appsec": "8.0.1", | ||
"@datadog/native-appsec": "8.1.1", | ||
"@datadog/native-iast-rewriter": "2.4.1", | ||
@@ -110,3 +110,3 @@ "@datadog/native-iast-taint-tracking": "3.1.0", | ||
"aws-sdk": "^2.1446.0", | ||
"axios": "^1.6.7", | ||
"axios": "^1.7.4", | ||
"benchmark": "^2.1.4", | ||
@@ -113,0 +113,0 @@ "body-parser": "^1.20.2", |
@@ -46,3 +46,3 @@ 'use strict' | ||
commandFactory => { | ||
return shimmer.wrap(commandFactory, wrapCreateCommand(commandFactory)) | ||
return shimmer.wrapFunction(commandFactory, f => wrapCreateCommand(f)) | ||
}) |
@@ -58,3 +58,3 @@ 'use strict' | ||
return shimmer.wrap(originalMiddleware, function (req, res, next) { | ||
return shimmer.wrapFunction(originalMiddleware, originalMiddleware => function (req, res, next) { | ||
if (!graphqlMiddlewareChannel.start.hasSubscribers) { | ||
@@ -61,0 +61,0 @@ return originalMiddleware.apply(this, arguments) |
@@ -78,3 +78,3 @@ 'use strict' | ||
if (typeof cb === 'function') { | ||
args[args.length - 1] = function (err, result) { | ||
args[args.length - 1] = shimmer.wrapFunction(cb, cb => function (err, result) { | ||
const message = getMessage(request, err, result) | ||
@@ -93,3 +93,3 @@ | ||
}) | ||
} | ||
}) | ||
} else { // always a promise | ||
@@ -118,3 +118,3 @@ return send.call(this, command, ...args) | ||
// eslint-disable-next-line n/handle-callback-err | ||
return function wrappedCb (err, response) { | ||
return shimmer.wrapFunction(cb, cb => function wrappedCb (err, response) { | ||
const obj = { request, response } | ||
@@ -147,3 +147,3 @@ return ar.runInAsyncScope(() => { | ||
}) | ||
} | ||
}) | ||
} | ||
@@ -150,0 +150,0 @@ |
@@ -9,3 +9,3 @@ 'use strict' | ||
function publishRequestBodyAndNext (req, res, next) { | ||
return function () { | ||
return shimmer.wrapFunction(next, next => function () { | ||
if (bodyParserReadCh.hasSubscribers && req) { | ||
@@ -21,3 +21,3 @@ const abortController = new AbortController() | ||
return next.apply(this, arguments) | ||
} | ||
}) | ||
} | ||
@@ -30,3 +30,3 @@ | ||
}, read => { | ||
return shimmer.wrap(read, function (req, res, next) { | ||
return shimmer.wrapFunction(read, read => function (req, res, next) { | ||
const nextResource = new AsyncResource('bound-anonymous-fn') | ||
@@ -43,3 +43,3 @@ arguments[2] = nextResource.bind(publishRequestBodyAndNext(req, res, next)) | ||
}, read => { | ||
return shimmer.wrap(read, function (req, res, next) { | ||
return shimmer.wrapFunction(read, read => function (req, res, next) { | ||
arguments[2] = publishRequestBodyAndNext(req, res, next) | ||
@@ -46,0 +46,0 @@ return read.apply(this, arguments) |
@@ -183,3 +183,3 @@ 'use strict' | ||
function wrapCallback (finishCh, errorCh, asyncResource, callback) { | ||
return asyncResource.bind(function (err) { | ||
return shimmer.wrapFunction(callback, callback => asyncResource.bind(function (err) { | ||
finish(finishCh, errorCh, err) | ||
@@ -189,3 +189,3 @@ if (callback) { | ||
} | ||
}) | ||
})) | ||
} | ||
@@ -192,0 +192,0 @@ |
@@ -136,4 +136,4 @@ 'use strict' | ||
const wrapedChildProcessCustomPromisifyMethod = | ||
shimmer.wrap(childProcessMethod[util.promisify.custom], | ||
wrapChildProcessCustomPromisifyMethod(childProcessMethod[util.promisify.custom]), shell) | ||
shimmer.wrapFunction(childProcessMethod[util.promisify.custom], | ||
promisify => wrapChildProcessCustomPromisifyMethod(promisify, shell)) | ||
@@ -140,0 +140,0 @@ // should do it in this way because the original property is readonly |
@@ -62,3 +62,3 @@ 'use strict' | ||
return shimmer.wrap(original, function () { | ||
return shimmer.wrapFunction(original, original => function () { | ||
if (!enterChannel.hasSubscribers) return original.apply(this, arguments) | ||
@@ -94,3 +94,3 @@ | ||
function wrapNext (req, next) { | ||
return function (error) { | ||
return shimmer.wrapFunction(next, next => function (error) { | ||
if (error) { | ||
@@ -104,7 +104,7 @@ errorChannel.publish({ req, error }) | ||
next.apply(this, arguments) | ||
} | ||
}) | ||
} | ||
addHook({ name: 'connect', versions: ['>=3'] }, connect => { | ||
return shimmer.wrap(connect, wrapConnect(connect)) | ||
return shimmer.wrapFunction(connect, connect => wrapConnect(connect)) | ||
}) | ||
@@ -111,0 +111,0 @@ |
@@ -9,3 +9,3 @@ 'use strict' | ||
function publishRequestCookieAndNext (req, res, next) { | ||
return function cookieParserWrapper () { | ||
return shimmer.wrapFunction(next, next => function cookieParserWrapper () { | ||
if (cookieParserReadCh.hasSubscribers && req) { | ||
@@ -22,3 +22,3 @@ const abortController = new AbortController() | ||
return next.apply(this, arguments) | ||
} | ||
}) | ||
} | ||
@@ -30,6 +30,6 @@ | ||
}, cookieParser => { | ||
return shimmer.wrap(cookieParser, function () { | ||
return shimmer.wrapFunction(cookieParser, cookieParser => function () { | ||
const cookieMiddleware = cookieParser.apply(this, arguments) | ||
return shimmer.wrap(cookieMiddleware, function (req, res, next) { | ||
return shimmer.wrapFunction(cookieMiddleware, cookieMiddleware => function (req, res, next) { | ||
arguments[2] = publishRequestCookieAndNext(req, res, next) | ||
@@ -36,0 +36,0 @@ return cookieMiddleware.apply(this, arguments) |
@@ -40,3 +40,3 @@ 'use strict' | ||
} | ||
return shimmer.wrap(_maybeInvoke, wrapped) | ||
return wrapped | ||
} | ||
@@ -55,3 +55,3 @@ | ||
} | ||
return shimmer.wrap(query, wrapped) | ||
return wrapped | ||
} | ||
@@ -81,3 +81,3 @@ | ||
arguments[callbackIndex] = asyncResource.bind(function (error, result) { | ||
arguments[callbackIndex] = shimmer.wrapFunction(cb, cb => asyncResource.bind(function (error, result) { | ||
if (error) { | ||
@@ -88,3 +88,3 @@ errorCh.publish(error) | ||
return cb.apply(this, arguments) | ||
}) | ||
})) | ||
@@ -101,3 +101,3 @@ try { | ||
} | ||
return shimmer.wrap(fn, wrapped) | ||
return wrapped | ||
} | ||
@@ -126,3 +126,3 @@ | ||
const cb = callbackResource.bind(args[cbIndex]) | ||
args[cbIndex] = asyncResource.bind(function (error, result) { | ||
args[cbIndex] = shimmer.wrapFunction(cb, cb => asyncResource.bind(function (error, result) { | ||
if (error) { | ||
@@ -133,3 +133,3 @@ errorCh.publish(error) | ||
return cb.apply(thisArg, arguments) | ||
}) | ||
})) | ||
} | ||
@@ -176,4 +176,4 @@ const res = fn.apply(thisArg, args) | ||
Bucket.prototype._maybeInvoke = wrapMaybeInvoke(Bucket.prototype._maybeInvoke) | ||
Bucket.prototype.query = wrapQuery(Bucket.prototype.query) | ||
shimmer.wrap(Bucket.prototype, '_maybeInvoke', maybeInvoke => wrapMaybeInvoke(maybeInvoke)) | ||
shimmer.wrap(Bucket.prototype, 'query', query => wrapQuery(query)) | ||
@@ -214,3 +214,3 @@ shimmer.wrap(Bucket.prototype, '_n1qlReq', _n1qlReq => function (host, q, adhoc, emitter) { | ||
wrapAllNames(['upsert', 'insert', 'replace', 'append', 'prepend'], name => { | ||
Bucket.prototype[name] = wrap(`apm:couchbase:${name}`, Bucket.prototype[name]) | ||
shimmer.wrap(Bucket.prototype, name, fn => wrap(`apm:couchbase:${name}`, fn)) | ||
}) | ||
@@ -222,4 +222,4 @@ | ||
addHook({ name: 'couchbase', file: 'lib/cluster.js', versions: ['^2.6.12'] }, Cluster => { | ||
Cluster.prototype._maybeInvoke = wrapMaybeInvoke(Cluster.prototype._maybeInvoke) | ||
Cluster.prototype.query = wrapQuery(Cluster.prototype.query) | ||
shimmer.wrap(Cluster.prototype, '_maybeInvoke', maybeInvoke => wrapMaybeInvoke(maybeInvoke)) | ||
shimmer.wrap(Cluster.prototype, 'query', query => wrapQuery(query)) | ||
@@ -226,0 +226,0 @@ shimmer.wrap(Cluster.prototype, 'openBucket', openBucket => { |
'use strict' | ||
const { createCoverageMap } = require('istanbul-lib-coverage') | ||
const { NUM_FAILED_TEST_RETRIES } = require('../../dd-trace/src/plugins/util/test') | ||
const { addHook, channel, AsyncResource } = require('./helpers/instrument') | ||
@@ -69,2 +68,3 @@ const shimmer = require('../../datadog-shimmer') | ||
let isFlakyTestRetriesEnabled = false | ||
let numTestRetries = 0 | ||
let knownTests = [] | ||
@@ -192,3 +192,3 @@ let skippedSuites = [] | ||
try { | ||
this.eventBroadcaster.on('envelope', (testCase) => { | ||
this.eventBroadcaster.on('envelope', shimmer.wrapFunction(null, () => (testCase) => { | ||
// Only supported from >=8.0.0 | ||
@@ -211,3 +211,3 @@ if (testCase?.testCaseFinished) { | ||
} | ||
}) | ||
})) | ||
let promise | ||
@@ -313,2 +313,3 @@ | ||
isFlakyTestRetriesEnabled = configurationResponse.libraryConfig?.isFlakyTestRetriesEnabled | ||
numTestRetries = configurationResponse.libraryConfig?.flakyTestRetriesCount | ||
@@ -351,4 +352,4 @@ if (isEarlyFlakeDetectionEnabled) { | ||
if (isFlakyTestRetriesEnabled && !this.options.retry) { | ||
this.options.retry = NUM_FAILED_TEST_RETRIES | ||
if (isFlakyTestRetriesEnabled && !this.options.retry && numTestRetries > 0) { | ||
this.options.retry = numTestRetries | ||
} | ||
@@ -355,0 +356,0 @@ |
@@ -24,6 +24,6 @@ 'use strict' | ||
addHook({ name: names }, dns => { | ||
dns.lookup = wrap('apm:dns:lookup', dns.lookup, 2) | ||
dns.lookupService = wrap('apm:dns:lookup_service', dns.lookupService, 3) | ||
dns.resolve = wrap('apm:dns:resolve', dns.resolve, 2) | ||
dns.reverse = wrap('apm:dns:reverse', dns.reverse, 2) | ||
shimmer.wrap(dns, 'lookup', fn => wrap('apm:dns:lookup', fn, 2)) | ||
shimmer.wrap(dns, 'lookupService', fn => wrap('apm:dns:lookup_service', fn, 2)) | ||
shimmer.wrap(dns, 'resolve', fn => wrap('apm:dns:resolve', fn, 2)) | ||
shimmer.wrap(dns, 'reverse', fn => wrap('apm:dns:reverse', fn, 2)) | ||
@@ -33,4 +33,4 @@ patchResolveShorthands(dns) | ||
if (dns.Resolver) { | ||
dns.Resolver.prototype.resolve = wrap('apm:dns:resolve', dns.Resolver.prototype.resolve, 2) | ||
dns.Resolver.prototype.reverse = wrap('apm:dns:reverse', dns.Resolver.prototype.reverse, 2) | ||
shimmer.wrap(dns.Resolver.prototype, 'resolve', fn => wrap('apm:dns:resolve', fn, 2)) | ||
shimmer.wrap(dns.Resolver.prototype, 'reverse', fn => wrap('apm:dns:reverse', fn, 2)) | ||
@@ -48,3 +48,3 @@ patchResolveShorthands(dns.Resolver.prototype) | ||
rrtypeMap.set(prototype[method], rrtypes[method]) | ||
prototype[method] = wrap('apm:dns:resolve', prototype[method], 2, rrtypes[method]) | ||
shimmer.wrap(prototype, method, fn => wrap('apm:dns:resolve', fn, 2, rrtypes[method])) | ||
}) | ||
@@ -78,3 +78,3 @@ } | ||
arguments[arguments.length - 1] = asyncResource.bind(function (error, result) { | ||
arguments[arguments.length - 1] = shimmer.wrapFunction(cb, cb => asyncResource.bind(function (error, result) { | ||
if (error) { | ||
@@ -85,3 +85,3 @@ errorCh.publish(error) | ||
cb.apply(this, arguments) | ||
}) | ||
})) | ||
@@ -100,3 +100,3 @@ try { | ||
return shimmer.wrap(fn, wrapped) | ||
return wrapped | ||
} |
@@ -51,3 +51,3 @@ 'use strict' | ||
const cb = arguments[0] | ||
arguments[0] = function (err, connection) { | ||
arguments[0] = shimmer.wrapFunction(cb, cb => function (err, connection) { | ||
if (connectCh.hasSubscribers && connection && connection.host) { | ||
@@ -57,3 +57,3 @@ connectCh.publish({ hostname: connection.host.host, port: connection.host.port }) | ||
cb(err, connection) | ||
} | ||
}) | ||
} | ||
@@ -91,6 +91,6 @@ return request.apply(this, arguments) | ||
arguments[lastIndex] = asyncResource.bind(function (error) { | ||
arguments[lastIndex] = shimmer.wrapFunction(cb, cb => asyncResource.bind(function (error) { | ||
finish(params, error) | ||
return cb.apply(null, arguments) | ||
}) | ||
})) | ||
return request.apply(this, arguments) | ||
@@ -97,0 +97,0 @@ } else { |
@@ -25,6 +25,6 @@ 'use strict' | ||
return shimmer.wrap(expressMongoSanitize, function () { | ||
return shimmer.wrapFunction(expressMongoSanitize, expressMongoSanitize => function () { | ||
const middleware = expressMongoSanitize.apply(this, arguments) | ||
return shimmer.wrap(middleware, function (req, res, next) { | ||
return shimmer.wrapFunction(middleware, middleware => function (req, res, next) { | ||
if (!sanitizeMiddlewareFinished.hasSubscribers) { | ||
@@ -34,3 +34,3 @@ return middleware.apply(this, arguments) | ||
const wrappedNext = shimmer.wrap(next, function () { | ||
const wrappedNext = shimmer.wrapFunction(next, next => function () { | ||
sanitizeMiddlewareFinished.publish({ | ||
@@ -37,0 +37,0 @@ sanitizedProperties: propertiesToSanitize, |
@@ -52,3 +52,3 @@ 'use strict' | ||
function publishQueryParsedAndNext (req, res, next) { | ||
return function () { | ||
return shimmer.wrapFunction(next, next => function () { | ||
if (queryParserReadCh.hasSubscribers && req) { | ||
@@ -64,3 +64,3 @@ const abortController = new AbortController() | ||
return next.apply(this, arguments) | ||
} | ||
}) | ||
} | ||
@@ -73,6 +73,6 @@ | ||
}, query => { | ||
return shimmer.wrap(query, function () { | ||
return shimmer.wrapFunction(query, query => function () { | ||
const queryMiddleware = query.apply(this, arguments) | ||
return shimmer.wrap(queryMiddleware, function (req, res, next) { | ||
return shimmer.wrapFunction(queryMiddleware, queryMiddleware => function (req, res, next) { | ||
arguments[2] = publishQueryParsedAndNext(req, res, next) | ||
@@ -79,0 +79,0 @@ return queryMiddleware.apply(this, arguments) |
@@ -37,3 +37,3 @@ 'use strict' | ||
function wrapAddHook (addHook) { | ||
return function addHookWithTrace (name, fn) { | ||
return shimmer.wrapFunction(addHook, addHook => function addHookWithTrace (name, fn) { | ||
fn = arguments[arguments.length - 1] | ||
@@ -43,3 +43,3 @@ | ||
arguments[arguments.length - 1] = shimmer.wrap(fn, function (request, reply, done) { | ||
arguments[arguments.length - 1] = shimmer.wrapFunction(fn, fn => function (request, reply, done) { | ||
const req = getReq(request) | ||
@@ -83,3 +83,3 @@ | ||
return addHook.apply(this, arguments) | ||
} | ||
}) | ||
} | ||
@@ -157,3 +157,3 @@ | ||
addHook({ name: 'fastify', versions: ['>=3'] }, fastify => { | ||
const wrapped = shimmer.wrap(fastify, wrapFastify(fastify, true)) | ||
const wrapped = shimmer.wrapFunction(fastify, fastify => wrapFastify(fastify, true)) | ||
@@ -167,7 +167,7 @@ wrapped.fastify = wrapped | ||
addHook({ name: 'fastify', versions: ['2'] }, fastify => { | ||
return shimmer.wrap(fastify, wrapFastify(fastify, true)) | ||
return shimmer.wrapFunction(fastify, fastify => wrapFastify(fastify, true)) | ||
}) | ||
addHook({ name: 'fastify', versions: ['1'] }, fastify => { | ||
return shimmer.wrap(fastify, wrapFastify(fastify, false)) | ||
return shimmer.wrapFunction(fastify, fastify => wrapFastify(fastify, false)) | ||
}) |
@@ -11,3 +11,3 @@ 'use strict' | ||
globalThis.fetch = shimmer.wrap(fetch, wrapFetch(fetch)) | ||
globalThis.fetch = shimmer.wrapFunction(fetch, fetch => wrapFetch(fetch)) | ||
} |
@@ -12,7 +12,7 @@ 'use strict' | ||
const handler = arguments[index] | ||
const wrapper = function (req) { | ||
const wrapper = shimmer.wrapFunction(handler, handler => function (req) { | ||
routeChannel.publish({ req, route: path }) | ||
return handler.apply(this, arguments) | ||
} | ||
}) | ||
@@ -19,0 +19,0 @@ if (typeof handler === 'function') { |
@@ -274,3 +274,3 @@ 'use strict' | ||
arguments[lastIndex] = innerResource.bind(function (e) { | ||
arguments[lastIndex] = shimmer.wrapFunction(cb, cb => innerResource.bind(function (e) { | ||
if (e !== null && typeof e === 'object') { // fs.exists receives a boolean | ||
@@ -283,3 +283,3 @@ errorChannel.publish(e) | ||
return outerResource.runInAsyncScope(() => cb.apply(this, arguments)) | ||
}) | ||
})) | ||
} | ||
@@ -286,0 +286,0 @@ |
@@ -79,3 +79,3 @@ 'use strict' | ||
arguments[arguments.length - 1] = innerAsyncResource.bind(function (error) { | ||
arguments[arguments.length - 1] = shimmer.wrapFunction(cb, cb => innerAsyncResource.bind(function (error) { | ||
if (error) { | ||
@@ -88,3 +88,3 @@ requestErrorCh.publish(error) | ||
return outerAsyncResource.runInAsyncScope(() => cb.apply(this, arguments)) | ||
}) | ||
})) | ||
@@ -91,0 +91,0 @@ return method.apply(this, arguments) |
@@ -91,9 +91,7 @@ 'use strict' | ||
const wrapped = function () { | ||
const wrapped = shimmer.wrapFunction(method, method => function () { | ||
const args = ensureMetadata(this, arguments, 1) | ||
return callMethod(this, method, args, path, args[1], type, hasPeer) | ||
} | ||
}) | ||
Object.assign(wrapped, method) | ||
patched.add(wrapped) | ||
@@ -105,3 +103,3 @@ | ||
function wrapCallback (ctx, callback = () => { }) { | ||
return function (err) { | ||
return shimmer.wrapFunction(callback, callback => function (err) { | ||
if (err) { | ||
@@ -116,3 +114,3 @@ ctx.error = err | ||
}) | ||
} | ||
}) | ||
} | ||
@@ -119,0 +117,0 @@ |
@@ -122,3 +122,3 @@ 'use strict' | ||
function wrapCallback (callback = () => {}, call, ctx, onCancel) { | ||
return function (err, value, trailer, flags) { | ||
return shimmer.wrapFunction(callback, callback => function (err, value, trailer, flags) { | ||
if (err) { | ||
@@ -140,3 +140,3 @@ ctx.error = err | ||
}) | ||
} | ||
}) | ||
} | ||
@@ -143,0 +143,0 @@ |
'use strict' | ||
const tracingChannel = require('dc-polyfill').tracingChannel | ||
const shimmer = require('../../datadog-shimmer') | ||
const { addHook, channel, AsyncResource } = require('./helpers/instrument') | ||
const { addHook, channel } = require('./helpers/instrument') | ||
@@ -9,3 +10,3 @@ const handleChannel = channel('apm:hapi:request:handle') | ||
const errorChannel = channel('apm:hapi:request:error') | ||
const enterChannel = channel('apm:hapi:extension:enter') | ||
const hapiTracingChannel = tracingChannel('apm:hapi:extension') | ||
@@ -31,3 +32,3 @@ function wrapServer (server) { | ||
function wrapStart (start) { | ||
return function () { | ||
return shimmer.wrapFunction(start, start => function () { | ||
if (this && typeof this.ext === 'function') { | ||
@@ -38,7 +39,7 @@ this.ext('onPreResponse', onPreResponse) | ||
return start.apply(this, arguments) | ||
} | ||
}) | ||
} | ||
function wrapExt (ext) { | ||
return function (events, method, options) { | ||
return shimmer.wrapFunction(ext, ext => function (events, method, options) { | ||
if (events !== null && typeof events === 'object') { | ||
@@ -51,3 +52,3 @@ arguments[0] = wrapEvents(events) | ||
return ext.apply(this, arguments) | ||
} | ||
}) | ||
} | ||
@@ -98,3 +99,3 @@ | ||
return function (request, h) { | ||
return shimmer.wrapFunction(handler, handler => function (request, h) { | ||
const req = request && request.raw && request.raw.req | ||
@@ -104,10 +105,6 @@ | ||
const asyncResource = new AsyncResource('bound-anonymous-fn') | ||
return asyncResource.runInAsyncScope(() => { | ||
enterChannel.publish({ req }) | ||
return hapiTracingChannel.traceSync(() => { | ||
return handler.apply(this, arguments) | ||
}) | ||
} | ||
}) | ||
} | ||
@@ -114,0 +111,0 @@ |
@@ -101,3 +101,3 @@ 'use strict' | ||
} | ||
if (!Object.hasOwnProperty(namesAndSuccesses, name)) { | ||
if (typeof namesAndSuccesses[`${name}@${version}`] === 'undefined') { | ||
namesAndSuccesses[`${name}@${version}`] = false | ||
@@ -104,0 +104,0 @@ } |
@@ -55,7 +55,7 @@ 'use strict' | ||
if (callback) { | ||
callback = function () { | ||
callback = shimmer.wrapFunction(args.callback, cb => function () { | ||
return asyncStartChannel.runStores(ctx, () => { | ||
return args.callback.apply(this, arguments) | ||
return cb.apply(this, arguments) | ||
}) | ||
} | ||
}) | ||
} | ||
@@ -62,0 +62,0 @@ |
@@ -15,4 +15,3 @@ 'use strict' | ||
removeEfdStringFromTestName, | ||
getIsFaultyEarlyFlakeDetection, | ||
NUM_FAILED_TEST_RETRIES | ||
getIsFaultyEarlyFlakeDetection | ||
} = require('../../dd-trace/src/plugins/util/test') | ||
@@ -136,2 +135,3 @@ const { | ||
this.isFlakyTestRetriesEnabled = this.testEnvironmentOptions._ddIsFlakyTestRetriesEnabled | ||
this.flakyTestRetriesCount = this.testEnvironmentOptions._ddFlakyTestRetriesCount | ||
@@ -154,3 +154,3 @@ if (this.isEarlyFlakeDetectionEnabled) { | ||
if (!currentNumRetries) { | ||
this.global[RETRY_TIMES] = NUM_FAILED_TEST_RETRIES | ||
this.global[RETRY_TIMES] = this.flakyTestRetriesCount | ||
} | ||
@@ -644,3 +644,3 @@ } | ||
const adapter = jestAdapter.default ? jestAdapter.default : jestAdapter | ||
const newAdapter = shimmer.wrap(adapter, function () { | ||
const newAdapter = shimmer.wrapFunction(adapter, adapter => function () { | ||
const environment = arguments[2] | ||
@@ -780,2 +780,3 @@ if (!environment) { | ||
_ddIsFlakyTestRetriesEnabled, | ||
_ddFlakyTestRetriesCount, | ||
...restOfTestEnvironmentOptions | ||
@@ -782,0 +783,0 @@ } = testEnvironmentOptions |
@@ -84,6 +84,6 @@ 'use strict' | ||
return function () { | ||
return shimmer.wrapFunction(callback, callback => function () { | ||
finish() | ||
callback.apply(this, arguments) | ||
} | ||
}) | ||
} |
@@ -74,3 +74,3 @@ 'use strict' | ||
const handler = shimmer.wrap(middleware, wrapMiddleware(middleware, layer)) | ||
const handler = shimmer.wrapFunction(middleware, middleware => wrapMiddleware(middleware, layer)) | ||
@@ -88,3 +88,3 @@ originals.set(handler, middleware) | ||
return function (ctx, next) { | ||
return shimmer.wrapFunction(fn, fn => function (ctx, next) { | ||
if (!ctx || !enterChannel.hasSubscribers) return fn.apply(this, arguments) | ||
@@ -127,3 +127,3 @@ | ||
} | ||
} | ||
}) | ||
} | ||
@@ -148,7 +148,7 @@ | ||
function wrapNext (req, next) { | ||
return function () { | ||
return shimmer.wrapFunction(next, next => function () { | ||
nextChannel.publish({ req }) | ||
return next.apply(this, arguments) | ||
} | ||
}) | ||
} | ||
@@ -155,0 +155,0 @@ |
@@ -80,3 +80,3 @@ 'use strict' | ||
// eslint-disable-next-line n/handle-callback-err | ||
arguments[callbackIndex] = shimmer.wrap(callback, function (err, corkedEmitter) { | ||
arguments[callbackIndex] = shimmer.wrapFunction(callback, callback => function (err, corkedEmitter) { | ||
if (corkedEmitter !== null && typeof corkedEmitter === 'object' && typeof corkedEmitter.on === 'function') { | ||
@@ -83,0 +83,0 @@ wrapEmitter(corkedEmitter) |
@@ -14,3 +14,3 @@ 'use strict' | ||
function wrapCommandStart (start, callbackResource) { | ||
return function () { | ||
return shimmer.wrapFunction(start, start => function () { | ||
if (!startCh.hasSubscribers) return start.apply(this, arguments) | ||
@@ -48,3 +48,3 @@ | ||
}) | ||
} | ||
}) | ||
} | ||
@@ -103,3 +103,3 @@ | ||
arguments[arguments.length - 1] = asyncResource.bind(function (err) { | ||
arguments[arguments.length - 1] = shimmer.wrapFunction(cb, cb => asyncResource.bind(function (err) { | ||
if (err) { | ||
@@ -114,3 +114,3 @@ errorCh.publish(err) | ||
} | ||
}) | ||
})) | ||
@@ -126,3 +126,3 @@ return asyncResource.runInAsyncScope(() => { | ||
function wrapConnection (Connection, promiseMethod) { | ||
function wrapConnection (promiseMethod, Connection) { | ||
return function (options) { | ||
@@ -178,11 +178,11 @@ Connection.apply(this, arguments) | ||
addHook({ name, file: 'lib/connection.js', versions: ['>=2.5.2 <3'] }, (Connection) => { | ||
return shimmer.wrap(Connection, wrapConnection(Connection, '_queryPromise')) | ||
return shimmer.wrapFunction(Connection, wrapConnection.bind(null, '_queryPromise')) | ||
}) | ||
addHook({ name, file: 'lib/connection.js', versions: ['>=2.0.4 <=2.5.1'] }, (Connection) => { | ||
return shimmer.wrap(Connection, wrapConnection(Connection, 'query')) | ||
return shimmer.wrapFunction(Connection, wrapConnection.bind(null, 'query')) | ||
}) | ||
addHook({ name, file: 'lib/pool-base.js', versions: ['>=2.0.4 <3'] }, (PoolBase) => { | ||
return shimmer.wrap(PoolBase, wrapPoolBase(PoolBase)) | ||
return shimmer.wrapFunction(PoolBase, wrapPoolBase) | ||
}) |
@@ -29,3 +29,3 @@ 'use strict' | ||
query.callback = asyncResource.bind(function (err) { | ||
query.callback = shimmer.wrapFunction(callback, callback => asyncResource.bind(function (err) { | ||
if (err) { | ||
@@ -37,3 +37,3 @@ errorCh.publish(err) | ||
return callback.apply(this, arguments) | ||
}) | ||
})) | ||
startCh.publish({ client, server, query }) | ||
@@ -40,0 +40,0 @@ |
@@ -43,3 +43,3 @@ 'use strict' | ||
function wrapNext (req, res, next) { | ||
return function nextWithTrace (err) { | ||
return shimmer.wrapFunction(next, next => function nextWithTrace (err) { | ||
const requestResource = requestResources.get(req) | ||
@@ -58,11 +58,11 @@ | ||
return next.apply(this, arguments) | ||
} | ||
}) | ||
} | ||
addHook({ name, versions, file: 'lib/config-proxy-middleware.js' }, configProxyFactory => { | ||
return shimmer.wrap(configProxyFactory, wrapConfigProxyFactory(configProxyFactory)) | ||
return shimmer.wrapFunction(configProxyFactory, wrapConfigProxyFactory) | ||
}) | ||
addHook({ name, versions, file: 'lib/plugins-middleware.js' }, pluginsFactory => { | ||
return shimmer.wrap(pluginsFactory, wrapPluginsFactory(pluginsFactory)) | ||
return shimmer.wrapFunction(pluginsFactory, wrapPluginsFactory) | ||
}) |
@@ -6,1 +6,5 @@ if (process.env.MOCHA_WORKER_ID) { | ||
} | ||
// TODO add appropriate calls to wrapFunction whenever we're adding a callback | ||
// wrapper. Right now this is less of an issue since that only has effect in | ||
// SSI, where CI Vis isn't supported. |
@@ -18,3 +18,3 @@ const { addHook, channel } = require('../helpers/instrument') | ||
return shimmer.wrap(mochaEach, function () { | ||
return shimmer.wrapFunction(mochaEach, mochaEach => function () { | ||
const [params] = arguments | ||
@@ -21,0 +21,0 @@ const { it, ...rest } = mochaEach.apply(this, arguments) |
@@ -220,2 +220,3 @@ 'use strict' | ||
config.isFlakyTestRetriesEnabled = isFlakyTestRetriesEnabled | ||
config.flakyTestRetriesCount = libraryConfig.flakyTestRetriesCount | ||
@@ -222,0 +223,0 @@ if (isEarlyFlakeDetectionEnabled) { |
@@ -6,4 +6,3 @@ 'use strict' | ||
removeEfdStringFromTestName, | ||
addEfdStringToTestName, | ||
NUM_FAILED_TEST_RETRIES | ||
addEfdStringToTestName | ||
} = require('../../../dd-trace/src/plugins/util/test') | ||
@@ -118,3 +117,3 @@ const { channel, AsyncResource } = require('../helpers/instrument') | ||
if (libraryConfig?.isFlakyTestRetriesEnabled) { | ||
this.retries(NUM_FAILED_TEST_RETRIES) | ||
this.retries(libraryConfig?.flakyTestRetriesCount) | ||
} | ||
@@ -121,0 +120,0 @@ // The reason why the wrapping logic is here is because we need to cover |
@@ -27,3 +27,3 @@ 'use strict' | ||
return function datadogMiddleware (ctx) { | ||
return shimmer.wrapFunction(next, next => function datadogMiddleware (ctx) { | ||
const actionResource = new AsyncResource('bound-anonymous-fn') | ||
@@ -51,3 +51,3 @@ | ||
}) | ||
} | ||
}) | ||
} | ||
@@ -54,0 +54,0 @@ } |
@@ -95,3 +95,3 @@ 'use strict' | ||
} | ||
return shimmer.wrap(command, wrapped) | ||
return wrapped | ||
} | ||
@@ -113,3 +113,3 @@ | ||
} | ||
return shimmer.wrap(command, wrapped) | ||
return wrapped | ||
} | ||
@@ -128,3 +128,3 @@ | ||
return shimmer.wrap(query, wrapped) | ||
return wrapped | ||
} | ||
@@ -141,3 +141,3 @@ | ||
} | ||
return shimmer.wrap(cursor, wrapped) | ||
return wrapped | ||
} | ||
@@ -152,3 +152,3 @@ | ||
} | ||
return shimmer.wrap(command, wrapped) | ||
return wrapped | ||
} | ||
@@ -172,3 +172,3 @@ | ||
args[index] = asyncResource.bind(function (err, res) { | ||
args[index] = shimmer.wrapFunction(callback, callback => asyncResource.bind(function (err, res) { | ||
if (err) { | ||
@@ -183,3 +183,3 @@ errorCh.publish(err) | ||
} | ||
}) | ||
})) | ||
@@ -186,0 +186,0 @@ try { |
@@ -131,4 +131,3 @@ 'use strict' | ||
// not using shimmer here because resolve/reject could be empty | ||
arguments[0] = function wrappedResolve () { | ||
arguments[0] = shimmer.wrapFunction(resolve, resolve => function wrappedResolve () { | ||
finish() | ||
@@ -139,5 +138,5 @@ | ||
} | ||
} | ||
}) | ||
arguments[1] = function wrappedReject () { | ||
arguments[1] = shimmer.wrapFunction(reject, reject => function wrappedReject () { | ||
finish() | ||
@@ -148,3 +147,3 @@ | ||
} | ||
} | ||
}) | ||
@@ -175,3 +174,3 @@ return originalThen.apply(this, arguments) | ||
}, sanitizeFilter => { | ||
return shimmer.wrap(sanitizeFilter, function wrappedSanitizeFilter () { | ||
return shimmer.wrapFunction(sanitizeFilter, sanitizeFilter => function wrappedSanitizeFilter () { | ||
const sanitizedObject = sanitizeFilter.apply(this, arguments) | ||
@@ -178,0 +177,0 @@ |
@@ -40,3 +40,3 @@ 'use strict' | ||
const cb = callbackResource.bind(res._callback) | ||
res._callback = asyncResource.bind(function (error, result) { | ||
res._callback = shimmer.wrapFunction(cb, cb => asyncResource.bind(function (error, result) { | ||
if (error) { | ||
@@ -48,3 +48,3 @@ errorCh.publish(error) | ||
return cb.apply(this, arguments) | ||
}) | ||
})) | ||
} else { | ||
@@ -97,3 +97,3 @@ const cb = asyncResource.bind(function () { | ||
if (typeof cb === 'function') { | ||
arguments[arguments.length - 1] = shimmer.wrap(cb, function () { | ||
arguments[arguments.length - 1] = shimmer.wrapFunction(cb, cb => function () { | ||
finish() | ||
@@ -100,0 +100,0 @@ return cb.apply(this, arguments) |
@@ -34,3 +34,3 @@ 'use strict' | ||
function bindExecute (cmd, execute, asyncResource) { | ||
return asyncResource.bind(function executeWithTrace (packet, connection) { | ||
return shimmer.wrapFunction(execute, execute => asyncResource.bind(function executeWithTrace (packet, connection) { | ||
if (this.onResult) { | ||
@@ -41,3 +41,3 @@ this.onResult = asyncResource.bind(this.onResult) | ||
return execute.apply(this, arguments) | ||
}, cmd) | ||
}, cmd)) | ||
} | ||
@@ -48,3 +48,3 @@ | ||
return asyncResource.bind(function executeWithTrace (packet, connection) { | ||
return shimmer.wrapFunction(execute, execute => asyncResource.bind(function executeWithTrace (packet, connection) { | ||
const sql = cmd.statement ? cmd.statement.query : cmd.sql | ||
@@ -63,3 +63,3 @@ const payload = { sql, conf: config } | ||
this.onResult = asyncResource.bind(function (error) { | ||
this.onResult = shimmer.wrapFunction(onResult, onResult => asyncResource.bind(function (error) { | ||
if (error) { | ||
@@ -70,3 +70,3 @@ errorCh.publish(error) | ||
onResult.apply(this, arguments) | ||
}, 'bound-anonymous-fn', this) | ||
}, 'bound-anonymous-fn', this)) | ||
} else { | ||
@@ -84,4 +84,4 @@ this.on('error', asyncResource.bind(error => errorCh.publish(error))) | ||
} | ||
}, cmd) | ||
}, cmd)) | ||
} | ||
}) |
@@ -61,3 +61,3 @@ 'use strict' | ||
const emit = this.emit | ||
this.emit = function (eventName) { | ||
this.emit = shimmer.wrapFunction(emit, emit => function (eventName) { | ||
switch (eventName) { | ||
@@ -72,3 +72,3 @@ case 'ready': | ||
} | ||
} | ||
}) | ||
@@ -75,0 +75,0 @@ try { |
@@ -191,3 +191,3 @@ 'use strict' | ||
name: 'next', | ||
versions: ['>=13.3.0'], | ||
versions: ['>=13.3.0 <14.2.7'], | ||
file: 'dist/server/web/spec-extension/adapters/next-request.js' | ||
@@ -207,3 +207,3 @@ }, NextRequestAdapter => { | ||
name: 'next', | ||
versions: ['>=11.1'], | ||
versions: ['>=11.1 <14.2.7'], | ||
file: 'dist/server/serve-static.js' | ||
@@ -218,3 +218,3 @@ }, serveStatic => shimmer.wrap(serveStatic, 'serveStatic', wrapServeStatic)) | ||
addHook({ name: 'next', versions: ['>=11.1'], file: 'dist/server/next-server.js' }, nextServer => { | ||
addHook({ name: 'next', versions: ['>=11.1 <14.2.7'], file: 'dist/server/next-server.js' }, nextServer => { | ||
const Server = nextServer.default | ||
@@ -236,3 +236,3 @@ | ||
// `handleApiRequest` changes parameters/implementation at 13.2.0 | ||
addHook({ name: 'next', versions: ['>=13.2'], file: 'dist/server/next-server.js' }, nextServer => { | ||
addHook({ name: 'next', versions: ['>=13.2 <14.2.7'], file: 'dist/server/next-server.js' }, nextServer => { | ||
const Server = nextServer.default | ||
@@ -271,3 +271,3 @@ shimmer.wrap(Server.prototype, 'handleApiRequest', wrapHandleApiRequestWithMatch) | ||
name: 'next', | ||
versions: ['>=13'], | ||
versions: ['>=13 <14.2.7'], | ||
file: 'dist/server/web/spec-extension/request.js' | ||
@@ -274,0 +274,0 @@ }, request => { |
'use strict' | ||
const { | ||
channel, | ||
addHook | ||
} = require('./helpers/instrument') | ||
const { addHook } = require('./helpers/instrument') | ||
const shimmer = require('../../datadog-shimmer') | ||
const startCh = channel('apm:openai:request:start') | ||
const finishCh = channel('apm:openai:request:finish') | ||
const errorCh = channel('apm:openai:request:error') | ||
const tracingChannel = require('dc-polyfill').tracingChannel | ||
const ch = tracingChannel('apm:openai:request') | ||
@@ -113,7 +109,7 @@ const V4_PACKAGE_SHIMS = [ | ||
shimmer.wrap(exports.OpenAIApi.prototype, methodName, fn => function () { | ||
if (!startCh.hasSubscribers) { | ||
if (!ch.start.hasSubscribers) { | ||
return fn.apply(this, arguments) | ||
} | ||
startCh.publish({ | ||
const ctx = { | ||
methodName, | ||
@@ -123,20 +119,5 @@ args: arguments, | ||
apiKey: this.configuration.apiKey | ||
}) | ||
} | ||
return fn.apply(this, arguments) | ||
.then((response) => { | ||
finish({ | ||
headers: response.headers, | ||
body: response.data, | ||
path: response.request.path, | ||
method: response.request.method | ||
}) | ||
return response | ||
}) | ||
.catch(error => { | ||
finish(undefined, error) | ||
throw error | ||
}) | ||
return ch.tracePromise(fn, ctx, this, ...arguments) | ||
}) | ||
@@ -218,3 +199,3 @@ } | ||
*/ | ||
function wrapStreamIterator (response, options, n) { | ||
function wrapStreamIterator (response, options, n, ctx) { | ||
let processChunksAsBuffers = false | ||
@@ -259,7 +240,9 @@ let chunks = [] | ||
finish({ | ||
finish(ctx, { | ||
headers: response.headers, | ||
body, | ||
path: response.url, | ||
method: options.method | ||
data: body, | ||
request: { | ||
path: response.url, | ||
method: options.method | ||
} | ||
}) | ||
@@ -288,3 +271,3 @@ } | ||
shimmer.wrap(targetPrototype, methodName, methodFn => function () { | ||
if (!startCh.hasSubscribers) { | ||
if (!ch.start.hasSubscribers) { | ||
return methodFn.apply(this, arguments) | ||
@@ -311,3 +294,3 @@ } | ||
startCh.publish({ | ||
const ctx = { | ||
methodName: `${baseResource}.${methodName}`, | ||
@@ -317,45 +300,49 @@ args: arguments, | ||
apiKey: client.apiKey | ||
}) | ||
} | ||
const apiProm = methodFn.apply(this, arguments) | ||
return ch.start.runStores(ctx, () => { | ||
const apiProm = methodFn.apply(this, arguments) | ||
// wrapping `parse` avoids problematic wrapping of `then` when trying to call | ||
// `withResponse` in userland code after. This way, we can return the whole `APIPromise` | ||
shimmer.wrap(apiProm, 'parse', origApiPromParse => function () { | ||
return origApiPromParse.apply(this, arguments) | ||
// wrapping `parse` avoids problematic wrapping of `then` when trying to call | ||
// `withResponse` in userland code after. This way, we can return the whole `APIPromise` | ||
shimmer.wrap(apiProm, 'parse', origApiPromParse => function () { | ||
return origApiPromParse.apply(this, arguments) | ||
// the original response is wrapped in a promise, so we need to unwrap it | ||
.then(body => Promise.all([this.responsePromise, body])) | ||
.then(([{ response, options }, body]) => { | ||
if (stream) { | ||
if (body.iterator) { | ||
shimmer.wrap(body, 'iterator', wrapStreamIterator(response, options, n)) | ||
.then(body => Promise.all([this.responsePromise, body])) | ||
.then(([{ response, options }, body]) => { | ||
if (stream) { | ||
if (body.iterator) { | ||
shimmer.wrap(body, 'iterator', wrapStreamIterator(response, options, n, ctx)) | ||
} else { | ||
shimmer.wrap( | ||
body.response.body, Symbol.asyncIterator, wrapStreamIterator(response, options, n, ctx) | ||
) | ||
} | ||
} else { | ||
shimmer.wrap( | ||
body.response.body, Symbol.asyncIterator, wrapStreamIterator(response, options, n) | ||
) | ||
finish(ctx, { | ||
headers: response.headers, | ||
data: body, | ||
request: { | ||
path: response.url, | ||
method: options.method | ||
} | ||
}) | ||
} | ||
} else { | ||
finish({ | ||
headers: response.headers, | ||
body, | ||
path: response.url, | ||
method: options.method | ||
}) | ||
} | ||
return body | ||
}) | ||
.catch(error => { | ||
finish(undefined, error) | ||
return body | ||
}) | ||
.catch(error => { | ||
finish(ctx, undefined, error) | ||
throw error | ||
}) | ||
.finally(() => { | ||
throw error | ||
}) | ||
.finally(() => { | ||
// maybe we don't want to unwrap here in case the promise is re-used? | ||
// other hand: we want to avoid resource leakage | ||
shimmer.unwrap(apiProm, 'parse') | ||
}) | ||
shimmer.unwrap(apiProm, 'parse') | ||
}) | ||
}) | ||
return apiProm | ||
}) | ||
return apiProm | ||
}) | ||
@@ -367,8 +354,10 @@ } | ||
function finish (response, error) { | ||
function finish (ctx, response, error) { | ||
if (error) { | ||
errorCh.publish({ error }) | ||
ctx.error = error | ||
ch.error.publish(ctx) | ||
} | ||
finishCh.publish(response) | ||
ctx.result = response | ||
ch.asyncEnd.publish(ctx) | ||
} | ||
@@ -375,0 +364,0 @@ |
@@ -34,6 +34,6 @@ 'use strict' | ||
const outerAr = new AsyncResource('apm:oracledb:outer-scope') | ||
arguments[arguments.length - 1] = function wrappedCb (err, result) { | ||
arguments[arguments.length - 1] = shimmer.wrapFunction(cb, cb => function wrappedCb (err, result) { | ||
finish(err) | ||
return outerAr.runInAsyncScope(() => cb.apply(this, arguments)) | ||
} | ||
}) | ||
} | ||
@@ -71,3 +71,3 @@ | ||
if (callback) { | ||
arguments[1] = (err, connection) => { | ||
arguments[1] = shimmer.wrapFunction(callback, callback => (err, connection) => { | ||
if (connection) { | ||
@@ -77,3 +77,3 @@ connectionAttributes.set(connection, connAttrs) | ||
callback(err, connection) | ||
} | ||
}) | ||
@@ -92,3 +92,3 @@ getConnection.apply(this, arguments) | ||
if (callback) { | ||
arguments[1] = (err, pool) => { | ||
arguments[1] = shimmer.wrapFunction(callback, callback => (err, pool) => { | ||
if (pool) { | ||
@@ -98,3 +98,3 @@ poolAttributes.set(pool, poolAttrs) | ||
callback(err, pool) | ||
} | ||
}) | ||
@@ -117,3 +117,3 @@ createPool.apply(this, arguments) | ||
if (callback) { | ||
arguments[arguments.length - 1] = (err, connection) => { | ||
arguments[arguments.length - 1] = shimmer.wrapFunction(callback, callback => (err, connection) => { | ||
if (connection) { | ||
@@ -123,3 +123,3 @@ connectionAttributes.set(connection, poolAttributes.get(this)) | ||
callback(err, connection) | ||
} | ||
}) | ||
getConnection.apply(this, arguments) | ||
@@ -126,0 +126,0 @@ } else { |
@@ -12,3 +12,3 @@ 'use strict' | ||
}, BasicStrategy => { | ||
return shimmer.wrap(BasicStrategy, function () { | ||
return shimmer.wrapFunction(BasicStrategy, BasicStrategy => function () { | ||
const type = 'http' | ||
@@ -15,0 +15,0 @@ |
@@ -12,3 +12,3 @@ 'use strict' | ||
}, Strategy => { | ||
return shimmer.wrap(Strategy, function () { | ||
return shimmer.wrapFunction(Strategy, Strategy => function () { | ||
const type = 'local' | ||
@@ -15,0 +15,0 @@ |
@@ -14,3 +14,3 @@ 'use strict' | ||
// eslint-disable-next-line n/handle-callback-err | ||
return shimmer.wrap(verified, function (err, user, info) { | ||
return shimmer.wrapFunction(verified, verified => function (err, user, info) { | ||
const credentials = { type, username } | ||
@@ -17,0 +17,0 @@ passportVerifyChannel.publish({ credentials, user }) |
@@ -125,3 +125,3 @@ 'use strict' | ||
if (typeof cb === 'function') { | ||
arguments[arguments.length - 1] = shimmer.wrap(cb, function () { | ||
arguments[arguments.length - 1] = shimmer.wrapFunction(cb, cb => function () { | ||
finish() | ||
@@ -128,0 +128,0 @@ return cb.apply(this, arguments) |
@@ -79,3 +79,3 @@ 'use strict' | ||
return shimmer.wrap(pino, wrapPino(asJsonSym, wrapAsJson, pino)) | ||
return shimmer.wrapFunction(pino, pino => wrapPino(asJsonSym, wrapAsJson, pino)) | ||
}) | ||
@@ -86,3 +86,3 @@ | ||
return shimmer.wrap(pino, wrapPino(mixinSym, wrapMixin, pino)) | ||
return shimmer.wrapFunction(pino, pino => wrapPino(mixinSym, wrapMixin, pino)) | ||
}) | ||
@@ -93,3 +93,3 @@ | ||
const wrapped = shimmer.wrap(pino, wrapPino(mixinSym, wrapMixin, pino)) | ||
const wrapped = shimmer.wrapFunction(pino, pino => wrapPino(mixinSym, wrapMixin, pino)) | ||
wrapped.pino = wrapped | ||
@@ -107,3 +107,3 @@ wrapped.default = wrapped | ||
addHook({ name: 'pino-pretty', versions: ['1 - 2'] }, prettyFactory => { | ||
return shimmer.wrap(prettyFactory, wrapPrettyFactory(prettyFactory)) | ||
return shimmer.wrapFunction(prettyFactory, wrapPrettyFactory) | ||
}) |
@@ -5,3 +5,3 @@ const semver = require('semver') | ||
const shimmer = require('../../datadog-shimmer') | ||
const { parseAnnotations, getTestSuitePath, NUM_FAILED_TEST_RETRIES } = require('../../dd-trace/src/plugins/util/test') | ||
const { parseAnnotations, getTestSuitePath } = require('../../dd-trace/src/plugins/util/test') | ||
const log = require('../../dd-trace/src/log') | ||
@@ -40,4 +40,5 @@ | ||
let isEarlyFlakeDetectionEnabled = false | ||
let earlyFlakeDetectionNumRetries = 0 | ||
let isFlakyTestRetriesEnabled = false | ||
let earlyFlakeDetectionNumRetries = 0 | ||
let flakyTestRetriesCount = 0 | ||
let knownTests = {} | ||
@@ -412,2 +413,3 @@ let rootDir = '' | ||
isFlakyTestRetriesEnabled = libraryConfig.isFlakyTestRetriesEnabled | ||
flakyTestRetriesCount = libraryConfig.flakyTestRetriesCount | ||
} | ||
@@ -435,6 +437,6 @@ } catch (e) { | ||
if (isFlakyTestRetriesEnabled) { | ||
if (isFlakyTestRetriesEnabled && flakyTestRetriesCount > 0) { | ||
projects.forEach(project => { | ||
if (project.retries === 0) { // Only if it hasn't been set by the user | ||
project.retries = NUM_FAILED_TEST_RETRIES | ||
project.retries = flakyTestRetriesCount | ||
} | ||
@@ -441,0 +443,0 @@ }) |
@@ -159,3 +159,3 @@ 'use strict' | ||
function wrapCallback (finishCh, errorCh, callback) { | ||
return function (err) { | ||
return shimmer.wrapFunction(callback, callback => function (err) { | ||
finish(finishCh, errorCh, err) | ||
@@ -165,3 +165,3 @@ if (callback) { | ||
} | ||
} | ||
}) | ||
} | ||
@@ -168,0 +168,0 @@ |
@@ -43,3 +43,3 @@ 'use strict' | ||
return function (req, res, next) { | ||
return shimmer.wrapFunction(fn, fn => function (req, res, next) { | ||
if (typeof next === 'function') { | ||
@@ -76,7 +76,7 @@ arguments[2] = wrapNext(req, next) | ||
} | ||
} | ||
}) | ||
} | ||
function wrapNext (req, next) { | ||
return function () { | ||
return shimmer.wrapFunction(next, next => function () { | ||
nextChannel.publish({ req }) | ||
@@ -86,3 +86,3 @@ finishChannel.publish({ req }) | ||
next.apply(this, arguments) | ||
} | ||
}) | ||
} | ||
@@ -89,0 +89,0 @@ |
@@ -156,7 +156,7 @@ 'use strict' | ||
const cb = asyncResource.bind(update) | ||
return AsyncResource.bind(function wrappedUpdate (settled, stateData) { | ||
return shimmer.wrapFunction(cb, cb => AsyncResource.bind(function wrappedUpdate (settled, stateData) { | ||
const state = getStateFromData(stateData) | ||
dispatchReceiveCh.publish({ state }) | ||
return cb.apply(this, arguments) | ||
}) | ||
})) | ||
} | ||
@@ -182,3 +182,3 @@ return function wrappedUpdate (settled, stateData) { | ||
shimmer.wrap(CircularBuffer.prototype, 'pop_if', popIf => function (fn) { | ||
arguments[0] = AsyncResource.bind(function (entry) { | ||
arguments[0] = shimmer.wrapFunction(fn, fn => AsyncResource.bind(function (entry) { | ||
const context = contexts.get(entry) | ||
@@ -203,3 +203,3 @@ const asyncResource = context && context.asyncResource | ||
return shouldPop | ||
}) | ||
})) | ||
return popIf.apply(this, arguments) | ||
@@ -206,0 +206,0 @@ }) |
@@ -21,3 +21,3 @@ 'use strict' | ||
const handle = shimmer.wrap(original, function () { | ||
const handle = shimmer.wrapFunction(original, original => function () { | ||
if (!enterChannel.hasSubscribers) return original.apply(this, arguments) | ||
@@ -93,3 +93,3 @@ | ||
function wrapNext (req, next) { | ||
return function (error) { | ||
return shimmer.wrapFunction(next, next => function (error) { | ||
if (error && error !== 'route' && error !== 'router') { | ||
@@ -103,3 +103,3 @@ errorChannel.publish({ req, error }) | ||
next.apply(this, arguments) | ||
} | ||
}) | ||
} | ||
@@ -157,3 +157,3 @@ | ||
function wrapMethod (original) { | ||
return function methodWithTrace (fn) { | ||
return shimmer.wrapFunction(original, original => function methodWithTrace (fn) { | ||
const offset = this.stack ? [].concat(this.stack).length : 0 | ||
@@ -169,3 +169,3 @@ const router = original.apply(this, arguments) | ||
return router | ||
} | ||
}) | ||
} | ||
@@ -172,0 +172,0 @@ |
@@ -51,3 +51,3 @@ 'use strict' | ||
arguments[1] = asyncResource.bind(function (error, res) { | ||
arguments[1] = shimmer.wrapFunction(callback, callback => asyncResource.bind(function (error, res) { | ||
if (error) { | ||
@@ -59,3 +59,3 @@ errorCh.publish(error) | ||
return callback.apply(this, arguments) | ||
}) | ||
})) | ||
@@ -62,0 +62,0 @@ try { |
const { addHook, channel, AsyncResource } = require('./helpers/instrument') | ||
const shimmer = require('../../datadog-shimmer') | ||
const { NUM_FAILED_TEST_RETRIES } = require('../../dd-trace/src/plugins/util/test') | ||
@@ -111,2 +110,3 @@ // test hooks | ||
let isFlakyTestRetriesEnabled = false | ||
let flakyTestRetriesCount = 0 | ||
@@ -117,2 +117,3 @@ try { | ||
isFlakyTestRetriesEnabled = libraryConfig.isFlakyTestRetriesEnabled | ||
flakyTestRetriesCount = libraryConfig.flakyTestRetriesCount | ||
} | ||
@@ -122,4 +123,4 @@ } catch (e) { | ||
} | ||
if (isFlakyTestRetriesEnabled && !this.ctx.config.retry) { | ||
this.ctx.config.retry = NUM_FAILED_TEST_RETRIES | ||
if (isFlakyTestRetriesEnabled && !this.ctx.config.retry && flakyTestRetriesCount > 0) { | ||
this.ctx.config.retry = flakyTestRetriesCount | ||
} | ||
@@ -126,0 +127,0 @@ |
@@ -45,4 +45,3 @@ 'use strict' | ||
const log = transport.log | ||
transport.log = function wrappedLog (level, msg, meta, callback) { | ||
shimmer.wrap(transport, 'log', log => function wrappedLog (level, msg, meta, callback) { | ||
const payload = { message: meta || {} } | ||
@@ -52,3 +51,3 @@ logCh.publish(payload) | ||
log.apply(this, arguments) | ||
} | ||
}) | ||
patched.add(transport) | ||
@@ -55,0 +54,0 @@ } |
@@ -31,4 +31,3 @@ const { | ||
TEST_IS_RETRY, | ||
TEST_EARLY_FLAKE_ENABLED, | ||
NUM_FAILED_TEST_RETRIES | ||
TEST_EARLY_FLAKE_ENABLED | ||
} = require('../../dd-trace/src/plugins/util/test') | ||
@@ -233,3 +232,4 @@ const { isMarkedAsUnskippable } = require('../../datadog-plugin-jest/src/util') | ||
earlyFlakeDetectionNumRetries, | ||
isFlakyTestRetriesEnabled | ||
isFlakyTestRetriesEnabled, | ||
flakyTestRetriesCount | ||
} | ||
@@ -241,5 +241,4 @@ } = libraryConfigurationResponse | ||
this.earlyFlakeDetectionNumRetries = earlyFlakeDetectionNumRetries | ||
this.isFlakyTestRetriesEnabled = isFlakyTestRetriesEnabled | ||
if (this.isFlakyTestRetriesEnabled) { | ||
this.cypressConfig.retries.runMode = NUM_FAILED_TEST_RETRIES | ||
if (isFlakyTestRetriesEnabled) { | ||
this.cypressConfig.retries.runMode = flakyTestRetriesCount | ||
} | ||
@@ -246,0 +245,0 @@ } |
@@ -35,4 +35,4 @@ 'use strict' | ||
this.addSub('apm:hapi:extension:enter', ({ req }) => { | ||
this.enter(this._requestSpans.get(req)) | ||
this.addBind('apm:hapi:extension:start', ({ req }) => { | ||
return this._requestSpans.get(req) | ||
}) | ||
@@ -39,0 +39,0 @@ } |
@@ -157,2 +157,3 @@ const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin') | ||
config._ddIsFlakyTestRetriesEnabled = this.libraryConfig?.isFlakyTestRetriesEnabled ?? false | ||
config._ddFlakyTestRetriesCount = this.libraryConfig?.flakyTestRetriesCount | ||
}) | ||
@@ -159,0 +160,0 @@ }) |
@@ -34,2 +34,5 @@ 'use strict' | ||
static get system () { return 'openai' } | ||
static get prefix () { | ||
return 'tracing:apm:openai:request' | ||
} | ||
@@ -59,4 +62,6 @@ constructor (...args) { | ||
start ({ methodName, args, basePath, apiKey }) { | ||
bindStart (ctx) { | ||
const { methodName, args, basePath, apiKey } = ctx | ||
const payload = normalizeRequestPayload(methodName, args) | ||
const store = storage.getStore() || {} | ||
@@ -92,7 +97,5 @@ const span = this.startSpan('openai.request', { | ||
} | ||
}) | ||
}, false) | ||
const fullStore = storage.getStore() || {} // certain request body fields are later used for logs | ||
const store = Object.create(null) | ||
fullStore.openai = store // namespacing these fields | ||
const openaiStore = Object.create(null) | ||
@@ -104,3 +107,3 @@ const tags = {} // The remaining tags are added one at a time | ||
const prompt = payload.prompt | ||
store.prompt = prompt | ||
openaiStore.prompt = prompt | ||
if (typeof prompt === 'string' || (Array.isArray(prompt) && typeof prompt[0] === 'number')) { | ||
@@ -121,3 +124,3 @@ // This is a single prompt, either String or [Number] | ||
tags['openai.request.input'] = truncateText(normalized) | ||
store.input = normalized | ||
openaiStore.input = normalized | ||
} | ||
@@ -149,3 +152,3 @@ | ||
case 'images.createVariation': | ||
commonCreateImageRequestExtraction(tags, payload, store) | ||
commonCreateImageRequestExtraction(tags, payload, openaiStore) | ||
break | ||
@@ -155,3 +158,3 @@ | ||
case 'chat.completions.create': | ||
createChatCompletionRequestExtraction(tags, payload, store) | ||
createChatCompletionRequestExtraction(tags, payload, openaiStore) | ||
break | ||
@@ -170,3 +173,3 @@ | ||
case 'audio.translations.create': | ||
commonCreateAudioRequestExtraction(tags, payload, store) | ||
commonCreateAudioRequestExtraction(tags, payload, openaiStore) | ||
break | ||
@@ -195,3 +198,3 @@ | ||
case 'edits.create': | ||
createEditRequestExtraction(tags, payload, store) | ||
createEditRequestExtraction(tags, payload, openaiStore) | ||
break | ||
@@ -201,6 +204,15 @@ } | ||
span.addTags(tags) | ||
ctx.currentStore = { ...store, span, openai: openaiStore } | ||
return ctx.currentStore | ||
} | ||
finish (response) { | ||
const span = this.activeSpan | ||
asyncEnd (ctx) { | ||
const { result } = ctx | ||
const store = ctx.currentStore | ||
const span = store?.span | ||
if (!span) return | ||
const error = !!span.context()._tags.error | ||
@@ -210,6 +222,6 @@ | ||
if (!error) { | ||
headers = response.headers | ||
body = response.body | ||
method = response.method | ||
path = response.path | ||
headers = result.headers | ||
body = result.data | ||
method = result.request.method | ||
path = result.request.path | ||
} | ||
@@ -224,6 +236,5 @@ | ||
const fullStore = storage.getStore() | ||
const store = fullStore.openai | ||
const openaiStore = store.openai | ||
if (!error && (path.startsWith('https://') || path.startsWith('http://'))) { | ||
if (!error && (path?.startsWith('https://') || path?.startsWith('http://'))) { | ||
// basic checking for if the path was set as a full URL | ||
@@ -254,7 +265,7 @@ // not using a full regex as it will likely be "https://api.openai.com/..." | ||
responseDataExtractionByMethod(methodName, tags, body, store) | ||
responseDataExtractionByMethod(methodName, tags, body, openaiStore) | ||
span.addTags(tags) | ||
super.finish() | ||
this.sendLog(methodName, span, tags, store, error) | ||
span.finish() | ||
this.sendLog(methodName, span, tags, openaiStore, error) | ||
this.sendMetrics(headers, body, endpoint, span._duration, error, tags) | ||
@@ -324,5 +335,5 @@ } | ||
sendLog (methodName, span, tags, store, error) { | ||
if (!store) return | ||
if (!Object.keys(store).length) return | ||
sendLog (methodName, span, tags, openaiStore, error) { | ||
if (!openaiStore) return | ||
if (!Object.keys(openaiStore).length) return | ||
if (!this.sampler.isSampled()) return | ||
@@ -333,3 +344,3 @@ | ||
message: `sampled ${methodName}`, | ||
...store | ||
...openaiStore | ||
} | ||
@@ -418,6 +429,6 @@ | ||
function createEditRequestExtraction (tags, payload, store) { | ||
function createEditRequestExtraction (tags, payload, openaiStore) { | ||
const instruction = payload.instruction | ||
tags['openai.request.instruction'] = instruction | ||
store.instruction = instruction | ||
openaiStore.instruction = instruction | ||
} | ||
@@ -429,7 +440,7 @@ | ||
function createChatCompletionRequestExtraction (tags, payload, store) { | ||
function createChatCompletionRequestExtraction (tags, payload, openaiStore) { | ||
const messages = payload.messages | ||
if (!defensiveArrayLength(messages)) return | ||
store.messages = payload.messages | ||
openaiStore.messages = payload.messages | ||
for (let i = 0; i < payload.messages.length; i++) { | ||
@@ -444,3 +455,3 @@ const message = payload.messages[i] | ||
function commonCreateImageRequestExtraction (tags, payload, store) { | ||
function commonCreateImageRequestExtraction (tags, payload, openaiStore) { | ||
// createImageEdit, createImageVariation | ||
@@ -451,3 +462,3 @@ const img = payload.file || payload.image | ||
tags['openai.request.image'] = file | ||
store.file = file | ||
openaiStore.file = file | ||
} | ||
@@ -459,3 +470,3 @@ | ||
tags['openai.request.mask'] = mask | ||
store.mask = mask | ||
openaiStore.mask = mask | ||
} | ||
@@ -468,3 +479,3 @@ | ||
function responseDataExtractionByMethod (methodName, tags, body, store) { | ||
function responseDataExtractionByMethod (methodName, tags, body, openaiStore) { | ||
switch (methodName) { | ||
@@ -482,3 +493,3 @@ case 'createModeration': | ||
case 'edits.create': | ||
commonCreateResponseExtraction(tags, body, store, methodName) | ||
commonCreateResponseExtraction(tags, body, openaiStore, methodName) | ||
break | ||
@@ -499,3 +510,3 @@ | ||
case 'embeddings.create': | ||
createEmbeddingResponseExtraction(tags, body) | ||
createEmbeddingResponseExtraction(tags, body, openaiStore) | ||
break | ||
@@ -655,3 +666,3 @@ | ||
function commonCreateAudioRequestExtraction (tags, body, store) { | ||
function commonCreateAudioRequestExtraction (tags, body, openaiStore) { | ||
tags['openai.request.response_format'] = body.response_format | ||
@@ -663,3 +674,3 @@ tags['openai.request.language'] = body.language | ||
tags['openai.request.filename'] = filename | ||
store.file = filename | ||
openaiStore.file = filename | ||
} | ||
@@ -687,4 +698,4 @@ } | ||
function createEmbeddingResponseExtraction (tags, body) { | ||
usageExtraction(tags, body) | ||
function createEmbeddingResponseExtraction (tags, body, openaiStore) { | ||
usageExtraction(tags, body, openaiStore) | ||
@@ -723,4 +734,4 @@ if (!body.data) return | ||
// createCompletion, createChatCompletion, createEdit | ||
function commonCreateResponseExtraction (tags, body, store, methodName) { | ||
usageExtraction(tags, body, methodName) | ||
function commonCreateResponseExtraction (tags, body, openaiStore, methodName) { | ||
usageExtraction(tags, body, methodName, openaiStore) | ||
@@ -731,3 +742,3 @@ if (!body.choices) return | ||
store.choices = body.choices | ||
openaiStore.choices = body.choices | ||
@@ -766,3 +777,3 @@ for (let choiceIdx = 0; choiceIdx < body.choices.length; choiceIdx++) { | ||
// createCompletion, createChatCompletion, createEdit, createEmbedding | ||
function usageExtraction (tags, body, methodName) { | ||
function usageExtraction (tags, body, methodName, openaiStore) { | ||
let promptTokens = 0 | ||
@@ -775,3 +786,3 @@ let completionTokens = 0 | ||
totalTokens = body.usage.total_tokens | ||
} else if (['chat.completions.create', 'completions.create'].includes(methodName)) { | ||
} else if (body.model && ['chat.completions.create', 'completions.create'].includes(methodName)) { | ||
// estimate tokens based on method name for completions and chat completions | ||
@@ -783,3 +794,3 @@ const { model } = body | ||
// prompt tokens | ||
const payload = storage.getStore().openai | ||
const payload = openaiStore | ||
const promptTokensCount = countPromptTokens(methodName, payload, model) | ||
@@ -786,0 +797,0 @@ promptTokens = promptTokensCount.promptTokens |
'use strict' | ||
const log = require('../../dd-trace/src/log') | ||
// Use a weak map to avoid polluting the wrapped function/method. | ||
@@ -21,5 +23,8 @@ const unwrappers = new WeakMap() | ||
function wrapFn (original, delegate) { | ||
assertFunction(delegate) | ||
assertNotClass(original) // TODO: support constructors of native classes | ||
function wrapFunction (original, wrapper) { | ||
if (typeof original === 'function') assertNotClass(original) | ||
// TODO This needs to be re-done so that this and wrapMethod are distinct. | ||
const target = { func: original } | ||
wrapMethod(target, 'func', wrapper, typeof original !== 'function') | ||
let delegate = target.func | ||
@@ -34,3 +39,3 @@ const shim = function shim () { | ||
copyProperties(original, shim) | ||
if (typeof original === 'function') copyProperties(original, shim) | ||
@@ -40,8 +45,135 @@ return shim | ||
function wrapMethod (target, name, wrapper) { | ||
assertMethod(target, name) | ||
assertFunction(wrapper) | ||
const wrapFn = function (original, delegate) { | ||
throw new Error('calling `wrap()` with 2 args is deprecated. Use wrapFunction instead.') | ||
} | ||
// This is only used in safe mode. It's a simple state machine to track if the | ||
// original method was called and if it returned. We need this to determine if | ||
// an error was thrown by the original method, or by us. We'll use one of these | ||
// per call to a wrapped method. | ||
class CallState { | ||
constructor () { | ||
this.called = false | ||
this.completed = false | ||
this.retVal = undefined | ||
} | ||
startCall () { | ||
this.called = true | ||
} | ||
endCall (retVal) { | ||
this.completed = true | ||
this.retVal = retVal | ||
} | ||
} | ||
function isPromise (obj) { | ||
return obj && typeof obj === 'object' && typeof obj.then === 'function' | ||
} | ||
let safeMode = !!process.env.DD_INEJCTION_ENABLED | ||
function setSafe (value) { | ||
safeMode = value | ||
} | ||
function wrapMethod (target, name, wrapper, noAssert) { | ||
if (!noAssert) { | ||
assertMethod(target, name) | ||
assertFunction(wrapper) | ||
} | ||
const original = target[name] | ||
const wrapped = wrapper(original) | ||
let wrapped | ||
if (safeMode && original) { | ||
// In this mode, we make a best-effort attempt to handle errors that are thrown | ||
// by us, rather than wrapped code. With such errors, we log them, and then attempt | ||
// to return the result as if no wrapping was done at all. | ||
// | ||
// Caveats: | ||
// * If the original function is called in a later iteration of the event loop, | ||
// and we throw _then_, then it won't be caught by this. In practice, we always call | ||
// the original function synchronously, so this is not a problem. | ||
// * While async errors are dealt with here, errors in callbacks are not. This | ||
// is because we don't necessarily know _for sure_ that any function arguments | ||
// are wrapped by us. We could wrap them all anyway and just make that assumption, | ||
// or just assume that the last argument is always a callback set by us if it's a | ||
// function, but those don't seem like things we can rely on. We could add a | ||
// `shimmer.markCallbackAsWrapped()` function that's a no-op outside safe-mode, | ||
// but that means modifying every instrumentation. Even then, the complexity of | ||
// this code increases because then we'd need to effectively do the reverse of | ||
// what we're doing for synchronous functions. This is a TODO. | ||
// We're going to hold on to current callState in this variable in this scope, | ||
// which is fine because any time we reference it, we're referencing it synchronously. | ||
// We'll use it in the our wrapper (which, again, is called syncrhonously), and in the | ||
// errorHandler, which will already have been bound to this callState. | ||
let currentCallState | ||
// Rather than calling the original function directly from the shim wrapper, we wrap | ||
// it again so that we can track if it was called and if it returned. This is because | ||
// we need to know if an error was thrown by the original function, or by us. | ||
// We could do this inside the `wrapper` function defined below, which would simplify | ||
// managing the callState, but then we'd be calling `wrapper` on each invocation, so | ||
// instead we do it here, once. | ||
const innerWrapped = wrapper(function (...args) { | ||
// We need to stash the callState here because of recursion. | ||
const callState = currentCallState | ||
callState.startCall() | ||
const retVal = original.apply(this, args) | ||
if (isPromise(retVal)) { | ||
retVal.then(callState.endCall.bind(callState)) | ||
} else { | ||
callState.endCall(retVal) | ||
} | ||
return retVal | ||
}) | ||
// This is the crux of what we're doing in safe mode. It handles errors | ||
// that _we_ cause, by logging them, and transparently providing results | ||
// as if no wrapping was done at all. That means detecting (via callState) | ||
// whether the function has already run or not, and if it has, returning | ||
// the result, and otherwise calling the original function unwrapped. | ||
const handleError = function (args, callState, e) { | ||
if (callState.completed) { | ||
// error was thrown after original function returned/resolved, so | ||
// it was us. log it. | ||
log.error(e) | ||
// original ran and returned something. return it. | ||
return callState.retVal | ||
} | ||
if (!callState.called) { | ||
// error was thrown before original function was called, so | ||
// it was us. log it. | ||
log.error(e) | ||
// original never ran. call it unwrapped. | ||
return original.apply(this, args) | ||
} | ||
// error was thrown during original function execution, so | ||
// it was them. throw. | ||
throw e | ||
} | ||
// The wrapped function is the one that will be called by the user. | ||
// It calls our version of the original function, which manages the | ||
// callState. That way when we use the errorHandler, it can tell where | ||
// the error originated. | ||
wrapped = function (...args) { | ||
currentCallState = new CallState() | ||
const errorHandler = handleError.bind(this, args, currentCallState) | ||
try { | ||
const retVal = innerWrapped.apply(this, args) | ||
return isPromise(retVal) ? retVal.catch(errorHandler) : retVal | ||
} catch (e) { | ||
return errorHandler(e) | ||
} | ||
} | ||
} else { | ||
// In non-safe mode, we just wrap the original function directly. | ||
wrapped = wrapper(original) | ||
} | ||
const descriptor = Object.getOwnPropertyDescriptor(target, name) | ||
@@ -54,3 +186,3 @@ | ||
copyProperties(original, wrapped) | ||
if (typeof original === 'function') copyProperties(original, wrapped) | ||
@@ -163,5 +295,7 @@ if (descriptor) { | ||
wrap, | ||
wrapFunction, | ||
massWrap, | ||
unwrap, | ||
massUnwrap | ||
massUnwrap, | ||
setSafe | ||
} |
@@ -12,2 +12,4 @@ 'use strict' | ||
let defaultBlockingActionParameters | ||
const responseBlockedSet = new WeakSet() | ||
@@ -27,3 +29,3 @@ | ||
function getBlockWithRedirectData (rootSpan, actionParameters) { | ||
function getBlockWithRedirectData (actionParameters) { | ||
let statusCode = actionParameters.status_code | ||
@@ -37,6 +39,2 @@ if (!statusCode || statusCode < 300 || statusCode >= 400) { | ||
rootSpan.addTags({ | ||
'appsec.blocked': 'true' | ||
}) | ||
return { headers, statusCode } | ||
@@ -55,3 +53,3 @@ } | ||
function getBlockWithContentData (req, specificType, rootSpan, actionParameters) { | ||
function getBlockWithContentData (req, specificType, actionParameters) { | ||
let type | ||
@@ -97,18 +95,14 @@ let body | ||
rootSpan.addTags({ | ||
'appsec.blocked': 'true' | ||
}) | ||
return { body, statusCode, headers } | ||
} | ||
function getBlockingData (req, specificType, rootSpan, actionParameters) { | ||
function getBlockingData (req, specificType, actionParameters) { | ||
if (actionParameters?.location) { | ||
return getBlockWithRedirectData(rootSpan, actionParameters) | ||
return getBlockWithRedirectData(actionParameters) | ||
} else { | ||
return getBlockWithContentData(req, specificType, rootSpan, actionParameters) | ||
return getBlockWithContentData(req, specificType, actionParameters) | ||
} | ||
} | ||
function block (req, res, rootSpan, abortController, actionParameters) { | ||
function block (req, res, rootSpan, abortController, actionParameters = defaultBlockingActionParameters) { | ||
if (res.headersSent) { | ||
@@ -119,4 +113,8 @@ log.warn('Cannot send blocking response when headers have already been sent') | ||
const { body, headers, statusCode } = getBlockingData(req, null, rootSpan, actionParameters) | ||
const { body, headers, statusCode } = getBlockingData(req, null, actionParameters) | ||
rootSpan.addTags({ | ||
'appsec.blocked': 'true' | ||
}) | ||
for (const headerName of res.getHeaderNames()) { | ||
@@ -134,3 +132,4 @@ res.removeHeader(headerName) | ||
function getBlockingAction (actions) { | ||
return actions?.block_request || actions?.redirect_request | ||
// waf only returns one action, but it prioritizes redirect over block | ||
return actions?.redirect_request || actions?.block_request | ||
} | ||
@@ -162,2 +161,8 @@ | ||
function setDefaultBlockingActionParameters (actions) { | ||
const blockAction = actions?.find(action => action.id === 'block') | ||
defaultBlockingActionParameters = blockAction?.parameters | ||
} | ||
module.exports = { | ||
@@ -170,3 +175,4 @@ addSpecificEndpoint, | ||
setTemplates, | ||
isBlocked | ||
isBlocked, | ||
setDefaultBlockingActionParameters | ||
} |
@@ -97,3 +97,3 @@ 'use strict' | ||
const blockingData = getBlockingData(req, specificBlockingTypes.GRAPHQL, rootSpan, requestData.wafAction) | ||
const blockingData = getBlockingData(req, specificBlockingTypes.GRAPHQL, requestData.wafAction) | ||
abortData.statusCode = blockingData.statusCode | ||
@@ -103,2 +103,4 @@ abortData.headers = blockingData.headers | ||
rootSpan.setTag('appsec.blocked', 'true') | ||
abortController?.abort() | ||
@@ -105,0 +107,0 @@ } |
@@ -81,3 +81,4 @@ 'use strict' | ||
this.error(data) | ||
return this.publish(data, 'ERROR') | ||
// publish is done automatically by log.error() | ||
return this | ||
} | ||
@@ -84,0 +85,0 @@ } |
@@ -123,3 +123,6 @@ 'use strict' | ||
method: 'POST', | ||
path: '/v0.7/config' | ||
path: '/v0.7/config', | ||
headers: { | ||
'Content-Type': 'application/json; charset=utf-8' | ||
} | ||
} | ||
@@ -126,0 +129,0 @@ |
@@ -7,2 +7,4 @@ 'use strict' | ||
const blocking = require('./blocking') | ||
let defaultRules | ||
@@ -23,2 +25,4 @@ | ||
waf.init(defaultRules, config) | ||
blocking.setDefaultBlockingActionParameters(defaultRules?.actions) | ||
} | ||
@@ -146,2 +150,4 @@ | ||
appliedActions = newActions | ||
blocking.setDefaultBlockingActionParameters(concatArrays(newActions)) | ||
} | ||
@@ -248,2 +254,4 @@ } catch (err) { | ||
appliedActions.clear() | ||
blocking.setDefaultBlockingActionParameters(undefined) | ||
} | ||
@@ -250,0 +258,0 @@ |
@@ -93,10 +93,10 @@ 'use strict' | ||
const tags = { rule_type: raspRuleType, waf_version: metrics.wafVersion } | ||
appsecMetrics.count('appsec.rasp.rule.eval', tags).inc(1) | ||
appsecMetrics.count('rasp.rule.eval', tags).inc(1) | ||
if (metrics.wafTimeout) { | ||
appsecMetrics.count('appsec.rasp.timeout', tags).inc(1) | ||
appsecMetrics.count('rasp.timeout', tags).inc(1) | ||
} | ||
if (metrics.ruleTriggered) { | ||
appsecMetrics.count('appsec.rasp.rule.match', tags).inc(1) | ||
appsecMetrics.count('rasp.rule.match', tags).inc(1) | ||
} | ||
@@ -103,0 +103,0 @@ } |
@@ -204,3 +204,4 @@ 'use strict' | ||
earlyFlakeDetectionFaultyThreshold, | ||
isFlakyTestRetriesEnabled | ||
isFlakyTestRetriesEnabled: isFlakyTestRetriesEnabled && this._config.isFlakyTestRetriesEnabled, | ||
flakyTestRetriesCount: this._config.flakyTestRetriesCount | ||
} | ||
@@ -207,0 +208,0 @@ } |
@@ -444,5 +444,8 @@ 'use strict' | ||
this._setValue(defaults, 'iast.telemetryVerbosity', 'INFORMATION') | ||
this._setValue(defaults, 'injectionEnabled', []) | ||
this._setValue(defaults, 'isAzureFunction', false) | ||
this._setValue(defaults, 'isCiVisibility', false) | ||
this._setValue(defaults, 'isEarlyFlakeDetectionEnabled', false) | ||
this._setValue(defaults, 'isFlakyTestRetriesEnabled', false) | ||
this._setValue(defaults, 'flakyTestRetriesCount', 5) | ||
this._setValue(defaults, 'isGCPFunction', false) | ||
@@ -463,4 +466,2 @@ this._setValue(defaults, 'isGitUploadEnabled', false) | ||
this._setValue(defaults, 'profiling.sourceMap', true) | ||
this._setValue(defaults, 'profiling.ssi', false) | ||
this._setValue(defaults, 'profiling.heuristicsEnabled', false) | ||
this._setValue(defaults, 'profiling.longLivedThreshold', undefined) | ||
@@ -686,2 +687,3 @@ this._setValue(defaults, 'protocolVersion', '0.4') | ||
this._setString(env, 'iast.telemetryVerbosity', DD_IAST_TELEMETRY_VERBOSITY) | ||
this._setArray(env, 'injectionEnabled', DD_INJECTION_ENABLED) | ||
this._setBoolean(env, 'isAzureFunction', getIsAzureFunction()) | ||
@@ -702,14 +704,14 @@ this._setBoolean(env, 'isGCPFunction', getIsGCPFunction()) | ||
this._setString(env, 'port', DD_TRACE_AGENT_PORT) | ||
this._setBoolean(env, 'profiling.enabled', coalesce(DD_EXPERIMENTAL_PROFILING_ENABLED, DD_PROFILING_ENABLED)) | ||
const profilingEnabledEnv = coalesce(DD_EXPERIMENTAL_PROFILING_ENABLED, DD_PROFILING_ENABLED) | ||
const profilingEnabled = isTrue(profilingEnabledEnv) | ||
? 'true' | ||
: isFalse(profilingEnabledEnv) | ||
? 'false' | ||
: profilingEnabledEnv === 'auto' ? 'auto' : undefined | ||
this._setString(env, 'profiling.enabled', profilingEnabled) | ||
this._setString(env, 'profiling.exporters', DD_PROFILING_EXPORTERS) | ||
this._setBoolean(env, 'profiling.sourceMap', DD_PROFILING_SOURCE_MAP && !isFalse(DD_PROFILING_SOURCE_MAP)) | ||
if (DD_PROFILING_ENABLED === 'auto' || DD_INJECTION_ENABLED) { | ||
this._setBoolean(env, 'profiling.ssi', true) | ||
if (DD_PROFILING_ENABLED === 'auto' || DD_INJECTION_ENABLED.split(',').includes('profiler')) { | ||
this._setBoolean(env, 'profiling.heuristicsEnabled', true) | ||
} | ||
if (DD_INTERNAL_PROFILING_LONG_LIVED_THRESHOLD) { | ||
// This is only used in testing to not have to wait 30s | ||
this._setValue(env, 'profiling.longLivedThreshold', Number(DD_INTERNAL_PROFILING_LONG_LIVED_THRESHOLD)) | ||
} | ||
if (DD_INTERNAL_PROFILING_LONG_LIVED_THRESHOLD) { | ||
// This is only used in testing to not have to wait 30s | ||
this._setValue(env, 'profiling.longLivedThreshold', Number(DD_INTERNAL_PROFILING_LONG_LIVED_THRESHOLD)) | ||
} | ||
@@ -769,8 +771,3 @@ | ||
this._envUnprocessed['telemetry.heartbeatInterval'] = DD_TELEMETRY_HEARTBEAT_INTERVAL * 1000 | ||
const hasTelemetryLogsUsingFeatures = | ||
env['iast.enabled'] || env['profiling.enabled'] || env['profiling.heuristicsEnabled'] | ||
? true | ||
: undefined | ||
this._setBoolean(env, 'telemetry.logCollection', coalesce(DD_TELEMETRY_LOG_COLLECTION_ENABLED, | ||
hasTelemetryLogsUsingFeatures)) | ||
this._setBoolean(env, 'telemetry.logCollection', DD_TELEMETRY_LOG_COLLECTION_ENABLED) | ||
this._setBoolean(env, 'telemetry.metrics', DD_TELEMETRY_METRICS_ENABLED) | ||
@@ -870,3 +867,6 @@ this._setBoolean(env, 'traceId128BitGenerationEnabled', DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED) | ||
this._setString(opts, 'port', options.port) | ||
this._setBoolean(opts, 'profiling.enabled', options.profiling) | ||
const strProfiling = String(options.profiling) | ||
if (['true', 'false', 'auto'].includes(strProfiling)) { | ||
this._setString(opts, 'profiling.enabled', strProfiling) | ||
} | ||
this._setString(opts, 'protocolVersion', options.protocolVersion) | ||
@@ -894,6 +894,2 @@ if (options.remoteConfig) { | ||
this._setTags(opts, 'tags', tags) | ||
const hasTelemetryLogsUsingFeatures = | ||
(options.iast && (options.iast === true || options.iast?.enabled === true)) || | ||
(options.profiling && options.profiling === true) | ||
this._setBoolean(opts, 'telemetry.logCollection', hasTelemetryLogsUsingFeatures) | ||
this._setBoolean(opts, 'traceId128BitGenerationEnabled', options.traceId128BitGenerationEnabled) | ||
@@ -997,3 +993,5 @@ this._setBoolean(opts, 'traceId128BitLoggingEnabled', options.traceId128BitLoggingEnabled) | ||
DD_CIVISIBILITY_AGENTLESS_URL, | ||
DD_CIVISIBILITY_EARLY_FLAKE_DETECTION_ENABLED | ||
DD_CIVISIBILITY_EARLY_FLAKE_DETECTION_ENABLED, | ||
DD_CIVISIBILITY_FLAKY_RETRY_ENABLED, | ||
DD_CIVISIBILITY_FLAKY_RETRY_COUNT | ||
} = process.env | ||
@@ -1009,2 +1007,5 @@ | ||
coalesce(DD_CIVISIBILITY_EARLY_FLAKE_DETECTION_ENABLED, true)) | ||
this._setBoolean(calc, 'isFlakyTestRetriesEnabled', | ||
coalesce(DD_CIVISIBILITY_FLAKY_RETRY_ENABLED, true)) | ||
this._setValue(calc, 'flakyTestRetriesCount', coalesce(maybeInt(DD_CIVISIBILITY_FLAKY_RETRY_COUNT), 5)) | ||
this._setBoolean(calc, 'isIntelligentTestRunnerEnabled', isTrue(this._isCiVisibilityItrEnabled())) | ||
@@ -1031,2 +1032,9 @@ this._setBoolean(calc, 'isManualApiEnabled', this._isCiVisibilityManualApiEnabled()) | ||
} | ||
const iastEnabled = coalesce(this._options['iast.enabled'], this._env['iast.enabled']) | ||
const profilingEnabled = coalesce(this._options['profiling.enabled'], this._env['profiling.enabled']) | ||
const injectionIncludesProfiler = (this._env.injectionEnabled || []).includes('profiler') | ||
if (iastEnabled || ['auto', 'true'].includes(profilingEnabled) || injectionIncludesProfiler) { | ||
this._setBoolean(calc, 'telemetry.logCollection', true) | ||
} | ||
} | ||
@@ -1156,13 +1164,14 @@ | ||
const container = containers[i] | ||
const origin = origins[i] | ||
const unprocessed = unprocessedValues[i] | ||
const value = container[name] | ||
if ((container[name] !== null && container[name] !== undefined) || container === this._defaults) { | ||
if (get(this, name) === container[name] && has(this, name)) break | ||
if ((value !== null && value !== undefined) || container === this._defaults) { | ||
if (get(this, name) === value && has(this, name)) break | ||
let value = container[name] | ||
set(this, name, value) | ||
value = unprocessed[name] || value | ||
changes.push({ name, value, origin }) | ||
changes.push({ | ||
name, | ||
value: unprocessedValues[i][name] || value, | ||
origin: origins[i] | ||
}) | ||
@@ -1169,0 +1178,0 @@ break |
@@ -96,4 +96,5 @@ 'use strict' | ||
} | ||
clearTimeout(__lambdaTimeout) | ||
return result | ||
} | ||
} |
@@ -5,2 +5,13 @@ 'use strict' | ||
registerLambdaHook() | ||
/** | ||
* It is safe to do it this way, since customers will never be expected to disable | ||
* this specific instrumentation through the init config object. | ||
*/ | ||
const _DD_TRACE_DISABLED_INSTRUMENTATIONS = process.env.DD_TRACE_DISABLED_INSTRUMENTATIONS || '' | ||
const _disabledInstrumentations = new Set( | ||
_DD_TRACE_DISABLED_INSTRUMENTATIONS ? _DD_TRACE_DISABLED_INSTRUMENTATIONS.split(',') : [] | ||
) | ||
if (!_disabledInstrumentations.has('lambda')) { | ||
registerLambdaHook() | ||
} |
@@ -239,4 +239,3 @@ 'use strict' | ||
_hasParentIdInTags (spanContext) { | ||
return tags.DD_PARENT_ID in spanContext._trace.tags && | ||
spanContext._trace.tags[tags.DD_PARENT_ID] !== zeroTraceId | ||
return tags.DD_PARENT_ID in spanContext._trace.tags | ||
} | ||
@@ -449,6 +448,2 @@ | ||
if (!spanContext._trace.tags[tags.DD_PARENT_ID]) { | ||
spanContext._trace.tags[tags.DD_PARENT_ID] = zeroTraceId | ||
} | ||
this._extractBaggageItems(carrier, spanContext) | ||
@@ -455,0 +450,0 @@ return spanContext |
@@ -98,5 +98,2 @@ const path = require('path') | ||
// Flaky test retries | ||
const NUM_FAILED_TEST_RETRIES = 5 | ||
module.exports = { | ||
@@ -174,4 +171,3 @@ TEST_CODE_OWNERS, | ||
TEST_BROWSER_NAME, | ||
TEST_BROWSER_VERSION, | ||
NUM_FAILED_TEST_RETRIES | ||
TEST_BROWSER_VERSION | ||
} | ||
@@ -178,0 +174,0 @@ |
@@ -11,4 +11,4 @@ 'use strict' | ||
start: config => { | ||
const { service, version, env, url, hostname, port, tags, repositoryUrl, commitSHA } = config | ||
const { enabled, sourceMap, exporters, heuristicsEnabled } = config.profiling | ||
const { service, version, env, url, hostname, port, tags, repositoryUrl, commitSHA, injectionEnabled } = config | ||
const { enabled, sourceMap, exporters } = config.profiling | ||
const logger = { | ||
@@ -21,5 +21,13 @@ debug: (message) => log.debug(message), | ||
const libraryInjected = injectionEnabled.length > 0 | ||
let activation | ||
if (enabled === 'auto') { | ||
activation = 'auto' | ||
} else if (enabled === 'true') { | ||
activation = 'manual' | ||
} else if (injectionEnabled.includes('profiler')) { | ||
activation = 'injection' | ||
} // else activation = undefined | ||
return profiler.start({ | ||
enabled, | ||
heuristicsEnabled, | ||
service, | ||
@@ -36,3 +44,5 @@ version, | ||
repositoryUrl, | ||
commitSHA | ||
commitSHA, | ||
libraryInjected, | ||
activation | ||
}) | ||
@@ -39,0 +49,0 @@ }, |
@@ -26,3 +26,2 @@ 'use strict' | ||
DD_PROFILING_DEBUG_SOURCE_MAPS, | ||
DD_PROFILING_ENABLED, | ||
DD_PROFILING_ENDPOINT_COLLECTION_ENABLED, | ||
@@ -53,3 +52,2 @@ DD_PROFILING_EXPERIMENTAL_CODEHOTSPOTS_ENABLED, | ||
const enabled = isTrue(coalesce(options.enabled, DD_PROFILING_ENABLED, true)) | ||
const env = coalesce(options.env, DD_ENV) | ||
@@ -69,4 +67,2 @@ const service = options.service || DD_SERVICE || 'node' | ||
this.enabled = enabled | ||
this.heuristicsEnabled = options.heuristicsEnabled | ||
this.service = service | ||
@@ -135,2 +131,4 @@ this.env = env | ||
this.libraryInjected = options.libraryInjected | ||
this.activation = options.activation | ||
this.exporters = ensureExporters(options.exporters || [ | ||
@@ -137,0 +135,0 @@ new AgentExporter(this) |
@@ -19,6 +19,18 @@ 'use strict' | ||
} else { | ||
const injectionEnabled = (process.env.DD_INJECTION_ENABLED || '').split(',') | ||
const libraryInjected = injectionEnabled.length > 0 | ||
const profilingEnabled = (process.env.DD_PROFILING_ENABLED || '').toLowerCase() | ||
const activation = ['true', '1'].includes(profilingEnabled) | ||
? 'manual' | ||
: profilingEnabled === 'auto' | ||
? 'auto' | ||
: injectionEnabled.includes('profiling') | ||
? 'injection' | ||
: 'unknown' | ||
return new AgentExporter({ | ||
url, | ||
logger, | ||
uploadTimeout: timeoutMs | ||
uploadTimeout: timeoutMs, | ||
libraryInjected, | ||
activation | ||
}) | ||
@@ -25,0 +37,0 @@ } |
@@ -56,3 +56,3 @@ 'use strict' | ||
class AgentExporter { | ||
constructor ({ url, logger, uploadTimeout, env, host, service, version } = {}) { | ||
constructor ({ url, logger, uploadTimeout, env, host, service, version, libraryInjected, activation } = {}) { | ||
this._url = url | ||
@@ -69,2 +69,4 @@ this._logger = logger | ||
this._appVersion = version | ||
this._libraryInjected = !!libraryInjected | ||
this._activation = activation || 'unknown' | ||
} | ||
@@ -110,2 +112,6 @@ | ||
profiler: { | ||
activation: this._activation, | ||
ssi: { | ||
mechanism: this._libraryInjected ? 'injected_agent' : 'none' | ||
}, | ||
version | ||
@@ -112,0 +118,0 @@ }, |
@@ -8,3 +8,2 @@ 'use strict' | ||
const dc = require('dc-polyfill') | ||
const telemetryLog = dc.channel('datadog:telemetry:log') | ||
@@ -24,9 +23,2 @@ const profileSubmittedChannel = dc.channel('datadog:profiling:profile-submitted') | ||
} | ||
if (telemetryLog.hasSubscribers) { | ||
telemetryLog.publish({ | ||
message: err.message, | ||
level: 'ERROR', | ||
stack_trace: err.stack | ||
}) | ||
} | ||
} | ||
@@ -60,3 +52,2 @@ | ||
const config = this._config = new Config(options) | ||
if (!config.enabled && !config.heuristicsEnabled) return false | ||
@@ -63,0 +54,0 @@ this._logger = config.logger |
@@ -10,36 +10,2 @@ 'use strict' | ||
const EnablementChoice = { | ||
MANUALLY_ENABLED: Symbol('SSITelemetry.EnablementChoice.MANUALLY_ENABLED'), | ||
SSI_ENABLED: Symbol('SSITelemetry.EnablementChoice.SSI_ENABLED'), | ||
SSI_NOT_ENABLED: Symbol('SSITelemetry.EnablementChoice.SSI_NOT_ENABLED'), | ||
DISABLED: Symbol('SSITelemetry.EnablementChoice.DISABLED') | ||
} | ||
Object.freeze(EnablementChoice) | ||
function getEnablementChoiceFromConfig (config) { | ||
if (config.ssi === false || config.enabled === false) { | ||
return EnablementChoice.DISABLED | ||
} else if (config.heuristicsEnabled === true) { | ||
return EnablementChoice.SSI_ENABLED | ||
} else if (config.enabled === true) { | ||
return EnablementChoice.MANUALLY_ENABLED | ||
} else { | ||
return EnablementChoice.SSI_NOT_ENABLED | ||
} | ||
} | ||
function enablementChoiceToTagValue (enablementChoice) { | ||
switch (enablementChoice) { | ||
case EnablementChoice.MANUALLY_ENABLED: | ||
return 'manually_enabled' | ||
case EnablementChoice.SSI_ENABLED: | ||
return 'ssi_enabled' | ||
case EnablementChoice.SSI_NOT_ENABLED: | ||
return 'not_enabled' | ||
case EnablementChoice.DISABLED: | ||
// Can't emit this one as a tag | ||
throw new Error('Invalid enablement choice') | ||
} | ||
} | ||
/** | ||
@@ -60,5 +26,19 @@ * This class embodies the SSI profiler-triggering heuristics and also emits telemetry metrics about | ||
constructor (config) { | ||
this.enablementChoice = getEnablementChoiceFromConfig(config) | ||
const injectionIncludesProfiler = config.injectionEnabled.includes('profiler') | ||
this._heuristicsActive = injectionIncludesProfiler || config.profiling.enabled === 'auto' | ||
this._emitsTelemetry = config.injectionEnabled.length > 0 && config.profiling.enabled !== 'false' | ||
const longLivedThreshold = config.longLivedThreshold || DEFAULT_LONG_LIVED_THRESHOLD | ||
if (this._emitsTelemetry) { | ||
if (config.profiling.enabled === 'true') { | ||
this.enablementChoice = 'manually_enabled' | ||
} else if (injectionIncludesProfiler) { | ||
this.enablementChoice = 'ssi_enabled' | ||
} else if (config.profiling.enabled === 'auto') { | ||
this.enablementChoice = 'auto_enabled' | ||
} else { | ||
this.enablementChoice = 'ssi_not_enabled' | ||
} | ||
} | ||
const longLivedThreshold = config.profiling.longLivedThreshold || DEFAULT_LONG_LIVED_THRESHOLD | ||
if (typeof longLivedThreshold !== 'number' || longLivedThreshold <= 0) { | ||
@@ -74,8 +54,12 @@ throw new Error('Long-lived threshold must be a positive number') | ||
enabled () { | ||
return this.enablementChoice !== EnablementChoice.DISABLED | ||
get emitsTelemetry () { | ||
return this._emitsTelemetry | ||
} | ||
get heuristicsActive () { | ||
return this._heuristicsActive | ||
} | ||
start () { | ||
if (this.enabled()) { | ||
if (this.heuristicsActive || this.emitsTelemetry) { | ||
// Used to determine short-livedness of the process. We could use the process start time as the | ||
@@ -91,9 +75,13 @@ // reference point, but the tracer initialization point is more relevant, as we couldn't be | ||
this._onSpanCreated = this._onSpanCreated.bind(this) | ||
this._onProfileSubmitted = this._onProfileSubmitted.bind(this) | ||
this._onMockProfileSubmitted = this._onMockProfileSubmitted.bind(this) | ||
dc.subscribe('dd-trace:span:start', this._onSpanCreated) | ||
if (this.emitsTelemetry) { | ||
this._onProfileSubmitted = this._onProfileSubmitted.bind(this) | ||
this._onMockProfileSubmitted = this._onMockProfileSubmitted.bind(this) | ||
dc.subscribe('datadog:profiling:profile-submitted', this._onProfileSubmitted) | ||
dc.subscribe('datadog:profiling:mock-profile-submitted', this._onMockProfileSubmitted) | ||
} | ||
this._onAppClosing = this._onAppClosing.bind(this) | ||
dc.subscribe('dd-trace:span:start', this._onSpanCreated) | ||
dc.subscribe('datadog:profiling:profile-submitted', this._onProfileSubmitted) | ||
dc.subscribe('datadog:profiling:mock-profile-submitted', this._onMockProfileSubmitted) | ||
dc.subscribe('datadog:telemetry:app-closing', this._onAppClosing) | ||
@@ -159,3 +147,3 @@ } | ||
'installation:ssi', | ||
`enablement_choice:${enablementChoiceToTagValue(this.enablementChoice)}`, | ||
`enablement_choice:${this.enablementChoice}`, | ||
`has_sent_profiles:${this.hasSentProfiles}`, | ||
@@ -171,5 +159,5 @@ `heuristic_hypothetical_decision:${decision.join('_')}` | ||
decision[0] === 'triggered' && | ||
// When enablement choice is SSI_ENABLED, hasSentProfiles can transition from false to true when the | ||
// When heuristics are active, hasSentProfiles can transition from false to true when the | ||
// profiler gets started and the first profile is submitted, so we have to wait for it. | ||
(this.enablementChoice !== EnablementChoice.SSI_ENABLED || this.hasSentProfiles) | ||
(!this.heuristicsActive || this.hasSentProfiles) | ||
) { | ||
@@ -183,13 +171,16 @@ // Tags won't change anymore, so we can emit the runtime ID metric now. | ||
_onAppClosing () { | ||
this._ensureProfileMetrics() | ||
// Last ditch effort to emit a runtime ID count metric | ||
if (!this._emittedRuntimeId) { | ||
this._emittedRuntimeId = true | ||
this._runtimeIdCount.inc() | ||
if (this.emitsTelemetry) { | ||
this._ensureProfileMetrics() | ||
// Last ditch effort to emit a runtime ID count metric | ||
if (!this._emittedRuntimeId) { | ||
this._emittedRuntimeId = true | ||
this._runtimeIdCount.inc() | ||
} | ||
// So we have the metrics in the final state | ||
this._profileCount.inc(0) | ||
dc.unsubscribe('datadog:profiling:profile-submitted', this._onProfileSubmitted) | ||
dc.unsubscribe('datadog:profiling:mock-profile-submitted', this._onMockProfileSubmitted) | ||
} | ||
// So we have the metrics in the final state | ||
this._profileCount.inc(0) | ||
dc.unsubscribe('datadog:profiling:profile-submitted', this._onProfileSubmitted) | ||
dc.unsubscribe('datadog:profiling:mock-profile-submitted', this._onMockProfileSubmitted) | ||
dc.unsubscribe('datadog:telemetry:app-closing', this._onAppClosing) | ||
@@ -202,2 +193,2 @@ if (this.noSpan) { | ||
module.exports = { SSIHeuristics, EnablementChoice } | ||
module.exports = { SSIHeuristics } |
@@ -17,3 +17,2 @@ 'use strict' | ||
const { SSIHeuristics } = require('./profiling/ssi-heuristics') | ||
const telemetryLog = require('dc-polyfill').channel('datadog:telemetry:log') | ||
const appsecStandalone = require('./appsec/standalone') | ||
@@ -121,21 +120,29 @@ | ||
const ssiHeuristics = new SSIHeuristics(config.profiling) | ||
ssiHeuristics.start() | ||
if (config.profiling.enabled) { | ||
this._profilerStarted = this._startProfiler(config) | ||
} else if (config.profiling.ssi) { | ||
const mockProfiler = require('./profiling/ssi-telemetry-mock-profiler') | ||
mockProfiler.start(config) | ||
if (config.profiling.enabled !== 'false') { | ||
const ssiHeuristics = new SSIHeuristics(config) | ||
ssiHeuristics.start() | ||
let mockProfiler = null | ||
if (config.profiling.enabled === 'true') { | ||
this._profilerStarted = this._startProfiler(config) | ||
} else if (ssiHeuristics.emitsTelemetry) { | ||
// Start a mock profiler that emits mock profile-submitted events for the telemetry. | ||
// It will be stopped if the real profiler is started by the heuristics. | ||
mockProfiler = require('./profiling/ssi-telemetry-mock-profiler') | ||
mockProfiler.start(config) | ||
} | ||
if (config.profiling.heuristicsEnabled) { | ||
if (ssiHeuristics.heuristicsActive) { | ||
ssiHeuristics.onTriggered(() => { | ||
mockProfiler.stop() | ||
if (mockProfiler) { | ||
mockProfiler.stop() | ||
} | ||
this._startProfiler(config) | ||
ssiHeuristics.onTriggered() | ||
ssiHeuristics.onTriggered() // deregister this callback | ||
}) | ||
} | ||
if (!this._profilerStarted) { | ||
this._profilerStarted = Promise.resolve(false) | ||
} | ||
} | ||
if (!this._profilerStarted) { | ||
this._profilerStarted = Promise.resolve(false) | ||
} | ||
@@ -168,9 +175,2 @@ if (config.runtimeMetrics) { | ||
log.error(e) | ||
if (telemetryLog.hasSubscribers) { | ||
telemetryLog.publish({ | ||
message: e.message, | ||
level: 'ERROR', | ||
stack_trace: e.stack | ||
}) | ||
} | ||
} | ||
@@ -177,0 +177,0 @@ } |
@@ -92,3 +92,3 @@ 'use strict' | ||
version: tracerVersion, | ||
enabled: config.profiling.enabled | ||
enabled: profilingEnabledToBoolean(config.profiling.enabled) | ||
} | ||
@@ -333,9 +333,13 @@ } | ||
if (namesNeedFormatting.has(entry.name)) entry.value = formatMapForTelemetry(entry.value) | ||
if (entry.name === 'url' && entry.value) entry.value = entry.value.toString() | ||
if (entry.name === 'DD_TRACE_SAMPLING_RULES') { | ||
if (namesNeedFormatting.has(entry.name)) { | ||
entry.value = formatMapForTelemetry(entry.value) | ||
} else if (entry.name === 'url') { | ||
if (entry.value) { | ||
entry.value = entry.value.toString() | ||
} | ||
} else if (entry.name === 'DD_TRACE_SAMPLING_RULES') { | ||
entry.value = JSON.stringify(entry.value) | ||
} else if (Array.isArray(entry.value)) { | ||
entry.value = value.join(',') | ||
} | ||
if (Array.isArray(entry.value)) entry.value = value.join(',') | ||
configuration.push(entry) | ||
@@ -359,2 +363,15 @@ } | ||
function profilingEnabledToBoolean (profilingEnabled) { | ||
if (typeof profilingEnabled === 'boolean') { | ||
return profilingEnabled | ||
} | ||
if (['auto', 'true'].includes(profilingEnabled)) { | ||
return true | ||
} | ||
if (profilingEnabled === 'false') { | ||
return false | ||
} | ||
return undefined | ||
} | ||
module.exports = { | ||
@@ -361,0 +378,0 @@ start, |
@@ -8,2 +8,3 @@ 'use strict' | ||
const telemetryLog = dc.channel('datadog:telemetry:log') | ||
const errorLog = dc.channel('datadog:log:error') | ||
@@ -37,2 +38,17 @@ let enabled = false | ||
function onErrorLog (msg) { | ||
if (msg instanceof Error) { | ||
onLog({ | ||
level: 'ERROR', | ||
message: msg.message, | ||
stack_trace: msg.stack | ||
}) | ||
} else if (typeof msg === 'string') { | ||
onLog({ | ||
level: 'ERROR', | ||
message: msg | ||
}) | ||
} | ||
} | ||
function start (config) { | ||
@@ -44,2 +60,4 @@ if (!config.telemetry.logCollection || enabled) return | ||
telemetryLog.subscribe(onLog) | ||
errorLog.subscribe(onErrorLog) | ||
} | ||
@@ -53,2 +71,4 @@ | ||
} | ||
errorLog.unsubscribe(onErrorLog) | ||
} | ||
@@ -55,0 +75,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
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 3 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1922266
55316
179
+ Added@datadog/native-appsec@8.1.1(transitive)
+ Added@types/node@22.5.4(transitive)
+ Addedpath-to-regexp@0.1.10(transitive)
- Removed@datadog/native-appsec@8.0.1(transitive)
- Removed@types/node@22.5.5(transitive)
- Removedpath-to-regexp@0.1.11(transitive)
Updated@datadog/native-appsec@8.1.1