dd-trace 5.24.0 → 5.26.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 (138) hide show
  1. package/LICENSE-3rdparty.csv +3 -0
  2. package/index.d.ts +345 -8
  3. package/init.js +60 -47
  4. package/package.json +16 -7
  5. package/packages/datadog-code-origin/index.js +4 -4
  6. package/packages/datadog-core/index.js +1 -3
  7. package/packages/datadog-core/src/storage.js +21 -0
  8. package/packages/datadog-core/src/utils/src/parse-tags.js +33 -0
  9. package/packages/datadog-esbuild/index.js +4 -2
  10. package/packages/datadog-instrumentations/src/amqplib.js +65 -5
  11. package/packages/datadog-instrumentations/src/child_process.js +135 -27
  12. package/packages/datadog-instrumentations/src/express.js +1 -1
  13. package/packages/datadog-instrumentations/src/handlebars.js +40 -0
  14. package/packages/datadog-instrumentations/src/helpers/hooks.js +5 -0
  15. package/packages/datadog-instrumentations/src/helpers/register.js +9 -0
  16. package/packages/datadog-instrumentations/src/jest.js +6 -2
  17. package/packages/datadog-instrumentations/src/kafkajs.js +123 -63
  18. package/packages/datadog-instrumentations/src/mocha/utils.js +2 -2
  19. package/packages/datadog-instrumentations/src/multer.js +37 -0
  20. package/packages/datadog-instrumentations/src/openai.js +2 -2
  21. package/packages/datadog-instrumentations/src/pug.js +23 -0
  22. package/packages/datadog-instrumentations/src/router.js +2 -3
  23. package/packages/datadog-instrumentations/src/url.js +84 -0
  24. package/packages/datadog-instrumentations/src/utils/src/extract-package-and-module-path.js +7 -4
  25. package/packages/datadog-plugin-amqplib/src/consumer.js +6 -5
  26. package/packages/datadog-plugin-aws-sdk/src/base.js +5 -0
  27. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -0
  28. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +10 -7
  29. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +35 -0
  30. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +11 -9
  31. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +59 -45
  32. package/packages/datadog-plugin-cypress/src/support.js +1 -0
  33. package/packages/datadog-plugin-fastify/src/code_origin.js +2 -2
  34. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +10 -2
  35. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +8 -0
  36. package/packages/datadog-plugin-grpc/src/client.js +3 -0
  37. package/packages/datadog-plugin-grpc/src/server.js +5 -1
  38. package/packages/datadog-plugin-http/src/client.js +42 -1
  39. package/packages/datadog-plugin-http2/src/client.js +26 -1
  40. package/packages/datadog-plugin-jest/src/index.js +2 -1
  41. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +6 -3
  42. package/packages/datadog-plugin-kafkajs/src/consumer.js +10 -5
  43. package/packages/datadog-plugin-kafkajs/src/producer.js +10 -4
  44. package/packages/datadog-plugin-mocha/src/index.js +5 -2
  45. package/packages/datadog-plugin-moleculer/src/server.js +2 -2
  46. package/packages/datadog-plugin-openai/src/index.js +9 -1015
  47. package/packages/datadog-plugin-openai/src/tracing.js +1023 -0
  48. package/packages/datadog-plugin-rhea/src/consumer.js +2 -1
  49. package/packages/datadog-plugin-vitest/src/index.js +2 -1
  50. package/packages/dd-trace/src/appsec/addresses.js +2 -0
  51. package/packages/dd-trace/src/appsec/api_security_sampler.js +50 -27
  52. package/packages/dd-trace/src/appsec/channels.js +3 -1
  53. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  54. package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +33 -16
  55. package/packages/dd-trace/src/appsec/iast/analyzers/template-injection-analyzer.js +18 -0
  56. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +55 -7
  57. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -2
  58. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  59. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +4 -2
  60. package/packages/dd-trace/src/appsec/index.js +9 -6
  61. package/packages/dd-trace/src/appsec/rasp/command_injection.js +49 -0
  62. package/packages/dd-trace/src/appsec/rasp/index.js +3 -0
  63. package/packages/dd-trace/src/appsec/rasp/ssrf.js +4 -3
  64. package/packages/dd-trace/src/appsec/rasp/utils.js +3 -2
  65. package/packages/dd-trace/src/appsec/recommended.json +354 -158
  66. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -1
  67. package/packages/dd-trace/src/appsec/remote_config/index.js +2 -7
  68. package/packages/dd-trace/src/appsec/reporter.js +6 -4
  69. package/packages/dd-trace/src/appsec/sdk/track_event.js +5 -3
  70. package/packages/dd-trace/src/appsec/waf/waf_manager.js +4 -0
  71. package/packages/dd-trace/src/azure_metadata.js +120 -0
  72. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +97 -0
  73. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +90 -0
  74. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +19 -1
  75. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +53 -0
  76. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +8 -1
  77. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +43 -0
  78. package/packages/dd-trace/src/config.js +88 -10
  79. package/packages/dd-trace/src/constants.js +8 -1
  80. package/packages/dd-trace/src/crashtracking/crashtracker.js +98 -0
  81. package/packages/dd-trace/src/crashtracking/index.js +15 -0
  82. package/packages/dd-trace/src/crashtracking/noop.js +8 -0
  83. package/packages/dd-trace/src/datastreams/pathway.js +1 -0
  84. package/packages/dd-trace/src/debugger/devtools_client/index.js +9 -13
  85. package/packages/dd-trace/src/debugger/devtools_client/send.js +15 -1
  86. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +57 -23
  87. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +12 -2
  88. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +31 -20
  89. package/packages/dd-trace/src/debugger/devtools_client/snapshot/symbols.js +6 -0
  90. package/packages/dd-trace/src/debugger/devtools_client/state.js +11 -2
  91. package/packages/dd-trace/src/debugger/index.js +10 -3
  92. package/packages/dd-trace/src/llmobs/constants/tags.js +34 -0
  93. package/packages/dd-trace/src/llmobs/constants/text.js +6 -0
  94. package/packages/dd-trace/src/llmobs/constants/writers.js +13 -0
  95. package/packages/dd-trace/src/llmobs/index.js +103 -0
  96. package/packages/dd-trace/src/llmobs/noop.js +82 -0
  97. package/packages/dd-trace/src/llmobs/plugins/base.js +65 -0
  98. package/packages/dd-trace/src/llmobs/plugins/openai.js +205 -0
  99. package/packages/dd-trace/src/llmobs/sdk.js +377 -0
  100. package/packages/dd-trace/src/llmobs/span_processor.js +195 -0
  101. package/packages/dd-trace/src/llmobs/storage.js +7 -0
  102. package/packages/dd-trace/src/llmobs/tagger.js +322 -0
  103. package/packages/dd-trace/src/llmobs/util.js +176 -0
  104. package/packages/dd-trace/src/llmobs/writers/base.js +111 -0
  105. package/packages/dd-trace/src/llmobs/writers/evaluations.js +29 -0
  106. package/packages/dd-trace/src/llmobs/writers/spans/agentProxy.js +23 -0
  107. package/packages/dd-trace/src/llmobs/writers/spans/agentless.js +17 -0
  108. package/packages/dd-trace/src/llmobs/writers/spans/base.js +52 -0
  109. package/packages/dd-trace/src/log/index.js +10 -13
  110. package/packages/dd-trace/src/log/log.js +52 -0
  111. package/packages/dd-trace/src/log/writer.js +50 -19
  112. package/packages/dd-trace/src/noop/proxy.js +3 -0
  113. package/packages/dd-trace/src/noop/span.js +4 -0
  114. package/packages/dd-trace/src/opentelemetry/span.js +16 -1
  115. package/packages/dd-trace/src/opentelemetry/tracer.js +1 -0
  116. package/packages/dd-trace/src/opentracing/propagation/text_map.js +106 -32
  117. package/packages/dd-trace/src/opentracing/span.js +26 -0
  118. package/packages/dd-trace/src/opentracing/span_context.js +1 -0
  119. package/packages/dd-trace/src/opentracing/tracer.js +8 -1
  120. package/packages/dd-trace/src/payload-tagging/config/aws.json +71 -3
  121. package/packages/dd-trace/src/plugins/outbound.js +9 -0
  122. package/packages/dd-trace/src/plugins/tracing.js +3 -3
  123. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +121 -0
  124. package/packages/dd-trace/src/plugins/util/ip_extractor.js +0 -1
  125. package/packages/dd-trace/src/plugins/util/web.js +39 -11
  126. package/packages/dd-trace/src/priority_sampler.js +16 -0
  127. package/packages/dd-trace/src/profiling/config.js +3 -1
  128. package/packages/dd-trace/src/profiling/exporters/agent.js +7 -5
  129. package/packages/dd-trace/src/profiling/profilers/wall.js +2 -1
  130. package/packages/dd-trace/src/proxy.js +13 -1
  131. package/packages/dd-trace/src/span_processor.js +5 -0
  132. package/packages/dd-trace/src/telemetry/index.js +11 -1
  133. package/packages/dd-trace/src/telemetry/logs/index.js +16 -11
  134. package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -8
  135. package/packages/dd-trace/src/telemetry/metrics.js +6 -1
  136. package/packages/dd-trace/src/util.js +16 -1
  137. package/version.js +4 -2
  138. /package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/{code-injection-sensitive-analyzer.js → tainted-range-based-sensitive-analyzer.js} +0 -0
