dd-trace 5.38.0 → 5.40.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 (97) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/index.d.ts +30 -21
  3. package/package.json +4 -2
  4. package/packages/datadog-instrumentations/src/apollo-server-core.js +1 -1
  5. package/packages/datadog-instrumentations/src/apollo-server.js +1 -1
  6. package/packages/datadog-instrumentations/src/express-session.js +41 -0
  7. package/packages/datadog-instrumentations/src/fetch.js +27 -6
  8. package/packages/datadog-instrumentations/src/helpers/fetch.js +6 -1
  9. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  10. package/packages/datadog-instrumentations/src/jest.js +16 -10
  11. package/packages/datadog-instrumentations/src/mocha/main.js +2 -1
  12. package/packages/datadog-instrumentations/src/nyc.js +2 -1
  13. package/packages/datadog-instrumentations/src/vitest.js +4 -2
  14. package/packages/datadog-plugin-amqplib/src/consumer.js +1 -1
  15. package/packages/datadog-plugin-amqplib/src/producer.js +1 -2
  16. package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
  17. package/packages/datadog-plugin-aws-sdk/src/base.js +5 -1
  18. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +9 -8
  19. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -4
  20. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -2
  21. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -2
  22. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +1 -1
  23. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +1 -2
  24. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +1 -1
  25. package/packages/datadog-plugin-kafkajs/src/consumer.js +5 -2
  26. package/packages/datadog-plugin-kafkajs/src/producer.js +4 -3
  27. package/packages/datadog-plugin-mongodb-core/src/index.js +10 -13
  28. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
  29. package/packages/datadog-plugin-rhea/src/consumer.js +1 -1
  30. package/packages/datadog-plugin-rhea/src/producer.js +1 -2
  31. package/packages/datadog-shimmer/src/shimmer.js +95 -95
  32. package/packages/dd-trace/src/appsec/addresses.js +1 -0
  33. package/packages/dd-trace/src/appsec/channels.js +1 -0
  34. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +1 -1
  35. package/packages/dd-trace/src/appsec/iast/iast-context.js +2 -2
  36. package/packages/dd-trace/src/appsec/iast/index.js +0 -1
  37. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +1 -2
  38. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +3 -5
  39. package/packages/dd-trace/src/appsec/index.js +23 -1
  40. package/packages/dd-trace/src/appsec/reporter.js +3 -8
  41. package/packages/dd-trace/src/appsec/rule_manager.js +1 -1
  42. package/packages/dd-trace/src/appsec/sdk/set_user.js +9 -5
  43. package/packages/dd-trace/src/appsec/sdk/track_event.js +2 -4
  44. package/packages/dd-trace/src/appsec/telemetry/common.js +24 -0
  45. package/packages/dd-trace/src/appsec/telemetry/index.js +126 -0
  46. package/packages/dd-trace/src/appsec/telemetry/rasp.js +35 -0
  47. package/packages/dd-trace/src/appsec/telemetry/user.js +24 -0
  48. package/packages/dd-trace/src/appsec/telemetry/waf.js +92 -0
  49. package/packages/dd-trace/src/appsec/user_tracking.js +2 -4
  50. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +16 -4
  51. package/packages/dd-trace/src/config.js +31 -14
  52. package/packages/dd-trace/src/constants.js +1 -1
  53. package/packages/dd-trace/src/{data_streams.js → datastreams/checkpointer.js} +1 -1
  54. package/packages/dd-trace/src/{data_streams_context.js → datastreams/context.js} +2 -2
  55. package/packages/dd-trace/src/datastreams/index.js +104 -0
  56. package/packages/dd-trace/src/datastreams/manager.js +27 -0
  57. package/packages/dd-trace/src/datastreams/processor.js +1 -44
  58. package/packages/dd-trace/src/datastreams/size.js +53 -0
  59. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +2 -2
  60. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +1 -1
  61. package/packages/dd-trace/src/debugger/devtools_client/source-maps.js +22 -15
  62. package/packages/dd-trace/src/dogstatsd.js +23 -4
  63. package/packages/dd-trace/src/exporters/agent/index.js +2 -2
  64. package/packages/dd-trace/src/flare/index.js +3 -0
  65. package/packages/dd-trace/src/noop/dogstatsd.js +6 -0
  66. package/packages/dd-trace/src/opentelemetry/tracer.js +45 -1
  67. package/packages/dd-trace/src/opentracing/propagation/text_map.js +11 -47
  68. package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +1 -1
  69. package/packages/dd-trace/src/opentracing/span.js +12 -2
  70. package/packages/dd-trace/src/payload-tagging/config/aws.json +8 -0
  71. package/packages/dd-trace/src/plugin_manager.js +4 -3
  72. package/packages/dd-trace/src/plugins/ci_plugin.js +2 -2
  73. package/packages/dd-trace/src/priority_sampler.js +5 -3
  74. package/packages/dd-trace/src/profiling/profiler.js +1 -1
  75. package/packages/dd-trace/src/profiling/profilers/wall.js +15 -4
  76. package/packages/dd-trace/src/proxy.js +41 -22
  77. package/packages/dd-trace/src/{appsec/remote_config → remote_config}/capabilities.js +1 -0
  78. package/packages/dd-trace/src/{appsec/remote_config → remote_config}/index.js +8 -5
  79. package/packages/dd-trace/src/{appsec/remote_config → remote_config}/manager.js +5 -5
  80. package/packages/dd-trace/src/runtime_metrics/index.js +34 -0
  81. package/packages/dd-trace/src/{runtime_metrics.js → runtime_metrics/runtime_metrics.js} +4 -4
  82. package/packages/dd-trace/src/serverless.js +10 -1
  83. package/packages/dd-trace/src/service-naming/index.js +12 -4
  84. package/packages/dd-trace/src/span_processor.js +7 -4
  85. package/packages/dd-trace/src/span_stats.js +1 -2
  86. package/packages/dd-trace/src/standalone/index.js +70 -0
  87. package/packages/dd-trace/src/standalone/product.js +24 -0
  88. package/packages/dd-trace/src/standalone/tracesource.js +22 -0
  89. package/packages/dd-trace/src/standalone/tracesource_priority_sampler.js +47 -0
  90. package/packages/dd-trace/src/telemetry/index.js +16 -387
  91. package/packages/dd-trace/src/telemetry/telemetry.js +394 -0
  92. package/packages/dd-trace/src/tracer.js +7 -15
  93. package/packages/dd-trace/src/appsec/standalone.js +0 -130
  94. package/packages/dd-trace/src/appsec/telemetry.js +0 -218
  95. package/packages/dd-trace/src/service-naming/schemas/index.js +0 -6
  96. /package/packages/dd-trace/src/{appsec/remote_config → remote_config}/apply_states.js +0 -0
  97. /package/packages/dd-trace/src/{appsec/remote_config → remote_config}/scheduler.js +0 -0
