dd-trace 2.26.2 → 2.27.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 +2 -2
  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
@@ -8,17 +8,9 @@ const {
8
8
  TEST_PARAMETERS,
9
9
  finishAllTraceSpans,
10
10
  getTestSuitePath,
11
- getTestParentSpan,
12
11
  getTestParametersString,
13
- getTestSessionCommonTags,
14
- getTestModuleCommonTags,
15
12
  getTestSuiteCommonTags,
16
- addIntelligentTestRunnerSpanTags,
17
- TEST_SUITE_ID,
18
- TEST_SESSION_ID,
19
- TEST_MODULE_ID,
20
- TEST_BUNDLE,
21
- TEST_COMMAND
13
+ addIntelligentTestRunnerSpanTags
22
14
  } = require('../../dd-trace/src/plugins/util/test')
23
15
  const { COMPONENT } = require('../../dd-trace/src/constants')
24
16
 
@@ -49,36 +41,11 @@ class MochaPlugin extends CiPlugin {
49
41
  })
50
42
  })
51
43
 
52
- this.addSub('ci:mocha:session:start', ({ command, frameworkVersion }) => {
53
- const childOf = getTestParentSpan(this.tracer)
54
- const testSessionSpanMetadata = getTestSessionCommonTags(command, frameworkVersion)
55
-
56
- this.command = command
57
- this.testSessionSpan = this.tracer.startSpan('mocha.test_session', {
58
- childOf,
59
- tags: {
60
- [COMPONENT]: this.constructor.name,
61
- ...this.testEnvironmentMetadata,
62
- ...testSessionSpanMetadata
63
- }
64
- })
65
-
66
- const testModuleSpanMetadata = getTestModuleCommonTags(command, frameworkVersion)
67
- this.testModuleSpan = this.tracer.startSpan('mocha.test_module', {
68
- childOf: this.testSessionSpan,
69
- tags: {
70
- [COMPONENT]: this.constructor.name,
71
- ...this.testEnvironmentMetadata,
72
- ...testModuleSpanMetadata
73
- }
74
- })
75
- })
76
-
77
44
  this.addSub('ci:mocha:test-suite:start', (suite) => {
78
45
  const store = storage.getStore()
79
46
  const testSuiteMetadata = getTestSuiteCommonTags(
80
47
  this.command,
81
- this.tracer._version,
48
+ this.frameworkVersion,
82
49
  getTestSuitePath(suite.file, this.sourceRoot)
83
50
  )
84
51
  const testSuiteSpan = this.tracer.startSpan('mocha.test_suite', {
@@ -94,18 +61,24 @@ class MochaPlugin extends CiPlugin {
94
61
  })
95
62
 
96
63
  this.addSub('ci:mocha:test-suite:finish', (status) => {
97
- const span = storage.getStore().span
98
- // the test status of the suite may have been set in ci:mocha:test-suite:error already
99
- if (!span.context()._tags[TEST_STATUS]) {
100
- span.setTag(TEST_STATUS, status)
64
+ const store = storage.getStore()
65
+ if (store && store.span) {
66
+ const span = storage.getStore().span
67
+ // the test status of the suite may have been set in ci:mocha:test-suite:error already
68
+ if (!span.context()._tags[TEST_STATUS]) {
69
+ span.setTag(TEST_STATUS, status)
70
+ }
71
+ span.finish()
101
72
  }
102
- span.finish()
103
73
  })
104
74
 
105
75
  this.addSub('ci:mocha:test-suite:error', (err) => {
106
- const span = storage.getStore().span
107
- span.setTag('error', err)
108
- span.setTag(TEST_STATUS, 'fail')
76
+ const store = storage.getStore()
77
+ if (store && store.span) {
78
+ const span = storage.getStore().span
79
+ span.setTag('error', err)
80
+ span.setTag(TEST_STATUS, 'fail')
81
+ }
109
82
  })
110
83
 
111
84
  this.addSub('ci:mocha:test:start', (test) => {
@@ -116,12 +89,16 @@ class MochaPlugin extends CiPlugin {
116
89
  })
117
90
 
118
91
  this.addSub('ci:mocha:test:finish', (status) => {
119
- const span = storage.getStore().span
92
+ const store = storage.getStore()
120
93
 
121
- span.setTag(TEST_STATUS, status)
94
+ if (store && store.span) {
95
+ const span = storage.getStore().span
96
+
97
+ span.setTag(TEST_STATUS, status)
122
98
 
123
- span.finish()
124
- finishAllTraceSpans(span)
99
+ span.finish()
100
+ finishAllTraceSpans(span)
101
+ }
125
102
  })
126
103
 
127
104
  this.addSub('ci:mocha:test:skip', (test) => {
@@ -135,8 +112,9 @@ class MochaPlugin extends CiPlugin {
135
112
  })
136
113
 
137
114
  this.addSub('ci:mocha:test:error', (err) => {
138
- if (err) {
139
- const span = storage.getStore().span
115
+ const store = storage.getStore()
116
+ if (err && store && store.span) {
117
+ const span = store.span
140
118
  if (err.constructor.name === 'Pending' && !this.forbidPending) {
141
119
  span.setTag(TEST_STATUS, 'skip')
142
120
  } else {
@@ -172,46 +150,19 @@ class MochaPlugin extends CiPlugin {
172
150
  }
173
151
 
174
152
  startTestSpan (test) {
175
- const childOf = getTestParentSpan(this.tracer)
176
- // This is a hack to get good time resolution on test events, while keeping
177
- // the test event as the root span of its trace.
178
- childOf._trace.startTime = this.testSessionSpan.context()._trace.startTime
179
- childOf._trace.ticks = this.testSessionSpan.context()._trace.ticks
180
-
181
- const testSuiteTags = {}
182
- const testSuiteSpan = this._testSuites.get(test.parent.file)
183
- if (testSuiteSpan) {
184
- const testSuiteId = testSuiteSpan.context().toSpanId()
185
- testSuiteTags[TEST_SUITE_ID] = testSuiteId
186
- }
153
+ const testName = test.fullTitle()
154
+ const { file: testSuiteAbsolutePath, title } = test
187
155
 
188
- if (this.testSessionSpan) {
189
- const testSessionId = this.testSessionSpan.context().toTraceId()
190
- testSuiteTags[TEST_SESSION_ID] = testSessionId
191
- testSuiteTags[TEST_COMMAND] = this.command
192
- }
193
-
194
- if (this.testModuleSpan) {
195
- const testModuleId = this.testModuleSpan.context().toSpanId()
196
- testSuiteTags[TEST_MODULE_ID] = testModuleId
197
- testSuiteTags[TEST_COMMAND] = this.command
198
- testSuiteTags[TEST_BUNDLE] = this.command
199
- }
200
-
201
- const { file: testSuiteAbsolutePath } = test
202
- const fullTestName = test.fullTitle()
203
- const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.sourceRoot)
204
-
205
- const extraTags = {
206
- ...testSuiteTags
207
- }
208
-
209
- const testParametersString = getTestParametersString(this._testNameToParams, test.title)
156
+ const extraTags = {}
157
+ const testParametersString = getTestParametersString(this._testNameToParams, title)
210
158
  if (testParametersString) {
211
159
  extraTags[TEST_PARAMETERS] = testParametersString
212
160
  }
213
161
 
214
- return super.startTestSpan(fullTestName, testSuite, extraTags, childOf)
162
+ const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.sourceRoot)
163
+ const testSuiteSpan = this._testSuites.get(testSuiteAbsolutePath)
164
+
165
+ return super.startTestSpan(testName, testSuite, testSuiteSpan, extraTags)
215
166
  }
216
167
  }
217
168
 
@@ -6,16 +6,8 @@ const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin')
6
6
  const {
7
7
  TEST_STATUS,
8
8
  finishAllTraceSpans,
9
- getTestParentSpan,
10
- getTestSessionCommonTags,
11
9
  getTestSuitePath,
12
- TEST_SESSION_ID,
13
- TEST_COMMAND,
14
- TEST_SUITE_ID,
15
- getTestSuiteCommonTags,
16
- getTestModuleCommonTags,
17
- TEST_MODULE_ID,
18
- TEST_BUNDLE
10
+ getTestSuiteCommonTags
19
11
  } = require('../../dd-trace/src/plugins/util/test')
20
12
  const { RESOURCE_NAME } = require('../../../ext/tags')
21
13
  const { COMPONENT } = require('../../dd-trace/src/constants')
@@ -30,32 +22,6 @@ class PlaywrightPlugin extends CiPlugin {
30
22
 
31
23
  this._testSuites = new Map()
32
24
 
33
- this.addSub('ci:playwright:session:start', ({ command, frameworkVersion, rootDir }) => {
34
- const childOf = getTestParentSpan(this.tracer)
35
- this.command = command
36
- this.frameworkVersion = frameworkVersion
37
- this.rootDir = rootDir
38
-
39
- const testSessionSpanMetadata = getTestSessionCommonTags(command, frameworkVersion)
40
- this.testSessionSpan = this.tracer.startSpan('playwright.test_session', {
41
- childOf,
42
- tags: {
43
- [COMPONENT]: this.constructor.name,
44
- ...this.testEnvironmentMetadata,
45
- ...testSessionSpanMetadata
46
- }
47
- })
48
- const testModuleSpanMetadata = getTestModuleCommonTags(command, frameworkVersion)
49
- this.testModuleSpan = this.tracer.startSpan('playwright.test_module', {
50
- childOf: this.testSessionSpan,
51
- tags: {
52
- [COMPONENT]: this.constructor.name,
53
- ...this.testEnvironmentMetadata,
54
- ...testModuleSpanMetadata
55
- }
56
- })
57
- })
58
-
59
25
  this.addSub('ci:playwright:session:finish', ({ status, onDone }) => {
60
26
  this.testModuleSpan.setTag(TEST_STATUS, status)
61
27
  this.testSessionSpan.setTag(TEST_STATUS, status)
@@ -138,33 +104,8 @@ class PlaywrightPlugin extends CiPlugin {
138
104
  }
139
105
 
140
106
  startTestSpan (testName, testSuite) {
141
- const childOf = getTestParentSpan(this.tracer)
142
- // This is a hack to get good time resolution on test events, while keeping
143
- // the test event as the root span of its trace.
144
- childOf._trace.startTime = this.testSessionSpan.context()._trace.startTime
145
- childOf._trace.ticks = this.testSessionSpan.context()._trace.ticks
146
-
147
- const testSuiteTags = {}
148
107
  const testSuiteSpan = this._testSuites.get(testSuite)
149
- if (testSuiteSpan) {
150
- const testSuiteId = testSuiteSpan.context().toSpanId()
151
- testSuiteTags[TEST_SUITE_ID] = testSuiteId
152
- }
153
-
154
- if (this.testSessionSpan) {
155
- const testSessionId = this.testSessionSpan.context().toTraceId()
156
- testSuiteTags[TEST_SESSION_ID] = testSessionId
157
- testSuiteTags[TEST_COMMAND] = this.command
158
- }
159
-
160
- if (this.testModuleSpan) {
161
- const testModuleId = this.testModuleSpan.context().toSpanId()
162
- testSuiteTags[TEST_MODULE_ID] = testModuleId
163
- testSuiteTags[TEST_COMMAND] = this.command
164
- testSuiteTags[TEST_BUNDLE] = this.command
165
- }
166
-
167
- return super.startTestSpan(testName, testSuite, testSuiteTags, childOf)
108
+ return super.startTestSpan(testName, testSuite, testSuiteSpan)
168
109
  }
169
110
  }
170
111
 
@@ -10,7 +10,11 @@ function copyProperties (original, wrapped) {
10
10
  const keys = Reflect.ownKeys(props)
11
11
 
12
12
  for (const key of keys) {
13
- Object.defineProperty(wrapped, key, props[key])
13
+ try {
14
+ Object.defineProperty(wrapped, key, props[key])
15
+ } catch (e) {
16
+ // TODO: figure out how to handle this without a try/catch
17
+ }
14
18
  }
15
19
  }
16
20
 
@@ -33,28 +37,41 @@ function wrapFn (original, delegate) {
33
37
 
34
38
  function wrapMethod (target, name, wrapper) {
35
39
  assertMethod(target, name)
36
- assertNotClass(target[name]) // TODO: support constructors of native classes
37
40
  assertFunction(wrapper)
38
41
 
39
42
  const original = target[name]
40
43
  const wrapped = wrapper(original)
41
44
  const descriptor = Object.getOwnPropertyDescriptor(target, name)
42
45
 
46
+ const attributes = {
47
+ configurable: true,
48
+ ...descriptor
49
+ }
50
+
51
+ copyProperties(original, wrapped)
52
+
43
53
  if (descriptor) {
44
54
  unwrappers.set(wrapped, () => Object.defineProperty(target, name, descriptor))
55
+
56
+ if (descriptor.get || descriptor.set) {
57
+ attributes.get = () => wrapped
58
+ } else {
59
+ attributes.value = wrapped
60
+ }
61
+
62
+ // TODO: create a single object for multiple wrapped methods
63
+ if (descriptor.configurable === false) {
64
+ return Object.create(target, {
65
+ [name]: attributes
66
+ })
67
+ }
45
68
  } else { // no descriptor means original was on the prototype
46
69
  unwrappers.set(wrapped, () => delete target[name])
70
+ attributes.value = wrapped
71
+ attributes.writable = true
47
72
  }
48
73
 
49
- Object.defineProperty(target, name, {
50
- configurable: true,
51
- writable: true,
52
- enumerable: false,
53
- ...descriptor,
54
- value: wrapped
55
- })
56
-
57
- copyProperties(original, wrapped)
74
+ Object.defineProperty(target, name, attributes)
58
75
 
59
76
  return target
60
77
  }
@@ -86,28 +86,28 @@ function formatHeaderName (name) {
86
86
 
87
87
  function reportMetrics (metrics, store) {
88
88
  const req = store && store.get('req')
89
- const topSpan = web.root(req)
90
- if (!topSpan) return false
89
+ const rootSpan = web.root(req)
90
+ if (!rootSpan) return false
91
91
 
92
92
  if (metrics.duration) {
93
- topSpan.setTag('_dd.appsec.waf.duration', metrics.duration)
93
+ rootSpan.setTag('_dd.appsec.waf.duration', metrics.duration)
94
94
  }
95
95
 
96
96
  if (metrics.durationExt) {
97
- topSpan.setTag('_dd.appsec.waf.duration_ext', metrics.durationExt)
97
+ rootSpan.setTag('_dd.appsec.waf.duration_ext', metrics.durationExt)
98
98
  }
99
99
 
100
100
  if (metrics.rulesVersion) {
101
- topSpan.setTag('_dd.appsec.event_rules.version', metrics.rulesVersion)
101
+ rootSpan.setTag('_dd.appsec.event_rules.version', metrics.rulesVersion)
102
102
  }
103
103
  }
104
104
 
105
105
  function reportAttack (attackData, store) {
106
106
  const req = store && store.get('req')
107
- const topSpan = web.root(req)
108
- if (!topSpan) return false
107
+ const rootSpan = web.root(req)
108
+ if (!rootSpan) return false
109
109
 
110
- const currentTags = topSpan.context()._tags
110
+ const currentTags = rootSpan.context()._tags
111
111
 
112
112
  const newTags = {
113
113
  'appsec.event': 'true'
@@ -146,20 +146,20 @@ function reportAttack (attackData, store) {
146
146
  newTags['network.client.ip'] = resolvedRequest.remote_ip
147
147
  }
148
148
 
149
- topSpan.addTags(newTags)
149
+ rootSpan.addTags(newTags)
150
150
  }
151
151
 
152
152
  function finishRequest (req, context) {
153
- const topSpan = web.root(req)
154
- if (!topSpan) return false
153
+ const rootSpan = web.root(req)
154
+ if (!rootSpan) return false
155
155
 
156
156
  if (metricsQueue.size) {
157
- topSpan.addTags(Object.fromEntries(metricsQueue))
157
+ rootSpan.addTags(Object.fromEntries(metricsQueue))
158
158
 
159
159
  metricsQueue.clear()
160
160
  }
161
161
 
162
- if (!context || !topSpan.context()._tags['appsec.event']) return false
162
+ if (!context || !rootSpan.context()._tags['appsec.event']) return false
163
163
 
164
164
  const resolvedResponse = resolveHTTPResponse(context)
165
165
 
@@ -169,7 +169,7 @@ function finishRequest (req, context) {
169
169
  newTags['http.endpoint'] = resolvedResponse.endpoint
170
170
  }
171
171
 
172
- topSpan.addTags(newTags)
172
+ rootSpan.addTags(newTags)
173
173
  }
174
174
 
175
175
  function setRateLimit (rateLimit) {
@@ -20,8 +20,7 @@ class AgentProxyCiVisibilityExporter extends CiVisibilityExporter {
20
20
  prioritySampler,
21
21
  lookup,
22
22
  protocolVersion,
23
- headers,
24
- isGitUploadEnabled
23
+ headers
25
24
  } = config
26
25
 
27
26
  this.getAgentInfo((err, agentInfo) => {
@@ -38,9 +37,6 @@ class AgentProxyCiVisibilityExporter extends CiVisibilityExporter {
38
37
  url: this._url,
39
38
  evpProxyPrefix: AGENT_EVP_PROXY_PATH
40
39
  })
41
- if (isGitUploadEnabled) {
42
- this.sendGitMetadata({ url: this._url, isEvpProxy: true })
43
- }
44
40
  } else {
45
41
  this._writer = new AgentWriter({
46
42
  url: this._url,
@@ -9,7 +9,7 @@ const log = require('../../../log')
9
9
  class AgentlessCiVisibilityExporter extends CiVisibilityExporter {
10
10
  constructor (config) {
11
11
  super(config)
12
- const { tags, site, url, isGitUploadEnabled } = config
12
+ const { tags, site, url } = config
13
13
  // we don't need to request /info because we are using agentless by configuration
14
14
  this._isInitialized = true
15
15
  this._resolveCanUseCiVisProtocol(true)
@@ -21,10 +21,6 @@ class AgentlessCiVisibilityExporter extends CiVisibilityExporter {
21
21
  this._coverageWriter = new CoverageWriter({ url: this._coverageUrl })
22
22
 
23
23
  this._apiUrl = url || new URL(`https://api.${site}`)
24
-
25
- if (isGitUploadEnabled) {
26
- this.sendGitMetadata({ url: this._getApiUrl() })
27
- }
28
24
  }
29
25
 
30
26
  setUrl (url, coverageUrl = url, apiUrl = url) {
@@ -14,6 +14,9 @@ function getIsTestSessionTrace (trace) {
14
14
  )
15
15
  }
16
16
 
17
+ const GIT_UPLOAD_TIMEOUT = 60000 // 60 seconds
18
+ const CAN_USE_CI_VIS_PROTOCOL_TIMEOUT = GIT_UPLOAD_TIMEOUT
19
+
17
20
  class CiVisibilityExporter extends AgentInfoExporter {
18
21
  constructor (config) {
19
22
  super(config)
@@ -24,14 +27,24 @@ class CiVisibilityExporter extends AgentInfoExporter {
24
27
  // AKA CI Vis Protocol
25
28
  this._canUseCiVisProtocol = false
26
29
 
27
- // TODO: add timeout to reject this promise
30
+ const gitUploadTimeoutId = setTimeout(() => {
31
+ this._resolveGit(new Error('Timeout while uploading git metadata'))
32
+ }, GIT_UPLOAD_TIMEOUT).unref()
33
+
34
+ const canUseCiVisProtocolTimeoutId = setTimeout(() => {
35
+ this._resolveCanUseCiVisProtocol(false)
36
+ }, CAN_USE_CI_VIS_PROTOCOL_TIMEOUT).unref()
37
+
28
38
  this._gitUploadPromise = new Promise(resolve => {
29
- this._resolveGit = resolve
39
+ this._resolveGit = (err) => {
40
+ clearTimeout(gitUploadTimeoutId)
41
+ resolve(err)
42
+ }
30
43
  })
31
44
 
32
- // TODO: add timeout to reject this promise
33
45
  this._canUseCiVisProtocolPromise = new Promise(resolve => {
34
46
  this._resolveCanUseCiVisProtocol = (canUseCiVisProtocol) => {
47
+ clearTimeout(canUseCiVisProtocolTimeoutId)
35
48
  this._canUseCiVisProtocol = canUseCiVisProtocol
36
49
  resolve(canUseCiVisProtocol)
37
50
  }
@@ -93,6 +106,7 @@ class CiVisibilityExporter extends AgentInfoExporter {
93
106
  * CI Visibility Protocol, hence the this._canUseCiVisProtocol promise.
94
107
  */
95
108
  getItrConfiguration (testConfiguration, callback) {
109
+ this.sendGitMetadata()
96
110
  if (!this.shouldRequestItrConfiguration()) {
97
111
  return callback(null, {})
98
112
  }
@@ -118,14 +132,22 @@ class CiVisibilityExporter extends AgentInfoExporter {
118
132
  })
119
133
  }
120
134
 
121
- sendGitMetadata ({ url, isEvpProxy }) {
122
- sendGitMetadataRequest(url, isEvpProxy, (err) => {
123
- if (err) {
124
- log.error(`Error uploading git metadata: ${err.message}`)
125
- } else {
126
- log.debug('Successfully uploaded git metadata')
135
+ sendGitMetadata () {
136
+ if (!this._config.isGitUploadEnabled) {
137
+ return
138
+ }
139
+ this._canUseCiVisProtocolPromise.then((canUseCiVisProtocol) => {
140
+ if (!canUseCiVisProtocol) {
141
+ return
127
142
  }
128
- this._resolveGit(err)
143
+ sendGitMetadataRequest(this._getApiUrl(), !!this._isUsingEvpProxy, (err) => {
144
+ if (err) {
145
+ log.error(`Error uploading git metadata: ${err.message}`)
146
+ } else {
147
+ log.debug('Successfully uploaded git metadata')
148
+ }
149
+ this._resolveGit(err)
150
+ })
129
151
  })
130
152
  }
131
153
 
@@ -19,7 +19,7 @@ function getSkippableSuites ({
19
19
  headers: {
20
20
  'Content-Type': 'application/json'
21
21
  },
22
- timeout: 15000,
22
+ timeout: 20000,
23
23
  url
24
24
  }
25
25
 
@@ -51,6 +51,32 @@ function remapify (input, mappings) {
51
51
  return output
52
52
  }
53
53
 
54
+ function propagationStyle (key, option, defaultValue) {
55
+ // Extract by key if in object-form value
56
+ if (typeof option === 'object' && !Array.isArray(option)) {
57
+ option = option[key]
58
+ }
59
+
60
+ // Should be an array at this point
61
+ if (Array.isArray(option)) return option.map(v => v.toLowerCase())
62
+
63
+ // If it's not an array but not undefined there's something wrong with the input
64
+ if (typeof option !== 'undefined') {
65
+ log.warn('Unexpected input for config.tracePropagationStyle')
66
+ }
67
+
68
+ // Otherwise, fallback to env var parsing
69
+ const envKey = `DD_TRACE_PROPAGATION_STYLE_${key.toUpperCase()}`
70
+ const envVar = coalesce(process.env[envKey], process.env.DD_TRACE_PROPAGATION_STYLE)
71
+ if (typeof envVar !== 'undefined') {
72
+ return envVar.split(',')
73
+ .filter(v => v !== '')
74
+ .map(v => v.trim().toLowerCase())
75
+ }
76
+
77
+ return defaultValue
78
+ }
79
+
54
80
  class Config {
55
81
  constructor (options) {
56
82
  options = options || {}
@@ -192,15 +218,36 @@ class Config {
192
218
  process.env.DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP,
193
219
  '.*'
194
220
  )
221
+ // TODO: Remove the experimental env vars as a major?
195
222
  const DD_TRACE_B3_ENABLED = coalesce(
196
223
  options.experimental && options.experimental.b3,
197
224
  process.env.DD_TRACE_EXPERIMENTAL_B3_ENABLED,
198
225
  false
199
226
  )
200
- const DD_TRACE_TRACEPARENT_ENABLED = coalesce(
201
- options.experimental && options.experimental.traceparent,
202
- process.env.DD_TRACE_EXPERIMENTAL_TRACEPARENT_ENABLED,
203
- false
227
+ const defaultPropagationStyle = ['tracecontext', 'datadog']
228
+ if (isTrue(DD_TRACE_B3_ENABLED)) {
229
+ defaultPropagationStyle.push('b3')
230
+ defaultPropagationStyle.push('b3 single header')
231
+ }
232
+ if (process.env.DD_TRACE_PROPAGATION_STYLE && (
233
+ process.env.DD_TRACE_PROPAGATION_STYLE_INJECT ||
234
+ process.env.DD_TRACE_PROPAGATION_STYLE_EXTRACT
235
+ )) {
236
+ log.warn(
237
+ 'Use either the DD_TRACE_PROPAGATION_STYLE environment variable or separate ' +
238
+ 'DD_TRACE_PROPAGATION_STYLE_INJECT and DD_TRACE_PROPAGATION_STYLE_EXTRACT ' +
239
+ 'environment variables'
240
+ )
241
+ }
242
+ const DD_TRACE_PROPAGATION_STYLE_INJECT = propagationStyle(
243
+ 'inject',
244
+ options.tracePropagationStyle,
245
+ defaultPropagationStyle
246
+ )
247
+ const DD_TRACE_PROPAGATION_STYLE_EXTRACT = propagationStyle(
248
+ 'extract',
249
+ options.tracePropagationStyle,
250
+ defaultPropagationStyle
204
251
  )
205
252
  const DD_TRACE_RUNTIME_ID_ENABLED = coalesce(
206
253
  options.experimental && options.experimental.runtimeId,
@@ -386,9 +433,11 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
386
433
  port: String(coalesce(dogstatsd.port, process.env.DD_DOGSTATSD_PORT, 8125))
387
434
  }
388
435
  this.runtimeMetrics = isTrue(DD_RUNTIME_METRICS_ENABLED)
436
+ this.tracePropagationStyle = {
437
+ inject: DD_TRACE_PROPAGATION_STYLE_INJECT,
438
+ extract: DD_TRACE_PROPAGATION_STYLE_EXTRACT
439
+ }
389
440
  this.experimental = {
390
- b3: isTrue(DD_TRACE_B3_ENABLED),
391
- traceparent: isTrue(DD_TRACE_TRACEPARENT_ENABLED),
392
441
  runtimeId: isTrue(DD_TRACE_RUNTIME_ID_ENABLED),
393
442
  exporter: DD_TRACE_EXPORTER,
394
443
  enableGetRumData: isTrue(DD_TRACE_GET_RUM_DATA_ENABLED)
@@ -14,7 +14,7 @@ float64Array[0] = -1
14
14
  const bigEndian = uInt8Float64Array[7] === 0
15
15
 
16
16
  function formatSpan (span) {
17
- return normalizeSpan(truncateSpan(span))
17
+ return normalizeSpan(truncateSpan(span, false))
18
18
  }
19
19
 
20
20
  class AgentEncoder {
@@ -7,7 +7,7 @@ const ARRAY_OF_TWO = 0x92
7
7
  const ARRAY_OF_TWELVE = 0x9c
8
8
 
9
9
  function formatSpan (span) {
10
- return normalizeSpan(truncateSpan(span))
10
+ return normalizeSpan(truncateSpan(span, false))
11
11
  }
12
12
 
13
13
  class AgentEncoder extends BaseEncoder {
@@ -38,11 +38,12 @@ function truncateToLength (value, maxLength) {
38
38
  return value
39
39
  }
40
40
 
41
- function truncateSpan (span) {
41
+ // normally the agent truncates the resource and parses it in certain scenarios (e.g. SQL Queries)
42
+ function truncateSpan (span, shouldTruncateResourceName = true) {
42
43
  return fromEntries(Object.entries(span).map(([key, value]) => {
43
44
  switch (key) {
44
45
  case 'resource':
45
- return ['resource', truncateToLength(value, MAX_RESOURCE_NAME_LENGTH)]
46
+ return ['resource', shouldTruncateResourceName ? truncateToLength(value, MAX_RESOURCE_NAME_LENGTH) : value]
46
47
  case 'meta':
47
48
  return ['meta', fromEntries(Object.entries(value).map(([metaKey, metaValue]) =>
48
49
  [truncateToLength(metaKey, MAX_META_KEY_LENGTH), truncateToLength(metaValue, MAX_META_VALUE_LENGTH)]