dd-trace 3.49.0 → 3.50.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/CONTRIBUTING.md +98 -0
- package/README.md +4 -102
- package/ci/cypress/after-run.js +1 -0
- package/package.json +1 -1
- package/packages/datadog-instrumentations/src/cucumber.js +156 -42
- package/packages/datadog-instrumentations/src/jest.js +69 -35
- package/packages/datadog-plugin-amqplib/src/consumer.js +5 -2
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +60 -50
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +40 -17
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +62 -26
- package/packages/datadog-plugin-cucumber/src/index.js +25 -9
- package/packages/datadog-plugin-cypress/src/after-run.js +3 -0
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +560 -0
- package/packages/datadog-plugin-cypress/src/plugin.js +6 -549
- package/packages/datadog-plugin-rhea/src/consumer.js +4 -1
- package/packages/dd-trace/src/config.js +3 -2
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +1 -1
- package/packages/dd-trace/src/opentracing/span.js +4 -4
- package/packages/dd-trace/src/profiling/exporters/agent.js +40 -31
|
@@ -53,7 +53,7 @@ class Kinesis extends BaseAwsSdkPlugin {
|
|
|
53
53
|
|
|
54
54
|
// extract DSM context after as we might not have a parent-child but may have a DSM context
|
|
55
55
|
this.responseExtractDSMContext(
|
|
56
|
-
request.operation, response, span
|
|
56
|
+
request.operation, response, span || null, streamName
|
|
57
57
|
)
|
|
58
58
|
}
|
|
59
59
|
})
|
|
@@ -143,62 +143,72 @@ class Kinesis extends BaseAwsSdkPlugin {
|
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
requestInject (span, request) {
|
|
146
|
-
const operation = request
|
|
147
|
-
if (
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
146
|
+
const { operation, params } = request
|
|
147
|
+
if (!params) return
|
|
148
|
+
|
|
149
|
+
let stream
|
|
150
|
+
switch (operation) {
|
|
151
|
+
case 'putRecord':
|
|
152
|
+
stream = params.StreamArn ? params.StreamArn : (params.StreamName ? params.StreamName : '')
|
|
153
|
+
this.injectToMessage(span, params, stream, true)
|
|
154
|
+
break
|
|
155
|
+
case 'putRecords':
|
|
156
|
+
stream = params.StreamArn ? params.StreamArn : (params.StreamName ? params.StreamName : '')
|
|
157
|
+
for (let i = 0; i < params.Records.length; i++) {
|
|
158
|
+
this.injectToMessage(span, params.Records[i], stream, i === 0)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
injectToMessage (span, params, stream, injectTraceContext) {
|
|
164
|
+
if (!params) {
|
|
165
|
+
return
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
let parsedData
|
|
169
|
+
if (injectTraceContext || this.config.dsmEnabled) {
|
|
170
|
+
parsedData = this._tryParse(params.Data)
|
|
171
|
+
if (!parsedData) {
|
|
172
|
+
log.error('Unable to parse payload, unable to pass trace context or set DSM checkpoint (if enabled)')
|
|
162
173
|
return
|
|
163
174
|
}
|
|
175
|
+
}
|
|
164
176
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
stream = request.params.StreamName
|
|
179
|
-
}
|
|
180
|
-
const dataStreamsContext = this.tracer
|
|
181
|
-
.setCheckpoint(['direction:out', `topic:${stream}`, 'type:kinesis'], span, payloadSize)
|
|
182
|
-
if (dataStreamsContext) {
|
|
183
|
-
const pathwayCtx = encodePathwayContext(dataStreamsContext)
|
|
184
|
-
parsedData._datadog[CONTEXT_PROPAGATION_KEY] = pathwayCtx.toJSON()
|
|
185
|
-
}
|
|
186
|
-
}
|
|
177
|
+
const ddInfo = {}
|
|
178
|
+
// for now, we only want to inject to the first message, this may change for batches in the future
|
|
179
|
+
if (injectTraceContext) { this.tracer.inject(span, 'text_map', ddInfo) }
|
|
180
|
+
|
|
181
|
+
// set DSM hash if enabled
|
|
182
|
+
if (this.config.dsmEnabled) {
|
|
183
|
+
parsedData._datadog = ddInfo
|
|
184
|
+
const dataStreamsContext = this.setDSMCheckpoint(span, parsedData, stream)
|
|
185
|
+
if (dataStreamsContext) {
|
|
186
|
+
const pathwayCtx = encodePathwayContext(dataStreamsContext)
|
|
187
|
+
ddInfo[CONTEXT_PROPAGATION_KEY] = pathwayCtx.toJSON()
|
|
188
|
+
}
|
|
189
|
+
}
|
|
187
190
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
} else {
|
|
198
|
-
log.error('Unable to parse payload, unable to pass trace context')
|
|
191
|
+
if (Object.keys(ddInfo).length !== 0) {
|
|
192
|
+
parsedData._datadog = ddInfo
|
|
193
|
+
const finalData = Buffer.from(JSON.stringify(parsedData))
|
|
194
|
+
const byteSize = finalData.length
|
|
195
|
+
// Kinesis max payload size is 1MB
|
|
196
|
+
// So we must ensure adding DD context won't go over that (512b is an estimate)
|
|
197
|
+
if (byteSize >= 1048576) {
|
|
198
|
+
log.info('Payload size too large to pass context')
|
|
199
|
+
return
|
|
199
200
|
}
|
|
201
|
+
params.Data = finalData
|
|
200
202
|
}
|
|
201
203
|
}
|
|
204
|
+
|
|
205
|
+
setDSMCheckpoint (span, parsedData, stream) {
|
|
206
|
+
// get payload size of request data
|
|
207
|
+
const payloadSize = Buffer.from(JSON.stringify(parsedData)).byteLength
|
|
208
|
+
const dataStreamsContext = this.tracer
|
|
209
|
+
.setCheckpoint(['direction:out', `topic:${stream}`, 'type:kinesis'], span, payloadSize)
|
|
210
|
+
return dataStreamsContext
|
|
211
|
+
}
|
|
202
212
|
}
|
|
203
213
|
|
|
204
214
|
module.exports = Kinesis
|
|
@@ -55,17 +55,17 @@ class Sns extends BaseAwsSdkPlugin {
|
|
|
55
55
|
|
|
56
56
|
switch (operation) {
|
|
57
57
|
case 'publish':
|
|
58
|
-
this.
|
|
58
|
+
this.injectToMessage(span, params, params.TopicArn, true)
|
|
59
59
|
break
|
|
60
60
|
case 'publishBatch':
|
|
61
|
-
|
|
62
|
-
this.
|
|
61
|
+
for (let i = 0; i < params.PublishBatchRequestEntries.length; i++) {
|
|
62
|
+
this.injectToMessage(span, params.PublishBatchRequestEntries[i], params.TopicArn, i === 0)
|
|
63
63
|
}
|
|
64
64
|
break
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
injectToMessage (span, params, topicArn, injectTraceContext) {
|
|
69
69
|
if (!params.MessageAttributes) {
|
|
70
70
|
params.MessageAttributes = {}
|
|
71
71
|
}
|
|
@@ -73,27 +73,50 @@ class Sns extends BaseAwsSdkPlugin {
|
|
|
73
73
|
log.info('Message attributes full, skipping trace context injection')
|
|
74
74
|
return
|
|
75
75
|
}
|
|
76
|
+
|
|
76
77
|
const ddInfo = {}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
// for now, we only want to inject to the first message, this may change for batches in the future
|
|
79
|
+
if (injectTraceContext) {
|
|
80
|
+
this.tracer.inject(span, 'text_map', ddInfo)
|
|
81
|
+
// add ddInfo before checking DSM so we can include DD attributes in payload size
|
|
82
|
+
params.MessageAttributes._datadog = {
|
|
83
|
+
DataType: 'Binary',
|
|
84
|
+
BinaryValue: ddInfo
|
|
85
|
+
}
|
|
82
86
|
}
|
|
87
|
+
|
|
83
88
|
if (this.config.dsmEnabled) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
if (!params.MessageAttributes._datadog) {
|
|
90
|
+
params.MessageAttributes._datadog = {
|
|
91
|
+
DataType: 'Binary',
|
|
92
|
+
BinaryValue: ddInfo
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const dataStreamsContext = this.setDSMCheckpoint(span, params, topicArn)
|
|
90
97
|
if (dataStreamsContext) {
|
|
91
98
|
const pathwayCtx = encodePathwayContext(dataStreamsContext)
|
|
92
99
|
ddInfo[CONTEXT_PROPAGATION_KEY] = pathwayCtx.toJSON()
|
|
93
100
|
}
|
|
94
101
|
}
|
|
95
|
-
|
|
96
|
-
|
|
102
|
+
|
|
103
|
+
if (Object.keys(ddInfo).length !== 0) {
|
|
104
|
+
// BINARY types are automatically base64 encoded
|
|
105
|
+
params.MessageAttributes._datadog.BinaryValue = Buffer.from(JSON.stringify(ddInfo))
|
|
106
|
+
} else if (params.MessageAttributes._datadog) {
|
|
107
|
+
// let's avoid adding any additional information to payload if we failed to inject
|
|
108
|
+
delete params.MessageAttributes._datadog
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
setDSMCheckpoint (span, params, topicArn) {
|
|
113
|
+
// only set a checkpoint if publishing to a topic
|
|
114
|
+
if (topicArn) {
|
|
115
|
+
const payloadSize = getHeadersSize(params)
|
|
116
|
+
const dataStreamsContext = this.tracer
|
|
117
|
+
.setCheckpoint(['direction:out', `topic:${topicArn}`, 'type:sns'], span, payloadSize)
|
|
118
|
+
return dataStreamsContext
|
|
119
|
+
}
|
|
97
120
|
}
|
|
98
121
|
}
|
|
99
122
|
|
|
@@ -40,7 +40,7 @@ class Sqs extends BaseAwsSdkPlugin {
|
|
|
40
40
|
}
|
|
41
41
|
// extract DSM context after as we might not have a parent-child but may have a DSM context
|
|
42
42
|
this.responseExtractDSMContext(
|
|
43
|
-
request.operation, request.params, response, span
|
|
43
|
+
request.operation, request.params, response, span || null, parsedMessageAttributes || null
|
|
44
44
|
)
|
|
45
45
|
})
|
|
46
46
|
|
|
@@ -206,39 +206,75 @@ class Sqs extends BaseAwsSdkPlugin {
|
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
requestInject (span, request) {
|
|
209
|
-
const operation = request
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
209
|
+
const { operation, params } = request
|
|
210
|
+
|
|
211
|
+
if (!params) return
|
|
212
|
+
|
|
213
|
+
switch (operation) {
|
|
214
|
+
case 'sendMessage':
|
|
215
|
+
this.injectToMessage(span, params, params.QueueUrl, true)
|
|
216
|
+
break
|
|
217
|
+
case 'sendMessageBatch':
|
|
218
|
+
for (let i = 0; i < params.Entries.length; i++) {
|
|
219
|
+
this.injectToMessage(span, params.Entries[i], params.QueueUrl, i === 0)
|
|
220
|
+
}
|
|
221
|
+
break
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
injectToMessage (span, params, queueUrl, injectTraceContext) {
|
|
226
|
+
if (!params) {
|
|
227
|
+
params = {}
|
|
228
|
+
}
|
|
229
|
+
if (!params.MessageAttributes) {
|
|
230
|
+
params.MessageAttributes = {}
|
|
231
|
+
} else if (Object.keys(params.MessageAttributes).length >= 10) { // SQS quota
|
|
232
|
+
// TODO: add test when the test suite is fixed
|
|
233
|
+
return
|
|
234
|
+
}
|
|
235
|
+
const ddInfo = {}
|
|
236
|
+
// for now, we only want to inject to the first message, this may change for batches in the future
|
|
237
|
+
if (injectTraceContext) {
|
|
221
238
|
this.tracer.inject(span, 'text_map', ddInfo)
|
|
222
|
-
|
|
239
|
+
params.MessageAttributes._datadog = {
|
|
223
240
|
DataType: 'String',
|
|
224
241
|
StringValue: JSON.stringify(ddInfo)
|
|
225
242
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
.setCheckpoint(['direction:out', `topic:${queue}`, 'type:sqs'], span, payloadSize)
|
|
234
|
-
if (dataStreamsContext) {
|
|
235
|
-
const pathwayCtx = encodePathwayContext(dataStreamsContext)
|
|
236
|
-
ddInfo[CONTEXT_PROPAGATION_KEY] = pathwayCtx.toJSON()
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (this.config.dsmEnabled) {
|
|
246
|
+
if (!params.MessageAttributes._datadog) {
|
|
247
|
+
params.MessageAttributes._datadog = {
|
|
248
|
+
DataType: 'String',
|
|
249
|
+
StringValue: JSON.stringify(ddInfo)
|
|
237
250
|
}
|
|
238
251
|
}
|
|
239
|
-
|
|
252
|
+
|
|
253
|
+
const dataStreamsContext = this.setDSMCheckpoint(span, params, queueUrl)
|
|
254
|
+
if (dataStreamsContext) {
|
|
255
|
+
const pathwayCtx = encodePathwayContext(dataStreamsContext)
|
|
256
|
+
ddInfo[CONTEXT_PROPAGATION_KEY] = pathwayCtx.toJSON()
|
|
257
|
+
|
|
258
|
+
params.MessageAttributes._datadog.StringValue = JSON.stringify(ddInfo)
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (params.MessageAttributes._datadog && Object.keys(ddInfo).length === 0) {
|
|
263
|
+
// let's avoid adding any additional information to payload if we failed to inject
|
|
264
|
+
delete params.MessageAttributes._datadog
|
|
240
265
|
}
|
|
241
266
|
}
|
|
267
|
+
|
|
268
|
+
setDSMCheckpoint (span, params, queueUrl) {
|
|
269
|
+
const payloadSize = getHeadersSize({
|
|
270
|
+
Body: params.MessageBody,
|
|
271
|
+
MessageAttributes: params.MessageAttributes
|
|
272
|
+
})
|
|
273
|
+
const queue = queueUrl.split('/').pop()
|
|
274
|
+
const dataStreamsContext = this.tracer
|
|
275
|
+
.setCheckpoint(['direction:out', `topic:${queue}`, 'type:sqs'], span, payloadSize)
|
|
276
|
+
return dataStreamsContext
|
|
277
|
+
}
|
|
242
278
|
}
|
|
243
279
|
|
|
244
280
|
module.exports = Sqs
|
|
@@ -15,7 +15,10 @@ const {
|
|
|
15
15
|
TEST_ITR_FORCED_RUN,
|
|
16
16
|
TEST_CODE_OWNERS,
|
|
17
17
|
ITR_CORRELATION_ID,
|
|
18
|
-
TEST_SOURCE_FILE
|
|
18
|
+
TEST_SOURCE_FILE,
|
|
19
|
+
TEST_EARLY_FLAKE_IS_ENABLED,
|
|
20
|
+
TEST_IS_NEW,
|
|
21
|
+
TEST_EARLY_FLAKE_IS_RETRY
|
|
19
22
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
20
23
|
const { RESOURCE_NAME } = require('../../../ext/tags')
|
|
21
24
|
const { COMPONENT, ERROR_MESSAGE } = require('../../dd-trace/src/constants')
|
|
@@ -46,7 +49,8 @@ class CucumberPlugin extends CiPlugin {
|
|
|
46
49
|
numSkippedSuites,
|
|
47
50
|
testCodeCoverageLinesTotal,
|
|
48
51
|
hasUnskippableSuites,
|
|
49
|
-
hasForcedToRunSuites
|
|
52
|
+
hasForcedToRunSuites,
|
|
53
|
+
isEarlyFlakeDetectionEnabled
|
|
50
54
|
}) => {
|
|
51
55
|
const { isSuitesSkippingEnabled, isCodeCoverageEnabled } = this.libraryConfig || {}
|
|
52
56
|
addIntelligentTestRunnerSpanTags(
|
|
@@ -63,6 +67,9 @@ class CucumberPlugin extends CiPlugin {
|
|
|
63
67
|
hasForcedToRunSuites
|
|
64
68
|
}
|
|
65
69
|
)
|
|
70
|
+
if (isEarlyFlakeDetectionEnabled) {
|
|
71
|
+
this.testSessionSpan.setTag(TEST_EARLY_FLAKE_IS_ENABLED, 'true')
|
|
72
|
+
}
|
|
66
73
|
|
|
67
74
|
this.testSessionSpan.setTag(TEST_STATUS, status)
|
|
68
75
|
this.testModuleSpan.setTag(TEST_STATUS, status)
|
|
@@ -141,7 +148,12 @@ class CucumberPlugin extends CiPlugin {
|
|
|
141
148
|
const store = storage.getStore()
|
|
142
149
|
const testSuite = getTestSuitePath(testFileAbsolutePath, this.sourceRoot)
|
|
143
150
|
const testSourceFile = getTestSuitePath(testFileAbsolutePath, this.repositoryRoot)
|
|
144
|
-
|
|
151
|
+
|
|
152
|
+
const extraTags = {
|
|
153
|
+
[TEST_SOURCE_START]: testSourceLine,
|
|
154
|
+
[TEST_SOURCE_FILE]: testSourceFile
|
|
155
|
+
}
|
|
156
|
+
const testSpan = this.startTestSpan(testName, testSuite, extraTags)
|
|
145
157
|
|
|
146
158
|
this.enter(testSpan, store)
|
|
147
159
|
})
|
|
@@ -160,12 +172,19 @@ class CucumberPlugin extends CiPlugin {
|
|
|
160
172
|
this.enter(span, store)
|
|
161
173
|
})
|
|
162
174
|
|
|
163
|
-
this.addSub('ci:cucumber:test:finish', ({ isStep, status, skipReason, errorMessage }) => {
|
|
175
|
+
this.addSub('ci:cucumber:test:finish', ({ isStep, status, skipReason, errorMessage, isNew, isEfdRetry }) => {
|
|
164
176
|
const span = storage.getStore().span
|
|
165
177
|
const statusTag = isStep ? 'step.status' : TEST_STATUS
|
|
166
178
|
|
|
167
179
|
span.setTag(statusTag, status)
|
|
168
180
|
|
|
181
|
+
if (isNew) {
|
|
182
|
+
span.setTag(TEST_IS_NEW, 'true')
|
|
183
|
+
if (isEfdRetry) {
|
|
184
|
+
span.setTag(TEST_EARLY_FLAKE_IS_RETRY, 'true')
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
169
188
|
if (skipReason) {
|
|
170
189
|
span.setTag(TEST_SKIP_REASON, skipReason)
|
|
171
190
|
}
|
|
@@ -193,15 +212,12 @@ class CucumberPlugin extends CiPlugin {
|
|
|
193
212
|
})
|
|
194
213
|
}
|
|
195
214
|
|
|
196
|
-
startTestSpan (testName, testSuite,
|
|
215
|
+
startTestSpan (testName, testSuite, extraTags) {
|
|
197
216
|
return super.startTestSpan(
|
|
198
217
|
testName,
|
|
199
218
|
testSuite,
|
|
200
219
|
this.testSuiteSpan,
|
|
201
|
-
|
|
202
|
-
[TEST_SOURCE_START]: testSourceLine,
|
|
203
|
-
[TEST_SOURCE_FILE]: testSourceFile
|
|
204
|
-
}
|
|
220
|
+
extraTags
|
|
205
221
|
)
|
|
206
222
|
}
|
|
207
223
|
}
|