@@ -5,7 +5,7 @@ const { LogCollapsingLowestDenseDDSketch } = require('@datadog/sketches-js')
5
5
  const { DsmPathwayCodec } = require('./pathway')
6
6
  const { DataStreamsWriter } = require('./writer')
7
7
  const { computePathwayHash } = require('./pathway')
8
- const { types } = require('util')
8
+ const { getAmqpMessageSize, getHeadersSize, getMessageSize, getSizeOrZero } = require('./size')
9
9
  const { PATHWAY_HASH } = require('../../../../ext/tags')
10
10
  const { SchemaBuilder } = require('./schemas/schema_builder')
11
11
  const { SchemaSampler } = require('./schemas/schema_sampler')
@@ -115,49 +115,6 @@ class StatsBucket {
115
115
  }
116
116
  }
117
117
 
118
- function getSizeOrZero (obj) {
119
- if (typeof obj === 'string') {
120
- return Buffer.from(obj, 'utf-8').length
121
- }
122
- if (types.isArrayBuffer(obj)) {
123
- return obj.byteLength
124
- }
125
- if (Buffer.isBuffer(obj)) {
126
- return obj.length
127
- }
128
- if (Array.isArray(obj) && obj.length > 0) {
129
- if (typeof obj[0] === 'number') return Buffer.from(obj).length
130
- let payloadSize = 0
131
- obj.forEach(item => {
132
- payloadSize += getSizeOrZero(item)
133
- })
134
- return payloadSize
135
- }
136
- if (obj !== null && typeof obj === 'object') {
137
- try {
138
- return getHeadersSize(obj)
139
- } catch {
140
- // pass
141
- }
142
- }
143
- return 0
144
- }
145
-
146
- function getHeadersSize (headers) {
147
- if (headers === undefined) return 0
148
- return Object.entries(headers).reduce((prev, [key, val]) => getSizeOrZero(key) + getSizeOrZero(val) + prev, 0)
149
- }
150
-
151
- function getMessageSize (message) {
152
- const { key, value, headers } = message
153
- return getSizeOrZero(key) + getSizeOrZero(value) + getHeadersSize(headers)
154
- }
155
-
156
- function getAmqpMessageSize (message) {
157
- const { headers, content } = message
158
- return getSizeOrZero(content) + getHeadersSize(headers)
159
- }
160
-
161
118
  class TimeBuckets extends Map {
162
119
  forTime (time) {
163
120
  if (!this.has(time)) {
@@ -0,0 +1,53 @@
1
+ 'use strict'
2
+
3
+ const { types } = require('util')
4
+
5
+ function getSizeOrZero (obj) {
6
+ if (typeof obj === 'string') {
7
+ return Buffer.from(obj, 'utf-8').length
8
+ }
9
+ if (types.isArrayBuffer(obj)) {
10
+ return obj.byteLength
11
+ }
12
+ if (Buffer.isBuffer(obj)) {
13
+ return obj.length
14
+ }
15
+ if (Array.isArray(obj) && obj.length > 0) {
16
+ if (typeof obj[0] === 'number') return Buffer.from(obj).length
17
+ let payloadSize = 0
18
+ obj.forEach(item => {
19
+ payloadSize += getSizeOrZero(item)
20
+ })
21
+ return payloadSize
22
+ }
23
+ if (obj !== null && typeof obj === 'object') {
24
+ try {
25
+ return getHeadersSize(obj)
26
+ } catch {
27
+ // pass
28
+ }
29
+ }
30
+ return 0
31
+ }
32
+
33
+ function getHeadersSize (headers) {
34
+ if (headers === undefined) return 0
35
+ return Object.entries(headers).reduce((prev, [key, val]) => getSizeOrZero(key) + getSizeOrZero(val) + prev, 0)
36
+ }
37
+
38
+ function getMessageSize (message) {
39
+ const { key, value, headers } = message
40
+ return getSizeOrZero(key) + getSizeOrZero(value) + getHeadersSize(headers)
41
+ }
42
+
43
+ function getAmqpMessageSize (message) {
44
+ const { headers, content } = message
45
+ return getSizeOrZero(content) + getHeadersSize(headers)
46
+ }
47
+
48
+ module.exports = {
49
+ getMessageSize,
50
+ getHeadersSize,
51
+ getSizeOrZero,
52
+ getAmqpMessageSize
53
+ }
@@ -76,12 +76,12 @@ async function removeBreakpoint ({ id }) {
76
76
  if (breakpoints.size === 0) return stop() // return instead of await to reduce number of promises created
77
77
  }
78
78
 
79
- async function start () {
79
+ function start () {
80
80
  sessionStarted = true
81
81
  return session.post('Debugger.enable') // return instead of await to reduce number of promises created
82
82
  }
83
83
 
84
- async function stop () {
84
+ function stop () {
85
85
  sessionStarted = false
86
86
  return session.post('Debugger.disable') // return instead of await to reduce number of promises created
87
87
  }
@@ -63,7 +63,7 @@ async function traverseGetPropertiesResult (props, opts, depth) {
63
63
  return props
64
64
  }
65
65
 
66
- async function getObjectProperties (subtype, objectId, opts, depth) {
66
+ function getObjectProperties (subtype, objectId, opts, depth) {
67
67
  if (ITERABLE_SUBTYPES.has(subtype)) {
68
68
  return getIterable(objectId, opts, depth)
69
69
  } else if (subtype === 'promise') {
@@ -4,10 +4,11 @@ const { join, dirname } = require('path')
4
4
  const { readFileSync } = require('fs')
5
5
  const { readFile } = require('fs/promises')
6
6
  const { SourceMapConsumer } = require('source-map')
7
+ const { NODE_MAJOR } = require('../../../../../version')
7
8
 
8
9
  const cache = new Map()
9
10
  let cacheTimer = null
10
- let cacheTimerLastSet = 0
11
+ let cacheTime = null
11
12
 
12
13
  const self = module.exports = {
13
14
  async loadSourceMap (dir, url) {
@@ -34,28 +35,34 @@ const self = module.exports = {
34
35
  }
35
36
  }
36
37
 
37
- // TODO: Remove if-statement around `setTimeout` below once it's safe to do so.
38
- //
39
- // This is a workaround for, what seems like a bug in Node.js core, that seems to trigger when, among other things, a
40
- // lot of timers are being created very rapidly. This makes the call to `setTimeout` throw an error from within
41
- // `AsyncLocalStorage._propagate` with the following error message:
38
+ // The version check inside this function is to guard against a bug Node.js version 18, in which calls to `setTimeout`
39
+ // might throw an uncatchable error from within `AsyncLocalStorage._propagate` with the following error message:
42
40
  //
43
41
  // TypeError: Cannot read properties of undefined (reading 'Symbol(kResourceStore)')
44
42
  //
45
43
  // Source: https://github.com/nodejs/node/blob/v18.20.6/lib/async_hooks.js#L312
46
44
  function cacheIt (key, value) {
47
- const now = Date.now()
48
- if (now > cacheTimerLastSet + 1_000) {
49
- clearTimeout(cacheTimer)
50
- cacheTimer = setTimeout(function () {
45
+ if (NODE_MAJOR < 20) return value
46
+ cacheTime = Date.now()
47
+ setCacheTTL()
48
+ cache.set(key, value)
49
+ return value
50
+ }
51
+
52
+ function setCacheTTL () {
53
+ if (cacheTimer !== null) return
54
+
55
+ cacheTimer = setTimeout(function () {
56
+ cacheTimer = null
57
+ if (Date.now() - cacheTime < 2_500) {
58
+ // If the last cache entry was added recently, keep the cache alive
59
+ setCacheTTL()
60
+ } else {
51
61
  // Optimize for app boot, where a lot of reads might happen
52
62
  // Clear cache a few seconds after it was last used
53
63
  cache.clear()
54
- }, 10_000).unref()
55
- cacheTimerLastSet = now
56
- }
57
- cache.set(key, value)
58
- return value
64
+ }
65
+ }, 5_000).unref()
59
66
  }
60
67
 
61
68
  function loadInlineSourceMap (data) {
@@ -14,6 +14,10 @@ const TYPE_GAUGE = 'g'
14
14
  const TYPE_DISTRIBUTION = 'd'
15
15
  const TYPE_HISTOGRAM = 'h'
16
16
 
17
+ /**
18
+ * @import { DogStatsD } from "../../../index.d.ts"
19
+ * @implements {DogStatsD}
20
+ */
17
21
  class DogStatsDClient {
18
22
  constructor (options = {}) {
19
23
  if (options.metricsProxyUrl) {
@@ -39,6 +43,10 @@ class DogStatsDClient {
39
43
  this._add(stat, value, TYPE_COUNTER, tags)
40
44
  }
41
45
 
46
+ decrement (stat, value, tags) {
47
+ this._add(stat, -value, TYPE_COUNTER, tags)
48
+ }
49
+
42
50
  gauge (stat, value, tags) {
43
51
  this._add(stat, value, TYPE_GAUGE, tags)
44
52
  }
@@ -77,7 +85,7 @@ class DogStatsDClient {
77
85
  // we're not getting a 200 from the proxy endpoint. If it's a 404,
78
86
  // then we know we'll never have the endpoint, so just clear out the
79
87
  // options. Either way, we can give UDP a try.
80
- this._httpOptions = null
88
+ this._httpOptions = undefined
81
89
  }
82
90
  this._sendUdp(queue)
83
91
  }
@@ -185,11 +193,22 @@ class DogStatsDClient {
185
193
  }
186
194
  }
187
195
 
188
- // This is a simplified user-facing proxy to the underlying DogStatsDClient instance
196
+ /**
197
+ * This is a simplified user-facing proxy to the underlying DogStatsDClient instance
198
+ *
199
+ * @implements {DogStatsD}
200
+ */
189
201
  class CustomMetrics {
190
202
  constructor (config) {
191
203
  const clientConfig = DogStatsDClient.generateClientConfig(config)
192
204
  this.dogstatsd = new DogStatsDClient(clientConfig)
205
+
206
+ const flush = this.flush.bind(this)
207
+
208
+ // TODO(bengl) this magic number should be configurable
209
+ setInterval(flush, 10 * 1000).unref()
210
+
211
+ process.once('beforeExit', flush)
193
212
  }
194
213
 
195
214
  increment (stat, value = 1, tags) {
@@ -201,9 +220,9 @@ class CustomMetrics {
201
220
  }
202
221
 
203
222
  decrement (stat, value = 1, tags) {
204
- return this.dogstatsd.increment(
223
+ return this.dogstatsd.decrement(
205
224
  stat,
206
- value * -1,
225
+ value,
207
226
  CustomMetrics.tagTranslator(tags)
208
227
  )
209
228
  }
@@ -7,7 +7,7 @@ const Writer = require('./writer')
7
7
  class AgentExporter {
8
8
  constructor (config, prioritySampler) {
9
9
  this._config = config
10
- const { url, hostname, port, lookup, protocolVersion, stats = {}, appsec } = config
10
+ const { url, hostname, port, lookup, protocolVersion, stats = {}, apmTracingEnabled } = config
11
11
  this._url = url || new URL(format({
12
12
  protocol: 'http:',
13
13
  hostname: hostname || 'localhost',
@@ -15,7 +15,7 @@ class AgentExporter {
15
15
  }))
16
16
 
17
17
  const headers = {}
18
- if (stats.enabled || appsec?.standalone?.enabled) {
18
+ if (stats.enabled || apmTracingEnabled === false) {
19
19
  headers['Datadog-Client-Computed-Stats'] = 'yes'
20
20
  }
21
21
 
@@ -92,6 +92,9 @@ const flare = {
92
92
  function recordLog (msg) {
93
93
  if (tracerLogs.length > MAX_LOG_SIZE) return
94
94
 
95
+ if (msg && typeof msg === 'object') {
96
+ msg = JSON.stringify(msg)
97
+ }
95
98
  tracerLogs.write(`${msg}\n`) // TODO: gzip
96
99
  }
97
100
 
@@ -1,6 +1,12 @@
1
+ /**
2
+ * @import { DogStatsD } from "../../../../index.d.ts"
3
+ * @implements {DogStatsD}
4
+ */
1
5
  module.exports = class NoopDogStatsDClient {
2
6
  increment () { }
3
7
 
8
+ decrement () { }
9
+
4
10
  gauge () { }
5
11
 
6
12
  distribution () { }
@@ -6,8 +6,10 @@ const { sanitizeAttributes } = require('@opentelemetry/core')
6
6
  const Sampler = require('./sampler')
7
7
  const Span = require('./span')
8
8
  const id = require('../id')
9
+ const log = require('../log')
9
10
  const SpanContext = require('./span_context')
10
11
  const TextMapPropagator = require('../opentracing/propagation/text_map')
12
+ const TraceState = require('../opentracing/propagation/tracestate')
11
13
 
12
14
  class Tracer {
13
15
  constructor (library, config, tracerProvider) {
@@ -39,7 +41,49 @@ class Tracer {
39
41
  // Extracted method to create span context for a new span
40
42
  _createSpanContextForNewSpan (context) {
41
43
  const { traceId, spanId, traceFlags, traceState } = context
42
- return TextMapPropagator._convertOtelContextToDatadog(traceId, spanId, traceFlags, traceState)
44
+ return this._convertOtelContextToDatadog(traceId, spanId, traceFlags, traceState)
45
+ }
46
+
47
+ _convertOtelContextToDatadog (traceId, spanId, traceFlag, ts, meta = {}) {
48
+ const origin = null
49
+ let samplingPriority = traceFlag
50
+
51
+ ts = ts?.traceparent || null
52
+
53
+ if (ts) {
54
+ // Use TraceState.fromString to parse the tracestate header
55
+ const traceState = TraceState.fromString(ts)
56
+ let ddTraceStateData = null
57
+
58
+ // Extract Datadog specific trace state data
59
+ traceState.forVendor('dd', (state) => {
60
+ ddTraceStateData = state
61
+ return state // You might need to adjust this part based on actual logic needed
62
+ })
63
+
64
+ if (ddTraceStateData) {
65
+ // Assuming ddTraceStateData is now a Map or similar structure containing Datadog trace state data
66
+ // Extract values as needed, similar to the original logic
67
+ const samplingPriorityTs = ddTraceStateData.get('s')
68
+ const origin = ddTraceStateData.get('o')
69
+ // Convert Map to object for meta
70
+ const otherPropagatedTags = Object.fromEntries(ddTraceStateData.entries())
71
+
72
+ // Update meta and samplingPriority based on extracted values
73
+ Object.assign(meta, otherPropagatedTags)
74
+ samplingPriority = TextMapPropagator._getSamplingPriority(traceFlag, parseInt(samplingPriorityTs, 10), origin)
75
+ } else {
76
+ log.debug(`no dd list member in tracestate from incoming request: ${ts}`)
77
+ }
78
+ }
79
+
80
+ const spanContext = new SpanContext({
81
+ traceId: id(traceId, 16), spanId: id(), tags: meta, parentId: id(spanId, 16)
82
+ })
83
+
84
+ spanContext._sampling = { priority: samplingPriority }
85
+ spanContext._trace = { origin }
86
+ return spanContext
43
87
  }
44
88
 
45
89
  startSpan (name, options = {}, context = api.context.active()) {
@@ -3,7 +3,6 @@
3
3
  const pick = require('../../../../datadog-core/src/utils/src/pick')
4
4
  const id = require('../../id')
5
5
  const DatadogSpanContext = require('../span_context')
6
- const OtelSpanContext = require('../../opentelemetry/span_context')
7
6
  const log = require('../../log')
8
7
  const TraceState = require('./tracestate')
9
8
  const tags = require('../../../../../ext/tags')
@@ -33,11 +32,13 @@ const b3HeaderExpr = /^(([0-9a-f]{16}){1,2}-[0-9a-f]{16}(-[01d](-[0-9a-f]{16})?)
33
32
  const baggageExpr = new RegExp(`^${baggagePrefix}(.+)$`)
34
33
  const tagKeyExpr = /^_dd\.p\.[\x21-\x2b\x2d-\x7e]+$/ // ASCII minus spaces and commas
35
34
  const tagValueExpr = /^[\x20-\x2b\x2d-\x7e]*$/ // ASCII minus commas
36
- const ddKeys = [traceKey, spanKey, samplingKey, originKey]
37
- const b3Keys = [b3TraceKey, b3SpanKey, b3ParentKey, b3SampledKey, b3FlagsKey, b3HeaderKey]
38
- const logKeys = ddKeys.concat(b3Keys)
39
35
  const traceparentExpr = /^([a-f0-9]{2})-([a-f0-9]{32})-([a-f0-9]{16})-([a-f0-9]{2})(-.*)?$/i
40
36
  const traceparentKey = 'traceparent'
37
+ const tracestateKey = 'tracestate'
38
+ const ddKeys = [traceKey, spanKey, samplingKey, originKey]
39
+ const b3Keys = [b3TraceKey, b3SpanKey, b3ParentKey, b3SampledKey, b3FlagsKey, b3HeaderKey]
40
+ const w3cKeys = [traceparentKey, tracestateKey]
41
+ const logKeys = ddKeys.concat(b3Keys, w3cKeys)
41
42
  // Origin value in tracestate replaces '~', ',' and ';' with '_"
42
43
  const tracestateOriginFilter = /[^\x20-\x2b\x2d-\x3a\x3c-\x7d]/g
43
44
  // Tag keys in tracestate replace ' ', ',' and '=' with '_'
@@ -78,7 +79,12 @@ class TextMapPropagator {
78
79
  extractCh.publish({ spanContext, carrier })
79
80
  }
80
81
 
81
- log.debug(() => `Extract from carrier: ${JSON.stringify(pick(carrier, logKeys))}.`)
82
+ log.debug(() => {
83
+ const keys = JSON.stringify(pick(carrier, logKeys))
84
+ const styles = this._config.tracePropagationStyle.extract.join(', ')
85
+
86
+ return `Extract from carrier (${styles}): ${keys}.`
87
+ })
82
88
 
83
89
  return spanContext
84
90
  }
@@ -708,48 +714,6 @@ class TextMapPropagator {
708
714
  return spanContext._traceId.toString(16)
709
715
  }
710
716
 
711
- static _convertOtelContextToDatadog (traceId, spanId, traceFlag, ts, meta = {}) {
712
- const origin = null
713
- let samplingPriority = traceFlag
714
-
715
- ts = ts?.traceparent || null
716
-
717
- if (ts) {
718
- // Use TraceState.fromString to parse the tracestate header
719
- const traceState = TraceState.fromString(ts)
720
- let ddTraceStateData = null
721
-
722
- // Extract Datadog specific trace state data
723
- traceState.forVendor('dd', (state) => {
724
- ddTraceStateData = state
725
- return state // You might need to adjust this part based on actual logic needed
726
- })
727
-
728
- if (ddTraceStateData) {
729
- // Assuming ddTraceStateData is now a Map or similar structure containing Datadog trace state data
730
- // Extract values as needed, similar to the original logic
731
- const samplingPriorityTs = ddTraceStateData.get('s')
732
- const origin = ddTraceStateData.get('o')
733
- // Convert Map to object for meta
734
- const otherPropagatedTags = Object.fromEntries(ddTraceStateData.entries())
735
-
736
- // Update meta and samplingPriority based on extracted values
737
- Object.assign(meta, otherPropagatedTags)
738
- samplingPriority = TextMapPropagator._getSamplingPriority(traceFlag, parseInt(samplingPriorityTs, 10), origin)
739
- } else {
740
- log.debug(`no dd list member in tracestate from incoming request: ${ts}`)
741
- }
742
- }
743
-
744
- const spanContext = new OtelSpanContext({
745
- traceId: id(traceId, 16), spanId: id(), tags: meta, parentId: id(spanId, 16)
746
- })
747
-
748
- spanContext._sampling = { priority: samplingPriority }
749
- spanContext._trace = { origin }
750
- return spanContext
751
- }
752
-
753
717
  static _getSamplingPriority (traceparentSampled, tracestateSamplingPriority, origin = null) {
754
718
  const fromRumWithoutPriority = !tracestateSamplingPriority && origin === 'rum'
755
719
 
@@ -1,7 +1,7 @@
1
1
  const pick = require('../../../../datadog-core/src/utils/src/pick')
2
2
  const log = require('../../log')
3
3
 
4
- const { DsmPathwayCodec } = require('../../datastreams/pathway')
4
+ const { DsmPathwayCodec } = require('../../datastreams')
5
5
 
6
6
  const base64Key = 'dd-pathway-ctx-base64'
7
7
  const logKeys = [base64Key]
@@ -13,7 +13,6 @@ const log = require('../log')
13
13
  const { storage } = require('../../../datadog-core')
14
14
  const telemetryMetrics = require('../telemetry/metrics')
15
15
  const { channel } = require('dc-polyfill')
16
- const spanleak = require('../spanleak')
17
16
  const util = require('util')
18
17
 
19
18
  const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
@@ -99,7 +98,18 @@ class DatadogSpan {
99
98
 
100
99
  unfinishedRegistry.register(this, operationName, this)
101
100
  }
102
- spanleak.addSpan(this, operationName)
101
+
102
+ // Nullish operator is used here because both `tracer` and `tracer._config`
103
+ // can be null and there are tests passing invalid values to the `Span`
104
+ // constructor which still succeed today. Part of the problem is that `Span`
105
+ // stores only the tracer and not the config, so anything that needs the
106
+ // config has to read it from the tracer stored on the span, including
107
+ // even `Span` itself in this case.
108
+ //
109
+ // TODO: Refactor Tracer/Span + tests to avoid having to do nullish checks.
110
+ if (tracer?._config?.spanLeakDebug > 0) {
111
+ require('../spanleak').addSpan(this, operationName)
112
+ }
103
113
 
104
114
  if (startCh.hasSubscribers) {
105
115
  startCh.publish({ span: this, fields })
@@ -94,5 +94,13 @@
94
94
  ],
95
95
  "expand": [
96
96
  ]
97
+ },
98
+ "dynamodb": {
99
+ "request": [
100
+ ],
101
+ "response": [
102
+ ],
103
+ "expand": [
104
+ ]
97
105
  }
98
106
  }
@@ -28,9 +28,6 @@ loadChannel.subscribe(({ name }) => {
28
28
  maybeEnable(plugins[name])
29
29
  })
30
30
 
31
- // Globals
32
- maybeEnable(require('../../datadog-plugin-fetch/src'))
33
-
34
31
  // Always enabled
35
32
  maybeEnable(require('../../datadog-plugin-dd-trace-api/src'))
36
33
 
@@ -106,6 +103,10 @@ module.exports = class PluginManager {
106
103
  this._tracerConfig = config
107
104
  this._tracer._nomenclature.configure(config)
108
105
 
106
+ if (!config._isInServerlessEnvironment?.()) {
107
+ maybeEnable(require('../../datadog-plugin-fetch/src'))
108
+ }
109
+
109
110
  for (const name in pluginClasses) {
110
111
  this.loadPlugin(name)
111
112
  }
@@ -40,6 +40,7 @@ const {
40
40
  } = require('../ci-visibility/telemetry')
41
41
  const { CI_PROVIDER_NAME, GIT_REPOSITORY_URL, GIT_COMMIT_SHA, GIT_BRANCH, CI_WORKSPACE_PATH } = require('./util/tags')
42
42
  const { OS_VERSION, OS_PLATFORM, OS_ARCHITECTURE, RUNTIME_NAME, RUNTIME_VERSION } = require('./util/env')
43
+ const getDiClient = require('../ci-visibility/dynamic-instrumentation')
43
44
 
44
45
  module.exports = class CiPlugin extends Plugin {
45
46
  constructor (...args) {
@@ -207,8 +208,7 @@ module.exports = class CiPlugin extends Plugin {
207
208
  }
208
209
 
209
210
  if (config.isTestDynamicInstrumentationEnabled && !this.di) {
210
- const testVisibilityDynamicInstrumentation = require('../ci-visibility/dynamic-instrumentation')
211
- this.di = testVisibilityDynamicInstrumentation
211
+ this.di = getDiClient()
212
212
  }
213
213
 
214
214
  this.testEnvironmentMetadata = getTestEnvironmentMetadata(this.constructor.id, this.config)
@@ -116,7 +116,7 @@ class PrioritySampler {
116
116
  }
117
117
  }
118
118
 
119
- setPriority (span, samplingPriority, mechanism = SAMPLING_MECHANISM_MANUAL) {
119
+ setPriority (span, samplingPriority, product) {
120
120
  if (!span || !this.validate(samplingPriority)) return
121
121
 
122
122
  const context = this._getContext(span)
@@ -128,6 +128,8 @@ class PrioritySampler {
128
128
  }
129
129
 
130
130
  context._sampling.priority = samplingPriority
131
+
132
+ const mechanism = product?.mechanism ?? SAMPLING_MECHANISM_MANUAL
131
133
  context._sampling.mechanism = mechanism
132
134
 
133
135
  log.trace(span, samplingPriority, mechanism)
@@ -229,8 +231,8 @@ class PrioritySampler {
229
231
  }
230
232
  }
231
233
 
232
- static keepTrace (span, mechanism) {
233
- span?._prioritySampler?.setPriority(span, USER_KEEP, mechanism)
234
+ static keepTrace (span, product) {
235
+ span?._prioritySampler?.setPriority(span, USER_KEEP, product)
234
236
  }
235
237
  }
236
238
 
@@ -126,7 +126,7 @@ class Profiler extends EventEmitter {
126
126
  this._timeoutInterval = this._config.flushInterval
127
127
  }
128
128
 
129
- async stop () {
129
+ stop () {
130
130
  if (!this._enabled) return
131
131
 
132
132
  // collect and export current profiles
@@ -286,14 +286,25 @@ class NativeWallProfiler {
286
286
 
287
287
  const labels = { ...getThreadLabels() }
288
288
 
289
- const { context: { ref }, timestamp } = context
290
- const { spanId, rootSpanId, webTags, endpoint } = ref ?? {}
291
-
292
289
  if (this._timelineEnabled) {
293
290
  // Incoming timestamps are in microseconds, we emit nanos.
294
- labels[END_TIMESTAMP_LABEL] = timestamp * 1000n
291
+ labels[END_TIMESTAMP_LABEL] = context.timestamp * 1000n
292
+ }
293
+
294
+ const asyncId = context.asyncId
295
+ if (asyncId !== undefined && asyncId !== -1) {
296
+ labels['async id'] = asyncId
295
297
  }
296
298
 
299
+ // Native profiler doesn't set context.context for some samples, such as idle samples or when
300
+ // the context was otherwise unavailable when the sample was taken.
301
+ const ref = context.context?.ref
302
+ if (typeof ref !== 'object') {
303
+ return labels
304
+ }
305
+
306
+ const { spanId, rootSpanId, webTags, endpoint } = ref
307
+
297
308
  if (spanId !== undefined) {
298
309
  labels[SPAN_ID_LABEL] = spanId
299
310
  }