dd-trace 4.47.0 → 4.48.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.
Files changed (84) hide show
  1. package/LICENSE-3rdparty.csv +0 -1
  2. package/ext/types.d.ts +1 -0
  3. package/ext/types.js +1 -0
  4. package/index.d.ts +26 -0
  5. package/package.json +6 -7
  6. package/packages/datadog-code-origin/index.js +38 -0
  7. package/packages/datadog-core/index.js +2 -2
  8. package/packages/datadog-instrumentations/src/avsc.js +37 -0
  9. package/packages/datadog-instrumentations/src/azure-functions.js +48 -0
  10. package/packages/datadog-instrumentations/src/child_process.js +17 -8
  11. package/packages/datadog-instrumentations/src/express.js +37 -4
  12. package/packages/datadog-instrumentations/src/fastify.js +12 -1
  13. package/packages/datadog-instrumentations/src/fs.js +27 -7
  14. package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
  15. package/packages/datadog-instrumentations/src/jest.js +2 -1
  16. package/packages/datadog-instrumentations/src/mocha/common.js +1 -1
  17. package/packages/datadog-instrumentations/src/mysql2.js +220 -1
  18. package/packages/datadog-instrumentations/src/protobufjs.js +127 -0
  19. package/packages/datadog-instrumentations/src/winston.js +22 -0
  20. package/packages/datadog-plugin-avsc/src/index.js +9 -0
  21. package/packages/datadog-plugin-avsc/src/schema_iterator.js +169 -0
  22. package/packages/datadog-plugin-azure-functions/src/index.js +77 -0
  23. package/packages/datadog-plugin-fastify/src/code_origin.js +31 -0
  24. package/packages/datadog-plugin-fastify/src/index.js +10 -12
  25. package/packages/datadog-plugin-fastify/src/tracing.js +19 -0
  26. package/packages/datadog-plugin-protobufjs/src/index.js +14 -0
  27. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +180 -0
  28. package/packages/dd-trace/src/appsec/addresses.js +6 -1
  29. package/packages/dd-trace/src/appsec/channels.js +5 -1
  30. package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +13 -1
  31. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +8 -1
  32. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
  33. package/packages/dd-trace/src/appsec/iast/index.js +3 -0
  34. package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +1 -0
  35. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +15 -0
  36. package/packages/dd-trace/src/appsec/index.js +58 -43
  37. package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +99 -0
  38. package/packages/dd-trace/src/appsec/rasp/index.js +24 -10
  39. package/packages/dd-trace/src/appsec/rasp/lfi.js +112 -0
  40. package/packages/dd-trace/src/appsec/rasp/sql_injection.js +24 -4
  41. package/packages/dd-trace/src/appsec/rasp/utils.js +2 -1
  42. package/packages/dd-trace/src/appsec/recommended.json +2 -4
  43. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +5 -1
  44. package/packages/dd-trace/src/appsec/remote_config/index.js +8 -0
  45. package/packages/dd-trace/src/appsec/reporter.js +12 -5
  46. package/packages/dd-trace/src/appsec/sdk/track_event.js +5 -0
  47. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +1 -1
  48. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +2 -14
  49. package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +53 -0
  50. package/packages/dd-trace/src/config.js +12 -1
  51. package/packages/dd-trace/src/datastreams/schemas/schema_builder.js +25 -17
  52. package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -0
  53. package/packages/dd-trace/src/debugger/devtools_client/index.js +56 -5
  54. package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +4 -4
  55. package/packages/dd-trace/src/debugger/devtools_client/send.js +14 -1
  56. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +153 -0
  57. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +30 -0
  58. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +241 -0
  59. package/packages/dd-trace/src/debugger/devtools_client/state.js +10 -4
  60. package/packages/dd-trace/src/exporters/common/request.js +8 -34
  61. package/packages/dd-trace/src/exporters/common/url-to-http-options-polyfill.js +31 -0
  62. package/packages/dd-trace/src/payload-tagging/index.js +1 -1
  63. package/packages/dd-trace/src/payload-tagging/jsonpath-plus.js +2094 -0
  64. package/packages/dd-trace/src/plugin_manager.js +4 -2
  65. package/packages/dd-trace/src/plugins/ci_plugin.js +2 -0
  66. package/packages/dd-trace/src/plugins/index.js +3 -0
  67. package/packages/dd-trace/src/plugins/log_plugin.js +1 -1
  68. package/packages/dd-trace/src/plugins/schema.js +35 -0
  69. package/packages/dd-trace/src/plugins/util/ci.js +23 -1
  70. package/packages/dd-trace/src/plugins/util/serverless.js +7 -0
  71. package/packages/dd-trace/src/plugins/util/stacktrace.js +94 -0
  72. package/packages/dd-trace/src/plugins/util/tags.js +7 -0
  73. package/packages/dd-trace/src/plugins/util/test.js +20 -22
  74. package/packages/dd-trace/src/plugins/util/web.js +6 -4
  75. package/packages/dd-trace/src/profiling/profiler.js +24 -14
  76. package/packages/dd-trace/src/profiling/profilers/events.js +3 -3
  77. package/packages/dd-trace/src/profiling/profilers/wall.js +94 -66
  78. package/packages/dd-trace/src/proxy.js +12 -0
  79. package/packages/dd-trace/src/service-naming/schemas/v0/index.js +2 -1
  80. package/packages/dd-trace/src/service-naming/schemas/v0/serverless.js +12 -0
  81. package/packages/dd-trace/src/service-naming/schemas/v1/index.js +2 -1
  82. package/packages/dd-trace/src/service-naming/schemas/v1/serverless.js +12 -0
  83. package/packages/datadog-core/src/storage/async_resource.js +0 -108
  84. package/packages/datadog-core/src/storage/index.js +0 -5
