dd-trace 4.18.0 → 4.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-3rdparty.csv +3 -2
- package/README.md +3 -3
- package/ext/kinds.d.ts +1 -0
- package/ext/kinds.js +2 -1
- package/ext/tags.d.ts +2 -1
- package/ext/tags.js +6 -1
- package/index.d.ts +29 -0
- package/package.json +12 -11
- package/packages/datadog-core/src/storage/async_resource.js +1 -1
- package/packages/datadog-esbuild/index.js +1 -20
- package/packages/datadog-instrumentations/src/aerospike.js +47 -0
- package/packages/datadog-instrumentations/src/apollo-server-core.js +41 -0
- package/packages/datadog-instrumentations/src/apollo-server.js +83 -0
- package/packages/datadog-instrumentations/src/child-process.js +4 -5
- package/packages/datadog-instrumentations/src/couchbase.js +5 -4
- package/packages/datadog-instrumentations/src/crypto.js +2 -1
- package/packages/datadog-instrumentations/src/dns.js +2 -1
- package/packages/datadog-instrumentations/src/graphql.js +18 -4
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +1 -2
- package/packages/datadog-instrumentations/src/helpers/hooks.js +10 -2
- package/packages/datadog-instrumentations/src/helpers/instrument.js +9 -4
- package/packages/datadog-instrumentations/src/helpers/register.js +19 -3
- package/packages/datadog-instrumentations/src/http/client.js +12 -2
- package/packages/datadog-instrumentations/src/http/server.js +7 -4
- package/packages/datadog-instrumentations/src/http2/client.js +3 -1
- package/packages/datadog-instrumentations/src/http2/server.js +3 -1
- package/packages/datadog-instrumentations/src/jest.js +12 -6
- package/packages/datadog-instrumentations/src/kafkajs.js +27 -0
- package/packages/datadog-instrumentations/src/net.js +10 -2
- package/packages/datadog-instrumentations/src/next.js +18 -6
- package/packages/datadog-instrumentations/src/restify.js +14 -1
- package/packages/datadog-instrumentations/src/rhea.js +15 -9
- package/packages/datadog-plugin-aerospike/src/index.js +113 -0
- package/packages/datadog-plugin-cucumber/src/index.js +34 -2
- package/packages/datadog-plugin-cypress/src/plugin.js +60 -8
- package/packages/datadog-plugin-graphql/src/resolve.js +26 -18
- package/packages/datadog-plugin-http/src/client.js +19 -2
- package/packages/datadog-plugin-jest/src/index.js +38 -4
- package/packages/datadog-plugin-kafkajs/src/consumer.js +59 -6
- package/packages/datadog-plugin-kafkajs/src/producer.js +64 -6
- package/packages/datadog-plugin-mocha/src/index.js +32 -1
- package/packages/datadog-plugin-next/src/index.js +40 -14
- package/packages/datadog-plugin-playwright/src/index.js +17 -1
- package/packages/dd-trace/src/appsec/activation.js +29 -0
- package/packages/dd-trace/src/appsec/addresses.js +3 -1
- package/packages/dd-trace/src/appsec/api_security_sampler.js +48 -0
- package/packages/dd-trace/src/appsec/blocked_templates.js +4 -1
- package/packages/dd-trace/src/appsec/blocking.js +95 -43
- package/packages/dd-trace/src/appsec/channels.js +5 -2
- package/packages/dd-trace/src/appsec/graphql.js +146 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +105 -0
- package/packages/dd-trace/src/appsec/iast/iast-log.js +1 -1
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
- package/packages/dd-trace/src/appsec/iast/index.js +1 -1
- package/packages/dd-trace/src/appsec/iast/path-line.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/constants.js +7 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +12 -19
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/header-sensitive-analyzer.js +20 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/json-sensitive-analyzer.js +6 -10
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +18 -25
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +79 -85
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +27 -36
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +14 -11
- package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
- package/packages/dd-trace/src/appsec/index.js +33 -32
- package/packages/dd-trace/src/appsec/recommended.json +1737 -120
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +6 -1
- package/packages/dd-trace/src/appsec/remote_config/index.js +40 -15
- package/packages/dd-trace/src/appsec/reporter.js +50 -34
- package/packages/dd-trace/src/appsec/rule_manager.js +9 -6
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +28 -13
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +0 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +30 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +30 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +17 -1
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +110 -59
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +40 -7
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +26 -1
- package/packages/dd-trace/src/ci-visibility/telemetry.js +130 -0
- package/packages/dd-trace/src/config.js +145 -63
- package/packages/dd-trace/src/datastreams/processor.js +166 -26
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +14 -1
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +14 -0
- package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +4 -0
- package/packages/dd-trace/src/exporters/common/form-data.js +4 -0
- package/packages/dd-trace/src/format.js +6 -1
- package/packages/dd-trace/src/id.js +12 -0
- package/packages/dd-trace/src/iitm.js +1 -1
- package/packages/dd-trace/src/log/channels.js +1 -1
- package/packages/dd-trace/src/noop/proxy.js +4 -0
- package/packages/dd-trace/src/opentelemetry/span.js +95 -2
- package/packages/dd-trace/src/opentelemetry/tracer.js +9 -10
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +14 -5
- package/packages/dd-trace/src/opentracing/span.js +6 -0
- package/packages/dd-trace/src/opentracing/span_context.js +5 -2
- package/packages/dd-trace/src/opentracing/tracer.js +2 -2
- package/packages/dd-trace/src/plugin_manager.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +46 -9
- package/packages/dd-trace/src/plugins/database.js +1 -1
- package/packages/dd-trace/src/plugins/index.js +6 -0
- package/packages/dd-trace/src/plugins/plugin.js +1 -1
- package/packages/dd-trace/src/plugins/util/ci.js +6 -19
- package/packages/dd-trace/src/plugins/util/exec.js +23 -2
- package/packages/dd-trace/src/plugins/util/git.js +98 -22
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +7 -6
- package/packages/dd-trace/src/plugins/util/test.js +3 -2
- package/packages/dd-trace/src/plugins/util/url.js +26 -0
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +4 -16
- package/packages/dd-trace/src/priority_sampler.js +30 -38
- package/packages/dd-trace/src/profiler.js +5 -3
- package/packages/dd-trace/src/profiling/config.js +26 -2
- package/packages/dd-trace/src/profiling/exporters/agent.js +1 -0
- package/packages/dd-trace/src/profiling/profiler.js +17 -10
- package/packages/dd-trace/src/profiling/profilers/events.js +264 -0
- package/packages/dd-trace/src/profiling/profilers/shared.js +39 -0
- package/packages/dd-trace/src/profiling/profilers/space.js +2 -1
- package/packages/dd-trace/src/profiling/profilers/wall.js +121 -58
- package/packages/dd-trace/src/proxy.js +25 -1
- package/packages/dd-trace/src/ritm.js +1 -1
- package/packages/dd-trace/src/sampling_rule.js +130 -0
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +5 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +4 -0
- package/packages/dd-trace/src/span_processor.js +4 -0
- package/packages/dd-trace/src/span_sampler.js +6 -64
- package/packages/dd-trace/src/spanleak.js +98 -0
- package/packages/dd-trace/src/startup-log.js +7 -1
- package/packages/dd-trace/src/telemetry/dependencies.js +56 -10
- package/packages/dd-trace/src/telemetry/index.js +171 -41
- package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
- package/packages/dd-trace/src/telemetry/send-data.js +47 -5
- package/packages/dd-trace/src/tracer.js +8 -2
- package/scripts/install_plugin_modules.js +11 -3
- package/packages/diagnostics_channel/index.js +0 -3
- package/packages/diagnostics_channel/src/index.js +0 -121
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { channel } = require('
|
|
3
|
+
const { channel } = require('dc-polyfill')
|
|
4
4
|
const path = require('path')
|
|
5
5
|
const semver = require('semver')
|
|
6
6
|
const Hook = require('./hook')
|
|
@@ -24,6 +24,7 @@ if (!disabledInstrumentations.has('fetch')) {
|
|
|
24
24
|
require('../fetch')
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
const HOOK_SYMBOL = Symbol('hookExportsMap')
|
|
27
28
|
// TODO: make this more efficient
|
|
28
29
|
|
|
29
30
|
for (const packageName of names) {
|
|
@@ -42,14 +43,29 @@ for (const packageName of names) {
|
|
|
42
43
|
for (const { name, file, versions, hook } of instrumentations[packageName]) {
|
|
43
44
|
const fullFilename = filename(name, file)
|
|
44
45
|
|
|
46
|
+
// Create a WeakMap associated with the hook function so that patches on the same moduleExport only happens once
|
|
47
|
+
// for example by instrumenting both dns and node:dns double the spans would be created
|
|
48
|
+
// since they both patch the same moduleExport, this WeakMap is used to mitigate that
|
|
49
|
+
if (!hook[HOOK_SYMBOL]) {
|
|
50
|
+
hook[HOOK_SYMBOL] = new WeakMap()
|
|
51
|
+
}
|
|
52
|
+
|
|
45
53
|
if (moduleName === fullFilename) {
|
|
46
54
|
const version = moduleVersion || getVersion(moduleBaseDir)
|
|
47
55
|
|
|
48
56
|
if (matchVersion(version, versions)) {
|
|
57
|
+
// Check if the hook already has a set moduleExport
|
|
58
|
+
if (hook[HOOK_SYMBOL].has(moduleExports)) {
|
|
59
|
+
return moduleExports
|
|
60
|
+
}
|
|
61
|
+
|
|
49
62
|
try {
|
|
50
63
|
loadChannel.publish({ name, version, file })
|
|
51
|
-
|
|
52
|
-
|
|
64
|
+
// Send the name and version of the module back to the callback because now addHook
|
|
65
|
+
// takes in an array of names so by passing the name the callback will know which module name is being used
|
|
66
|
+
moduleExports = hook(moduleExports, version, name)
|
|
67
|
+
// Set the moduleExports in the hooks weakmap
|
|
68
|
+
hook[HOOK_SYMBOL].set(moduleExports, name)
|
|
53
69
|
} catch (e) {
|
|
54
70
|
log.error(e)
|
|
55
71
|
}
|
|
@@ -14,9 +14,9 @@ const endChannel = channel('apm:http:client:request:end')
|
|
|
14
14
|
const asyncStartChannel = channel('apm:http:client:request:asyncStart')
|
|
15
15
|
const errorChannel = channel('apm:http:client:request:error')
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
const names = ['http', 'https', 'node:http', 'node:https']
|
|
18
18
|
|
|
19
|
-
addHook({ name:
|
|
19
|
+
addHook({ name: names }, hookFn)
|
|
20
20
|
|
|
21
21
|
function hookFn (http) {
|
|
22
22
|
patch(http, 'request')
|
|
@@ -58,6 +58,7 @@ function patch (http, methodName) {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
const options = args.options
|
|
61
|
+
|
|
61
62
|
const finish = () => {
|
|
62
63
|
if (!finished) {
|
|
63
64
|
finished = true
|
|
@@ -68,9 +69,17 @@ function patch (http, methodName) {
|
|
|
68
69
|
try {
|
|
69
70
|
const req = request.call(this, options, callback)
|
|
70
71
|
const emit = req.emit
|
|
72
|
+
const setTimeout = req.setTimeout
|
|
71
73
|
|
|
72
74
|
ctx.req = req
|
|
73
75
|
|
|
76
|
+
// tracked to accurately discern custom request socket timeout
|
|
77
|
+
let customRequestTimeout = false
|
|
78
|
+
req.setTimeout = function () {
|
|
79
|
+
customRequestTimeout = true
|
|
80
|
+
return setTimeout.apply(this, arguments)
|
|
81
|
+
}
|
|
82
|
+
|
|
74
83
|
req.emit = function (eventName, arg) {
|
|
75
84
|
switch (eventName) {
|
|
76
85
|
case 'response': {
|
|
@@ -88,6 +97,7 @@ function patch (http, methodName) {
|
|
|
88
97
|
case 'error':
|
|
89
98
|
case 'timeout':
|
|
90
99
|
ctx.error = arg
|
|
100
|
+
ctx.customRequestTimeout = customRequestTimeout
|
|
91
101
|
errorChannel.publish(ctx)
|
|
92
102
|
case 'abort': // deprecated and replaced by `close` in node 17
|
|
93
103
|
case 'close':
|
|
@@ -15,14 +15,17 @@ const finishSetHeaderCh = channel('datadog:http:server:response:set-header:finis
|
|
|
15
15
|
|
|
16
16
|
const requestFinishedSet = new WeakSet()
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
const httpNames = ['http', 'node:http']
|
|
19
|
+
const httpsNames = ['https', 'node:https']
|
|
20
|
+
|
|
21
|
+
addHook({ name: httpNames }, http => {
|
|
22
|
+
shimmer.wrap(http.ServerResponse.prototype, 'emit', wrapResponseEmit)
|
|
20
23
|
shimmer.wrap(http.Server.prototype, 'emit', wrapEmit)
|
|
21
24
|
return http
|
|
22
25
|
})
|
|
23
26
|
|
|
24
|
-
addHook({ name:
|
|
25
|
-
|
|
27
|
+
addHook({ name: httpsNames }, http => {
|
|
28
|
+
// http.ServerResponse not present on https
|
|
26
29
|
shimmer.wrap(http.Server.prototype, 'emit', wrapEmit)
|
|
27
30
|
return http
|
|
28
31
|
})
|
|
@@ -10,6 +10,8 @@ const asyncStartChannel = channel('apm:http2:client:request:asyncStart')
|
|
|
10
10
|
const asyncEndChannel = channel('apm:http2:client:request:asyncEnd')
|
|
11
11
|
const errorChannel = channel('apm:http2:client:request:error')
|
|
12
12
|
|
|
13
|
+
const names = ['http2', 'node:http2']
|
|
14
|
+
|
|
13
15
|
function createWrapEmit (ctx) {
|
|
14
16
|
return function wrapEmit (emit) {
|
|
15
17
|
return function (event, arg1) {
|
|
@@ -66,7 +68,7 @@ function wrapConnect (connect) {
|
|
|
66
68
|
}
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
addHook({ name:
|
|
71
|
+
addHook({ name: names }, http2 => {
|
|
70
72
|
shimmer.wrap(http2, 'connect', wrapConnect)
|
|
71
73
|
|
|
72
74
|
return http2
|
|
@@ -14,7 +14,9 @@ const startServerCh = channel('apm:http2:server:request:start')
|
|
|
14
14
|
const errorServerCh = channel('apm:http2:server:request:error')
|
|
15
15
|
const finishServerCh = channel('apm:http2:server:request:finish')
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
const names = ['http2', 'node:http2']
|
|
18
|
+
|
|
19
|
+
addHook({ name: names }, http2 => {
|
|
18
20
|
shimmer.wrap(http2, 'createSecureServer', wrapCreateServer)
|
|
19
21
|
shimmer.wrap(http2, 'createServer', wrapCreateServer)
|
|
20
22
|
return http2
|
|
@@ -44,6 +44,7 @@ const itrSkippedSuitesCh = channel('ci:jest:itr:skipped-suites')
|
|
|
44
44
|
let skippableSuites = []
|
|
45
45
|
let isCodeCoverageEnabled = false
|
|
46
46
|
let isSuitesSkippingEnabled = false
|
|
47
|
+
let isUserCodeCoverageEnabled = false
|
|
47
48
|
let isSuitesSkipped = false
|
|
48
49
|
let numSkippedSuites = 0
|
|
49
50
|
let hasUnskippableSuites = false
|
|
@@ -289,11 +290,14 @@ function cliWrapper (cli, jestVersion) {
|
|
|
289
290
|
} = result
|
|
290
291
|
|
|
291
292
|
let testCodeCoverageLinesTotal
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
293
|
+
|
|
294
|
+
if (isUserCodeCoverageEnabled) {
|
|
295
|
+
try {
|
|
296
|
+
const { pct, total } = coverageMap.getCoverageSummary().lines
|
|
297
|
+
testCodeCoverageLinesTotal = total !== 0 ? pct : 0
|
|
298
|
+
} catch (e) {
|
|
299
|
+
// ignore errors
|
|
300
|
+
}
|
|
297
301
|
}
|
|
298
302
|
let status, error
|
|
299
303
|
|
|
@@ -399,7 +403,7 @@ function jestAdapterWrapper (jestAdapter, jestVersion) {
|
|
|
399
403
|
const coverageFiles = getCoveredFilenamesFromCoverage(environment.global.__coverage__)
|
|
400
404
|
.map(filename => getTestSuitePath(filename, environment.rootDir))
|
|
401
405
|
asyncResource.runInAsyncScope(() => {
|
|
402
|
-
testSuiteCodeCoverageCh.publish(
|
|
406
|
+
testSuiteCodeCoverageCh.publish({ coverageFiles, testSuite: environment.testSuite })
|
|
403
407
|
})
|
|
404
408
|
}
|
|
405
409
|
testSuiteFinishCh.publish({ status, errorMessage })
|
|
@@ -436,6 +440,8 @@ function configureTestEnvironment (readConfigsResult) {
|
|
|
436
440
|
config.testEnvironmentOptions._ddTestCodeCoverageEnabled = isCodeCoverageEnabled
|
|
437
441
|
})
|
|
438
442
|
|
|
443
|
+
isUserCodeCoverageEnabled = !!readConfigsResult.globalConfig.collectCoverage
|
|
444
|
+
|
|
439
445
|
if (isCodeCoverageEnabled) {
|
|
440
446
|
const globalConfig = {
|
|
441
447
|
...readConfigsResult.globalConfig,
|
|
@@ -8,13 +8,31 @@ const {
|
|
|
8
8
|
const shimmer = require('../../datadog-shimmer')
|
|
9
9
|
|
|
10
10
|
const producerStartCh = channel('apm:kafkajs:produce:start')
|
|
11
|
+
const producerCommitCh = channel('apm:kafkajs:produce:commit')
|
|
11
12
|
const producerFinishCh = channel('apm:kafkajs:produce:finish')
|
|
12
13
|
const producerErrorCh = channel('apm:kafkajs:produce:error')
|
|
13
14
|
|
|
14
15
|
const consumerStartCh = channel('apm:kafkajs:consume:start')
|
|
16
|
+
const consumerCommitCh = channel('apm:kafkajs:consume:commit')
|
|
15
17
|
const consumerFinishCh = channel('apm:kafkajs:consume:finish')
|
|
16
18
|
const consumerErrorCh = channel('apm:kafkajs:consume:error')
|
|
17
19
|
|
|
20
|
+
function commitsFromEvent (event) {
|
|
21
|
+
const { payload: { groupId, topics } } = event
|
|
22
|
+
const commitList = []
|
|
23
|
+
for (const { topic, partitions } of topics) {
|
|
24
|
+
for (const { partition, offset } of partitions) {
|
|
25
|
+
commitList.push({
|
|
26
|
+
groupId,
|
|
27
|
+
partition,
|
|
28
|
+
offset,
|
|
29
|
+
topic
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
consumerCommitCh.publish(commitList)
|
|
34
|
+
}
|
|
35
|
+
|
|
18
36
|
addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKafka) => {
|
|
19
37
|
class Kafka extends BaseKafka {
|
|
20
38
|
constructor (options) {
|
|
@@ -58,6 +76,12 @@ addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKaf
|
|
|
58
76
|
})
|
|
59
77
|
)
|
|
60
78
|
|
|
79
|
+
result.then(res => {
|
|
80
|
+
if (producerCommitCh.hasSubscribers) {
|
|
81
|
+
producerCommitCh.publish(res)
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
|
|
61
85
|
return result
|
|
62
86
|
} catch (e) {
|
|
63
87
|
producerErrorCh.publish(e)
|
|
@@ -75,6 +99,9 @@ addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKaf
|
|
|
75
99
|
}
|
|
76
100
|
|
|
77
101
|
const consumer = createConsumer.apply(this, arguments)
|
|
102
|
+
|
|
103
|
+
consumer.on(consumer.events.COMMIT_OFFSETS, commitsFromEvent)
|
|
104
|
+
|
|
78
105
|
const run = consumer.run
|
|
79
106
|
|
|
80
107
|
const groupId = arguments[0].groupId
|
|
@@ -17,8 +17,16 @@ const errorTCPCh = channel('apm:net:tcp:error')
|
|
|
17
17
|
|
|
18
18
|
const connectionCh = channel(`apm:net:tcp:connection`)
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
const names = ['net', 'node:net']
|
|
21
|
+
|
|
22
|
+
addHook({ name: names }, (net, version, name) => {
|
|
23
|
+
// explicitly require dns so that net gets an instrumented instance
|
|
24
|
+
// so that we don't miss the dns calls
|
|
25
|
+
if (name === 'net') {
|
|
26
|
+
require('dns')
|
|
27
|
+
} else {
|
|
28
|
+
require('node:dns')
|
|
29
|
+
}
|
|
22
30
|
|
|
23
31
|
shimmer.wrap(net.Socket.prototype, 'connect', connect => function () {
|
|
24
32
|
if (!startICPCh.hasSubscribers || !startTCPCh.hasSubscribers) {
|
|
@@ -65,7 +65,7 @@ function wrapRenderToHTML (renderToHTML) {
|
|
|
65
65
|
|
|
66
66
|
function wrapRenderErrorToHTML (renderErrorToHTML) {
|
|
67
67
|
return function (err, req, res, pathname, query) {
|
|
68
|
-
return instrument(req, res, () => renderErrorToHTML.apply(this, arguments))
|
|
68
|
+
return instrument(req, res, err, () => renderErrorToHTML.apply(this, arguments))
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
@@ -76,8 +76,8 @@ function wrapRenderToResponse (renderToResponse) {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
function wrapRenderErrorToResponse (renderErrorToResponse) {
|
|
79
|
-
return function (ctx) {
|
|
80
|
-
return instrument(ctx.req, ctx.res, () => renderErrorToResponse.apply(this, arguments))
|
|
79
|
+
return function (ctx, err) {
|
|
80
|
+
return instrument(ctx.req, ctx.res, err, () => renderErrorToResponse.apply(this, arguments))
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
|
|
@@ -111,13 +111,23 @@ function getPageFromPath (page, dynamicRoutes = []) {
|
|
|
111
111
|
return getPagePath(page)
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
function instrument (req, res, handler) {
|
|
114
|
+
function instrument (req, res, error, handler) {
|
|
115
|
+
if (typeof error === 'function') {
|
|
116
|
+
handler = error
|
|
117
|
+
error = null
|
|
118
|
+
}
|
|
119
|
+
|
|
115
120
|
req = req.originalRequest || req
|
|
116
121
|
res = res.originalResponse || res
|
|
117
122
|
|
|
118
123
|
// TODO support middleware properly in the future?
|
|
119
124
|
const isMiddleware = req.headers[MIDDLEWARE_HEADER]
|
|
120
|
-
if (isMiddleware || requests.has(req))
|
|
125
|
+
if (isMiddleware || requests.has(req)) {
|
|
126
|
+
if (error) {
|
|
127
|
+
errorChannel.publish({ error })
|
|
128
|
+
}
|
|
129
|
+
return handler()
|
|
130
|
+
}
|
|
121
131
|
|
|
122
132
|
requests.add(req)
|
|
123
133
|
|
|
@@ -144,7 +154,9 @@ function instrument (req, res, handler) {
|
|
|
144
154
|
function wrapServeStatic (serveStatic) {
|
|
145
155
|
return function (req, res, path) {
|
|
146
156
|
return instrument(req, res, () => {
|
|
147
|
-
if (pageLoadChannel.hasSubscribers && path)
|
|
157
|
+
if (pageLoadChannel.hasSubscribers && path) {
|
|
158
|
+
pageLoadChannel.publish({ page: path, isStatic: true })
|
|
159
|
+
}
|
|
148
160
|
|
|
149
161
|
return serveStatic.apply(this, arguments)
|
|
150
162
|
})
|
|
@@ -50,7 +50,20 @@ function wrapFn (fn) {
|
|
|
50
50
|
enterChannel.publish({ req, route })
|
|
51
51
|
|
|
52
52
|
try {
|
|
53
|
-
|
|
53
|
+
const result = fn.apply(this, arguments)
|
|
54
|
+
if (result && typeof result === 'object' && typeof result.then === 'function') {
|
|
55
|
+
return result.then(function () {
|
|
56
|
+
nextChannel.publish({ req })
|
|
57
|
+
finishChannel.publish({ req })
|
|
58
|
+
return arguments[0]
|
|
59
|
+
}).catch(function (error) {
|
|
60
|
+
errorChannel.publish({ req, error })
|
|
61
|
+
nextChannel.publish({ req })
|
|
62
|
+
finishChannel.publish({ req })
|
|
63
|
+
throw error
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
return result
|
|
54
67
|
} catch (error) {
|
|
55
68
|
errorChannel.publish({ req, error })
|
|
56
69
|
nextChannel.publish({ req })
|
|
@@ -22,7 +22,7 @@ const dispatchReceiveCh = channel('apm:rhea:receive:dispatch')
|
|
|
22
22
|
const errorReceiveCh = channel('apm:rhea:receive:error')
|
|
23
23
|
const finishReceiveCh = channel('apm:rhea:receive:finish')
|
|
24
24
|
|
|
25
|
-
const contexts = new WeakMap()
|
|
25
|
+
const contexts = new WeakMap() // key: delivery Fn, val: context
|
|
26
26
|
|
|
27
27
|
addHook({ name: 'rhea', versions: ['>=1'] }, rhea => {
|
|
28
28
|
shimmer.wrap(rhea.message, 'encode', encode => function (msg) {
|
|
@@ -52,7 +52,8 @@ addHook({ name: 'rhea', versions: ['>=1'], file: 'lib/link.js' }, obj => {
|
|
|
52
52
|
startSendCh.publish({ targetAddress, host, port, msg })
|
|
53
53
|
const delivery = send.apply(this, arguments)
|
|
54
54
|
const context = {
|
|
55
|
-
asyncResource
|
|
55
|
+
asyncResource,
|
|
56
|
+
connection: this.connection
|
|
56
57
|
}
|
|
57
58
|
contexts.set(delivery, context)
|
|
58
59
|
|
|
@@ -80,7 +81,8 @@ addHook({ name: 'rhea', versions: ['>=1'], file: 'lib/link.js' }, obj => {
|
|
|
80
81
|
|
|
81
82
|
if (msgObj.delivery) {
|
|
82
83
|
const context = {
|
|
83
|
-
asyncResource
|
|
84
|
+
asyncResource,
|
|
85
|
+
connection: this.connection
|
|
84
86
|
}
|
|
85
87
|
contexts.set(msgObj.delivery, context)
|
|
86
88
|
msgObj.delivery.update = wrapDeliveryUpdate(msgObj.delivery, msgObj.delivery.update)
|
|
@@ -114,7 +116,7 @@ addHook({ name: 'rhea', versions: ['>=1'], file: 'lib/connection.js' }, Connecti
|
|
|
114
116
|
|
|
115
117
|
asyncResource.runInAsyncScope(() => {
|
|
116
118
|
errorReceiveCh.publish(error)
|
|
117
|
-
beforeFinish(delivery, null)
|
|
119
|
+
exports.beforeFinish(delivery, null)
|
|
118
120
|
finishReceiveCh.publish()
|
|
119
121
|
})
|
|
120
122
|
})
|
|
@@ -187,7 +189,7 @@ function patchCircularBuffer (proto, Session) {
|
|
|
187
189
|
const state = remoteState && remoteState.constructor
|
|
188
190
|
? entry.remote_state.constructor.composite_type : undefined
|
|
189
191
|
asyncResource.runInAsyncScope(() => {
|
|
190
|
-
beforeFinish(entry, state)
|
|
192
|
+
exports.beforeFinish(entry, state)
|
|
191
193
|
finishSendCh.publish()
|
|
192
194
|
})
|
|
193
195
|
}
|
|
@@ -217,13 +219,13 @@ function addToInFlightDeliveries (connection, delivery) {
|
|
|
217
219
|
}
|
|
218
220
|
|
|
219
221
|
function beforeFinish (delivery, state) {
|
|
220
|
-
const
|
|
221
|
-
if (
|
|
222
|
+
const context = contexts.get(delivery)
|
|
223
|
+
if (context) {
|
|
222
224
|
if (state) {
|
|
223
225
|
dispatchReceiveCh.publish({ state })
|
|
224
226
|
}
|
|
225
|
-
if (
|
|
226
|
-
|
|
227
|
+
if (context.connection && context.connection[inFlightDeliveries]) {
|
|
228
|
+
context.connection[inFlightDeliveries].delete(delivery)
|
|
227
229
|
}
|
|
228
230
|
}
|
|
229
231
|
}
|
|
@@ -238,3 +240,7 @@ function getStateFromData (stateData) {
|
|
|
238
240
|
}
|
|
239
241
|
}
|
|
240
242
|
}
|
|
243
|
+
|
|
244
|
+
module.exports.inFlightDeliveries = inFlightDeliveries
|
|
245
|
+
module.exports.beforeFinish = beforeFinish
|
|
246
|
+
module.exports.contexts = contexts
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { storage } = require('../../datadog-core')
|
|
4
|
+
const DatabasePlugin = require('../../dd-trace/src/plugins/database')
|
|
5
|
+
|
|
6
|
+
const AEROSPIKE_PEER_SERVICE = 'aerospike.namespace'
|
|
7
|
+
|
|
8
|
+
class AerospikePlugin extends DatabasePlugin {
|
|
9
|
+
static get id () { return 'aerospike' }
|
|
10
|
+
static get operation () { return 'command' }
|
|
11
|
+
static get system () { return 'aerospike' }
|
|
12
|
+
static get prefix () {
|
|
13
|
+
return 'tracing:apm:aerospike:command'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static get peerServicePrecursors () {
|
|
17
|
+
return [AEROSPIKE_PEER_SERVICE]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
bindStart (ctx) {
|
|
21
|
+
const { commandName, commandArgs } = ctx
|
|
22
|
+
const resourceName = commandName.slice(0, commandName.indexOf('Command'))
|
|
23
|
+
const store = storage.getStore()
|
|
24
|
+
const childOf = store ? store.span : null
|
|
25
|
+
const meta = getMeta(resourceName, commandArgs)
|
|
26
|
+
|
|
27
|
+
const span = this.startSpan(this.operationName(), {
|
|
28
|
+
childOf,
|
|
29
|
+
service: this.serviceName({ pluginConfig: this.config }),
|
|
30
|
+
type: 'aerospike',
|
|
31
|
+
kind: 'client',
|
|
32
|
+
resource: resourceName,
|
|
33
|
+
meta
|
|
34
|
+
}, false)
|
|
35
|
+
|
|
36
|
+
ctx.parentStore = store
|
|
37
|
+
ctx.currentStore = { ...store, span }
|
|
38
|
+
|
|
39
|
+
return ctx.currentStore
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
bindAsyncStart (ctx) {
|
|
43
|
+
if (ctx.currentStore) {
|
|
44
|
+
// have to manually trigger peer service calculation when using tracing channel
|
|
45
|
+
this.tagPeerService(ctx.currentStore.span)
|
|
46
|
+
ctx.currentStore.span.finish()
|
|
47
|
+
}
|
|
48
|
+
return ctx.parentStore
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
end (ctx) {
|
|
52
|
+
if (ctx.result) {
|
|
53
|
+
// have to manually trigger peer service calculation when using tracing channel
|
|
54
|
+
this.tagPeerService(ctx.currentStore.span)
|
|
55
|
+
ctx.currentStore.span.finish()
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
error (ctx) {
|
|
60
|
+
if (ctx.error) {
|
|
61
|
+
const error = ctx.error
|
|
62
|
+
const span = ctx.currentStore.span
|
|
63
|
+
span.setTag('error', error)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function getMeta (resourceName, commandArgs) {
|
|
69
|
+
let meta = {}
|
|
70
|
+
if (resourceName.includes('Index')) {
|
|
71
|
+
const [ns, set, bin, index] = commandArgs
|
|
72
|
+
meta = getMetaForIndex(ns, set, bin, index)
|
|
73
|
+
} else if (resourceName === 'Query') {
|
|
74
|
+
const { ns, set } = commandArgs[2]
|
|
75
|
+
meta = getMetaForQuery({ ns, set })
|
|
76
|
+
} else if (isKeyObject(commandArgs[0])) {
|
|
77
|
+
const { ns, set, key } = commandArgs[0]
|
|
78
|
+
meta = getMetaForKey(ns, set, key)
|
|
79
|
+
}
|
|
80
|
+
return meta
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function getMetaForIndex (ns, set, bin, index) {
|
|
84
|
+
return {
|
|
85
|
+
[AEROSPIKE_PEER_SERVICE]: ns,
|
|
86
|
+
'aerospike.setname': set,
|
|
87
|
+
'aerospike.bin': bin,
|
|
88
|
+
'aerospike.index': index
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function getMetaForKey (ns, set, key) {
|
|
93
|
+
return {
|
|
94
|
+
'aerospike.key': `${ns}:${set}:${key}`,
|
|
95
|
+
[AEROSPIKE_PEER_SERVICE]: ns,
|
|
96
|
+
'aerospike.setname': set,
|
|
97
|
+
'aerospike.userkey': key
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function getMetaForQuery (queryObj) {
|
|
102
|
+
const { ns, set } = queryObj
|
|
103
|
+
return {
|
|
104
|
+
[AEROSPIKE_PEER_SERVICE]: ns,
|
|
105
|
+
'aerospike.setname': set
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function isKeyObject (obj) {
|
|
110
|
+
return obj && obj.ns !== undefined && obj.set !== undefined && obj.key !== undefined
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
module.exports = AerospikePlugin
|
|
@@ -12,10 +12,21 @@ const {
|
|
|
12
12
|
getTestSuiteCommonTags,
|
|
13
13
|
addIntelligentTestRunnerSpanTags,
|
|
14
14
|
TEST_ITR_UNSKIPPABLE,
|
|
15
|
-
TEST_ITR_FORCED_RUN
|
|
15
|
+
TEST_ITR_FORCED_RUN,
|
|
16
|
+
TEST_CODE_OWNERS
|
|
16
17
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
17
18
|
const { RESOURCE_NAME } = require('../../../ext/tags')
|
|
18
19
|
const { COMPONENT, ERROR_MESSAGE } = require('../../dd-trace/src/constants')
|
|
20
|
+
const {
|
|
21
|
+
TELEMETRY_EVENT_CREATED,
|
|
22
|
+
TELEMETRY_EVENT_FINISHED,
|
|
23
|
+
TELEMETRY_CODE_COVERAGE_STARTED,
|
|
24
|
+
TELEMETRY_CODE_COVERAGE_FINISHED,
|
|
25
|
+
TELEMETRY_ITR_FORCED_TO_RUN,
|
|
26
|
+
TELEMETRY_CODE_COVERAGE_EMPTY,
|
|
27
|
+
TELEMETRY_ITR_UNSKIPPABLE,
|
|
28
|
+
TELEMETRY_CODE_COVERAGE_NUM_FILES
|
|
29
|
+
} = require('../../dd-trace/src/ci-visibility/telemetry')
|
|
19
30
|
|
|
20
31
|
class CucumberPlugin extends CiPlugin {
|
|
21
32
|
static get id () {
|
|
@@ -54,7 +65,9 @@ class CucumberPlugin extends CiPlugin {
|
|
|
54
65
|
this.testSessionSpan.setTag(TEST_STATUS, status)
|
|
55
66
|
this.testModuleSpan.setTag(TEST_STATUS, status)
|
|
56
67
|
this.testModuleSpan.finish()
|
|
68
|
+
this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'module')
|
|
57
69
|
this.testSessionSpan.finish()
|
|
70
|
+
this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'session')
|
|
58
71
|
finishAllTraceSpans(this.testSessionSpan)
|
|
59
72
|
|
|
60
73
|
this.itrConfig = null
|
|
@@ -69,9 +82,11 @@ class CucumberPlugin extends CiPlugin {
|
|
|
69
82
|
'cucumber'
|
|
70
83
|
)
|
|
71
84
|
if (isUnskippable) {
|
|
85
|
+
this.telemetry.count(TELEMETRY_ITR_UNSKIPPABLE, { testLevel: 'suite' })
|
|
72
86
|
testSuiteMetadata[TEST_ITR_UNSKIPPABLE] = 'true'
|
|
73
87
|
}
|
|
74
88
|
if (isForcedToRun) {
|
|
89
|
+
this.telemetry.count(TELEMETRY_ITR_FORCED_TO_RUN, { testLevel: 'suite' })
|
|
75
90
|
testSuiteMetadata[TEST_ITR_FORCED_RUN] = 'true'
|
|
76
91
|
}
|
|
77
92
|
this.testSuiteSpan = this.tracer.startSpan('cucumber.test_suite', {
|
|
@@ -82,20 +97,31 @@ class CucumberPlugin extends CiPlugin {
|
|
|
82
97
|
...testSuiteMetadata
|
|
83
98
|
}
|
|
84
99
|
})
|
|
100
|
+
this.telemetry.ciVisEvent(TELEMETRY_EVENT_CREATED, 'suite')
|
|
101
|
+
if (this.itrConfig?.isCodeCoverageEnabled) {
|
|
102
|
+
this.telemetry.ciVisEvent(TELEMETRY_CODE_COVERAGE_STARTED, 'suite', { library: 'istanbul' })
|
|
103
|
+
}
|
|
85
104
|
})
|
|
86
105
|
|
|
87
106
|
this.addSub('ci:cucumber:test-suite:finish', status => {
|
|
88
107
|
this.testSuiteSpan.setTag(TEST_STATUS, status)
|
|
89
108
|
this.testSuiteSpan.finish()
|
|
109
|
+
this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'suite')
|
|
90
110
|
})
|
|
91
111
|
|
|
92
112
|
this.addSub('ci:cucumber:test-suite:code-coverage', ({ coverageFiles, suiteFile }) => {
|
|
93
|
-
if (!this.itrConfig
|
|
113
|
+
if (!this.itrConfig?.isCodeCoverageEnabled) {
|
|
94
114
|
return
|
|
95
115
|
}
|
|
116
|
+
if (!coverageFiles.length) {
|
|
117
|
+
this.telemetry.count(TELEMETRY_CODE_COVERAGE_EMPTY)
|
|
118
|
+
}
|
|
119
|
+
|
|
96
120
|
const relativeCoverageFiles = [...coverageFiles, suiteFile]
|
|
97
121
|
.map(filename => getTestSuitePath(filename, this.sourceRoot))
|
|
98
122
|
|
|
123
|
+
this.telemetry.distribution(TELEMETRY_CODE_COVERAGE_NUM_FILES, {}, relativeCoverageFiles.length)
|
|
124
|
+
|
|
99
125
|
const formattedCoverage = {
|
|
100
126
|
sessionId: this.testSuiteSpan.context()._traceId,
|
|
101
127
|
suiteId: this.testSuiteSpan.context()._spanId,
|
|
@@ -103,6 +129,7 @@ class CucumberPlugin extends CiPlugin {
|
|
|
103
129
|
}
|
|
104
130
|
|
|
105
131
|
this.tracer._exporter.exportCoverage(formattedCoverage)
|
|
132
|
+
this.telemetry.ciVisEvent(TELEMETRY_CODE_COVERAGE_FINISHED, 'suite', { library: 'istanbul' })
|
|
106
133
|
})
|
|
107
134
|
|
|
108
135
|
this.addSub('ci:cucumber:test:start', ({ testName, fullTestSuite, testSourceLine }) => {
|
|
@@ -142,6 +169,11 @@ class CucumberPlugin extends CiPlugin {
|
|
|
142
169
|
}
|
|
143
170
|
|
|
144
171
|
span.finish()
|
|
172
|
+
this.telemetry.ciVisEvent(
|
|
173
|
+
TELEMETRY_EVENT_FINISHED,
|
|
174
|
+
'test',
|
|
175
|
+
{ hasCodeOwners: !!span.context()._tags[TEST_CODE_OWNERS] }
|
|
176
|
+
)
|
|
145
177
|
if (!isStep) {
|
|
146
178
|
finishAllTraceSpans(span)
|
|
147
179
|
}
|