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.
- package/LICENSE-3rdparty.csv +6 -1
- package/index.d.ts +193 -1
- package/package.json +10 -1
- package/packages/datadog-core/src/storage.js +14 -13
- package/packages/datadog-esbuild/index.js +62 -26
- package/packages/datadog-instrumentations/src/helpers/instrument.js +4 -3
- package/packages/datadog-plugin-confluentinc-kafka-javascript/src/index.js +6 -0
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +0 -1
- package/packages/datadog-plugin-mongodb-core/src/index.js +18 -5
- package/packages/dd-trace/src/aiguard/client.js +25 -0
- package/packages/dd-trace/src/aiguard/noop.js +9 -0
- package/packages/dd-trace/src/aiguard/sdk.js +173 -0
- package/packages/dd-trace/src/aiguard/tags.js +11 -0
- package/packages/dd-trace/src/appsec/iast/path-line.js +21 -4
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +6 -3
- package/packages/dd-trace/src/appsec/stack_trace.js +20 -1
- package/packages/dd-trace/src/config-helper.js +8 -1
- package/packages/dd-trace/src/config.js +23 -0
- package/packages/dd-trace/src/config_defaults.js +5 -0
- package/packages/dd-trace/src/datastreams/index.js +23 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/index.js +11 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +8 -6
- package/packages/dd-trace/src/log/index.js +4 -4
- package/packages/dd-trace/src/noop/proxy.js +4 -0
- package/packages/dd-trace/src/opentracing/span.js +1 -1
- package/packages/dd-trace/src/payload-tagging/config/index.js +16 -0
- package/packages/dd-trace/src/payload-tagging/index.js +26 -15
- package/packages/dd-trace/src/payload-tagging/tagging.js +17 -8
- package/packages/dd-trace/src/pkg.js +3 -1
- package/packages/dd-trace/src/plugins/composite.js +3 -0
- package/packages/dd-trace/src/plugins/plugin.js +67 -0
- package/packages/dd-trace/src/plugins/util/git.js +1 -1
- package/packages/dd-trace/src/plugins/util/test.js +19 -0
- package/packages/dd-trace/src/priority_sampler.js +70 -46
- package/packages/dd-trace/src/proxy.js +15 -0
- package/packages/dd-trace/src/rate_limiter.js +26 -1
- package/packages/dd-trace/src/sampling_rule.js +124 -2
- package/packages/dd-trace/src/span_sampler.js +19 -0
- package/packages/dd-trace/src/standalone/product.js +9 -0
- package/packages/dd-trace/src/standalone/tracesource.js +16 -1
- package/packages/dd-trace/src/standalone/tracesource_priority_sampler.js +13 -0
- package/packages/dd-trace/src/startup-log.js +19 -1
- package/packages/dd-trace/src/supported-configurations.json +6 -0
- package/packages/dd-trace/src/util.js +1 -1
- 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 {
|
|
18
|
-
* @returns {
|
|
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 {
|
|
36
|
-
* @param {[
|
|
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 {
|
|
50
|
-
* @param {[
|
|
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 {
|
|
69
|
-
* @param {
|
|
70
|
-
* @param {
|
|
71
|
-
* @
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
|
26
|
+
return require(filePath)
|
|
25
27
|
} catch {
|
|
26
28
|
return {}
|
|
27
29
|
}
|
|
@@ -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 {
|
|
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] -
|
|
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<
|
|
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
|
|
73
|
-
* @param
|
|
73
|
+
* @param {string} env
|
|
74
|
+
* @param {SamplingConfig} config
|
|
74
75
|
*/
|
|
75
|
-
configure (env,
|
|
76
|
-
const { sampleRate, provenance, rateLimit = 100, rules } =
|
|
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,
|
|
82
|
+
log.trace(env, config)
|
|
82
83
|
setSamplingRules(this._rules)
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
/**
|
|
86
|
-
* @param
|
|
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
|
|
98
|
-
* @param
|
|
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
|
|
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
|
|
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
|
|
167
|
-
* @param
|
|
168
|
-
* @param
|
|
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
|
|
199
|
+
* @param {DatadogSpan|DatadogSpanContext} span
|
|
194
200
|
* @returns {DatadogSpanContext}
|
|
195
201
|
*/
|
|
196
202
|
_getContext (span) {
|
|
197
|
-
return typeof span.context === 'function'
|
|
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
|
|
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
|
-
*
|
|
219
|
-
* @
|
|
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
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
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
|
|
239
|
-
* @param
|
|
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
|
|
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
|
|
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
|
|
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
|
-
*
|
|
305
|
-
*
|
|
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 {
|
|
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
|
|
330
|
-
* @returns {
|
|
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
|
|
344
|
-
* @param
|
|
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
|
}
|