dd-trace 5.0.0-pre-069b62a → 5.0.0-pre-e2df7ec
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 +1 -0
- package/index.d.ts +5 -0
- package/package.json +4 -3
- 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/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/hooks.js +9 -2
- package/packages/datadog-instrumentations/src/helpers/instrument.js +8 -3
- package/packages/datadog-instrumentations/src/helpers/register.js +18 -2
- package/packages/datadog-instrumentations/src/http/client.js +4 -16
- 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 +1 -1
- 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 +15 -5
- package/packages/datadog-instrumentations/src/restify.js +1 -1
- package/packages/datadog-instrumentations/src/rhea.js +15 -9
- 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 +1 -1
- package/packages/datadog-plugin-jest/src/index.js +38 -4
- package/packages/datadog-plugin-kafkajs/src/consumer.js +51 -0
- package/packages/datadog-plugin-kafkajs/src/producer.js +55 -0
- package/packages/datadog-plugin-mocha/src/index.js +32 -1
- package/packages/datadog-plugin-next/src/index.js +32 -6
- 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 +1 -0
- 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 +4 -1
- package/packages/dd-trace/src/appsec/graphql.js +146 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +16 -7
- package/packages/dd-trace/src/appsec/index.js +29 -40
- package/packages/dd-trace/src/appsec/recommended.json +1395 -2
- 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 +2 -4
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +25 -13
- 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/git/git_metadata.js +36 -4
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +18 -1
- 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 +110 -56
- package/packages/dd-trace/src/datastreams/processor.js +107 -12
- 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/opentracing/span.js +2 -0
- package/packages/dd-trace/src/opentracing/tracer.js +2 -2
- package/packages/dd-trace/src/plugins/ci_plugin.js +44 -8
- package/packages/dd-trace/src/plugins/index.js +5 -0
- package/packages/dd-trace/src/plugins/util/exec.js +23 -2
- package/packages/dd-trace/src/plugins/util/git.js +94 -19
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +3 -2
- package/packages/dd-trace/src/profiling/exporters/agent.js +1 -0
- package/packages/dd-trace/src/profiling/profiler.js +7 -6
- package/packages/dd-trace/src/profiling/profilers/events.js +19 -51
- package/packages/dd-trace/src/profiling/profilers/shared.js +34 -4
- package/packages/dd-trace/src/profiling/profilers/space.js +2 -1
- package/packages/dd-trace/src/profiling/profilers/wall.js +17 -12
- package/packages/dd-trace/src/proxy.js +14 -0
- package/packages/dd-trace/src/spanleak.js +98 -0
- package/packages/dd-trace/src/telemetry/index.js +43 -5
- package/packages/dd-trace/src/tracer.js +4 -0
|
@@ -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
|
|
@@ -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
|
}
|
|
@@ -29,6 +29,29 @@ const { ORIGIN_KEY, COMPONENT } = require('../../dd-trace/src/constants')
|
|
|
29
29
|
const log = require('../../dd-trace/src/log')
|
|
30
30
|
const NoopTracer = require('../../dd-trace/src/noop/tracer')
|
|
31
31
|
const { isMarkedAsUnskippable } = require('../../datadog-plugin-jest/src/util')
|
|
32
|
+
const {
|
|
33
|
+
TELEMETRY_EVENT_CREATED,
|
|
34
|
+
TELEMETRY_EVENT_FINISHED,
|
|
35
|
+
TELEMETRY_ITR_FORCED_TO_RUN,
|
|
36
|
+
TELEMETRY_CODE_COVERAGE_EMPTY,
|
|
37
|
+
TELEMETRY_ITR_UNSKIPPABLE,
|
|
38
|
+
TELEMETRY_CODE_COVERAGE_NUM_FILES,
|
|
39
|
+
incrementCountMetric,
|
|
40
|
+
distributionMetric
|
|
41
|
+
} = require('../../dd-trace/src/ci-visibility/telemetry')
|
|
42
|
+
const {
|
|
43
|
+
GIT_REPOSITORY_URL,
|
|
44
|
+
GIT_COMMIT_SHA,
|
|
45
|
+
GIT_BRANCH,
|
|
46
|
+
CI_PROVIDER_NAME
|
|
47
|
+
} = require('../../dd-trace/src/plugins/util/tags')
|
|
48
|
+
const {
|
|
49
|
+
OS_VERSION,
|
|
50
|
+
OS_PLATFORM,
|
|
51
|
+
OS_ARCHITECTURE,
|
|
52
|
+
RUNTIME_NAME,
|
|
53
|
+
RUNTIME_VERSION
|
|
54
|
+
} = require('../../dd-trace/src/plugins/util/env')
|
|
32
55
|
|
|
33
56
|
const TEST_FRAMEWORK_NAME = 'cypress'
|
|
34
57
|
|
|
@@ -152,16 +175,19 @@ module.exports = (on, config) => {
|
|
|
152
175
|
const testEnvironmentMetadata = getTestEnvironmentMetadata(TEST_FRAMEWORK_NAME)
|
|
153
176
|
|
|
154
177
|
const {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
178
|
+
[GIT_REPOSITORY_URL]: repositoryUrl,
|
|
179
|
+
[GIT_COMMIT_SHA]: sha,
|
|
180
|
+
[OS_VERSION]: osVersion,
|
|
181
|
+
[OS_PLATFORM]: osPlatform,
|
|
182
|
+
[OS_ARCHITECTURE]: osArchitecture,
|
|
183
|
+
[RUNTIME_NAME]: runtimeName,
|
|
184
|
+
[RUNTIME_VERSION]: runtimeVersion,
|
|
185
|
+
[GIT_BRANCH]: branch,
|
|
186
|
+
[CI_PROVIDER_NAME]: ciProviderName
|
|
163
187
|
} = testEnvironmentMetadata
|
|
164
188
|
|
|
189
|
+
const isUnsupportedCIProvider = !ciProviderName
|
|
190
|
+
|
|
165
191
|
const finishedTestsByFile = {}
|
|
166
192
|
|
|
167
193
|
const testConfiguration = {
|
|
@@ -192,6 +218,15 @@ module.exports = (on, config) => {
|
|
|
192
218
|
let hasForcedToRunSuites = false
|
|
193
219
|
let hasUnskippableSuites = false
|
|
194
220
|
|
|
221
|
+
function ciVisEvent (name, testLevel, tags = {}) {
|
|
222
|
+
incrementCountMetric(name, {
|
|
223
|
+
testLevel,
|
|
224
|
+
testFramework: 'cypress',
|
|
225
|
+
isUnsupportedCIProvider,
|
|
226
|
+
...tags
|
|
227
|
+
})
|
|
228
|
+
}
|
|
229
|
+
|
|
195
230
|
function getTestSpan (testName, testSuite, isUnskippable, isForcedToRun) {
|
|
196
231
|
const testSuiteTags = {
|
|
197
232
|
[TEST_COMMAND]: command,
|
|
@@ -220,14 +255,18 @@ module.exports = (on, config) => {
|
|
|
220
255
|
|
|
221
256
|
if (isUnskippable) {
|
|
222
257
|
hasUnskippableSuites = true
|
|
258
|
+
incrementCountMetric(TELEMETRY_ITR_UNSKIPPABLE, { testLevel: 'suite' })
|
|
223
259
|
testSpanMetadata[TEST_ITR_UNSKIPPABLE] = 'true'
|
|
224
260
|
}
|
|
225
261
|
|
|
226
262
|
if (isForcedToRun) {
|
|
227
263
|
hasForcedToRunSuites = true
|
|
264
|
+
incrementCountMetric(TELEMETRY_ITR_FORCED_TO_RUN, { testLevel: 'suite' })
|
|
228
265
|
testSpanMetadata[TEST_ITR_FORCED_RUN] = 'true'
|
|
229
266
|
}
|
|
230
267
|
|
|
268
|
+
ciVisEvent(TELEMETRY_EVENT_CREATED, 'test', { hasCodeOwners: !!codeOwners })
|
|
269
|
+
|
|
231
270
|
return tracer.startSpan(`${TEST_FRAMEWORK_NAME}.test`, {
|
|
232
271
|
childOf,
|
|
233
272
|
tags: {
|
|
@@ -281,6 +320,8 @@ module.exports = (on, config) => {
|
|
|
281
320
|
...testSessionSpanMetadata
|
|
282
321
|
}
|
|
283
322
|
})
|
|
323
|
+
ciVisEvent(TELEMETRY_EVENT_CREATED, 'session')
|
|
324
|
+
|
|
284
325
|
testModuleSpan = tracer.startSpan(`${TEST_FRAMEWORK_NAME}.test_module`, {
|
|
285
326
|
childOf: testSessionSpan,
|
|
286
327
|
tags: {
|
|
@@ -289,6 +330,8 @@ module.exports = (on, config) => {
|
|
|
289
330
|
...testModuleSpanMetadata
|
|
290
331
|
}
|
|
291
332
|
})
|
|
333
|
+
ciVisEvent(TELEMETRY_EVENT_CREATED, 'module')
|
|
334
|
+
|
|
292
335
|
return details
|
|
293
336
|
})
|
|
294
337
|
})
|
|
@@ -347,6 +390,7 @@ module.exports = (on, config) => {
|
|
|
347
390
|
}
|
|
348
391
|
testSuiteSpan.finish()
|
|
349
392
|
testSuiteSpan = null
|
|
393
|
+
ciVisEvent(TELEMETRY_EVENT_FINISHED, 'suite')
|
|
350
394
|
}
|
|
351
395
|
})
|
|
352
396
|
|
|
@@ -371,7 +415,9 @@ module.exports = (on, config) => {
|
|
|
371
415
|
)
|
|
372
416
|
|
|
373
417
|
testModuleSpan.finish()
|
|
418
|
+
ciVisEvent(TELEMETRY_EVENT_FINISHED, 'module')
|
|
374
419
|
testSessionSpan.finish()
|
|
420
|
+
ciVisEvent(TELEMETRY_EVENT_FINISHED, 'session')
|
|
375
421
|
|
|
376
422
|
finishAllTraceSpans(testSessionSpan)
|
|
377
423
|
}
|
|
@@ -406,6 +452,7 @@ module.exports = (on, config) => {
|
|
|
406
452
|
...testSuiteSpanMetadata
|
|
407
453
|
}
|
|
408
454
|
})
|
|
455
|
+
ciVisEvent(TELEMETRY_EVENT_CREATED, 'suite')
|
|
409
456
|
return null
|
|
410
457
|
},
|
|
411
458
|
'dd:beforeEach': (test) => {
|
|
@@ -435,6 +482,10 @@ module.exports = (on, config) => {
|
|
|
435
482
|
if (coverage && isCodeCoverageEnabled && tracer._tracer._exporter && tracer._tracer._exporter.exportCoverage) {
|
|
436
483
|
const coverageFiles = getCoveredFilenamesFromCoverage(coverage)
|
|
437
484
|
const relativeCoverageFiles = coverageFiles.map(file => getTestSuitePath(file, rootDir))
|
|
485
|
+
if (!relativeCoverageFiles.length) {
|
|
486
|
+
incrementCountMetric(TELEMETRY_CODE_COVERAGE_EMPTY)
|
|
487
|
+
}
|
|
488
|
+
distributionMetric(TELEMETRY_CODE_COVERAGE_NUM_FILES, {}, relativeCoverageFiles.length)
|
|
438
489
|
const { _traceId, _spanId } = testSuiteSpan.context()
|
|
439
490
|
const formattedCoverage = {
|
|
440
491
|
sessionId: _traceId,
|
|
@@ -470,6 +521,7 @@ module.exports = (on, config) => {
|
|
|
470
521
|
// test spans are finished at after:spec
|
|
471
522
|
}
|
|
472
523
|
activeSpan = null
|
|
524
|
+
ciVisEvent(TELEMETRY_EVENT_FINISHED, 'test')
|
|
473
525
|
return null
|
|
474
526
|
},
|
|
475
527
|
'dd:addTags': (tags) => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
|
|
4
|
+
const dc = require('dc-polyfill')
|
|
4
5
|
|
|
5
6
|
const collapsedPathSym = Symbol('collapsedPaths')
|
|
6
7
|
|
|
@@ -14,8 +15,6 @@ class GraphQLResolvePlugin extends TracingPlugin {
|
|
|
14
15
|
if (!shouldInstrument(this.config, path)) return
|
|
15
16
|
const computedPathString = path.join('.')
|
|
16
17
|
|
|
17
|
-
addResolver(context, info, args)
|
|
18
|
-
|
|
19
18
|
if (this.config.collapse) {
|
|
20
19
|
if (!context[collapsedPathSym]) {
|
|
21
20
|
context[collapsedPathSym] = {}
|
|
@@ -55,6 +54,10 @@ class GraphQLResolvePlugin extends TracingPlugin {
|
|
|
55
54
|
span.setTag(`graphql.variables.${name}`, variables[name])
|
|
56
55
|
})
|
|
57
56
|
}
|
|
57
|
+
|
|
58
|
+
if (this.resolverStartCh.hasSubscribers) {
|
|
59
|
+
this.resolverStartCh.publish({ context, resolverInfo: getResolverInfo(info, args) })
|
|
60
|
+
}
|
|
58
61
|
}
|
|
59
62
|
|
|
60
63
|
constructor (...args) {
|
|
@@ -69,6 +72,8 @@ class GraphQLResolvePlugin extends TracingPlugin {
|
|
|
69
72
|
field.finishTime = span._getTime ? span._getTime() : 0
|
|
70
73
|
field.error = field.error || err
|
|
71
74
|
})
|
|
75
|
+
|
|
76
|
+
this.resolverStartCh = dc.channel('datadog:graphql:resolver:start')
|
|
72
77
|
}
|
|
73
78
|
|
|
74
79
|
configure (config) {
|
|
@@ -109,28 +114,31 @@ function withCollapse (responsePathAsArray) {
|
|
|
109
114
|
}
|
|
110
115
|
}
|
|
111
116
|
|
|
112
|
-
function
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
117
|
+
function getResolverInfo (info, args) {
|
|
118
|
+
let resolverInfo = null
|
|
119
|
+
const resolverVars = {}
|
|
116
120
|
|
|
117
|
-
if (
|
|
118
|
-
|
|
121
|
+
if (args && Object.keys(args).length) {
|
|
122
|
+
Object.assign(resolverVars, args)
|
|
119
123
|
}
|
|
120
124
|
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
} else {
|
|
127
|
-
resolvers[info.fieldName] = []
|
|
125
|
+
const directives = info.fieldNodes[0].directives
|
|
126
|
+
for (const directive of directives) {
|
|
127
|
+
const argList = {}
|
|
128
|
+
for (const argument of directive['arguments']) {
|
|
129
|
+
argList[argument.name.value] = argument.value.value
|
|
128
130
|
}
|
|
129
|
-
|
|
130
|
-
if (
|
|
131
|
-
|
|
131
|
+
|
|
132
|
+
if (Object.keys(argList).length) {
|
|
133
|
+
resolverVars[directive.name.value] = argList
|
|
132
134
|
}
|
|
133
135
|
}
|
|
136
|
+
|
|
137
|
+
if (Object.keys(resolverVars).length) {
|
|
138
|
+
resolverInfo = { [info.fieldName]: resolverVars }
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return resolverInfo
|
|
134
142
|
}
|
|
135
143
|
|
|
136
144
|
module.exports = GraphQLResolvePlugin
|
|
@@ -121,7 +121,7 @@ class HttpClientPlugin extends ClientPlugin {
|
|
|
121
121
|
} else {
|
|
122
122
|
// conditions for no error:
|
|
123
123
|
// 1. not using a custom agent instance with custom timeout specified
|
|
124
|
-
// 2. no invocation of `req.setTimeout`
|
|
124
|
+
// 2. no invocation of `req.setTimeout`
|
|
125
125
|
if (!args.options.agent?.options.timeout && !customRequestTimeout) return
|
|
126
126
|
|
|
127
127
|
span.setTag('error', 1)
|
|
@@ -12,10 +12,21 @@ const {
|
|
|
12
12
|
TEST_FRAMEWORK_VERSION,
|
|
13
13
|
TEST_SOURCE_START,
|
|
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 { COMPONENT } = require('../../dd-trace/src/constants')
|
|
18
19
|
const id = require('../../dd-trace/src/id')
|
|
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
|
const isJestWorker = !!process.env.JEST_WORKER_ID
|
|
21
32
|
|
|
@@ -81,7 +92,9 @@ class JestPlugin extends CiPlugin {
|
|
|
81
92
|
)
|
|
82
93
|
|
|
83
94
|
this.testModuleSpan.finish()
|
|
95
|
+
this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'module')
|
|
84
96
|
this.testSessionSpan.finish()
|
|
97
|
+
this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'session')
|
|
85
98
|
finishAllTraceSpans(this.testSessionSpan)
|
|
86
99
|
this.tracer._exporter.flush()
|
|
87
100
|
})
|
|
@@ -103,7 +116,8 @@ class JestPlugin extends CiPlugin {
|
|
|
103
116
|
_ddTestCommand: testCommand,
|
|
104
117
|
_ddTestModuleId: testModuleId,
|
|
105
118
|
_ddForcedToRun,
|
|
106
|
-
_ddUnskippable
|
|
119
|
+
_ddUnskippable,
|
|
120
|
+
_ddTestCodeCoverageEnabled
|
|
107
121
|
} = testEnvironmentOptions
|
|
108
122
|
|
|
109
123
|
const testSessionSpanContext = this.tracer.extract('text_map', {
|
|
@@ -114,8 +128,10 @@ class JestPlugin extends CiPlugin {
|
|
|
114
128
|
const testSuiteMetadata = getTestSuiteCommonTags(testCommand, frameworkVersion, testSuite, 'jest')
|
|
115
129
|
|
|
116
130
|
if (_ddUnskippable) {
|
|
131
|
+
this.telemetry.count(TELEMETRY_ITR_UNSKIPPABLE, { testLevel: 'suite' })
|
|
117
132
|
testSuiteMetadata[TEST_ITR_UNSKIPPABLE] = 'true'
|
|
118
133
|
if (_ddForcedToRun) {
|
|
134
|
+
this.telemetry.count(TELEMETRY_ITR_FORCED_TO_RUN, { testLevel: 'suite' })
|
|
119
135
|
testSuiteMetadata[TEST_ITR_FORCED_RUN] = 'true'
|
|
120
136
|
}
|
|
121
137
|
}
|
|
@@ -128,6 +144,10 @@ class JestPlugin extends CiPlugin {
|
|
|
128
144
|
...testSuiteMetadata
|
|
129
145
|
}
|
|
130
146
|
})
|
|
147
|
+
this.telemetry.ciVisEvent(TELEMETRY_EVENT_CREATED, 'suite')
|
|
148
|
+
if (_ddTestCodeCoverageEnabled) {
|
|
149
|
+
this.telemetry.ciVisEvent(TELEMETRY_CODE_COVERAGE_STARTED, 'suite', { library: 'istanbul' })
|
|
150
|
+
}
|
|
131
151
|
})
|
|
132
152
|
|
|
133
153
|
this.addSub('ci:jest:worker-report:trace', traces => {
|
|
@@ -164,6 +184,7 @@ class JestPlugin extends CiPlugin {
|
|
|
164
184
|
this.testSuiteSpan.setTag('error', new Error(errorMessage))
|
|
165
185
|
}
|
|
166
186
|
this.testSuiteSpan.finish()
|
|
187
|
+
this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'suite')
|
|
167
188
|
// Suites potentially run in a different process than the session,
|
|
168
189
|
// so calling finishAllTraceSpans on the session span is not enough
|
|
169
190
|
finishAllTraceSpans(this.testSuiteSpan)
|
|
@@ -180,14 +201,22 @@ class JestPlugin extends CiPlugin {
|
|
|
180
201
|
* because this subscription happens in a different process from the one
|
|
181
202
|
* fetching the ITR config.
|
|
182
203
|
*/
|
|
183
|
-
this.addSub('ci:jest:test-suite:code-coverage', (coverageFiles) => {
|
|
204
|
+
this.addSub('ci:jest:test-suite:code-coverage', ({ coverageFiles, testSuite }) => {
|
|
205
|
+
if (!coverageFiles.length) {
|
|
206
|
+
this.telemetry.count(TELEMETRY_CODE_COVERAGE_EMPTY)
|
|
207
|
+
}
|
|
208
|
+
const files = [...coverageFiles, testSuite]
|
|
209
|
+
|
|
184
210
|
const { _traceId, _spanId } = this.testSuiteSpan.context()
|
|
185
211
|
const formattedCoverage = {
|
|
186
212
|
sessionId: _traceId,
|
|
187
213
|
suiteId: _spanId,
|
|
188
|
-
files
|
|
214
|
+
files
|
|
189
215
|
}
|
|
216
|
+
|
|
190
217
|
this.tracer._exporter.exportCoverage(formattedCoverage)
|
|
218
|
+
this.telemetry.ciVisEvent(TELEMETRY_CODE_COVERAGE_FINISHED, 'suite', { library: 'istanbul' })
|
|
219
|
+
this.telemetry.distribution(TELEMETRY_CODE_COVERAGE_NUM_FILES, {}, files.length)
|
|
191
220
|
})
|
|
192
221
|
|
|
193
222
|
this.addSub('ci:jest:test:start', (test) => {
|
|
@@ -204,6 +233,11 @@ class JestPlugin extends CiPlugin {
|
|
|
204
233
|
span.setTag(TEST_SOURCE_START, testStartLine)
|
|
205
234
|
}
|
|
206
235
|
span.finish()
|
|
236
|
+
this.telemetry.ciVisEvent(
|
|
237
|
+
TELEMETRY_EVENT_FINISHED,
|
|
238
|
+
'test',
|
|
239
|
+
{ hasCodeOwners: !!span.context()._tags[TEST_CODE_OWNERS] }
|
|
240
|
+
)
|
|
207
241
|
finishAllTraceSpans(span)
|
|
208
242
|
})
|
|
209
243
|
|
|
@@ -7,6 +7,57 @@ class KafkajsConsumerPlugin extends ConsumerPlugin {
|
|
|
7
7
|
static get id () { return 'kafkajs' }
|
|
8
8
|
static get operation () { return 'consume' }
|
|
9
9
|
|
|
10
|
+
constructor () {
|
|
11
|
+
super(...arguments)
|
|
12
|
+
this.addSub('apm:kafkajs:consume:commit', message => this.commit(message))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Transform individual commit details sent by kafkajs' event reporter
|
|
17
|
+
* into actionable backlog items for DSM
|
|
18
|
+
*
|
|
19
|
+
* @typedef {object} ConsumerBacklog
|
|
20
|
+
* @property {number} type
|
|
21
|
+
* @property {string} consumer_group
|
|
22
|
+
* @property {string} topic
|
|
23
|
+
* @property {number} partition
|
|
24
|
+
* @property {number} offset
|
|
25
|
+
*
|
|
26
|
+
* @typedef {object} CommitEventItem
|
|
27
|
+
* @property {string} groupId
|
|
28
|
+
* @property {string} topic
|
|
29
|
+
* @property {number} partition
|
|
30
|
+
* @property {import('kafkajs/utils/long').Long} offset
|
|
31
|
+
*
|
|
32
|
+
* @param {CommitEventItem} commit
|
|
33
|
+
* @returns {ConsumerBacklog}
|
|
34
|
+
*/
|
|
35
|
+
transformCommit (commit) {
|
|
36
|
+
const { groupId, partition, offset, topic } = commit
|
|
37
|
+
return {
|
|
38
|
+
partition,
|
|
39
|
+
topic,
|
|
40
|
+
type: 'kafka_commit',
|
|
41
|
+
offset: Number(offset),
|
|
42
|
+
consumer_group: groupId
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
commit (commitList) {
|
|
47
|
+
if (!this.config.dsmEnabled) return
|
|
48
|
+
const keys = [
|
|
49
|
+
'consumer_group',
|
|
50
|
+
'type',
|
|
51
|
+
'partition',
|
|
52
|
+
'offset',
|
|
53
|
+
'topic'
|
|
54
|
+
]
|
|
55
|
+
for (const commit of commitList.map(this.transformCommit)) {
|
|
56
|
+
if (keys.some(key => !commit.hasOwnProperty(key))) continue
|
|
57
|
+
this.tracer.setOffset(commit)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
10
61
|
start ({ topic, partition, message, groupId }) {
|
|
11
62
|
const childOf = extract(this.tracer, message.headers)
|
|
12
63
|
const span = this.startSpan({
|
|
@@ -11,6 +11,61 @@ class KafkajsProducerPlugin extends ProducerPlugin {
|
|
|
11
11
|
static get operation () { return 'produce' }
|
|
12
12
|
static get peerServicePrecursors () { return [BOOTSTRAP_SERVERS_KEY] }
|
|
13
13
|
|
|
14
|
+
constructor () {
|
|
15
|
+
super(...arguments)
|
|
16
|
+
this.addSub('apm:kafkajs:produce:commit', message => this.commit(message))
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Transform individual commit details sent by kafkajs' event reporter
|
|
21
|
+
* into actionable backlog items for DSM
|
|
22
|
+
*
|
|
23
|
+
* @typedef {object} ProducerBacklog
|
|
24
|
+
* @property {number} type
|
|
25
|
+
* @property {string} topic
|
|
26
|
+
* @property {number} partition
|
|
27
|
+
* @property {number} offset
|
|
28
|
+
*
|
|
29
|
+
* @typedef {object} ProducerResponseItem
|
|
30
|
+
* @property {string} topic
|
|
31
|
+
* @property {number} partition
|
|
32
|
+
* @property {import('kafkajs/utils/long').Long} [offset]
|
|
33
|
+
* @property {import('kafkajs/utils/long').Long} [baseOffset]
|
|
34
|
+
*
|
|
35
|
+
* @param {ProducerResponseItem} response
|
|
36
|
+
* @returns {ProducerBacklog}
|
|
37
|
+
*/
|
|
38
|
+
transformProduceResponse (response) {
|
|
39
|
+
// In produce protocol >=v3, the offset key changes from `offset` to `baseOffset`
|
|
40
|
+
const { topicName: topic, partition, offset, baseOffset } = response
|
|
41
|
+
const offsetAsLong = offset || baseOffset
|
|
42
|
+
return {
|
|
43
|
+
type: 'kafka_produce',
|
|
44
|
+
partition,
|
|
45
|
+
offset: offsetAsLong ? Number(offsetAsLong) : undefined,
|
|
46
|
+
topic
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
*
|
|
52
|
+
* @param {ProducerResponseItem[]} commitList
|
|
53
|
+
* @returns {void}
|
|
54
|
+
*/
|
|
55
|
+
commit (commitList) {
|
|
56
|
+
if (!this.config.dsmEnabled) return
|
|
57
|
+
const keys = [
|
|
58
|
+
'type',
|
|
59
|
+
'partition',
|
|
60
|
+
'offset',
|
|
61
|
+
'topic'
|
|
62
|
+
]
|
|
63
|
+
for (const commit of commitList.map(this.transformProduceResponse)) {
|
|
64
|
+
if (keys.some(key => !commit.hasOwnProperty(key))) continue
|
|
65
|
+
this.tracer.setOffset(commit)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
14
69
|
start ({ topic, messages, bootstrapServers }) {
|
|
15
70
|
let pathwayCtx
|
|
16
71
|
const span = this.startSpan({
|