dd-trace 3.13.2 → 3.14.1

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.
Files changed (39) hide show
  1. package/ci/init.js +2 -1
  2. package/index.d.ts +20 -0
  3. package/package.json +1 -1
  4. package/packages/datadog-instrumentations/src/aws-sdk.js +86 -0
  5. package/packages/datadog-instrumentations/src/cucumber.js +74 -15
  6. package/packages/datadog-instrumentations/src/cypress.js +1 -1
  7. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  8. package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
  9. package/packages/datadog-instrumentations/src/jest.js +24 -33
  10. package/packages/datadog-instrumentations/src/mocha.js +4 -7
  11. package/packages/datadog-instrumentations/src/playwright.js +2 -4
  12. package/packages/datadog-plugin-aws-sdk/src/base.js +12 -5
  13. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -2
  14. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +29 -24
  15. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +31 -16
  16. package/packages/datadog-plugin-cucumber/src/index.js +42 -11
  17. package/packages/datadog-plugin-cypress/src/plugin.js +129 -4
  18. package/packages/datadog-plugin-cypress/src/support.js +5 -0
  19. package/packages/datadog-plugin-hapi/src/index.js +5 -1
  20. package/packages/datadog-plugin-jest/src/index.js +18 -67
  21. package/packages/datadog-plugin-mocha/src/index.js +35 -84
  22. package/packages/datadog-plugin-playwright/src/index.js +2 -61
  23. package/packages/datadog-shimmer/src/shimmer.js +28 -11
  24. package/packages/dd-trace/src/appsec/reporter.js +14 -14
  25. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +1 -5
  26. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +1 -5
  27. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +32 -10
  28. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +1 -1
  29. package/packages/dd-trace/src/config.js +55 -6
  30. package/packages/dd-trace/src/encode/0.4.js +1 -1
  31. package/packages/dd-trace/src/encode/0.5.js +1 -1
  32. package/packages/dd-trace/src/encode/tags-processors.js +3 -2
  33. package/packages/dd-trace/src/opentracing/propagation/text_map.js +188 -36
  34. package/packages/dd-trace/src/opentracing/propagation/tracestate.js +99 -0
  35. package/packages/dd-trace/src/opentracing/span.js +2 -1
  36. package/packages/dd-trace/src/opentracing/span_context.js +5 -2
  37. package/packages/dd-trace/src/plugins/ci_plugin.js +69 -12
  38. package/packages/dd-trace/src/plugins/index.js +1 -0
  39. package/packages/dd-trace/src/telemetry/send-data.js +4 -1
package/ci/init.js CHANGED
@@ -8,7 +8,8 @@ const options = {
8
8
  tags: {
9
9
  [ORIGIN_KEY]: 'ciapp-test'
10
10
  },
11
- isCiVisibility: true
11
+ isCiVisibility: true,
12
+ flushInterval: 5000
12
13
  }
13
14
 
14
15
  let shouldInit = true
package/index.d.ts CHANGED
@@ -221,6 +221,21 @@ export declare interface SpanSamplingRule {
221
221
  name?: string
222
222
  }
223
223
 
224
+ /**
225
+ * Selection and priority order of context propagation injection and extraction mechanisms.
226
+ */
227
+ export declare interface PropagationStyle {
228
+ /**
229
+ * Selection of context propagation injection mechanisms.
230
+ */
231
+ inject: string[],
232
+
233
+ /**
234
+ * Selection and priority order of context propagation extraction mechanisms.
235
+ */
236
+ extract: string[]
237
+ }
238
+
224
239
  /**
225
240
  * List of options available to the tracer.
226
241
  */
@@ -550,6 +565,11 @@ export declare interface TracerOptions {
550
565
  * Custom header name to source the http.client_ip tag from.
551
566
  */
552
567
  clientIpHeader?: string,
568
+
569
+ /**
570
+ * The selection and priority order of context propagation injection and extraction mechanisms.
571
+ */
572
+ propagationStyle?: string[] | PropagationStyle
553
573
  }
554
574
 
