dd-trace 5.68.0 → 5.69.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 (45) hide show
  1. package/LICENSE-3rdparty.csv +6 -1
  2. package/index.d.ts +193 -1
  3. package/package.json +10 -1
  4. package/packages/datadog-core/src/storage.js +14 -13
  5. package/packages/datadog-esbuild/index.js +62 -26
  6. package/packages/datadog-instrumentations/src/helpers/instrument.js +4 -3
  7. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/index.js +6 -0
  8. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +0 -1
  9. package/packages/datadog-plugin-mongodb-core/src/index.js +18 -5
  10. package/packages/dd-trace/src/aiguard/client.js +25 -0
  11. package/packages/dd-trace/src/aiguard/noop.js +9 -0
  12. package/packages/dd-trace/src/aiguard/sdk.js +173 -0
  13. package/packages/dd-trace/src/aiguard/tags.js +11 -0
  14. package/packages/dd-trace/src/appsec/iast/path-line.js +21 -4
  15. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +6 -3
  16. package/packages/dd-trace/src/appsec/stack_trace.js +20 -1
  17. package/packages/dd-trace/src/config-helper.js +8 -1
  18. package/packages/dd-trace/src/config.js +23 -0
  19. package/packages/dd-trace/src/config_defaults.js +5 -0
  20. package/packages/dd-trace/src/datastreams/index.js +23 -1
  21. package/packages/dd-trace/src/llmobs/plugins/ai/index.js +11 -1
  22. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +8 -6
  23. package/packages/dd-trace/src/log/index.js +4 -4
  24. package/packages/dd-trace/src/noop/proxy.js +4 -0
  25. package/packages/dd-trace/src/opentracing/span.js +1 -1
  26. package/packages/dd-trace/src/payload-tagging/config/index.js +16 -0
  27. package/packages/dd-trace/src/payload-tagging/index.js +26 -15
  28. package/packages/dd-trace/src/payload-tagging/tagging.js +17 -8
  29. package/packages/dd-trace/src/pkg.js +3 -1
  30. package/packages/dd-trace/src/plugins/composite.js +3 -0
  31. package/packages/dd-trace/src/plugins/plugin.js +67 -0
  32. package/packages/dd-trace/src/plugins/util/git.js +1 -1
  33. package/packages/dd-trace/src/plugins/util/test.js +19 -0
  34. package/packages/dd-trace/src/priority_sampler.js +70 -46
  35. package/packages/dd-trace/src/proxy.js +15 -0
  36. package/packages/dd-trace/src/rate_limiter.js +26 -1
  37. package/packages/dd-trace/src/sampling_rule.js +124 -2
  38. package/packages/dd-trace/src/span_sampler.js +19 -0
  39. package/packages/dd-trace/src/standalone/product.js +9 -0
  40. package/packages/dd-trace/src/standalone/tracesource.js +16 -1
  41. package/packages/dd-trace/src/standalone/tracesource_priority_sampler.js +13 -0
  42. package/packages/dd-trace/src/startup-log.js +19 -1
  43. package/packages/dd-trace/src/supported-configurations.json +6 -0
  44. package/packages/dd-trace/src/util.js +1 -1
  45. package/version.js +4 -2
@@ -14,8 +14,8 @@ const { tagsFromObject } = require('./tagging')
14
14
  /**
15
15
  * Given an identified value, attempt to parse it as JSON if relevant
16
16
  *
17
- * @param {any} value
18
- * @returns {any} the parsed object if parsing was successful, the input if not
17
+ * @param {unknown} value
18
+ * @returns {unknown} the parsed object if parsing was successful, the input if not
19
19
  */