@@ -108,6 +108,18 @@ class PrioritySampler {
108
108
  }
109
109
  }
110
110
 
111
+ setPriority (span, samplingPriority, mechanism = SAMPLING_MECHANISM_MANUAL) {
112
+ if (!span || !this.validate(samplingPriority)) return
113
+
114
+ const context = this._getContext(span)
115
+
116
+ context._sampling.priority = samplingPriority
117
+ context._sampling.mechanism = mechanism
118
+
119
+ const root = context._trace.started[0]
120
+ this._addDecisionMaker(root)
121
+ }
122
+
111
123
  _getContext (span) {
112
124
  return typeof span.context === 'function' ? span.context() : span
113
125
  }
@@ -201,6 +213,10 @@ class PrioritySampler {
201
213
  if (rule.match(span)) return rule
202
214
  }
203
215
  }
216
+
217
+ static keepTrace (span, mechanism) {
218
+ span?._prioritySampler?.setPriority(span, USER_KEEP, mechanism)
219
+ }
204
220
  }
205
221
 
206
222
  module.exports = PrioritySampler
@@ -14,6 +14,7 @@ const { oomExportStrategies, snapshotKinds } = require('./constants')
14
14
  const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('../plugins/util/tags')
15
15
  const { tagger } = require('./tagger')