555
575
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "3.13.2",
3
+ "version": "3.14.1",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -39,6 +39,77 @@ function wrapRequest (send) {
39
39
  }
40
40
  }
41
41
 
42
+ function wrapSmithySend (send) {
43
+ return function (command, ...args) {
44
+ const cb = args[args.length - 1]
45
+ const innerAr = new AsyncResource('apm:aws:request:inner')
46
+ const outerAr = new AsyncResource('apm:aws:request:outer')
47
+ const serviceIdentifier = this.config.serviceId.toLowerCase()
48
+ const channelSuffix = getChannelSuffix(serviceIdentifier)
49
+ const commandName = command.constructor.name
50
+ const clientName = this.constructor.name.replace(/Client$/, '')
51
+ const operation = `${commandName[0].toLowerCase()}${commandName.slice(1).replace(/Command$/, '')}`
52
+ const request = {
53
+ operation,
54
+ params: command.input
55
+ }
56
+
57
+ const startCh = channel(`apm:aws:request:start:${channelSuffix}`)
58
+ const regionCh = channel(`apm:aws:request:region:${channelSuffix}`)
59
+ const completeChannel = channel(`apm:aws:request:complete:${channelSuffix}`)
60
+ const responseStartChannel = channel(`apm:aws:response:start:${channelSuffix}`)
61
+ const responseFinishChannel = channel(`apm:aws:response:finish:${channelSuffix}`)
62
+
63
+ return innerAr.runInAsyncScope(() => {
64
+ startCh.publish({
65
+ serviceIdentifier,
66
+ operation,
67
+ awsService: clientName,
68
+ request
69
+ })
70
+
71
+ // When the region is not set this never resolves so we can't await.
72
+ this.config.region().then(region => {
73
+ regionCh.publish(region)
74
+ })
75
+
76
+ if (typeof cb === 'function') {
77
+ args[args.length - 1] = function (err, result) {
78
+ const message = getMessage(request, err, result)
79
+
80
+ completeChannel.publish(message)
81
+
82
+ outerAr.runInAsyncScope(() => {
83
+ responseStartChannel.publish(message)
84
+
85
+ cb.apply(this, arguments)
86
+
87
+ if (message.needsFinish) {
88
+ responseFinishChannel.publish(message.response.error)
89
+ }
90
+ })
91
+ }
92
+ } else { // always a promise
93
+ return send.call(this, command, ...args)
94
+ .then(
95
+ result => {
96
+ const message = getMessage(request, null, result)
97
+ completeChannel.publish(message)
98
+ return result
99
+ },
100
+ error => {
101
+ const message = getMessage(request, error)
102
+ completeChannel.publish(message)
103
+ throw error
104
+ }
105
+ )
106
+ }
107
+
108
+ return send.call(this, command, ...args)
109
+ })
110
+ }
111
+ }
112
+
42
113
  function wrapCb (cb, serviceName, request, ar) {
43
114
  return function wrappedCb (err, response) {
44
115
  const obj = { request, response }
@@ -71,6 +142,16 @@ function wrapCb (cb, serviceName, request, ar) {
71
142
  }
72
143
  }
73
144
 
145
+ function getMessage (request, error, result) {
146
+ const response = { request, error, ...result }
147
+
148
+ if (result && result.$metadata) {
149
+ response.requestId = result.$metadata.requestId
150
+ }
151
+
152
+ return { request, response }
153
+ }
154
+
74
155
  function getChannelSuffix (name) {
75
156
  return [
76
157
  'cloudwatchlogs',
@@ -85,6 +166,11 @@ function getChannelSuffix (name) {
85
166
  ].includes(name) ? name : 'default'
86
167
  }
87
168
 
169
+ addHook({ name: '@aws-sdk/smithy-client', versions: ['>=3'] }, smithy => {
170
+ shimmer.wrap(smithy.Client.prototype, 'send', wrapSmithySend)
171
+ return smithy
172
+ })
173
+
88
174
  addHook({ name: 'aws-sdk', versions: ['>=2.3.0'] }, AWS => {
89
175
  shimmer.wrap(AWS.Request.prototype, 'promise', wrapRequest)
90
176
  shimmer.wrap(AWS.config, 'setPromisesDependency', setPromisesDependency => {
@@ -3,15 +3,35 @@
3
3
  const { addHook, channel, AsyncResource } = require('./helpers/instrument')
4
4
  const shimmer = require('../../datadog-shimmer')
5
5
 
6
- const runStartCh = channel('ci:cucumber:run:start')
7
- const runFinishCh = channel('ci:cucumber:run:finish')
8
- const runStepStartCh = channel('ci:cucumber:run-step:start')
6
+ const testStartCh = channel('ci:cucumber:test:start')
7
+ const testFinishCh = channel('ci:cucumber:test:finish') // used for test steps too
8
+
9
+ const testStepStartCh = channel('ci:cucumber:test-step:start')
10
+
9
11
  const errorCh = channel('ci:cucumber:error')
12
+
13
+ const testSuiteStartCh = channel('ci:cucumber:test-suite:start')
14
+ const testSuiteFinishCh = channel('ci:cucumber:test-suite:finish')
15
+
16
+ const sessionStartCh = channel('ci:cucumber:session:start')
10
17
  const sessionFinishCh = channel('ci:cucumber:session:finish')
11
18
 
12
19
  // TODO: remove in a later major version
13
20
  const patched = new WeakSet()
14
21
 
22
+ let pickleByFile = {}
23
+ const pickleResultByFile = {}
24
+
25
+ function getSuiteStatusFromTestStatuses (testStatuses) {
26
+ if (testStatuses.some(status => status === 'fail')) {
27
+ return 'fail'
28
+ }
29
+ if (testStatuses.every(status => status === 'skip')) {
30
+ return 'skip'
31
+ }
32
+ return 'pass'
33
+ }
34
+
15
35
  function getStatusFromResult (result) {
16
36
  if (result.status === 1) {
17
37
  return { status: 'pass' }
@@ -44,13 +64,18 @@ function wrapRun (pl, isLatestVersion) {
44
64
  patched.add(pl)
45
65
 
46
66
  shimmer.wrap(pl.prototype, 'run', run => function () {
47
- if (!runStartCh.hasSubscribers) {
67
+ if (!testStartCh.hasSubscribers) {
48
68
  return run.apply(this, arguments)
49
69
  }
50
70
 
51
71
  const asyncResource = new AsyncResource('bound-anonymous-fn')
52
72
  return asyncResource.runInAsyncScope(() => {
53
- runStartCh.publish({ testName: this.pickle.name, fullTestSuite: this.pickle.uri })
73
+ const testSuiteFullPath = this.pickle.uri
74
+
75
+ if (!pickleResultByFile[testSuiteFullPath]) { // first test in suite
76
+ testSuiteStartCh.publish(testSuiteFullPath)
77
+ }
78
+ testStartCh.publish({ testName: this.pickle.name, fullTestSuite: testSuiteFullPath })
54
79
  try {
55
80
  const promise = run.apply(this, arguments)
56
81
  promise.finally(() => {
@@ -58,7 +83,17 @@ function wrapRun (pl, isLatestVersion) {
58
83
  const { status, skipReason, errorMessage } = isLatestVersion
59
84
  ? getStatusFromResultLatest(result) : getStatusFromResult(result)
60
85
 
61
- runFinishCh.publish({ status, skipReason, errorMessage })
86
+ if (!pickleResultByFile[testSuiteFullPath]) {
87
+ pickleResultByFile[testSuiteFullPath] = [status]
88
+ } else {
89
+ pickleResultByFile[testSuiteFullPath].push(status)
90
+ }
91
+ // last test in suite
92
+ if (pickleResultByFile[testSuiteFullPath].length === pickleByFile[testSuiteFullPath].length) {
93
+ const testSuiteStatus = getSuiteStatusFromTestStatuses(pickleResultByFile[testSuiteFullPath])
94
+ testSuiteFinishCh.publish(testSuiteStatus)
95
+ }
96
+ testFinishCh.publish({ status, skipReason, errorMessage })
62
97
  })
63
98
  return promise
64
99
  } catch (err) {
@@ -68,7 +103,7 @@ function wrapRun (pl, isLatestVersion) {
68
103
  })
69
104
  })
70
105
  shimmer.wrap(pl.prototype, 'runStep', runStep => function () {
71
- if (!runStepStartCh.hasSubscribers) {
106
+ if (!testStepStartCh.hasSubscribers) {
72
107
  return runStep.apply(this, arguments)
73
108
  }
74
109
  const testStep = arguments[0]
@@ -82,7 +117,7 @@ function wrapRun (pl, isLatestVersion) {
82
117
 
83
118
  const asyncResource = new AsyncResource('bound-anonymous-fn')
84
119
  return asyncResource.runInAsyncScope(() => {
85
- runStepStartCh.publish({ resource })
120
+ testStepStartCh.publish({ resource })
86
121
  try {
87
122
  const promise = runStep.apply(this, arguments)
88
123
 
@@ -90,7 +125,7 @@ function wrapRun (pl, isLatestVersion) {
90
125
  const { status, skipReason, errorMessage } = isLatestVersion
91
126
  ? getStatusFromResultLatest(result) : getStatusFromResult(result)
92
127
 
93
- runFinishCh.publish({ isStep: true, status, skipReason, errorMessage })
128
+ testFinishCh.publish({ isStep: true, status, skipReason, errorMessage })
94
129
  })
95
130
  return promise
96
131
  } catch (err) {
@@ -129,16 +164,40 @@ addHook({
129
164
  file: 'lib/runtime/test_case_runner.js'
130
165
  }, testCaseHook)
131
166
 
167
+ function getPickleByFile (runtime) {
168
+ return runtime.pickleIds.reduce((acc, pickleId) => {
169
+ const test = runtime.eventDataCollector.getPickle(pickleId)
170
+ if (acc[test.uri]) {
171
+ acc[test.uri].push(test)
172
+ } else {
173
+ acc[test.uri] = [test]
174
+ }
175
+ return acc
176
+ }, {})
177
+ }
178
+
132
179
  addHook({
133
180
  name: '@cucumber/cucumber',
134
181
  versions: ['>=7.0.0'],
135
182
  file: 'lib/runtime/index.js'
136
- }, (Runtime) => {
137
- shimmer.wrap(Runtime.default.prototype, 'start', start => async function () {
138
- const result = await start.apply(this, arguments)
139
- sessionFinishCh.publish(undefined)
140
- return result
183
+ }, (runtimePackage, cucumberVersion) => {
184
+ shimmer.wrap(runtimePackage.default.prototype, 'start', start => async function () {
185
+ pickleByFile = getPickleByFile(this)
186
+
187
+ const processArgv = process.argv.slice(2).join(' ')
188
+ const command = process.env.npm_lifecycle_script || `cucumber-js ${processArgv}`
189
+
190
+ const asyncResource = new AsyncResource('bound-anonymous-fn')
191
+ asyncResource.runInAsyncScope(() => {
192
+ sessionStartCh.publish({ command, frameworkVersion: cucumberVersion })
193
+ })
194
+ const success = await start.apply(this, arguments)
195
+
196
+ asyncResource.runInAsyncScope(() => {
197
+ sessionFinishCh.publish(success ? 'pass' : 'fail')
198
+ })
199
+ return success
141
200
  })
142
201
 
143
- return Runtime
202
+ return runtimePackage
144
203
  })
@@ -5,4 +5,4 @@ const { addHook } = require('./helpers/instrument')
5
5
  addHook({
6
6
  name: 'cypress',
7
7
  versions: ['>=6.7.0']
8
- })
8
+ }, lib => lib)
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  module.exports = {
4
+ '@aws-sdk/smithy-client': () => require('../aws-sdk'),
4
5
  '@cucumber/cucumber': () => require('../cucumber'),
5
6
  '@playwright/test': () => require('../playwright'),
6
7
  '@elastic/elasticsearch': () => require('../elasticsearch'),
@@ -32,7 +32,7 @@ for (const packageName of names) {
32
32
  try {
33
33
  loadChannel.publish({ name, version, file })
34
34
 
35
- moduleExports = hook(moduleExports)
35
+ moduleExports = hook(moduleExports, version)
36
36
  } catch (e) {
37
37
  log.error(e)
38
38
  }
@@ -72,7 +72,7 @@ function getTestEnvironmentOptions (config) {
72
72
  return {}
73
73
  }
74
74
 
75
- function getWrappedEnvironment (BaseEnvironment) {
75
+ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
76
76
  return class DatadogEnvironment extends BaseEnvironment {
77
77
  constructor (config, context) {
78
78
  super(config, context)
@@ -116,7 +116,8 @@ function getWrappedEnvironment (BaseEnvironment) {
116
116
  name: getJestTestName(event.test),
117
117
  suite: this.testSuite,
118
118
  runner: 'jest-circus',
119
- testParameters
119
+ testParameters,
120
+ frameworkVersion: jestVersion
120
121
  })
121
122
  originalTestFns.set(event.test, event.test.fn)
122
123
  event.test.fn = asyncResource.bind(event.test.fn)
@@ -142,7 +143,8 @@ function getWrappedEnvironment (BaseEnvironment) {
142
143
  testSkippedCh.publish({
143
144
  name: getJestTestName(event.test),
144
145
  suite: this.testSuite,
145
- runner: 'jest-circus'
146
+ runner: 'jest-circus',
147
+ frameworkVersion: jestVersion
146
148
  })
147
149
  })
148
150
  }
@@ -150,14 +152,14 @@ function getWrappedEnvironment (BaseEnvironment) {
150
152
  }
151
153
  }
152
154
 
153
- function getTestEnvironment (pkg) {
155
+ function getTestEnvironment (pkg, jestVersion) {
154
156
  if (pkg.default) {
155
- const wrappedTestEnvironment = getWrappedEnvironment(pkg.default)
157
+ const wrappedTestEnvironment = getWrappedEnvironment(pkg.default, jestVersion)
156
158
  pkg.default = wrappedTestEnvironment
157
159
  pkg.TestEnvironment = wrappedTestEnvironment
158
160
  return pkg
159
161
  }
160
- return getWrappedEnvironment(pkg)
162
+ return getWrappedEnvironment(pkg, jestVersion)
161
163
  }
162
164
 
163
165
  addHook({
@@ -170,7 +172,7 @@ addHook({
170
172
  versions: ['>=24.8.0']
171
173
  }, getTestEnvironment)
172
174
 
173
- function cliWrapper (cli) {
175
+ function cliWrapper (cli, jestVersion) {
174
176
  const wrapped = shimmer.wrap(cli, 'runCLI', runCLI => async function () {
175
177
  let onDone
176
178
  const configurationPromise = new Promise((resolve) => {
@@ -186,13 +188,12 @@ function cliWrapper (cli) {
186
188
 
187
189
  try {
188
190
  const { err, itrConfig } = await configurationPromise
189
- if (err) {
190
- log.error(err)
191
+ if (!err) {
192
+ isCodeCoverageEnabled = itrConfig.isCodeCoverageEnabled
193
+ isSuitesSkippingEnabled = itrConfig.isSuitesSkippingEnabled
191
194
  }
192
- isCodeCoverageEnabled = itrConfig.isCodeCoverageEnabled
193
- isSuitesSkippingEnabled = itrConfig.isSuitesSkippingEnabled
194
- } catch (e) {
195
- log.error(e)
195
+ } catch (err) {
196
+ log.error(err)
196
197
  }
197
198
 
198
199
  if (isSuitesSkippingEnabled) {
@@ -206,31 +207,19 @@ function cliWrapper (cli) {
206
207
 
207
208
  try {
208
209
  const { err, skippableSuites: receivedSkippableSuites } = await skippableSuitesPromise
209
- if (err) {
210
- log.error(err)
211
- } else {
210
+ if (!err) {
212
211
  skippableSuites = receivedSkippableSuites
213
212
  }
214
- } catch (e) {
215
- log.error(e)
213
+ } catch (err) {
214
+ log.error(err)
216
215
  }
217
216
  }
218
217
 
219
218
  const isSuitesSkipped = !!skippableSuites.length
220
219
 
221
- let testFrameworkVersion
222
- try {
223
- testFrameworkVersion = this.getVersion()
224
- } catch (e) {
225
- try {
226
- testFrameworkVersion = this.default.getVersion()
227
- } catch (e) {
228
- // ignore errors
229
- }
230
- }
231
220
  const processArgv = process.argv.slice(2).join(' ')
232
221
  sessionAsyncResource.runInAsyncScope(() => {
233
- testSessionStartCh.publish({ command: `jest ${processArgv}`, testFrameworkVersion })
222
+ testSessionStartCh.publish({ command: `jest ${processArgv}`, frameworkVersion: jestVersion })
234
223
  })
235
224
 
236
225
  const result = await runCLI.apply(this, arguments)
@@ -298,7 +287,7 @@ addHook({
298
287
  versions: ['>=24.8.0']
299
288
  }, cliWrapper)
300
289
 
301
- function jestAdapterWrapper (jestAdapter) {
290
+ function jestAdapterWrapper (jestAdapter, jestVersion) {
302
291
  const adapter = jestAdapter.default ? jestAdapter.default : jestAdapter
303
292
  const newAdapter = shimmer.wrap(adapter, function () {
304
293
  const environment = arguments[2]
@@ -309,7 +298,8 @@ function jestAdapterWrapper (jestAdapter) {
309
298
  return asyncResource.runInAsyncScope(() => {
310
299
  testSuiteStartCh.publish({
311
300
  testSuite: environment.testSuite,
312
- testEnvironmentOptions: environment.testEnvironmentOptions
301
+ testEnvironmentOptions: environment.testEnvironmentOptions,
302
+ frameworkVersion: jestVersion
313
303
  })
314
304
  return adapter.apply(this, arguments).then(suiteResults => {
315
305
  const { numFailingTests, skipped, failureMessage: errorMessage } = suiteResults
@@ -450,7 +440,7 @@ addHook({
450
440
  versions: ['24.8.0 - 24.9.0']
451
441
  }, jestConfigSyncWrapper)
452
442
 
453
- function jasmineAsyncInstallWraper (jasmineAsyncInstallExport) {
443
+ function jasmineAsyncInstallWraper (jasmineAsyncInstallExport, jestVersion) {
454
444
  return function (globalConfig, globalInput) {
455
445
  globalInput._ddtrace = global._ddtrace
456
446
  shimmer.wrap(globalInput.jasmine.Spec.prototype, 'execute', execute => function (onComplete) {
@@ -460,7 +450,8 @@ function jasmineAsyncInstallWraper (jasmineAsyncInstallExport) {
460
450
  testStartCh.publish({
461
451
  name: this.getFullName(),
462
452
  suite: testSuite,
463
- runner: 'jest-jasmine2'
453
+ runner: 'jest-jasmine2',
454
+ frameworkVersion: jestVersion
464
455
  })
465
456
  const spec = this
466
457
  const callback = asyncResource.bind(function () {
@@ -2,7 +2,6 @@ const { createCoverageMap } = require('istanbul-lib-coverage')
2
2
 
3
3
  const { addHook, channel, AsyncResource } = require('./helpers/instrument')
4
4
  const shimmer = require('../../datadog-shimmer')
5
- const log = require('../../dd-trace/src/log')
6
5
  const {
7
6
  getCoveredFilenamesFromCoverage,
8
7
  resetCoverage,
@@ -39,7 +38,7 @@ const testFileToSuiteAr = new Map()
39
38
  const originalCoverageMap = createCoverageMap()
40
39
 
41
40
  let suitesToSkip = []
42
- let mochaVersion
41
+ let frameworkVersion
43
42
 
44
43
  function getSuitesByTestFile (root) {
45
44
  const suitesByTestFile = {}
@@ -129,7 +128,7 @@ function mochaHook (Runner) {
129
128
  this.once('start', testRunAsyncResource.bind(function () {
130
129
  const processArgv = process.argv.slice(2).join(' ')
131
130
  const command = `mocha ${processArgv}`
132
- testSessionStartCh.publish({ command, frameworkVersion: mochaVersion })
131
+ testSessionStartCh.publish({ command, frameworkVersion })
133
132
  }))
134
133
 
135
134
  this.on('suite', function (suite) {
@@ -314,14 +313,14 @@ addHook({
314
313
  name: 'mocha',
315
314
  versions: ['>=5.2.0'],
316
315
  file: 'lib/mocha.js'
317
- }, (Mocha) => {
316
+ }, (Mocha, mochaVersion) => {
317
+ frameworkVersion = mochaVersion
318
318
  const mochaRunAsyncResource = new AsyncResource('bound-anonymous-fn')
319
319
  /**
320
320
  * Get ITR configuration and skippable suites
321
321
  * If ITR is disabled, `onDone` is called immediately on the subscriber
322
322
  */
323
323
  shimmer.wrap(Mocha.prototype, 'run', run => function () {
324
- mochaVersion = this.version
325
324
  if (!itrConfigurationCh.hasSubscribers) {
326
325
  return run.apply(this, arguments)
327
326
  }
@@ -331,7 +330,6 @@ addHook({
331
330
 
332
331
  const onReceivedSkippableSuites = ({ err, skippableSuites }) => {
333
332
  if (err) {
334
- log.error(err)
335
333
  suitesToSkip = []
336
334
  } else {
337
335
  suitesToSkip = skippableSuites
@@ -343,7 +341,6 @@ addHook({
343
341
 
344
342
  const onReceivedConfiguration = ({ err }) => {
345
343
  if (err) {
346
- log.error(err)
347
344
  return global.run()
348
345
  }
349
346
  if (!skippableSuitesCh.hasSubscribers) {
@@ -181,17 +181,15 @@ function dispatcherHookNew (dispatcherExport) {
181
181
  return dispatcherExport
182
182
  }
183
183
 
184
- function runnerHook (runnerExport) {
184
+ function runnerHook (runnerExport, playwrightVersion) {
185
185
  shimmer.wrap(runnerExport.Runner.prototype, 'runAllTests', runAllTests => async function () {
186
186
  const testSessionAsyncResource = new AsyncResource('bound-anonymous-fn')
187
- const { version: frameworkVersion } = getPlaywrightConfig(this)
188
-
189
187
  const rootDir = getRootDir(this)
190
188
 
191
189
  const processArgv = process.argv.slice(2).join(' ')
192
190
  const command = `playwright ${processArgv}`
193
191
  testSessionAsyncResource.runInAsyncScope(() => {
194
- testSessionStartCh.publish({ command, frameworkVersion, rootDir })
192
+ testSessionStartCh.publish({ command, frameworkVersion: playwrightVersion, rootDir })
195
193
  })
196
194
 
197
195
  const res = await runAllTests.apply(this, arguments)
@@ -23,13 +23,12 @@ class BaseAwsSdkPlugin extends Plugin {
23
23
  request,
24
24
  operation,
25
25
  awsRegion,
26
- awsService,
27
- serviceIdentifier
26
+ awsService
28
27
  }) => {
29
28
  if (!this.isEnabled(request)) {
30
29
  return
31
30
  }
32
- const serviceName = this.getServiceName(serviceIdentifier)
31
+ const serviceName = this.getServiceName()
33
32
  const childOf = this.tracer.scope().active()
34
33
  const tags = {
35
34
  'span.kind': 'client',
@@ -52,6 +51,14 @@ class BaseAwsSdkPlugin extends Plugin {
52
51
  this.enter(span, store)
53
52
  })
54
53
 
54
+ this.addSub(`apm:aws:request:region:${this.serviceIdentifier}`, region => {
55
+ const store = storage.getStore()
56
+ if (!store) return
57
+ const { span } = store
58
+ if (!span) return
59
+ span.setTag('aws.region', region)
60
+ })
61
+
55
62
  this.addSub(`apm:aws:request:complete:${this.serviceIdentifier}`, ({ response }) => {
56
63
  const store = storage.getStore()
57
64
  if (!store) return
@@ -109,10 +116,10 @@ class BaseAwsSdkPlugin extends Plugin {
109
116
  }
110
117
 
111
118
  // TODO: test splitByAwsService when the test suite is fixed
112
- getServiceName (serviceIdentifier) {
119
+ getServiceName () {
113
120
  return this.config.service
114
121
  ? this.config.service
115
- : `${this.tracer._service}-aws-${serviceIdentifier}`
122
+ : `${this.tracer._service}-aws-${this.serviceIdentifier}`
116
123
  }
117
124
  }
118
125
 
@@ -48,8 +48,8 @@ class Kinesis extends BaseAwsSdkPlugin {
48
48
  const parsedData = this._tryParse(injectPath.Data)
49
49
  if (parsedData) {
50
50
  parsedData._datadog = traceData
51
- const finalData = JSON.stringify(parsedData)
52
- const byteSize = Buffer.byteLength(finalData, 'ascii')
51
+ const finalData = Buffer.from(JSON.stringify(parsedData))
52
+ const byteSize = finalData.length
53
53
  // Kinesis max payload size is 1MB
54
54
  // So we must ensure adding DD context won't go over that (512b is an estimate)
55
55
  if (byteSize >= 1048576) {
@@ -18,30 +18,35 @@ class Sns extends BaseAwsSdkPlugin {
18
18
  }
19
19
 
20
20
  requestInject (span, request) {
21
- const operation = request.operation
22
- if (operation === 'publish' || operation === 'publishBatch') {
23
- if (!request.params) {
24
- request.params = {}
25
- }
26
- let injectPath
27
- if (request.params.PublishBatchRequestEntries && request.params.PublishBatchRequestEntries.length > 0) {
28
- injectPath = request.params.PublishBatchRequestEntries[0]
29
- } else if (request.params.Message) {
30
- injectPath = request.params
31
- }
32
- if (!injectPath.MessageAttributes) {
33
- injectPath.MessageAttributes = {}
34
- }
35
- if (Object.keys(injectPath.MessageAttributes).length >= 10) { // SNS quota
36
- log.info('Message attributes full, skipping trace context injection')
37
- return
38
- }
39
- const ddInfo = {}
40
- this.tracer.inject(span, 'text_map', ddInfo)
41
- injectPath.MessageAttributes._datadog = {
42
- DataType: 'Binary',
43
- BinaryValue: JSON.stringify(ddInfo) // BINARY types are automatically base64 encoded
44
- }
21
+ const { operation, params } = request
22
+
23
+ if (!params) return
24
+
25
+ switch (operation) {
26
+ case 'publish':
27
+ this._injectMessageAttributes(span, params)
28
+ break
29
+ case 'publishBatch':
30
+ if (params.PublishBatchRequestEntries && params.PublishBatchRequestEntries.length > 0) {
31
+ this._injectMessageAttributes(span, params.PublishBatchRequestEntries[0])
32
+ }
33
+ break
34
+ }
35
+ }
36
+
37
+ _injectMessageAttributes (span, params) {
38
+ if (!params.MessageAttributes) {
39
+ params.MessageAttributes = {}
40
+ }
41
+ if (Object.keys(params.MessageAttributes).length >= 10) { // SNS quota
42
+ log.info('Message attributes full, skipping trace context injection')
43
+ return
44
+ }
45
+ const ddInfo = {}
46
+ this.tracer.inject(span, 'text_map', ddInfo)
47
+ params.MessageAttributes._datadog = {
48
+ DataType: 'Binary',
49
+ BinaryValue: Buffer.from(JSON.stringify(ddInfo)) // BINARY types are automatically base64 encoded
45
50
  }
46
51
  }
47
52
  }