dd-trace 4.28.0 → 4.30.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 +8 -99
- package/ci/cypress/after-run.js +1 -0
- package/ci/cypress/after-spec.js +1 -0
- package/index.d.ts +1499 -1486
- package/package.json +3 -3
- package/packages/datadog-core/src/utils/src/get.js +11 -0
- package/packages/datadog-core/src/utils/src/has.js +14 -0
- package/packages/datadog-core/src/utils/src/set.js +16 -0
- package/packages/datadog-instrumentations/src/amqplib.js +1 -1
- package/packages/datadog-instrumentations/src/cucumber.js +157 -42
- package/packages/datadog-instrumentations/src/grpc/server.js +3 -1
- package/packages/datadog-instrumentations/src/jest.js +80 -40
- package/packages/datadog-instrumentations/src/mocha.js +4 -1
- package/packages/datadog-instrumentations/src/mongodb-core.js +34 -3
- package/packages/datadog-instrumentations/src/playwright.js +78 -16
- package/packages/datadog-plugin-amqplib/src/consumer.js +8 -4
- package/packages/datadog-plugin-amqplib/src/producer.js +3 -4
- package/packages/datadog-plugin-aws-sdk/src/base.js +3 -2
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +60 -57
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +42 -22
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +64 -30
- 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/after-spec.js +3 -0
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +625 -0
- package/packages/datadog-plugin-cypress/src/plugin.js +6 -549
- package/packages/datadog-plugin-cypress/src/support.js +50 -3
- package/packages/datadog-plugin-graphql/src/index.js +1 -1
- package/packages/datadog-plugin-graphql/src/resolve.js +10 -8
- package/packages/datadog-plugin-grpc/src/util.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +11 -2
- package/packages/datadog-plugin-kafkajs/src/consumer.js +4 -3
- package/packages/datadog-plugin-kafkajs/src/producer.js +3 -5
- package/packages/datadog-plugin-playwright/src/index.js +34 -3
- package/packages/datadog-plugin-rhea/src/consumer.js +8 -3
- package/packages/datadog-plugin-rhea/src/producer.js +3 -4
- package/packages/dd-trace/src/appsec/iast/index.js +10 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +18 -5
- package/packages/dd-trace/src/appsec/recommended.json +67 -27
- package/packages/dd-trace/src/appsec/remote_config/index.js +1 -1
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -3
- package/packages/dd-trace/src/config.js +451 -459
- package/packages/dd-trace/src/data_streams_context.js +1 -1
- package/packages/dd-trace/src/datastreams/pathway.js +58 -1
- package/packages/dd-trace/src/datastreams/processor.js +3 -5
- package/packages/dd-trace/src/format.js +0 -1
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +2 -2
- package/packages/dd-trace/src/opentracing/span.js +4 -4
- package/packages/dd-trace/src/plugins/util/test.js +2 -0
- package/packages/dd-trace/src/plugins/util/web.js +1 -1
- package/packages/dd-trace/src/profiling/exporters/agent.js +77 -32
- package/packages/dd-trace/src/telemetry/index.js +22 -34
- package/packages/dd-trace/src/tracer.js +3 -3
- package/register.js +4 -0
- /package/packages/{utils → datadog-core/src/utils}/src/kebabcase.js +0 -0
- /package/packages/{utils → datadog-core/src/utils}/src/pick.js +0 -0
- /package/packages/{utils → datadog-core/src/utils}/src/uniq.js +0 -0
|
@@ -14,6 +14,7 @@ const testSuiteFinishCh = channel('ci:playwright:test-suite:finish')
|
|
|
14
14
|
const testToAr = new WeakMap()
|
|
15
15
|
const testSuiteToAr = new Map()
|
|
16
16
|
const testSuiteToTestStatuses = new Map()
|
|
17
|
+
const testSuiteToErrors = new Map()
|
|
17
18
|
|
|
18
19
|
let startedSuites = []
|
|
19
20
|
|
|
@@ -81,7 +82,12 @@ function getRootDir (playwrightRunner) {
|
|
|
81
82
|
|
|
82
83
|
function getProjectsFromRunner (runner) {
|
|
83
84
|
const config = getPlaywrightConfig(runner)
|
|
84
|
-
return config.projects?.map((
|
|
85
|
+
return config.projects?.map((project) => {
|
|
86
|
+
if (project.project) {
|
|
87
|
+
return project.project
|
|
88
|
+
}
|
|
89
|
+
return project
|
|
90
|
+
})
|
|
85
91
|
}
|
|
86
92
|
|
|
87
93
|
function getProjectsFromDispatcher (dispatcher) {
|
|
@@ -93,13 +99,55 @@ function getProjectsFromDispatcher (dispatcher) {
|
|
|
93
99
|
return dispatcher._loader?.fullConfig()?.projects
|
|
94
100
|
}
|
|
95
101
|
|
|
96
|
-
function getBrowserNameFromProjects (projects,
|
|
97
|
-
if (!projects) {
|
|
102
|
+
function getBrowserNameFromProjects (projects, test) {
|
|
103
|
+
if (!projects || !test) {
|
|
98
104
|
return null
|
|
99
105
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
)
|
|
106
|
+
const { _projectIndex, _projectId: testProjectId } = test
|
|
107
|
+
|
|
108
|
+
if (_projectIndex !== undefined) {
|
|
109
|
+
return projects[_projectIndex]?.name
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return projects.find(({ __projectId, _id, name }) => {
|
|
113
|
+
if (__projectId !== undefined) {
|
|
114
|
+
return __projectId === testProjectId
|
|
115
|
+
}
|
|
116
|
+
if (_id !== undefined) {
|
|
117
|
+
return _id === testProjectId
|
|
118
|
+
}
|
|
119
|
+
return name === testProjectId
|
|
120
|
+
})?.name
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function formatTestHookError (error, hookType, isTimeout) {
|
|
124
|
+
let hookError = error
|
|
125
|
+
if (error) {
|
|
126
|
+
hookError.message = `Error in ${hookType} hook: ${error.message}`
|
|
127
|
+
}
|
|
128
|
+
if (!hookError && isTimeout) {
|
|
129
|
+
hookError = new Error(`${hookType} hook timed out`)
|
|
130
|
+
}
|
|
131
|
+
return hookError
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function addErrorToTestSuite (testSuiteAbsolutePath, error) {
|
|
135
|
+
if (testSuiteToErrors.has(testSuiteAbsolutePath)) {
|
|
136
|
+
testSuiteToErrors.get(testSuiteAbsolutePath).push(error)
|
|
137
|
+
} else {
|
|
138
|
+
testSuiteToErrors.set(testSuiteAbsolutePath, [error])
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function getTestSuiteError (testSuiteAbsolutePath) {
|
|
143
|
+
const errors = testSuiteToErrors.get(testSuiteAbsolutePath)
|
|
144
|
+
if (!errors) {
|
|
145
|
+
return null
|
|
146
|
+
}
|
|
147
|
+
if (errors.length === 1) {
|
|
148
|
+
return errors[0]
|
|
149
|
+
}
|
|
150
|
+
return new Error(`${errors.length} errors in this test suite:\n${errors.map(e => e.message).join('\n------\n')}`)
|
|
103
151
|
}
|
|
104
152
|
|
|
105
153
|
function testBeginHandler (test, browserName) {
|
|
@@ -131,7 +179,7 @@ function testBeginHandler (test, browserName) {
|
|
|
131
179
|
})
|
|
132
180
|
}
|
|
133
181
|
|
|
134
|
-
function testEndHandler (test, annotations, testStatus, error) {
|
|
182
|
+
function testEndHandler (test, annotations, testStatus, error, isTimeout) {
|
|
135
183
|
let annotationTags
|
|
136
184
|
if (annotations.length) {
|
|
137
185
|
annotationTags = parseAnnotations(annotations)
|
|
@@ -139,6 +187,11 @@ function testEndHandler (test, annotations, testStatus, error) {
|
|
|
139
187
|
const { _requireFile: testSuiteAbsolutePath, results, _type } = test
|
|
140
188
|
|
|
141
189
|
if (_type === 'beforeAll' || _type === 'afterAll') {
|
|
190
|
+
const hookError = formatTestHookError(error, _type, isTimeout)
|
|
191
|
+
|
|
192
|
+
if (hookError) {
|
|
193
|
+
addErrorToTestSuite(testSuiteAbsolutePath, hookError)
|
|
194
|
+
}
|
|
142
195
|
return
|
|
143
196
|
}
|
|
144
197
|
|
|
@@ -148,15 +201,20 @@ function testEndHandler (test, annotations, testStatus, error) {
|
|
|
148
201
|
testFinishCh.publish({ testStatus, steps: testResult.steps, error, extraTags: annotationTags })
|
|
149
202
|
})
|
|
150
203
|
|
|
151
|
-
if (
|
|
152
|
-
testSuiteToTestStatuses.set(testSuiteAbsolutePath, [testStatus])
|
|
153
|
-
} else {
|
|
204
|
+
if (testSuiteToTestStatuses.has(testSuiteAbsolutePath)) {
|
|
154
205
|
testSuiteToTestStatuses.get(testSuiteAbsolutePath).push(testStatus)
|
|
206
|
+
} else {
|
|
207
|
+
testSuiteToTestStatuses.set(testSuiteAbsolutePath, [testStatus])
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (error) {
|
|
211
|
+
addErrorToTestSuite(testSuiteAbsolutePath, error)
|
|
155
212
|
}
|
|
156
213
|
|
|
157
214
|
remainingTestsByFile[testSuiteAbsolutePath] = remainingTestsByFile[testSuiteAbsolutePath]
|
|
158
215
|
.filter(currentTest => currentTest !== test)
|
|
159
216
|
|
|
217
|
+
// Last test, we finish the suite
|
|
160
218
|
if (!remainingTestsByFile[testSuiteAbsolutePath].length) {
|
|
161
219
|
const testStatuses = testSuiteToTestStatuses.get(testSuiteAbsolutePath)
|
|
162
220
|
|
|
@@ -167,9 +225,10 @@ function testEndHandler (test, annotations, testStatus, error) {
|
|
|
167
225
|
testSuiteStatus = 'skip'
|
|
168
226
|
}
|
|
169
227
|
|
|
228
|
+
const suiteError = getTestSuiteError(testSuiteAbsolutePath)
|
|
170
229
|
const testSuiteAsyncResource = testSuiteToAr.get(testSuiteAbsolutePath)
|
|
171
230
|
testSuiteAsyncResource.runInAsyncScope(() => {
|
|
172
|
-
testSuiteFinishCh.publish(testSuiteStatus)
|
|
231
|
+
testSuiteFinishCh.publish({ status: testSuiteStatus, error: suiteError })
|
|
173
232
|
})
|
|
174
233
|
}
|
|
175
234
|
}
|
|
@@ -197,7 +256,7 @@ function dispatcherHook (dispatcherExport) {
|
|
|
197
256
|
if (method === 'testBegin') {
|
|
198
257
|
const { test } = dispatcher._testById.get(params.testId)
|
|
199
258
|
const projects = getProjectsFromDispatcher(dispatcher)
|
|
200
|
-
const browser = getBrowserNameFromProjects(projects, test
|
|
259
|
+
const browser = getBrowserNameFromProjects(projects, test)
|
|
201
260
|
testBeginHandler(test, browser)
|
|
202
261
|
} else if (method === 'testEnd') {
|
|
203
262
|
const { test } = dispatcher._testById.get(params.testId)
|
|
@@ -205,7 +264,8 @@ function dispatcherHook (dispatcherExport) {
|
|
|
205
264
|
const { results } = test
|
|
206
265
|
const testResult = results[results.length - 1]
|
|
207
266
|
|
|
208
|
-
|
|
267
|
+
const isTimeout = testResult.status === 'timedOut'
|
|
268
|
+
testEndHandler(test, params.annotations, STATUS_TO_TEST_STATUS[testResult.status], testResult.error, isTimeout)
|
|
209
269
|
}
|
|
210
270
|
})
|
|
211
271
|
|
|
@@ -232,13 +292,14 @@ function dispatcherHookNew (dispatcherExport, runWrapper) {
|
|
|
232
292
|
worker.on('testBegin', ({ testId }) => {
|
|
233
293
|
const test = getTestByTestId(dispatcher, testId)
|
|
234
294
|
const projects = getProjectsFromDispatcher(dispatcher)
|
|
235
|
-
const browser = getBrowserNameFromProjects(projects, test
|
|
295
|
+
const browser = getBrowserNameFromProjects(projects, test)
|
|
236
296
|
testBeginHandler(test, browser)
|
|
237
297
|
})
|
|
238
298
|
worker.on('testEnd', ({ testId, status, errors, annotations }) => {
|
|
239
299
|
const test = getTestByTestId(dispatcher, testId)
|
|
240
300
|
|
|
241
|
-
|
|
301
|
+
const isTimeout = status === 'timedOut'
|
|
302
|
+
testEndHandler(test, annotations, STATUS_TO_TEST_STATUS[status], errors && errors[0], isTimeout)
|
|
242
303
|
})
|
|
243
304
|
|
|
244
305
|
return worker
|
|
@@ -265,7 +326,7 @@ function runnerHook (runnerExport, playwrightVersion) {
|
|
|
265
326
|
// there were tests that did not go through `testBegin` or `testEnd`,
|
|
266
327
|
// because they were skipped
|
|
267
328
|
tests.forEach(test => {
|
|
268
|
-
const browser = getBrowserNameFromProjects(projects, test
|
|
329
|
+
const browser = getBrowserNameFromProjects(projects, test)
|
|
269
330
|
testBeginHandler(test, browser)
|
|
270
331
|
testEndHandler(test, [], 'skip')
|
|
271
332
|
})
|
|
@@ -327,6 +388,7 @@ addHook({
|
|
|
327
388
|
file: 'lib/runner/runner.js',
|
|
328
389
|
versions: ['>=1.38.0']
|
|
329
390
|
}, runnerHook)
|
|
391
|
+
|
|
330
392
|
addHook({
|
|
331
393
|
name: 'playwright',
|
|
332
394
|
file: 'lib/runner/dispatcher.js',
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const { TEXT_MAP } = require('../../../ext/formats')
|
|
4
4
|
const ConsumerPlugin = require('../../dd-trace/src/plugins/consumer')
|
|
5
|
-
const { getAmqpMessageSize
|
|
5
|
+
const { getAmqpMessageSize } = require('../../dd-trace/src/datastreams/processor')
|
|
6
|
+
const { DsmPathwayCodec } = require('../../dd-trace/src/datastreams/pathway')
|
|
6
7
|
const { getResourceName } = require('./util')
|
|
7
8
|
|
|
8
9
|
class AmqplibConsumerPlugin extends ConsumerPlugin {
|
|
@@ -28,10 +29,13 @@ class AmqplibConsumerPlugin extends ConsumerPlugin {
|
|
|
28
29
|
}
|
|
29
30
|
})
|
|
30
31
|
|
|
31
|
-
if (
|
|
32
|
+
if (
|
|
33
|
+
this.config.dsmEnabled && message?.properties?.headers &&
|
|
34
|
+
DsmPathwayCodec.contextExists(message.properties.headers)
|
|
35
|
+
) {
|
|
32
36
|
const payloadSize = getAmqpMessageSize({ headers: message.properties.headers, content: message.content })
|
|
33
|
-
const queue = fields.queue
|
|
34
|
-
this.tracer.decodeDataStreamsContext(message.properties.headers
|
|
37
|
+
const queue = fields.queue ? fields.queue : fields.routingKey
|
|
38
|
+
this.tracer.decodeDataStreamsContext(message.properties.headers)
|
|
35
39
|
this.tracer
|
|
36
40
|
.setCheckpoint(['direction:in', `topic:${queue}`, 'type:rabbitmq'], span, payloadSize)
|
|
37
41
|
}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
const { TEXT_MAP } = require('../../../ext/formats')
|
|
4
4
|
const { CLIENT_PORT_KEY } = require('../../dd-trace/src/constants')
|
|
5
5
|
const ProducerPlugin = require('../../dd-trace/src/plugins/producer')
|
|
6
|
-
const {
|
|
7
|
-
const { getAmqpMessageSize
|
|
6
|
+
const { DsmPathwayCodec } = require('../../dd-trace/src/datastreams/pathway')
|
|
7
|
+
const { getAmqpMessageSize } = require('../../dd-trace/src/datastreams/processor')
|
|
8
8
|
const { getResourceName } = require('./util')
|
|
9
9
|
|
|
10
10
|
class AmqplibProducerPlugin extends ProducerPlugin {
|
|
@@ -40,8 +40,7 @@ class AmqplibProducerPlugin extends ProducerPlugin {
|
|
|
40
40
|
.setCheckpoint(
|
|
41
41
|
['direction:out', `exchange:${fields.exchange}`, `has_routing_key:${hasRoutingKey}`, 'type:rabbitmq']
|
|
42
42
|
, span, payloadSize)
|
|
43
|
-
|
|
44
|
-
fields.headers[CONTEXT_PROPAGATION_KEY] = pathwayCtx
|
|
43
|
+
DsmPathwayCodec.encode(dataStreamsContext, fields.headers)
|
|
45
44
|
}
|
|
46
45
|
}
|
|
47
46
|
}
|
|
@@ -126,8 +126,9 @@ class BaseAwsSdkPlugin extends ClientPlugin {
|
|
|
126
126
|
if (err) {
|
|
127
127
|
span.setTag('error', err)
|
|
128
128
|
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
const requestId = err.RequestId || err.requestId
|
|
130
|
+
if (requestId) {
|
|
131
|
+
span.addTags({ 'aws.response.request_id': requestId })
|
|
131
132
|
}
|
|
132
133
|
}
|
|
133
134
|
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const {
|
|
3
|
-
CONTEXT_PROPAGATION_KEY,
|
|
4
3
|
getSizeOrZero
|
|
5
4
|
} = require('../../../dd-trace/src/datastreams/processor')
|
|
6
|
-
const {
|
|
5
|
+
const { DsmPathwayCodec } = require('../../../dd-trace/src/datastreams/pathway')
|
|
7
6
|
const log = require('../../../dd-trace/src/log')
|
|
8
7
|
const BaseAwsSdkPlugin = require('../base')
|
|
9
8
|
const { storage } = require('../../../datadog-core')
|
|
@@ -53,7 +52,7 @@ class Kinesis extends BaseAwsSdkPlugin {
|
|
|
53
52
|
|
|
54
53
|
// extract DSM context after as we might not have a parent-child but may have a DSM context
|
|
55
54
|
this.responseExtractDSMContext(
|
|
56
|
-
request.operation, response, span
|
|
55
|
+
request.operation, response, span || null, streamName
|
|
57
56
|
)
|
|
58
57
|
}
|
|
59
58
|
})
|
|
@@ -113,13 +112,10 @@ class Kinesis extends BaseAwsSdkPlugin {
|
|
|
113
112
|
const parsedAttributes = JSON.parse(Buffer.from(record.Data).toString())
|
|
114
113
|
|
|
115
114
|
if (
|
|
116
|
-
parsedAttributes &&
|
|
117
|
-
parsedAttributes._datadog &&
|
|
118
|
-
parsedAttributes._datadog[CONTEXT_PROPAGATION_KEY] &&
|
|
119
|
-
streamName
|
|
115
|
+
parsedAttributes?._datadog && streamName && DsmPathwayCodec.contextExists(parsedAttributes._datadog)
|
|
120
116
|
) {
|
|
121
117
|
const payloadSize = getSizeOrZero(record.Data)
|
|
122
|
-
this.tracer.decodeDataStreamsContext(
|
|
118
|
+
this.tracer.decodeDataStreamsContext(parsedAttributes._datadog)
|
|
123
119
|
this.tracer
|
|
124
120
|
.setCheckpoint(['direction:in', `topic:${streamName}`, 'type:kinesis'], span, payloadSize)
|
|
125
121
|
}
|
|
@@ -143,62 +139,69 @@ class Kinesis extends BaseAwsSdkPlugin {
|
|
|
143
139
|
}
|
|
144
140
|
|
|
145
141
|
requestInject (span, request) {
|
|
146
|
-
const operation = request
|
|
147
|
-
if (
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
142
|
+
const { operation, params } = request
|
|
143
|
+
if (!params) return
|
|
144
|
+
|
|
145
|
+
let stream
|
|
146
|
+
switch (operation) {
|
|
147
|
+
case 'putRecord':
|
|
148
|
+
stream = params.StreamArn ? params.StreamArn : (params.StreamName ? params.StreamName : '')
|
|
149
|
+
this.injectToMessage(span, params, stream, true)
|
|
150
|
+
break
|
|
151
|
+
case 'putRecords':
|
|
152
|
+
stream = params.StreamArn ? params.StreamArn : (params.StreamName ? params.StreamName : '')
|
|
153
|
+
for (let i = 0; i < params.Records.length; i++) {
|
|
154
|
+
this.injectToMessage(span, params.Records[i], stream, i === 0)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
injectToMessage (span, params, stream, injectTraceContext) {
|
|
160
|
+
if (!params) {
|
|
161
|
+
return
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
let parsedData
|
|
165
|
+
if (injectTraceContext || this.config.dsmEnabled) {
|
|
166
|
+
parsedData = this._tryParse(params.Data)
|
|
167
|
+
if (!parsedData) {
|
|
168
|
+
log.error('Unable to parse payload, unable to pass trace context or set DSM checkpoint (if enabled)')
|
|
162
169
|
return
|
|
163
170
|
}
|
|
171
|
+
}
|
|
164
172
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
// set DSM hash if enabled
|
|
170
|
-
if (this.config.dsmEnabled) {
|
|
171
|
-
// get payload size of request data
|
|
172
|
-
const payloadSize = Buffer.from(JSON.stringify(parsedData)).byteLength
|
|
173
|
-
let stream
|
|
174
|
-
// users can optionally use either stream name or stream arn
|
|
175
|
-
if (request.params && request.params.StreamArn) {
|
|
176
|
-
stream = request.params.StreamArn
|
|
177
|
-
} else if (request.params && request.params.StreamName) {
|
|
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
|
-
}
|
|
173
|
+
const ddInfo = {}
|
|
174
|
+
// for now, we only want to inject to the first message, this may change for batches in the future
|
|
175
|
+
if (injectTraceContext) { this.tracer.inject(span, 'text_map', ddInfo) }
|
|
187
176
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
177
|
+
// set DSM hash if enabled
|
|
178
|
+
if (this.config.dsmEnabled) {
|
|
179
|
+
parsedData._datadog = ddInfo
|
|
180
|
+
const dataStreamsContext = this.setDSMCheckpoint(span, parsedData, stream)
|
|
181
|
+
DsmPathwayCodec.encode(dataStreamsContext, ddInfo)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (Object.keys(ddInfo).length !== 0) {
|
|
185
|
+
parsedData._datadog = ddInfo
|
|
186
|
+
const finalData = Buffer.from(JSON.stringify(parsedData))
|
|
187
|
+
const byteSize = finalData.length
|
|
188
|
+
// Kinesis max payload size is 1MB
|
|
189
|
+
// So we must ensure adding DD context won't go over that (512b is an estimate)
|
|
190
|
+
if (byteSize >= 1048576) {
|
|
191
|
+
log.info('Payload size too large to pass context')
|
|
192
|
+
return
|
|
199
193
|
}
|
|
194
|
+
params.Data = finalData
|
|
200
195
|
}
|
|
201
196
|
}
|
|
197
|
+
|
|
198
|
+
setDSMCheckpoint (span, parsedData, stream) {
|
|
199
|
+
// get payload size of request data
|
|
200
|
+
const payloadSize = Buffer.from(JSON.stringify(parsedData)).byteLength
|
|
201
|
+
const dataStreamsContext = this.tracer
|
|
202
|
+
.setCheckpoint(['direction:out', `topic:${stream}`, 'type:kinesis'], span, payloadSize)
|
|
203
|
+
return dataStreamsContext
|
|
204
|
+
}
|
|
202
205
|
}
|
|
203
206
|
|
|
204
207
|
module.exports = Kinesis
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
-
const {
|
|
3
|
-
const {
|
|
2
|
+
const { getHeadersSize } = require('../../../dd-trace/src/datastreams/processor')
|
|
3
|
+
const { DsmPathwayCodec } = require('../../../dd-trace/src/datastreams/pathway')
|
|
4
4
|
const log = require('../../../dd-trace/src/log')
|
|
5
5
|
const BaseAwsSdkPlugin = require('../base')
|
|
6
6
|
|
|
@@ -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,47 @@ 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
|
-
.setCheckpoint(['direction:out', `topic:${params.TopicArn}`, 'type:sns'], span, payloadSize)
|
|
90
|
-
if (dataStreamsContext) {
|
|
91
|
-
const pathwayCtx = encodePathwayContext(dataStreamsContext)
|
|
92
|
-
ddInfo[CONTEXT_PROPAGATION_KEY] = pathwayCtx.toJSON()
|
|
89
|
+
if (!params.MessageAttributes._datadog) {
|
|
90
|
+
params.MessageAttributes._datadog = {
|
|
91
|
+
DataType: 'Binary',
|
|
92
|
+
BinaryValue: ddInfo
|
|
93
|
+
}
|
|
93
94
|
}
|
|
95
|
+
|
|
96
|
+
const dataStreamsContext = this.setDSMCheckpoint(span, params, topicArn)
|
|
97
|
+
DsmPathwayCodec.encode(dataStreamsContext, ddInfo)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (Object.keys(ddInfo).length !== 0) {
|
|
101
|
+
// BINARY types are automatically base64 encoded
|
|
102
|
+
params.MessageAttributes._datadog.BinaryValue = Buffer.from(JSON.stringify(ddInfo))
|
|
103
|
+
} else if (params.MessageAttributes._datadog) {
|
|
104
|
+
// let's avoid adding any additional information to payload if we failed to inject
|
|
105
|
+
delete params.MessageAttributes._datadog
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
setDSMCheckpoint (span, params, topicArn) {
|
|
110
|
+
// only set a checkpoint if publishing to a topic
|
|
111
|
+
if (topicArn) {
|
|
112
|
+
const payloadSize = getHeadersSize(params)
|
|
113
|
+
const dataStreamsContext = this.tracer
|
|
114
|
+
.setCheckpoint(['direction:out', `topic:${topicArn}`, 'type:sns'], span, payloadSize)
|
|
115
|
+
return dataStreamsContext
|
|
94
116
|
}
|
|
95
|
-
// BINARY types are automatically base64 encoded
|
|
96
|
-
params.MessageAttributes._datadog.BinaryValue = Buffer.from(JSON.stringify(ddInfo))
|
|
97
117
|
}
|
|
98
118
|
}
|
|
99
119
|
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
const log = require('../../../dd-trace/src/log')
|
|
4
4
|
const BaseAwsSdkPlugin = require('../base')
|
|
5
5
|
const { storage } = require('../../../datadog-core')
|
|
6
|
-
const {
|
|
7
|
-
const {
|
|
6
|
+
const { getHeadersSize } = require('../../../dd-trace/src/datastreams/processor')
|
|
7
|
+
const { DsmPathwayCodec } = require('../../../dd-trace/src/datastreams/pathway')
|
|
8
8
|
|
|
9
9
|
class Sqs extends BaseAwsSdkPlugin {
|
|
10
10
|
static get id () { return 'sqs' }
|
|
@@ -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
|
|
|
@@ -192,13 +192,13 @@ class Sqs extends BaseAwsSdkPlugin {
|
|
|
192
192
|
parsedAttributes = this.parseDatadogAttributes(message.MessageAttributes._datadog)
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
|
-
if (parsedAttributes && parsedAttributes
|
|
195
|
+
if (parsedAttributes && DsmPathwayCodec.contextExists(parsedAttributes)) {
|
|
196
196
|
const payloadSize = getHeadersSize({
|
|
197
197
|
Body: message.Body,
|
|
198
198
|
MessageAttributes: message.MessageAttributes
|
|
199
199
|
})
|
|
200
200
|
const queue = params.QueueUrl.split('/').pop()
|
|
201
|
-
this.tracer.decodeDataStreamsContext(
|
|
201
|
+
this.tracer.decodeDataStreamsContext(parsedAttributes)
|
|
202
202
|
this.tracer
|
|
203
203
|
.setCheckpoint(['direction:in', `topic:${queue}`, 'type:sqs'], span, payloadSize)
|
|
204
204
|
}
|
|
@@ -206,39 +206,73 @@ 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
|
+
DsmPathwayCodec.encode(dataStreamsContext, ddInfo)
|
|
256
|
+
params.MessageAttributes._datadog.StringValue = JSON.stringify(ddInfo)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (params.MessageAttributes._datadog && Object.keys(ddInfo).length === 0) {
|
|
261
|
+
// let's avoid adding any additional information to payload if we failed to inject
|
|
262
|
+
delete params.MessageAttributes._datadog
|
|
240
263
|
}
|
|
241
264
|
}
|
|
265
|
+
|
|
266
|
+
setDSMCheckpoint (span, params, queueUrl) {
|
|
267
|
+
const payloadSize = getHeadersSize({
|
|
268
|
+
Body: params.MessageBody,
|
|
269
|
+
MessageAttributes: params.MessageAttributes
|
|
270
|
+
})
|
|
271
|
+
const queue = queueUrl.split('/').pop()
|
|
272
|
+
const dataStreamsContext = this.tracer
|
|
273
|
+
.setCheckpoint(['direction:out', `topic:${queue}`, 'type:sqs'], span, payloadSize)
|
|
274
|
+
return dataStreamsContext
|
|
275
|
+
}
|
|
242
276
|
}
|
|
243
277
|
|
|
244
278
|
module.exports = Sqs
|