@@ -20,7 +20,7 @@ const enterCh = dc.channel('dd-trace:storage:enter')
20
20
  const spanFinishCh = dc.channel('dd-trace:span:finish')
21
21
  const profilerTelemetryMetrics = telemetryMetrics.manager.namespace('profilers')
22
22
 
23
- const MemoizedWebTags = Symbol('NativeWallProfiler.MemoizedWebTags')
23
+ const ProfilingContext = Symbol('NativeWallProfiler.ProfilingContext')
24
24
 
25
25
  let kSampleCount
26
26
 
@@ -44,36 +44,42 @@ function endpointNameFromTags (tags) {
44
44
  ].filter(v => v).join(' ')
45
45
  }
46
46
 
47
- function getWebTags (startedSpans, i, span) {
48
- // Are web tags for this span already memoized?
49
- const memoizedWebTags = span[MemoizedWebTags]
50
- if (memoizedWebTags !== undefined) {
51
- return memoizedWebTags
52
- }
53
- // No, we'll have to memoize a new value
54
- function memoize (tags) {
55
- span[MemoizedWebTags] = tags
56
- return tags
57
- }
58
- // Is this span itself a web span?
59
- const context = span.context()
60
- const tags = context._tags
61
- if (isWebServerSpan(tags)) {
62
- return memoize(tags)
63
- }
64
- // It isn't. Get parent's web tags (memoize them too recursively.)
65
- // There might be several webspans, for example with next.js, http plugin creates the first span
66
- // and then next.js plugin creates a child span, and this child span has the correct endpoint
67
- // information. That's why we always use the tags of the closest ancestor web span.
68
- const parentId = context._parentId
69
- while (--i >= 0) {
70
- const ispan = startedSpans[i]
71
- if (ispan.context()._spanId === parentId) {
72
- return memoize(getWebTags(startedSpans, i, ispan))
47
+ let channelsActivated = false
48
+ function ensureChannelsActivated () {
49
+ if (channelsActivated) return
50
+
51
+ const { AsyncLocalStorage, createHook } = require('async_hooks')
52
+ const shimmer = require('../../../../datadog-shimmer')
53
+
54
+ createHook({ before: () => beforeCh.publish() }).enable()
55
+
56
+ let inRun = false
57
+ shimmer.wrap(AsyncLocalStorage.prototype, 'enterWith', function (original) {
58
+ return function (...args) {
59
+ const retVal = original.apply(this, args)
60
+ if (!inRun) enterCh.publish()
61
+ return retVal
73
62
  }
74
- }
75
- // Local root span with no web span
76
- return memoize(null)
63
+ })
64
+
65
+ shimmer.wrap(AsyncLocalStorage.prototype, 'run', function (original) {
66
+ return function (store, callback, ...args) {
67
+ const wrappedCb = shimmer.wrapFunction(callback, cb => function (...args) {
68
+ inRun = false
69
+ enterCh.publish()
70
+ const retVal = cb.apply(this, args)
71
+ inRun = true
72
+ return retVal
73
+ })
74
+ inRun = true
75
+ const retVal = original.call(this, store, wrappedCb, ...args)
76
+ enterCh.publish()
77
+ inRun = false
78
+ return retVal
79
+ }
80
+ })
81
+
82
+ channelsActivated = true
77
83
  }
78
84
 
79
85
  class NativeWallProfiler {
@@ -121,6 +127,8 @@ class NativeWallProfiler {
121
127
  start ({ mapper } = {}) {
122
128
  if (this._started) return
123
129
 
130
+ ensureChannelsActivated()
131
+
124
132
  this._mapper = mapper
125
133
  this._pprof = require('@datadog/pprof')
126
134
  kSampleCount = this._pprof.time.constants.kSampleCount
@@ -144,14 +152,10 @@ class NativeWallProfiler {
144
152
  })
145
153
 
146
154
  if (this._withContexts) {
147
- this._currentContext = {}
148
- this._pprof.time.setContext(this._currentContext)
155
+ this._setNewContext()
149
156
 
150
157
  if (this._captureSpanData) {
151
158
  this._profilerState = this._pprof.time.getState()
152
- this._lastSpan = undefined
153
- this._lastStartedSpans = undefined
154
- this._lastWebTags = undefined
155
159
  this._lastSampleCount = 0
156
160
 
157
161
  beforeCh.subscribe(this._enter)
@@ -169,51 +173,78 @@ class NativeWallProfiler {
169
173
  const sampleCount = this._profilerState[kSampleCount]
170
174
  if (sampleCount !== this._lastSampleCount) {
171
175
  this._lastSampleCount = sampleCount
172
- const context = this._currentContext
173
- this._currentContext = {}
174
- this._pprof.time.setContext(this._currentContext)
176
+ const context = this._currentContext.ref
177
+ this._setNewContext()
175
178
 
176
179
  this._updateContext(context)
177
180
  }
178
181
 
179
182
  const span = getActiveSpan()
180
- if (span) {
183
+ this._currentContext.ref = span ? this._getProfilingContext(span) : {}
184
+ }
185
+
186
+ _getProfilingContext (span) {
187
+ let profilingContext = span[ProfilingContext]
188
+ if (profilingContext === undefined) {
181
189
  const context = span.context()
182
- this._lastSpan = span
183
190
  const startedSpans = getStartedSpans(context)
184
- this._lastStartedSpans = startedSpans
191
+
192
+ let spanId
193
+ let rootSpanId
194
+ if (this._codeHotspotsEnabled) {
195
+ spanId = context._spanId
196
+ rootSpanId = startedSpans.length ? startedSpans[0].context()._spanId : context._spanId
197
+ }
198
+
199
+ let webTags
185
200
  if (this._endpointCollectionEnabled) {
186
- this._lastWebTags = getWebTags(startedSpans, startedSpans.length, span)
201
+ const tags = context._tags
202
+ if (isWebServerSpan(tags)) {
203
+ webTags = tags
204
+ } else {
205
+ // Get parent's context's web tags
206
+ const parentId = context._parentId
207
+ for (let i = startedSpans.length; --i >= 0;) {
208
+ const ispan = startedSpans[i]
209
+ if (ispan.context()._spanId === parentId) {
210
+ webTags = this._getProfilingContext(ispan).webTags
211
+ break
212
+ }
213
+ }
214
+ }
187
215
  }
188
- } else {
189
- this._lastStartedSpans = undefined
190
- this._lastSpan = undefined
191
- this._lastWebTags = undefined
216
+
217
+ profilingContext = { spanId, rootSpanId, webTags }
218
+ span[ProfilingContext] = profilingContext
192
219
  }
220
+ return profilingContext
221
+ }
222
+
223
+ _setNewContext () {
224
+ this._pprof.time.setContext(
225
+ this._currentContext = {
226
+ ref: {}
227
+ }
228
+ )
193
229
  }
194
230
 
195
231
  _updateContext (context) {
196
- if (!this._lastSpan) {
197
- return
232
+ if (typeof context.spanId === 'object') {
233
+ context.spanId = context.spanId.toString(10)
198
234
  }
199
- if (this._codeHotspotsEnabled) {
200
- context.spanId = this._lastSpan.context().toSpanId()
201
- const rootSpan = this._lastStartedSpans[0]
202
- if (rootSpan) {
203
- context.rootSpanId = rootSpan.context().toSpanId()
204
- }
235
+ if (typeof context.rootSpanId === 'object') {
236
+ context.rootSpanId = context.rootSpanId.toString(10)
205
237
  }
206
- if (this._lastWebTags) {
207
- context.webTags = this._lastWebTags
238
+ if (context.webTags !== undefined && context.endpoint === undefined) {
208
239
  // endpoint may not be determined yet, but keep it as fallback
209
240
  // if tags are not available anymore during serialization
210
- context.endpoint = endpointNameFromTags(this._lastWebTags)
241
+ context.endpoint = endpointNameFromTags(context.webTags)
211
242
  }
212
243
  }
213
244
 
214
245
  _spanFinished (span) {
215
- if (span[MemoizedWebTags]) {
216
- span[MemoizedWebTags] = undefined
246
+ if (span[ProfilingContext] !== undefined) {
247
+ span[ProfilingContext] = undefined
217
248
  }
218
249
  }
219
250
 
@@ -248,9 +279,6 @@ class NativeWallProfiler {
248
279
  enterCh.unsubscribe(this._enter)
249
280
  spanFinishCh.unsubscribe(this._spanFinished)
250
281
  this._profilerState = undefined
251
- this._lastSpan = undefined
252
- this._lastStartedSpans = undefined
253
- this._lastWebTags = undefined
254
282
  }
255
283
  this._started = false
256
284
  }
@@ -273,20 +301,20 @@ class NativeWallProfiler {
273
301
 
274
302
  const labels = { ...getThreadLabels() }
275
303
 
276
- const { context: { spanId, rootSpanId, webTags, endpoint }, timestamp } = context
304
+ const { context: { ref: { spanId, rootSpanId, webTags, endpoint } }, timestamp } = context
277
305
 
278
306
  if (this._timelineEnabled) {
279
307
  // Incoming timestamps are in microseconds, we emit nanos.
280
308
  labels[END_TIMESTAMP_LABEL] = timestamp * 1000n
281
309
  }
282
310
 
283
- if (spanId) {
311
+ if (spanId !== undefined) {
284
312
  labels[SPAN_ID_LABEL] = spanId
285
313
  }
286
- if (rootSpanId) {
314
+ if (rootSpanId !== undefined) {
287
315
  labels[LOCAL_ROOT_SPAN_ID_LABEL] = rootSpanId
288
316
  }
289
- if (webTags && Object.keys(webTags).length !== 0) {
317
+ if (webTags !== undefined && Object.keys(webTags).length !== 0) {
290
318
  labels['trace endpoint'] = endpointNameFromTags(webTags)
291
319
  } else if (endpoint) {
292
320
  // fallback to endpoint computed when sample was taken
@@ -162,6 +162,18 @@ class Tracer extends NoopProxy {
162
162
  this._testApiManualPlugin.configure({ ...config, enabled: true })
163
163
  }
164
164
  }
165
+ if (config.ciVisAgentlessLogSubmissionEnabled) {
166
+ if (process.env.DD_API_KEY) {
167
+ const LogSubmissionPlugin = require('./ci-visibility/log-submission/log-submission-plugin')
168
+ const automaticLogPlugin = new LogSubmissionPlugin(this)
169
+ automaticLogPlugin.configure({ ...config, enabled: true })
170
+ } else {
171
+ log.warn(
172
+ 'DD_AGENTLESS_LOG_SUBMISSION_ENABLED is set, ' +
173
+ 'but DD_API_KEY is undefined, so no automatic log submission will be performed.'
174
+ )
175
+ }
176
+ }
165
177
  } catch (e) {
166
178
  log.error(e)
167
179
  }
@@ -3,5 +3,6 @@ const messaging = require('./messaging')
3
3
  const storage = require('./storage')
4
4
  const graphql = require('./graphql')
5
5
  const web = require('./web')
6
+ const serverless = require('./serverless')
6
7
 
7
- module.exports = new SchemaDefinition({ messaging, storage, web, graphql })
8
+ module.exports = new SchemaDefinition({ messaging, storage, web, graphql, serverless })
@@ -0,0 +1,12 @@
1
+ const { identityService } = require('../util')
2
+
3
+ const serverless = {
4
+ server: {
5
+ 'azure-functions': {
6
+ opName: () => 'azure-functions.invoke',
7
+ serviceName: identityService
8
+ }
9
+ }
10
+ }
11
+
12
+ module.exports = serverless
@@ -3,5 +3,6 @@ const messaging = require('./messaging')
3
3
  const storage = require('./storage')
4
4
  const graphql = require('./graphql')
5
5
  const web = require('./web')
6
+ const serverless = require('./serverless')
6
7
 
7
- module.exports = new SchemaDefinition({ messaging, storage, web, graphql })
8
+ module.exports = new SchemaDefinition({ messaging, storage, web, graphql, serverless })
@@ -0,0 +1,12 @@
1
+ const { identityService } = require('../util')
2
+
3
+ const serverless = {
4
+ server: {
5
+ 'azure-functions': {
6
+ opName: () => 'azure-functions.invoke',
7
+ serviceName: identityService
8
+ }
9
+ }
10
+ }
11
+
12
+ module.exports = serverless
@@ -1,108 +0,0 @@
1
- 'use strict'
2
-
3
- const { createHook, executionAsyncResource } = require('async_hooks')
4
- const { channel } = require('dc-polyfill')
5
-
6
- const beforeCh = channel('dd-trace:storage:before')
7
- const afterCh = channel('dd-trace:storage:after')
8
- const enterCh = channel('dd-trace:storage:enter')
9
-
10
- let PrivateSymbol = Symbol
11
- function makePrivateSymbol () {
12
- // eslint-disable-next-line no-new-func
13
- PrivateSymbol = new Function('name', 'return %CreatePrivateSymbol(name)')
14
- }
15
-
16
- try {
17
- makePrivateSymbol()
18
- } catch (e) {
19
- try {
20
- const v8 = require('v8')
21
- v8.setFlagsFromString('--allow-natives-syntax')
22
- makePrivateSymbol()
23
- v8.setFlagsFromString('--no-allow-natives-syntax')
24
- // eslint-disable-next-line no-empty
25
- } catch (e) {}
26
- }
27
-
28
- class AsyncResourceStorage {
29
- constructor () {
30
- this._ddResourceStore = PrivateSymbol('ddResourceStore')
31
- this._enabled = false
32
- this._hook = createHook(this._createHook())
33
- }
34
-
35
- disable () {
36
- if (!this._enabled) return
37
-
38
- this._hook.disable()
39
- this._enabled = false
40
- }
41
-
42
- getStore () {
43
- if (!this._enabled) return
44
-
45
- const resource = this._executionAsyncResource()
46
-
47
- return resource[this._ddResourceStore]
48
- }
49
-
50
- enterWith (store) {
51
- this._enable()
52
-
53
- const resource = this._executionAsyncResource()
54
-
55
- resource[this._ddResourceStore] = store
56
- enterCh.publish()
57
- }
58
-
59
- run (store, callback, ...args) {
60
- this._enable()
61
-
62
- const resource = this._executionAsyncResource()
63
- const oldStore = resource[this._ddResourceStore]
64
-
65
- resource[this._ddResourceStore] = store
66
- enterCh.publish()
67
-
68
- try {
69
- return callback(...args)
70
- } finally {
71
- resource[this._ddResourceStore] = oldStore
72
- enterCh.publish()
73
- }
74
- }
75
-
76
- _createHook () {
77
- return {
78
- init: this._init.bind(this),
79
- before () {
80
- beforeCh.publish()
81
- },
82
- after () {
83
- afterCh.publish()
84
- }
85
- }
86
- }
87
-
88
- _enable () {
89
- if (this._enabled) return
90
-
91
- this._enabled = true
92
- this._hook.enable()
93
- }
94
-
95
- _init (asyncId, type, triggerAsyncId, resource) {
96
- const currentResource = this._executionAsyncResource()
97
-
98
- if (Object.prototype.hasOwnProperty.call(currentResource, this._ddResourceStore)) {
99
- resource[this._ddResourceStore] = currentResource[this._ddResourceStore]
100
- }
101
- }
102
-
103
- _executionAsyncResource () {
104
- return executionAsyncResource() || {}
105
- }
106
- }
107
-
108
- module.exports = AsyncResourceStorage
@@ -1,5 +0,0 @@
1
- 'use strict'
2
-
3
- // TODO: default to AsyncLocalStorage when it supports triggerAsyncResource
4
-
5
- module.exports = require('./async_resource')