16
16
  const { isFalse, isTrue } = require('../util')
17
+ const { getAzureTagsFromMetadata, getAzureAppMetadata } = require('../azure_metadata')
17
18
 
18
19
  class Config {
19
20
  constructor (options = {}) {
@@ -71,7 +72,8 @@ class Config {
71
72
  this.tags = Object.assign(
72
73
  tagger.parse(DD_TAGS),
73
74
  tagger.parse(options.tags),
74
- tagger.parse({ env, host, service, version, functionname })
75
+ tagger.parse({ env, host, service, version, functionname }),
76
+ getAzureTagsFromMetadata(getAzureAppMetadata())
75
77
  )
76
78
 
77
79
  // Add source code integration tags if available
@@ -195,11 +195,13 @@ class AgentExporter {
195
195
  })
196
196
 
197
197
  sendRequest(options, form, (err, response) => {
198
- if (operation.retry(err)) {
199
- this._logger.error(`Error from the agent: ${err.message}`)
200
- return
201
- } else if (err) {
202
- reject(err)
198
+ if (err) {
199
+ const { status } = err
200
+ if ((typeof status !== 'number' || status >= 500 || status === 429) && operation.retry(err)) {
201
+ this._logger.error(`Error from the agent: ${err.message}`)
202
+ } else {
203
+ reject(err)
204
+ }
203
205
  return
204
206
  }
205
207
 
@@ -301,7 +301,8 @@ class NativeWallProfiler {
301
301
 
302
302
  const labels = { ...getThreadLabels() }
303
303
 
304
- const { context: { ref: { spanId, rootSpanId, webTags, endpoint } }, timestamp } = context
304
+ const { context: { ref }, timestamp } = context
305
+ const { spanId, rootSpanId, webTags, endpoint } = ref ?? {}
305
306
 
306
307
  if (this._timelineEnabled) {
307
308
  // Incoming timestamps are in microseconds, we emit nanos.
@@ -16,6 +16,7 @@ const NoopDogStatsDClient = require('./noop/dogstatsd')
16
16
  const spanleak = require('./spanleak')
17
17
  const { SSIHeuristics } = require('./profiling/ssi-heuristics')
18
18
  const appsecStandalone = require('./appsec/standalone')
19
+ const LLMObsSDK = require('./llmobs/sdk')
19
20
 
20
21
  class LazyModule {
21
22
  constructor (provider) {
@@ -46,7 +47,8 @@ class Tracer extends NoopProxy {
46
47
  // these requires must work with esm bundler
47
48
  this._modules = {
48
49
  appsec: new LazyModule(() => require('./appsec')),
49
- iast: new LazyModule(() => require('./appsec/iast'))
50
+ iast: new LazyModule(() => require('./appsec/iast')),
51
+ llmobs: new LazyModule(() => require('./llmobs'))
50
52
  }
51
53
  }
52
54
 
@@ -57,6 +59,11 @@ class Tracer extends NoopProxy {
57
59
 
58
60
  try {
59
61
  const config = new Config(options) // TODO: support dynamic code config
62
+
63
+ if (config.crashtracking.enabled) {
64
+ require('./crashtracking').start(config)
65
+ }
66
+
60
67
  telemetry.start(config, this._pluginManager)
61
68
 
62
69
  if (config.dogstatsd) {
@@ -195,11 +202,15 @@ class Tracer extends NoopProxy {
195
202
  if (config.appsec.enabled) {
196
203
  this._modules.appsec.enable(config)
197
204
  }
205
+ if (config.llmobs.enabled) {
206
+ this._modules.llmobs.enable(config)
207
+ }
198
208
  if (!this._tracingInitialized) {
199
209
  const prioritySampler = appsecStandalone.configure(config)
200
210
  this._tracer = new DatadogTracer(config, prioritySampler)
201
211
  this.dataStreamsCheckpointer = this._tracer.dataStreamsCheckpointer
202
212
  this.appsec = new AppsecSdk(this._tracer, config)
213
+ this.llmobs = new LLMObsSDK(this._tracer, this._modules.llmobs, config)
203
214
  this._tracingInitialized = true
204
215
  }
205
216
  if (config.iast.enabled) {
@@ -208,6 +219,7 @@ class Tracer extends NoopProxy {
208
219
  } else if (this._tracingInitialized) {
209
220
  this._modules.appsec.disable()
210
221
  this._modules.iast.disable()
222
+ this._modules.llmobs.disable()
211
223
  }
212
224
 
213
225
  if (this._tracingInitialized) {
@@ -10,6 +10,9 @@ const { SpanStatsProcessor } = require('./span_stats')
10
10
  const startedSpans = new WeakSet()
11
11
  const finishedSpans = new WeakSet()
12
12
 
13
+ const { channel } = require('dc-polyfill')
14
+ const spanProcessCh = channel('dd-trace:span:process')
15
+
13
16
  class SpanProcessor {
14
17
  constructor (exporter, prioritySampler, config) {
15
18
  this._exporter = exporter
@@ -45,6 +48,8 @@ class SpanProcessor {
45
48
  const formattedSpan = format(span)
46
49
  this._stats.onSpanFinished(formattedSpan)
47
50
  formatted.push(formattedSpan)
51
+
52
+ spanProcessCh.publish({ span })
48
53
  } else {
49
54
  active.push(span)
50
55
  }
@@ -314,7 +314,17 @@ function updateConfig (changes, config) {
314
314
  logInjection: 'DD_LOG_INJECTION',
315
315
  headerTags: 'DD_TRACE_HEADER_TAGS',
316
316
  tags: 'DD_TAGS',
317
- 'sampler.rules': 'DD_TRACE_SAMPLING_RULES'
317
+ 'sampler.rules': 'DD_TRACE_SAMPLING_RULES',
318
+ traceEnabled: 'DD_TRACE_ENABLED',
319
+ url: 'DD_TRACE_AGENT_URL',
320
+ 'sampler.rateLimit': 'DD_TRACE_RATE_LIMIT',
321
+ queryStringObfuscation: 'DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP',
322
+ version: 'DD_VERSION',
323
+ env: 'DD_ENV',
324
+ service: 'DD_SERVICE',
325
+ clientIpHeader: 'DD_TRACE_CLIENT_IP_HEADER',
326
+ 'grpc.client.error.statuses': 'DD_GRPC_CLIENT_ERROR_STATUSES',
327
+ 'grpc.server.error.statuses': 'DD_GRPC_SERVER_ERROR_STATUSES'
318
328
  }
319
329
 
320
330
  const namesNeedFormatting = new Set(['DD_TAGS', 'peerServiceMapping', 'serviceMapping'])
@@ -35,18 +35,23 @@ function onLog (log) {
35
35
  }
36
36
 
37
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
- })
38
+ const { message, cause } = msg
39
+ if (!message && !cause) return
40
+
41
+ const telLog = {
42
+ level: 'ERROR',
43
+
44
+ // existing log.error(err) without message will be reported as 'Generic Error'
45
+ message: message ?? 'Generic Error'
49
46
  }
47
+
48
+ if (cause) {
49
+ telLog.stack_trace = cause.stack
50
+ const errorType = cause.name ?? 'Error'
51
+ telLog.message = `${errorType}: ${telLog.message}`
52
+ }
53
+
54
+ onLog(telLog)
50
55
  }
51
56
 
52
57
  function start (config) {
@@ -48,16 +48,11 @@ function sanitize (logEntry) {
48
48
  .map(line => line.replace(ddBasePath, ''))
49
49
 
50
50
  logEntry.stack_trace = stackLines.join(EOL)
51
- if (logEntry.stack_trace === '') {
52
- // If entire stack was removed, we'd just have a message saying "omitted"
53
- // in which case we'd rather not log it at all.
51
+ if (logEntry.stack_trace === '' && !logEntry.message) {
52
+ // If entire stack was removed and there is no message we'd rather not log it at all.
54
53
  return null
55
54
  }
56
55
 
57
- if (!isDDCode) {
58
- logEntry.message = 'omitted'
59
- }
60
-
61
56
  return logEntry
62
57
  }
63
58
 
@@ -82,7 +77,7 @@ const logCollector = {
82
77
  return true
83
78
  }
84
79
  } catch (e) {
85
- log.error(`Unable to add log to logCollector: ${e.message}`)
80
+ log.error('Unable to add log to logCollector: %s', e.message)
86
81
  }
87
82
  return false
88
83
  },
@@ -27,13 +27,18 @@ function hasPoints (metric) {
27
27
  return metric.points.length > 0
28
28
  }
29
29
 
30
+ let versionTag
31
+
30
32
  class Metric {
31
33
  constructor (namespace, metric, common, tags) {
32
34
  this.namespace = namespace.toString()
33
35
  this.metric = common ? metric : `nodejs.${metric}`
34
36
  this.tags = tagArray(tags)
35
37
  if (common) {
36
- this.tags.push(`version:${process.version}`)
38
+ if (versionTag === undefined) {
39
+ versionTag = `version:${process.version}`
40
+ }
41
+ this.tags.push(versionTag)
37
42
  }
38
43
  this.common = common
39
44
 
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
 
3
+ const crypto = require('crypto')
3
4
  const path = require('path')
4
5
 
5
6
  function isTrue (str) {
@@ -73,11 +74,25 @@ function hasOwn (object, prop) {
73
74
  return Object.prototype.hasOwnProperty.call(object, prop)
74
75
  }
75
76
 
77
+ /**
78
+ * Generates a unique hash from an array of strings by joining them with | before hashing.
79
+ * Used to uniquely identify AWS requests for span pointers.
80
+ * @param {string[]} components - Array of strings to hash
81
+ * @returns {string} A 32-character hash uniquely identifying the components
82
+ */
83
+ function generatePointerHash (components) {
84
+ // If passing S3's ETag as a component, make sure any quotes have already been removed!
85
+ const dataToHash = components.join('|')
86
+ const hash = crypto.createHash('sha256').update(dataToHash).digest('hex')
87
+ return hash.substring(0, 32)
88
+ }
89
+
76
90
  module.exports = {
77
91
  isTrue,
78
92
  isFalse,
79
93
  isError,
80
94
  globMatch,
81
95
  calculateDDBasePath,
82
- hasOwn
96
+ hasOwn,
97
+ generatePointerHash
83
98
  }
package/version.js CHANGED
@@ -1,7 +1,9 @@
1
1
  'use strict'
2
2
 
3
- const ddMatches = require('./package.json').version.match(/^(\d+)\.(\d+)\.(\d+)/)
4
- const nodeMatches = process.versions.node.match(/^(\d+)\.(\d+)\.(\d+)/)
3
+ /* eslint-disable no-var */
4
+
5
+ var ddMatches = require('./package.json').version.match(/^(\d+)\.(\d+)\.(\d+)/)
6
+ var nodeMatches = process.versions.node.match(/^(\d+)\.(\d+)\.(\d+)/)
5
7
 
6
8
  module.exports = {
7
9
  DD_MAJOR: parseInt(ddMatches[1]),