20
20
  function maybeJSONParseValue (value) {
21
21
  if (typeof value !== 'string' || value[0] !== '{') {
@@ -32,8 +32,8 @@ function maybeJSONParseValue (value) {
32
32
  /**
33
33
  * Apply expansion to all expansion JSONPath queries
34
34
  *
35
- * @param {Object} object
36
- * @param {[String]} expansionRules list of JSONPath queries
35
+ * @param {Record<string, unknown>} object
36
+ * @param {string[]} expansionRules list of JSONPath queries
37
37
  */
38
38
  function expand (object, expansionRules) {
39
39
  for (const rule of expansionRules) {
@@ -46,8 +46,8 @@ function expand (object, expansionRules) {
46
46
  /**
47
47
  * Apply redaction to all redaction JSONPath queries
48
48
  *
49
- * @param {Object} object
50
- * @param {[String]} redactionRules
49
+ * @param {Record<string, unknown>} object
50
+ * @param {string[]} redactionRules
51
51
  */
52
52
  function redact (object, redactionRules) {
53
53
  for (const rule of redactionRules) {
@@ -65,15 +65,10 @@ function redact (object, redactionRules) {
65
65
  * as there are leaf values in the object
66
66
  * This function performs side-effects on a _copy_ of the input object.
67
67
  *
68
- * @param {Object} config sdk configuration for the service
69
- * @param {[String]} config.expand expansion rules for the service
70
- * @param {[String]} config.request redaction rules for the request
71
- * @param {[String]} config.response redaction rules for the response
72
- * @param {Object} object the input object to generate tags from
73
- * @param {Object} opts tag generation options
74
- * @param {String} opts.prefix prefix for all generated tags
75
- * @param {number} opts.maxDepth maximum depth to traverse the object
76
- * @returns
68
+ * @param {{ expand: string[], request: string[], response: string[] }} config sdk configuration for the service
69
+ * @param {Record<string, unknown>} object the input object to generate tags from
70
+ * @param {{ prefix: string, maxDepth: number }} opts tag generation options
71
+ * @returns {Record<string, string|boolean>} Tags map
77
72
  */
78
73
  function computeTags (config, object, opts) {
79
74
  const payload = rfdc(object)
@@ -84,10 +79,26 @@ function computeTags (config, object, opts) {
84
79
  return tagsFromObject(payload, opts)
85
80
  }
86
81
 
82
+ /**
83
+ * Compute request tags with the request prefix.
84
+ *
85
+ * @param {{ expand: string[], request: string[], response: string[] }} config
86
+ * @param {Record<string, unknown>} object
87
+ * @param {{ maxDepth: number }} opts
88
+ * @returns {Record<string, string|boolean>}
89
+ */
87
90
  function tagsFromRequest (config, object, opts) {
88
91
  return computeTags(config, object, { ...opts, prefix: PAYLOAD_TAG_REQUEST_PREFIX })
89
92
  }
90
93
 
94
+ /**
95
+ * Compute response tags with the response prefix.
96
+ *
97
+ * @param {{ expand: string[], request: string[], response: string[] }} config
98
+ * @param {Record<string, unknown>} object
99
+ * @param {{ maxDepth: number }} opts
100
+ * @returns {Record<string, string|boolean>}
101
+ */
91
102
  function tagsFromResponse (config, object, opts) {
92
103
  return computeTags(config, object, { ...opts, prefix: PAYLOAD_TAG_RESPONSE_PREFIX })
93
104
  }
@@ -8,24 +8,33 @@ const redactedKeys = new Set([
8
8
  const truncated = 'truncated'
9
9
  const redacted = 'redacted'
10
10
 
11
+ /**
12
+ * Escapes dots in keys to preserve hierarchy in flattened tag names.
13
+ *
14
+ * @param {string} key
15
+ * @returns {string}
16
+ */
11
17
  function escapeKey (key) {
12
18
  return key.replaceAll('.', String.raw`\.`)
13
19
  }
14
20
 
15
21
  /**
16
- * Compute normalized payload tags from any given object.
17
- *
18
- * @param {object} object
19
- * @param {import('./mask').Mask} mask
20
- * @param {number} maxDepth
21
- * @param {string} prefix
22
- * @returns
23
- */
22
+ * Compute normalized payload tags from any given object.
23
+ *
24
+ * - Limits total tag count to `PAYLOAD_TAGGING_MAX_TAGS - 1` plus the `_dd.payload_tags_incomplete` flag
25
+ * - Truncates values at max depth and for large scalars
26
+ * - Redacts known sensitive keys
27
+ *
28
+ * @param {unknown} object - Input to flatten into tags
29
+ * @param {{ maxDepth: number, prefix: string }} opts - Traversal options
30
+ * @returns {Record<string, string|boolean>} Map of tag names to values
31
+ */
24
32
  function tagsFromObject (object, opts) {
25
33
  const { maxDepth, prefix } = opts
26
34
 
27
35
  let tagCount = 0
28
36
  let abort = false
37
+ /** @type {Record<string, string|boolean>} */
29
38
  const result = {}
30
39
 
31
40
  function tagRec (prefix, object, depth = 0) {
@@ -20,8 +20,10 @@ function findPkg () {
20
20
 
21
21
  const filePath = findUp('package.json', root, directory)
22
22
 
23
+ if (filePath === undefined) return {}
24
+
23
25
  try {
24
- return JSON.parse(fs.readFileSync(filePath, 'utf8'))
26
+ return require(filePath)
25
27
  } catch {
26
28
  return {}
27
29
  }
@@ -11,6 +11,9 @@ class CompositePlugin extends Plugin {
11
11
  }
12
12
  }
13
13
 
14
+ /**
15
+ * @override
16
+ */
14
17
  configure (config) {
15
18
  super.configure(config)
16
19
  for (const name in this.constructor.plugins) {
@@ -6,6 +6,24 @@ const dc = require('dc-polyfill')
6
6
  const logger = require('../log')
7
7
  const { storage } = require('../../../datadog-core')
8
8
 
9
+ /**
10
+ * Base class for all Datadog plugins.
11
+ *
12
+ * Subclasses MUST define a static field `id` with the integration identifier
13
+ * used across channels, span names, tags and telemetry.
14
+ *
15
+ * Example:
16
+ * ```js
17
+ * class MyPlugin extends Plugin {
18
+ * static id = 'myframework'
19
+ * }
20
+ * ```
21
+ *
22
+ * Notes about the tracer instance:
23
+ * - In some contexts the tracer may be wrapped and available as `{ _tracer: Tracer }`.
24
+ * Use the `tracer` getter which normalizes access.
25
+ */
26
+
9
27
  class Subscription {
10
28
  constructor (event, handler) {
11
29
  this._channel = dc.channel(event)
@@ -50,6 +68,12 @@ class StoreBinding {
50
68
  }
51
69
 
52
70
  module.exports = class Plugin {
71
+ /**
72
+ * Create a new plugin instance.
73
+ *
74
+ * @param {object} tracer Tracer instance or wrapper containing it under `_tracer`.
75
+ * @param {object} tracerConfig Global tracer configuration object.
76
+ */
53
77
  constructor (tracer, tracerConfig) {
54
78
  this._subscriptions = []
55
79
  this._bindings = []
@@ -59,10 +83,22 @@ module.exports = class Plugin {
59
83
  this._tracerConfig = tracerConfig // global tracer configuration
60
84
  }
61
85
 
86
+ /**
87
+ * Normalized tracer access. Returns the underlying tracer even if wrapped.
88
+ *
89
+ * @returns {object}
90
+ */
62
91
  get tracer () {
63
92
  return this._tracer?._tracer || this._tracer
64
93
  }
65
94
 
95
+ /**
96
+ * Enter a context with the provided span bound in storage.
97
+ *
98
+ * @param {object} span The span to bind as current.
99
+ * @param {object=} store Optional existing store to extend; if omitted, uses current store.
100
+ * @returns {void}
101
+ */
66
102
  enter (span, store) {
67
103
  store = store || storage('legacy').getStore()
68
104
  storage('legacy').enterWith({ ...store, span })
@@ -74,8 +110,19 @@ module.exports = class Plugin {
74
110
  storage('legacy').enterWith({ noop: true })
75
111
  }
76
112
 
113
+ /**
114
+ * Subscribe to a diagnostic channel with automatic error handling and enable/disable lifecycle.
115
+ *
116
+ * @param {string} channelName Diagnostic channel name.
117
+ * @param {(...args: unknown[]) => unknown} handler Handler invoked on messages.
118
+ * @returns {void}
119
+ */
77
120
  addSub (channelName, handler) {
78
121
  const plugin = this
122
+ /**
123
+ * @this {unknown}
124
+ * @returns {unknown}
125
+ */
79
126
  const wrappedHandler = function () {
80
127
  try {
81
128
  return handler.apply(this, arguments)
@@ -88,10 +135,23 @@ module.exports = class Plugin {
88
135
  this._subscriptions.push(new Subscription(channelName, wrappedHandler))
89
136
  }
90
137
 
138
+ /**
139
+ * Bind the tracer store to a diagnostic channel with a transform function.
140
+ *
141
+ * @param {string} channelName Diagnostic channel name.
142
+ * @param {(data: unknown) => object} transform Transform to compute the bound store.
143
+ * @returns {void}
144
+ */
91
145
  addBind (channelName, transform) {
92
146
  this._bindings.push(new StoreBinding(channelName, transform))
93
147
  }
94
148
 
149
+ /**
150
+ * Attach an error to the current active span (if any).
151
+ *
152
+ * @param {unknown} error Error object or sentinel value.
153
+ * @returns {void}
154
+ */
95
155
  addError (error) {
96
156
  const store = storage('legacy').getStore()
97
157
 
@@ -102,6 +162,13 @@ module.exports = class Plugin {
102
162
  }
103
163
  }
104
164
 
165
+ /**
166
+ * Enable or disable the plugin and (re)apply its configuration.
167
+ *
168
+ * @param {boolean|object} config Either a boolean to enable/disable or a configuration object
169
+ * containing at least `{ enabled: boolean }`.
170
+ * @returns {void}
171
+ */
105
172
  configure (config) {
106
173
  if (typeof config === 'boolean') {
107
174
  config = { enabled: config }
@@ -116,7 +116,7 @@ function isShallowRepository () {
116
116
 
117
117
  function getGitVersion () {
118
118
  const gitVersionString = sanitizedExec('git', ['version'])
119
- const gitVersionMatches = gitVersionString.match(/git version (\d+)\.(\d+)\.(\d+)/)
119
+ const gitVersionMatches = /** @type {RegExpMatchArray} */ (gitVersionString.match(/git version (\d+)\.(\d+)\.(\d+)/))
120
120
  try {
121
121
  return {
122
122
  major: Number.parseInt(gitVersionMatches[1]),
@@ -49,6 +49,13 @@ const { SAMPLING_RULE_DECISION } = require('../../constants')
49
49
  const { AUTO_KEEP } = require('../../../../../ext/priority')
50
50
  const { version: ddTraceVersion } = require('../../../../../package.json')
51
51
 
52
+ /**
53
+ * JSDoc types for test environment metadata helpers.
54
+ *
55
+ * @typedef {{ service?: string, isServiceUserProvided?: boolean }} TestEnvironmentConfig
56
+ * @typedef {Record<string, string|number|undefined>} TestEnvironmentMetadata
57
+ */
58
+
52
59
  // session tags
53
60
  const TEST_SESSION_NAME = 'test_session.name'
54
61
 
@@ -331,6 +338,10 @@ function validateUrl (url) {
331
338
  }
332
339
  }
333
340
 
341
+ /**
342
+ * @param {TestEnvironmentMetadata} metadata
343
+ * @returns {TestEnvironmentMetadata}
344
+ */
334
345
  function removeInvalidMetadata (metadata) {
335
346
  return Object.keys(metadata).reduce((filteredTags, tag) => {
336
347
  if (tag === GIT_REPOSITORY_URL && !validateGitRepositoryUrl(metadata[GIT_REPOSITORY_URL])) {
@@ -444,6 +455,13 @@ function checkShaDiscrepancies (ciMetadata, userProvidedGitMetadata) {
444
455
  )
445
456
  }
446
457
 
458
+ /**
459
+ * Build environment metadata for tests by merging CI, Git, runtime/OS and user-provided metadata.
460
+ *
461
+ * @param {string=} testFramework
462
+ * @param {TestEnvironmentConfig=} config
463
+ * @returns {TestEnvironmentMetadata}
464
+ */
447
465
  function getTestEnvironmentMetadata (testFramework, config, shouldSkipGitMetadataExtraction = false) {
448
466
  const ciMetadata = getCIMetadata()
449
467
  const userProvidedGitMetadata = getUserProviderGitMetadata()
@@ -479,6 +497,7 @@ function getTestEnvironmentMetadata (testFramework, config, shouldSkipGitMetadat
479
497
  })
480
498
  }
481
499
 
500
+ /** @type {TestEnvironmentMetadata} */
482
501
  const runtimeAndOSMetadata = getRuntimeAndOSMetadata()
483
502
 
484
503
  const metadata = {
@@ -46,8 +46,9 @@ const defaultSampler = new Sampler(AUTO_KEEP)
46
46
  * @class PrioritySampler
47
47
  * @typedef {import('./opentracing/span')} DatadogSpan
48
48
  * @typedef {import('./opentracing/span_context')} DatadogSpanContext
49
- * @typedef {import('./standalone/product')} PRODUCTS
49
+ * @typedef {{ id: number, mechanism?: number }} Product
50
50
  * @typedef {2|-1|1|0} SamplingPriority Empirically defined sampling priorities.
51
+ * @typedef {import('./sampling_rule')|Record<string, unknown>} SamplingRuleLike
51
52
  */
52
53
  class PrioritySampler {
53
54
  /**
@@ -55,12 +56,12 @@ class PrioritySampler {
55
56
  *
56
57
  * @typedef {Object} SamplingConfig
57
58
  * @property {number} [sampleRate] - The default sample rate for traces.
58
- * @property {string} [provenance] - The provenance of the sampling rule (e.g., "customer", "dynamic").
59
+ * @property {string} [provenance] - Optional rule provenance ("customer" or "dynamic").
59
60
  * @property {number} [rateLimit=100] - The maximum number of traces to sample per second.
60
- * @property {Array<SamplingRule>} [rules=[]] - An array of sampling rules to apply.
61
+ * @property {Array<import('./sampling_rule')>|Array<Record<string, unknown>>} [rules=[]] - Sampling rules or configs.
61
62
  *
62
63
  * @param {string} env - The environment name (e.g., "production", "staging").
63
- * @param {SamplingConfig} config - The configuration object for sampling.
64
+ * @param {SamplingConfig} [config] - The configuration object for sampling.
64
65
  */
65
66
  constructor (env, config) {
66
67
  this.configure(env, config)
@@ -69,22 +70,22 @@ class PrioritySampler {
69
70
 
70
71
  /**
71
72
  *
72
- * @param env {string}
73
- * @param opts {SamplingConfig}
73
+ * @param {string} env
74
+ * @param {SamplingConfig} config
74
75
  */
75
- configure (env, opts = {}) {
76
- const { sampleRate, provenance, rateLimit = 100, rules } = opts
76
+ configure (env, config = {}) {
77
+ const { sampleRate, provenance, rateLimit = 100, rules } = config
77
78
  this._env = env
78
79
  this._rules = this.#normalizeRules(rules || [], sampleRate, rateLimit, provenance)
79
80
  this._limiter = new RateLimiter(rateLimit)
80
81
 
81
- log.trace(env, opts)
82
+ log.trace(env, config)
82
83
  setSamplingRules(this._rules)
83
84
  }
84
85
 
85
86
  /**
86
- * @param span {DatadogSpan}
87
- * @returns {boolean}
87
+ * @param {DatadogSpan} span
88
+ * @returns {boolean} True if the trace should be sampled based on priority.
88
89
  */
89
90
  isSampled (span) {
90
91
  const priority = this._getPriorityFromAuto(span)
@@ -93,9 +94,10 @@ class PrioritySampler {
93
94
  }
94
95
 
95
96
  /**
97
+ * Assigns a sampling priority to a span if not already set.
96
98
  *
97
- * @param span {DatadogSpan}
98
- * @param auto {boolean}
99
+ * @param {DatadogSpan} span
100
+ * @param {boolean} [auto=true] - Whether to use automatic sampling if no manual tags are present.
99
101
  * @returns {void}
100
102
  */
101
103
  sample (span, auto = true) {
@@ -125,8 +127,9 @@ class PrioritySampler {
125
127
  }
126
128
 
127
129
  /**
130
+ * Updates agent-provided sampling rates keyed by `service:,env:`.
128
131
  *
129
- * @param rates {Record<string, number>}
132
+ * @param {Record<string, number>} rates
130
133
  * @returns {void}
131
134
  */
132
135
  update (rates) {
@@ -145,8 +148,9 @@ class PrioritySampler {
145
148
  }
146
149
 
147
150
  /**
151
+ * Validates that a sampling priority value is one of the allowed constants.
148
152
  *
149
- * @param samplingPriority {SamplingPriority}
153
+ * @param {SamplingPriority|undefined} samplingPriority
150
154
  * @returns {boolean}
151
155
  */
152
156
  validate (samplingPriority) {
@@ -162,10 +166,11 @@ class PrioritySampler {
162
166
  }
163
167
 
164
168
  /**
169
+ * Explicitly sets the priority and mechanism for the span's trace.
165
170
  *
166
- * @param span {DatadogSpan}
167
- * @param samplingPriority {SamplingPriority}
168
- * @param product {import('./standalone/product')}
171
+ * @param {DatadogSpan} span
172
+ * @param {SamplingPriority} samplingPriority
173
+ * @param {Product} [product]
169
174
  */
170
175
  setPriority (span, samplingPriority, product) {
171
176
  if (!span || !this.validate(samplingPriority)) return
@@ -189,17 +194,21 @@ class PrioritySampler {
189
194
  }
190
195
 
191
196
  /**
197
+ * Returns the span context, accepting either a span or a span context.
192
198
  *
193
- * @param span {DatadogSpan}
199
+ * @param {DatadogSpan|DatadogSpanContext} span
194
200
  * @returns {DatadogSpanContext}
195
201
  */
196
202
  _getContext (span) {
197
- return typeof span.context === 'function' ? span.context() : span
203
+ return typeof /** @type {DatadogSpan} */ (span).context === 'function'
204
+ ? /** @type {DatadogSpan} */ (span).context()
205
+ : /** @type {DatadogSpanContext} */ (span)
198
206
  }
199
207
 
200
208
  /**
209
+ * Computes priority using rules and agent rates when no manual tag is present.
201
210
  *
202
- * @param span {DatadogSpan}
211
+ * @param {DatadogSpan} span
203
212
  * @returns {SamplingPriority}
204
213
  */
205
214
  _getPriorityFromAuto (span) {
@@ -212,11 +221,12 @@ class PrioritySampler {
212
221
  }
213
222
 
214
223
  /**
215
- *
216
- * @param tags {Record<string, symbol | unknown>}
224
+ * Computes priority from manual sampling tags if present.
217
225
  * Included for compatibility with {@link import('./standalone/tracesource_priority_sampler')._getPriorityFromTags}
218
- * @param _context {DatadogSpanContext}
219
- * @returns {SamplingPriority}
226
+ *
227
+ * @param {Record<string, unknown>} tags
228
+ * @param {DatadogSpanContext} _context
229
+ * @returns {SamplingPriority|undefined}
220
230
  */
221
231
  _getPriorityFromTags (tags, _context) {
222
232
  if (Object.hasOwn(tags, MANUAL_KEEP) && tags[MANUAL_KEEP] !== false) {
@@ -224,19 +234,23 @@ class PrioritySampler {
224
234
  } else if (Object.hasOwn(tags, MANUAL_DROP) && tags[MANUAL_DROP] !== false) {
225
235
  return USER_REJECT
226
236
  }
227
- const priority = Number.parseInt(tags[SAMPLING_PRIORITY], 10)
228
-
229
- if (priority === 1 || priority === 2) {
230
- return USER_KEEP
231
- } else if (priority === 0 || priority === -1) {
232
- return USER_REJECT
237
+ const rawPriority = tags[SAMPLING_PRIORITY]
238
+ if (rawPriority !== undefined) {
239
+ const priority = Number.parseInt(String(rawPriority), 10)
240
+
241
+ if (priority === 1 || priority === 2) {
242
+ return USER_KEEP
243
+ } else if (priority === 0 || priority === -1) {
244
+ return USER_REJECT
245
+ }
233
246
  }
234
247
  }
235
248
 
236
249
  /**
250
+ * Applies a matching rule and rate limit to compute the sampling priority.
237
251
  *
238
- * @param context {DatadogSpanContext}
239
- * @param rule {SamplingRule}
252
+ * @param {DatadogSpanContext} context
253
+ * @param {import('./sampling_rule')} rule
240
254
  * @returns {SamplingPriority}
241
255
  */
242
256
  #getPriorityByRule (context, rule) {
@@ -251,12 +265,14 @@ class PrioritySampler {
251
265
  }
252
266
 
253
267
  /**
268
+ * Checks if the rate limiter allows sampling for the current window and
269
+ * records the effective rate on the trace.
254
270
  *
255
- * @param context {DatadogSpanContext}
271
+ * @param {DatadogSpanContext} context
256
272
  * @returns {boolean}
257
- * @private
258
273
  */
259
274
  _isSampledByRateLimit (context) {
275
+ // TODO: Change underscored properties to private ones.
260
276
  const allowed = this._limiter.isAllowed()
261
277
 
262
278
  context._trace[SAMPLING_LIMIT_DECISION] = this._limiter.effectiveRate()
@@ -265,12 +281,14 @@ class PrioritySampler {
265
281
  }
266
282
 
267
283
  /**
284
+ * Computes priority using agent-provided sampling rates.
268
285
  *
269
- * @param context {DatadogSpanContext}
286
+ * @param {DatadogSpanContext} context
270
287
  * @returns {SamplingPriority}
271
288
  */
272
289
  #getPriorityByAgent (context) {
273
290
  const key = `service:${context._tags[SERVICE_NAME]},env:${this._env}`
291
+ // TODO: Change underscored properties to private ones.
274
292
  const sampler = this._samplers[key] || this._samplers[DEFAULT_KEY]
275
293
 
276
294
  context._trace[SAMPLING_AGENT_DECISION] = sampler.rate()
@@ -281,8 +299,9 @@ class PrioritySampler {
281
299
  }
282
300
 
283
301
  /**
302
+ * Tags the trace with a decision maker when priority is keep, or removes it otherwise.
284
303
  *
285
- * @param span {DatadogSpan}
304
+ * @param {DatadogSpan} span
286
305
  * @returns {void}
287
306
  */
288
307
  #addDecisionMaker (span) {
@@ -301,11 +320,13 @@ class PrioritySampler {
301
320
  }
302
321
 
303
322
  /**
304
- * @param {Record<string, unknown>[] | Record<string, unknown>} rules - The sampling rules to normalize.
305
- * @param {number} sampleRate
323
+ * Normalizes rule inputs to SamplingRule instances, applying defaults.
324
+ *
325
+ * @param {Array<SamplingRuleLike>|SamplingRuleLike} rules - Rules to normalize.
326
+ * @param {number|undefined} sampleRate
306
327
  * @param {number} rateLimit
307
- * @param {string} provenance
308
- * @returns {SamplingRule[]}
328
+ * @param {string|undefined} provenance
329
+ * @returns {Array<import('./sampling_rule')>}
309
330
  */
310
331
  #normalizeRules (rules, sampleRate, rateLimit, provenance) {
311
332
  rules = Array.isArray(rules) ? rules.flat() : [rules]
@@ -314,7 +335,7 @@ class PrioritySampler {
314
335
 
315
336
  const result = []
316
337
  for (const rule of rules) {
317
- const sampleRate = Number.parseFloat(rule.sampleRate)
338
+ const sampleRate = Number.parseFloat(String(rule.sampleRate))
318
339
  // TODO(BridgeAR): Debug logging invalid rules fails our tests.
319
340
  // Should we definitely not know about these?
320
341
  if (!Number.isNaN(sampleRate)) {
@@ -325,11 +346,13 @@ class PrioritySampler {
325
346
  }
326
347
 
327
348
  /**
349
+ * Finds the first matching rule for the given span.
328
350
  *
329
- * @param span {DatadogSpan}
330
- * @returns {SamplingRule|undefined}
351
+ * @param {DatadogSpan} span
352
+ * @returns {import('./sampling_rule')|undefined}
331
353
  */
332
354
  #findRule (span) {
355
+ // TODO: Change underscored properties to private ones.
333
356
  for (const rule of this._rules) {
334
357
  // Rule is a special object with a .match() property.
335
358
  // It has nothing to do with a regular expression.
@@ -339,9 +362,10 @@ class PrioritySampler {
339
362
  }
340
363
 
341
364
  /**
365
+ * Convenience helper to keep a trace with an optional product mechanism.
342
366
  *
343
- * @param span {DatadogSpan}
344
- * @param product {import('./standalone/product')}
367
+ * @param {DatadogSpan} span
368
+ * @param {Product} [product]
345
369
  */
346
370
  static keepTrace (span, product) {
347
371
  span?._prioritySampler?.setPriority(span, USER_KEEP, product)
@@ -88,6 +88,9 @@ class Tracer extends NoopProxy {
88
88
  }
89
89
  }
90
90
 
91
+ /**
92
+ * @override
93
+ */
91
94
  init (options) {
92
95
  if (this._initialized) return this
93
96
 
@@ -241,6 +244,9 @@ class Tracer extends NoopProxy {
241
244
  this.dataStreamsCheckpointer = this._tracer.dataStreamsCheckpointer
242
245
  lazyProxy(this, 'appsec', config, () => require('./appsec/sdk'), this._tracer, config)
243
246
  lazyProxy(this, 'llmobs', config, () => require('./llmobs/sdk'), this._tracer, this._modules.llmobs, config)
247
+ if (config.experimental?.aiguard?.enabled) {
248
+ lazyProxy(this, 'aiguard', config, () => require('./aiguard/sdk'), this._tracer, config)
249
+ }
244
250
  this._tracingInitialized = true
245
251
  }
246
252
  if (config.iast.enabled) {
@@ -261,6 +267,9 @@ class Tracer extends NoopProxy {
261
267
  }
262
268
  }
263
269
 
270
+ /**
271
+ * @override
272
+ */
264
273
  profilerStarted () {
265
274
  if (!this._profilerStarted) {
266
275
  // injection hardening: this is only ever invoked from tests.
@@ -269,11 +278,17 @@ class Tracer extends NoopProxy {
269
278
  return this._profilerStarted
270
279
  }
271
280
 
281
+ /**
282
+ * @override
283
+ */
272
284
  use () {
273
285
  this._pluginManager.configurePlugin(...arguments)
274
286
  return this
275
287
  }
276
288
 
289
+ /**
290
+ * @override
291
+ */
277
292
  get TracerProvider () {
278
293
  return require('./opentelemetry/tracer_provider')
279
294
  }