dd-trace 5.20.0 → 5.22.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 (108) hide show
  1. package/index.d.ts +2 -1
  2. package/package.json +6 -6
  3. package/packages/datadog-instrumentations/src/aerospike.js +1 -1
  4. package/packages/datadog-instrumentations/src/apollo-server.js +1 -1
  5. package/packages/datadog-instrumentations/src/aws-sdk.js +4 -4
  6. package/packages/datadog-instrumentations/src/body-parser.js +17 -5
  7. package/packages/datadog-instrumentations/src/cassandra-driver.js +2 -2
  8. package/packages/datadog-instrumentations/src/child_process.js +2 -2
  9. package/packages/datadog-instrumentations/src/connect.js +4 -4
  10. package/packages/datadog-instrumentations/src/cookie-parser.js +4 -4
  11. package/packages/datadog-instrumentations/src/couchbase.js +12 -12
  12. package/packages/datadog-instrumentations/src/cucumber.js +16 -5
  13. package/packages/datadog-instrumentations/src/dns.js +10 -10
  14. package/packages/datadog-instrumentations/src/elasticsearch.js +4 -4
  15. package/packages/datadog-instrumentations/src/express-mongo-sanitize.js +3 -3
  16. package/packages/datadog-instrumentations/src/express.js +4 -4
  17. package/packages/datadog-instrumentations/src/fastify.js +6 -6
  18. package/packages/datadog-instrumentations/src/fetch.js +1 -1
  19. package/packages/datadog-instrumentations/src/find-my-way.js +2 -2
  20. package/packages/datadog-instrumentations/src/fs.js +2 -2
  21. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +2 -2
  22. package/packages/datadog-instrumentations/src/grpc/client.js +4 -6
  23. package/packages/datadog-instrumentations/src/grpc/server.js +2 -2
  24. package/packages/datadog-instrumentations/src/hapi.js +10 -13
  25. package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -2
  26. package/packages/datadog-instrumentations/src/helpers/register.js +9 -2
  27. package/packages/datadog-instrumentations/src/http/client.js +3 -3
  28. package/packages/datadog-instrumentations/src/jest.js +5 -4
  29. package/packages/datadog-instrumentations/src/knex.js +2 -2
  30. package/packages/datadog-instrumentations/src/koa.js +5 -5
  31. package/packages/datadog-instrumentations/src/ldapjs.js +1 -1
  32. package/packages/datadog-instrumentations/src/mariadb.js +8 -8
  33. package/packages/datadog-instrumentations/src/memcached.js +2 -2
  34. package/packages/datadog-instrumentations/src/microgateway-core.js +4 -4
  35. package/packages/datadog-instrumentations/src/mocha/common.js +1 -1
  36. package/packages/datadog-instrumentations/src/mocha/main.js +91 -70
  37. package/packages/datadog-instrumentations/src/mocha/utils.js +2 -3
  38. package/packages/datadog-instrumentations/src/mocha.js +4 -0
  39. package/packages/datadog-instrumentations/src/moleculer/server.js +2 -2
  40. package/packages/datadog-instrumentations/src/mongodb-core.js +7 -7
  41. package/packages/datadog-instrumentations/src/mongoose.js +5 -6
  42. package/packages/datadog-instrumentations/src/mysql.js +3 -3
  43. package/packages/datadog-instrumentations/src/mysql2.js +6 -6
  44. package/packages/datadog-instrumentations/src/net.js +2 -2
  45. package/packages/datadog-instrumentations/src/next.js +5 -5
  46. package/packages/datadog-instrumentations/src/nyc.js +23 -0
  47. package/packages/datadog-instrumentations/src/openai.js +58 -69
  48. package/packages/datadog-instrumentations/src/oracledb.js +8 -8
  49. package/packages/datadog-instrumentations/src/passport-http.js +1 -1
  50. package/packages/datadog-instrumentations/src/passport-local.js +1 -1
  51. package/packages/datadog-instrumentations/src/passport-utils.js +1 -1
  52. package/packages/datadog-instrumentations/src/pg.js +1 -1
  53. package/packages/datadog-instrumentations/src/pino.js +4 -4
  54. package/packages/datadog-instrumentations/src/playwright.js +6 -4
  55. package/packages/datadog-instrumentations/src/redis.js +2 -2
  56. package/packages/datadog-instrumentations/src/restify.js +4 -4
  57. package/packages/datadog-instrumentations/src/rhea.js +4 -4
  58. package/packages/datadog-instrumentations/src/router.js +5 -5
  59. package/packages/datadog-instrumentations/src/sharedb.js +2 -2
  60. package/packages/datadog-instrumentations/src/vitest.js +22 -5
  61. package/packages/datadog-instrumentations/src/winston.js +2 -3
  62. package/packages/datadog-plugin-cucumber/src/index.js +12 -2
  63. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +21 -10
  64. package/packages/datadog-plugin-hapi/src/index.js +2 -2
  65. package/packages/datadog-plugin-jest/src/index.js +18 -4
  66. package/packages/datadog-plugin-mocha/src/index.js +25 -6
  67. package/packages/datadog-plugin-nyc/src/index.js +35 -0
  68. package/packages/datadog-plugin-openai/src/index.js +58 -47
  69. package/packages/datadog-plugin-playwright/src/index.js +9 -4
  70. package/packages/datadog-plugin-vitest/src/index.js +30 -4
  71. package/packages/datadog-shimmer/src/shimmer.js +144 -10
  72. package/packages/dd-trace/src/appsec/blocking.js +23 -17
  73. package/packages/dd-trace/src/appsec/graphql.js +3 -1
  74. package/packages/dd-trace/src/appsec/iast/iast-log.js +2 -1
  75. package/packages/dd-trace/src/appsec/remote_config/manager.js +4 -1
  76. package/packages/dd-trace/src/appsec/rule_manager.js +8 -0
  77. package/packages/dd-trace/src/appsec/telemetry.js +3 -3
  78. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +40 -1
  79. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +2 -4
  80. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -4
  81. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +2 -1
  82. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +8 -7
  83. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -4
  84. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +2 -4
  85. package/packages/dd-trace/src/ci-visibility/telemetry.js +29 -2
  86. package/packages/dd-trace/src/config.js +157 -142
  87. package/packages/dd-trace/src/lambda/handler.js +1 -0
  88. package/packages/dd-trace/src/lambda/index.js +12 -1
  89. package/packages/dd-trace/src/opentelemetry/context_manager.js +22 -39
  90. package/packages/dd-trace/src/opentelemetry/span_context.js +2 -2
  91. package/packages/dd-trace/src/opentelemetry/tracer.js +23 -14
  92. package/packages/dd-trace/src/opentelemetry/tracer_provider.js +9 -1
  93. package/packages/dd-trace/src/opentracing/propagation/log.js +1 -1
  94. package/packages/dd-trace/src/opentracing/propagation/text_map.js +61 -6
  95. package/packages/dd-trace/src/opentracing/span_context.js +1 -0
  96. package/packages/dd-trace/src/plugins/ci_plugin.js +2 -2
  97. package/packages/dd-trace/src/plugins/index.js +1 -0
  98. package/packages/dd-trace/src/plugins/util/git.js +14 -1
  99. package/packages/dd-trace/src/plugins/util/test.js +1 -5
  100. package/packages/dd-trace/src/profiler.js +15 -5
  101. package/packages/dd-trace/src/profiling/config.js +2 -4
  102. package/packages/dd-trace/src/profiling/exporter_cli.js +13 -1
  103. package/packages/dd-trace/src/profiling/exporters/agent.js +7 -1
  104. package/packages/dd-trace/src/profiling/profiler.js +0 -9
  105. package/packages/dd-trace/src/profiling/ssi-heuristics.js +49 -58
  106. package/packages/dd-trace/src/proxy.js +21 -21
  107. package/packages/dd-trace/src/telemetry/index.js +24 -7
  108. package/packages/dd-trace/src/telemetry/logs/index.js +20 -0
@@ -7,40 +7,6 @@ const dc = require('dc-polyfill')
7
7
  // If the process lives for at least 30 seconds, it's considered long-lived
8
8
  const DEFAULT_LONG_LIVED_THRESHOLD = 30000
9
9
 
10
- const EnablementChoice = {
11
- MANUALLY_ENABLED: Symbol('SSITelemetry.EnablementChoice.MANUALLY_ENABLED'),
12
- SSI_ENABLED: Symbol('SSITelemetry.EnablementChoice.SSI_ENABLED'),
13
- SSI_NOT_ENABLED: Symbol('SSITelemetry.EnablementChoice.SSI_NOT_ENABLED'),
14
- DISABLED: Symbol('SSITelemetry.EnablementChoice.DISABLED')
15
- }
16
- Object.freeze(EnablementChoice)
17
-
18
- function getEnablementChoiceFromConfig (config) {
19
- if (config.ssi === false || config.enabled === false) {
20
- return EnablementChoice.DISABLED
21
- } else if (config.heuristicsEnabled === true) {
22
- return EnablementChoice.SSI_ENABLED
23
- } else if (config.enabled === true) {
24
- return EnablementChoice.MANUALLY_ENABLED
25
- } else {
26
- return EnablementChoice.SSI_NOT_ENABLED
27
- }
28
- }
29
-
30
- function enablementChoiceToTagValue (enablementChoice) {
31
- switch (enablementChoice) {
32
- case EnablementChoice.MANUALLY_ENABLED:
33
- return 'manually_enabled'
34
- case EnablementChoice.SSI_ENABLED:
35
- return 'ssi_enabled'
36
- case EnablementChoice.SSI_NOT_ENABLED:
37
- return 'not_enabled'
38
- case EnablementChoice.DISABLED:
39
- // Can't emit this one as a tag
40
- throw new Error('Invalid enablement choice')
41
- }
42
- }
43
-
44
10
  /**
45
11
  * This class embodies the SSI profiler-triggering heuristics and also emits telemetry metrics about
46
12
  * the profiler behavior under SSI. It emits the following metrics:
@@ -56,9 +22,23 @@ function enablementChoiceToTagValue (enablementChoice) {
56
22
  */
57
23
  class SSIHeuristics {
58
24
  constructor (config) {
59
- this.enablementChoice = getEnablementChoiceFromConfig(config)
25
+ const injectionIncludesProfiler = config.injectionEnabled.includes('profiler')
26
+ this._heuristicsActive = injectionIncludesProfiler || config.profiling.enabled === 'auto'
27
+ this._emitsTelemetry = config.injectionEnabled.length > 0 && config.profiling.enabled !== 'false'
28
+
29
+ if (this._emitsTelemetry) {
30
+ if (config.profiling.enabled === 'true') {
31
+ this.enablementChoice = 'manually_enabled'
32
+ } else if (injectionIncludesProfiler) {
33
+ this.enablementChoice = 'ssi_enabled'
34
+ } else if (config.profiling.enabled === 'auto') {
35
+ this.enablementChoice = 'auto_enabled'
36
+ } else {
37
+ this.enablementChoice = 'ssi_not_enabled'
38
+ }
39
+ }
60
40
 
61
- const longLivedThreshold = config.longLivedThreshold || DEFAULT_LONG_LIVED_THRESHOLD
41
+ const longLivedThreshold = config.profiling.longLivedThreshold || DEFAULT_LONG_LIVED_THRESHOLD
62
42
  if (typeof longLivedThreshold !== 'number' || longLivedThreshold <= 0) {
63
43
  throw new Error('Long-lived threshold must be a positive number')
64
44
  }
@@ -69,12 +49,16 @@ class SSIHeuristics {
69
49
  this.shortLived = true
70
50
  }
71
51
 
72
- enabled () {
73
- return this.enablementChoice !== EnablementChoice.DISABLED
52
+ get emitsTelemetry () {
53
+ return this._emitsTelemetry
54
+ }
55
+
56
+ get heuristicsActive () {
57
+ return this._heuristicsActive
74
58
  }
75
59
 
76
60
  start () {
77
- if (this.enabled()) {
61
+ if (this.heuristicsActive || this.emitsTelemetry) {
78
62
  // Used to determine short-livedness of the process. We could use the process start time as the
79
63
  // reference point, but the tracer initialization point is more relevant, as we couldn't be
80
64
  // collecting profiles earlier anyway. The difference is not particularly significant if the
@@ -85,13 +69,17 @@ class SSIHeuristics {
85
69
  }, this.longLivedThreshold).unref()
86
70
 
87
71
  this._onSpanCreated = this._onSpanCreated.bind(this)
88
- this._onProfileSubmitted = this._onProfileSubmitted.bind(this)
89
- this._onMockProfileSubmitted = this._onMockProfileSubmitted.bind(this)
90
- this._onAppClosing = this._onAppClosing.bind(this)
91
-
92
72
  dc.subscribe('dd-trace:span:start', this._onSpanCreated)
93
- dc.subscribe('datadog:profiling:profile-submitted', this._onProfileSubmitted)
94
- dc.subscribe('datadog:profiling:mock-profile-submitted', this._onMockProfileSubmitted)
73
+
74
+ if (this.emitsTelemetry) {
75
+ this._onProfileSubmitted = this._onProfileSubmitted.bind(this)
76
+ this._onMockProfileSubmitted = this._onMockProfileSubmitted.bind(this)
77
+
78
+ dc.subscribe('datadog:profiling:profile-submitted', this._onProfileSubmitted)
79
+ dc.subscribe('datadog:profiling:mock-profile-submitted', this._onMockProfileSubmitted)
80
+ }
81
+
82
+ this._onAppClosing = this._onAppClosing.bind(this)
95
83
  dc.subscribe('datadog:telemetry:app-closing', this._onAppClosing)
96
84
  }
97
85
  }
@@ -152,7 +140,7 @@ class SSIHeuristics {
152
140
 
153
141
  const tags = [
154
142
  'installation:ssi',
155
- `enablement_choice:${enablementChoiceToTagValue(this.enablementChoice)}`,
143
+ `enablement_choice:${this.enablementChoice}`,
156
144
  `has_sent_profiles:${this.hasSentProfiles}`,
157
145
  `heuristic_hypothetical_decision:${decision.join('_')}`
158
146
  ]
@@ -163,9 +151,9 @@ class SSIHeuristics {
163
151
  if (
164
152
  !this._emittedRuntimeId &&
165
153
  decision[0] === 'triggered' &&
166
- // When enablement choice is SSI_ENABLED, hasSentProfiles can transition from false to true when the
154
+ // When heuristics are active, hasSentProfiles can transition from false to true when the
167
155
  // profiler gets started and the first profile is submitted, so we have to wait for it.
168
- (this.enablementChoice !== EnablementChoice.SSI_ENABLED || this.hasSentProfiles)
156
+ (!this.heuristicsActive || this.hasSentProfiles)
169
157
  ) {
170
158
  // Tags won't change anymore, so we can emit the runtime ID metric now.
171
159
  this._emittedRuntimeId = true
@@ -174,17 +162,20 @@ class SSIHeuristics {
174
162
  }
175
163
 
176
164
  _onAppClosing () {
177
- this._ensureProfileMetrics()
178
- // Last ditch effort to emit a runtime ID count metric
179
- if (!this._emittedRuntimeId) {
180
- this._emittedRuntimeId = true
181
- this._runtimeIdCount.inc()
165
+ if (this.emitsTelemetry) {
166
+ this._ensureProfileMetrics()
167
+ // Last ditch effort to emit a runtime ID count metric
168
+ if (!this._emittedRuntimeId) {
169
+ this._emittedRuntimeId = true
170
+ this._runtimeIdCount.inc()
171
+ }
172
+ // So we have the metrics in the final state
173
+ this._profileCount.inc(0)
174
+
175
+ dc.unsubscribe('datadog:profiling:profile-submitted', this._onProfileSubmitted)
176
+ dc.unsubscribe('datadog:profiling:mock-profile-submitted', this._onMockProfileSubmitted)
182
177
  }
183
- // So we have the metrics in the final state
184
- this._profileCount.inc(0)
185
178
 
186
- dc.unsubscribe('datadog:profiling:profile-submitted', this._onProfileSubmitted)
187
- dc.unsubscribe('datadog:profiling:mock-profile-submitted', this._onMockProfileSubmitted)
188
179
  dc.unsubscribe('datadog:telemetry:app-closing', this._onAppClosing)
189
180
  if (this.noSpan) {
190
181
  dc.unsubscribe('dd-trace:span:start', this._onSpanCreated)
@@ -192,4 +183,4 @@ class SSIHeuristics {
192
183
  }
193
184
  }
194
185
 
195
- module.exports = { SSIHeuristics, EnablementChoice }
186
+ module.exports = { SSIHeuristics }
@@ -14,7 +14,6 @@ const dogstatsd = require('./dogstatsd')
14
14
  const NoopDogStatsDClient = require('./noop/dogstatsd')
15
15
  const spanleak = require('./spanleak')
16
16
  const { SSIHeuristics } = require('./profiling/ssi-heuristics')
17
- const telemetryLog = require('dc-polyfill').channel('datadog:telemetry:log')
18
17
  const appsecStandalone = require('./appsec/standalone')
19
18
 
20
19
  class LazyModule {
@@ -117,24 +116,32 @@ class Tracer extends NoopProxy {
117
116
  require('./serverless').maybeStartServerlessMiniAgent(config)
118
117
  }
119
118
 
120
- const ssiHeuristics = new SSIHeuristics(config.profiling)
121
- ssiHeuristics.start()
122
- if (config.profiling.enabled) {
123
- this._profilerStarted = this._startProfiler(config)
124
- } else if (config.profiling.ssi) {
125
- const mockProfiler = require('./profiling/ssi-telemetry-mock-profiler')
126
- mockProfiler.start(config)
119
+ if (config.profiling.enabled !== 'false') {
120
+ const ssiHeuristics = new SSIHeuristics(config)
121
+ ssiHeuristics.start()
122
+ let mockProfiler = null
123
+ if (config.profiling.enabled === 'true') {
124
+ this._profilerStarted = this._startProfiler(config)
125
+ } else if (ssiHeuristics.emitsTelemetry) {
126
+ // Start a mock profiler that emits mock profile-submitted events for the telemetry.
127
+ // It will be stopped if the real profiler is started by the heuristics.
128
+ mockProfiler = require('./profiling/ssi-telemetry-mock-profiler')
129
+ mockProfiler.start(config)
130
+ }
127
131
 
128
- if (config.profiling.heuristicsEnabled) {
132
+ if (ssiHeuristics.heuristicsActive) {
129
133
  ssiHeuristics.onTriggered(() => {
130
- mockProfiler.stop()
134
+ if (mockProfiler) {
135
+ mockProfiler.stop()
136
+ }
131
137
  this._startProfiler(config)
132
- ssiHeuristics.onTriggered()
138
+ ssiHeuristics.onTriggered() // deregister this callback
133
139
  })
134
140
  }
135
- }
136
- if (!this._profilerStarted) {
137
- this._profilerStarted = Promise.resolve(false)
141
+
142
+ if (!this._profilerStarted) {
143
+ this._profilerStarted = Promise.resolve(false)
144
+ }
138
145
  }
139
146
 
140
147
  if (config.runtimeMetrics) {
@@ -163,13 +170,6 @@ class Tracer extends NoopProxy {
163
170
  return require('./profiler').start(config)
164
171
  } catch (e) {
165
172
  log.error(e)
166
- if (telemetryLog.hasSubscribers) {
167
- telemetryLog.publish({
168
- message: e.message,
169
- level: 'ERROR',
170
- stack_trace: e.stack
171
- })
172
- }
173
173
  }
174
174
  }
175
175
 
@@ -89,7 +89,7 @@ function getProducts (config) {
89
89
  },
90
90
  profiler: {
91
91
  version: tracerVersion,
92
- enabled: config.profiling.enabled
92
+ enabled: profilingEnabledToBoolean(config.profiling.enabled)
93
93
  }
94
94
  }
95
95
  if (errors.profilingError) {
@@ -317,7 +317,7 @@ function updateConfig (changes, config) {
317
317
  'sampler.rules': 'DD_TRACE_SAMPLING_RULES'
318
318
  }
319
319
 
320
- const namesNeedFormatting = new Set(['DD_TAGS', 'peerServiceMapping'])
320
+ const namesNeedFormatting = new Set(['DD_TAGS', 'peerServiceMapping', 'serviceMapping'])
321
321
 
322
322
  const configuration = []
323
323
  const names = [] // list of config names whose values have been changed
@@ -329,13 +329,17 @@ function updateConfig (changes, config) {
329
329
  const { origin, value } = change
330
330
  const entry = { name, value, origin }
331
331
 
332
- if (namesNeedFormatting.has(entry.name)) entry.value = formatMapForTelemetry(entry.value)
333
- if (entry.name === 'url' && entry.value) entry.value = entry.value.toString()
334
- if (entry.name === 'DD_TRACE_SAMPLING_RULES') {
332
+ if (namesNeedFormatting.has(entry.name)) {
333
+ entry.value = formatMapForTelemetry(entry.value)
334
+ } else if (entry.name === 'url') {
335
+ if (entry.value) {
336
+ entry.value = entry.value.toString()
337
+ }
338
+ } else if (entry.name === 'DD_TRACE_SAMPLING_RULES') {
335
339
  entry.value = JSON.stringify(entry.value)
340
+ } else if (Array.isArray(entry.value)) {
341
+ entry.value = value.join(',')
336
342
  }
337
- if (Array.isArray(entry.value)) entry.value = value.join(',')
338
-
339
343
  configuration.push(entry)
340
344
  }
341
345
 
@@ -354,6 +358,19 @@ function updateConfig (changes, config) {
354
358
  }
355
359
  }
356
360
 
361
+ function profilingEnabledToBoolean (profilingEnabled) {
362
+ if (typeof profilingEnabled === 'boolean') {
363
+ return profilingEnabled
364
+ }
365
+ if (['auto', 'true'].includes(profilingEnabled)) {
366
+ return true
367
+ }
368
+ if (profilingEnabled === 'false') {
369
+ return false
370
+ }
371
+ return undefined
372
+ }
373
+
357
374
  module.exports = {
358
375
  start,
359
376
  stop,
@@ -5,6 +5,7 @@ const logCollector = require('./log-collector')
5
5
  const { sendData } = require('../send-data')
6
6
 
7
7
  const telemetryLog = dc.channel('datadog:telemetry:log')
8
+ const errorLog = dc.channel('datadog:log:error')
8
9
 
9
10
  let enabled = false
10
11
 
@@ -33,12 +34,29 @@ function onLog (log) {
33
34
  }
34
35
  }
35
36
 
37
+ function onErrorLog (msg) {
38
+ if (msg instanceof Error) {
39
+ onLog({
40
+ level: 'ERROR',
41
+ message: msg.message,
42
+ stack_trace: msg.stack
43
+ })
44
+ } else if (typeof msg === 'string') {
45
+ onLog({
46
+ level: 'ERROR',
47
+ message: msg
48
+ })
49
+ }
50
+ }
51
+
36
52
  function start (config) {
37
53
  if (!config.telemetry.logCollection || enabled) return
38
54
 
39
55
  enabled = true
40
56
 
41
57
  telemetryLog.subscribe(onLog)
58
+
59
+ errorLog.subscribe(onErrorLog)
42
60
  }
43
61
 
44
62
  function stop () {
@@ -47,6 +65,8 @@ function stop () {
47
65
  if (telemetryLog.hasSubscribers) {
48
66
  telemetryLog.unsubscribe(onLog)
49
67
  }
68
+
69
+ errorLog.unsubscribe(onErrorLog)
50
70
  }
51
71
 
52
72
  function send (config, application, host) {