dd-trace 5.55.0 → 5.56.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 +1 -0
- package/package.json +5 -4
- package/packages/datadog-core/src/utils/src/set.js +8 -10
- package/packages/datadog-instrumentations/src/jest.js +396 -320
- package/packages/datadog-plugin-azure-functions/src/index.js +5 -4
- package/packages/datadog-plugin-oracledb/src/index.js +2 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/security-controls/index.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +44 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +2 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +7 -2
- package/packages/dd-trace/src/appsec/index.js +12 -1
- package/packages/dd-trace/src/appsec/reporter.js +6 -4
- package/packages/dd-trace/src/baggage.js +2 -2
- package/packages/dd-trace/src/config.js +58 -52
- package/packages/dd-trace/src/debugger/devtools_client/send.js +5 -1
- package/packages/dd-trace/src/debugger/devtools_client/status.js +5 -1
- package/packages/dd-trace/src/exporters/agent/writer.js +3 -1
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +18 -24
- package/packages/dd-trace/src/profiling/profilers/events.js +10 -2
- package/packages/dd-trace/src/supported-configurations.json +1 -0
- package/packages/dd-trace/src/telemetry/telemetry.js +6 -3
- package/packages/datadog-core/src/utils/src/get.js +0 -11
- package/packages/datadog-core/src/utils/src/has.js +0 -14
|
@@ -19,14 +19,15 @@ class AzureFunctionsPlugin extends TracingPlugin {
|
|
|
19
19
|
static get operation () { return 'invoke' }
|
|
20
20
|
static get kind () { return 'server' }
|
|
21
21
|
static get type () { return 'serverless' }
|
|
22
|
-
|
|
23
22
|
static get prefix () { return 'tracing:datadog:azure:functions:invoke' }
|
|
24
23
|
|
|
25
24
|
bindStart (ctx) {
|
|
26
|
-
const { functionName, methodName } = ctx
|
|
25
|
+
const { functionName, methodName, httpRequest } = ctx
|
|
27
26
|
const store = storage('legacy').getStore()
|
|
28
|
-
|
|
27
|
+
// httpRequest.headers is a map
|
|
28
|
+
const childOf = this._tracer.extract('http_headers', Object.fromEntries(httpRequest.headers))
|
|
29
29
|
const span = this.startSpan(this.operationName(), {
|
|
30
|
+
childOf,
|
|
30
31
|
service: this.serviceName(),
|
|
31
32
|
type: 'serverless',
|
|
32
33
|
meta: {
|
|
@@ -52,7 +53,7 @@ class AzureFunctionsPlugin extends TracingPlugin {
|
|
|
52
53
|
const path = (new URL(httpRequest.url)).pathname
|
|
53
54
|
const req = {
|
|
54
55
|
method: httpRequest.method,
|
|
55
|
-
headers: Object.fromEntries(httpRequest.headers
|
|
56
|
+
headers: Object.fromEntries(httpRequest.headers),
|
|
56
57
|
url: path
|
|
57
58
|
}
|
|
58
59
|
|
|
@@ -11,7 +11,8 @@ class OracledbPlugin extends DatabasePlugin {
|
|
|
11
11
|
|
|
12
12
|
start ({ query, connAttrs }) {
|
|
13
13
|
const service = this.serviceName({ pluginConfig: this.config, params: connAttrs })
|
|
14
|
-
|
|
14
|
+
// Users can pass either connectString or connectionString
|
|
15
|
+
const url = getUrl(connAttrs.connectString || connAttrs.connectionString)
|
|
15
16
|
|
|
16
17
|
this.startSpan(this.operationName(), {
|
|
17
18
|
service,
|
|
@@ -15,7 +15,7 @@ class SqlInjectionAnalyzer extends StoredInjectionAnalyzer {
|
|
|
15
15
|
|
|
16
16
|
onConfigure () {
|
|
17
17
|
this.addSub('apm:mysql:query:start', ({ sql }) => this.analyze(sql, undefined, 'MYSQL'))
|
|
18
|
-
this.addSub('
|
|
18
|
+
this.addSub('datadog:mysql2:outerquery:start', ({ sql }) => this.analyze(sql, undefined, 'MYSQL'))
|
|
19
19
|
this.addSub('apm:pg:query:start', ({ query }) => this.analyze(query.text, undefined, 'POSTGRES'))
|
|
20
20
|
|
|
21
21
|
this.addSub(
|
|
@@ -85,7 +85,7 @@ function hookModule (filename, module, controlsByFile) {
|
|
|
85
85
|
}
|
|
86
86
|
})
|
|
87
87
|
} catch (e) {
|
|
88
|
-
log.error('[ASM] Error initializing IAST security control for %', filename, e)
|
|
88
|
+
log.error('[ASM] Error initializing IAST security control for %s', filename, e)
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
return module
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
const TaintedUtils = require('@datadog/native-iast-taint-tracking')
|
|
4
4
|
const { IAST_TRANSACTION_ID } = require('../iast-context')
|
|
5
|
+
const { HTTP_REQUEST_PARAMETER } = require('./source-types')
|
|
5
6
|
const log = require('../../../log')
|
|
6
7
|
|
|
8
|
+
const SEPARATOR = '\u0000' // Unit Separator (cannot be in URL keys)
|
|
9
|
+
|
|
7
10
|
function taintObject (iastContext, object, type) {
|
|
8
11
|
let result = object
|
|
9
12
|
const transactionId = iastContext?.[IAST_TRANSACTION_ID]
|
|
@@ -40,6 +43,46 @@ function taintObject (iastContext, object, type) {
|
|
|
40
43
|
return result
|
|
41
44
|
}
|
|
42
45
|
|
|
46
|
+
function taintQueryWithCache (iastContext, query) {
|
|
47
|
+
const transactionId = iastContext?.[IAST_TRANSACTION_ID]
|
|
48
|
+
if (!transactionId || !query) return query
|
|
49
|
+
|
|
50
|
+
iastContext.queryCache ??= new Map() // key: "a.b.c", value: tainted string
|
|
51
|
+
|
|
52
|
+
traverseAndTaint(query, '', iastContext.queryCache, transactionId)
|
|
53
|
+
return query
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function traverseAndTaint (node, path, cache, transactionId) {
|
|
57
|
+
if (node == null) return node
|
|
58
|
+
|
|
59
|
+
if (typeof node === 'string') {
|
|
60
|
+
const cachedValue = cache.get(path)
|
|
61
|
+
|
|
62
|
+
if (cachedValue === node) {
|
|
63
|
+
return cachedValue
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const tainted = TaintedUtils.newTaintedString(transactionId, node, path, HTTP_REQUEST_PARAMETER)
|
|
67
|
+
cache.set(path, tainted)
|
|
68
|
+
|
|
69
|
+
return tainted
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (typeof node === 'object') {
|
|
73
|
+
const keys = Array.isArray(node) ? node.keys() : Object.keys(node)
|
|
74
|
+
|
|
75
|
+
for (const key of keys) {
|
|
76
|
+
const childPath = path ? `${path}${SEPARATOR}${key}` : String(key)
|
|
77
|
+
const tainted = traverseAndTaint(node[key], childPath, cache, transactionId)
|
|
78
|
+
node[key] = tainted
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return node
|
|
83
|
+
}
|
|
84
|
+
|
|
43
85
|
module.exports = {
|
|
44
|
-
taintObject
|
|
86
|
+
taintObject,
|
|
87
|
+
taintQueryWithCache
|
|
45
88
|
}
|
|
@@ -11,7 +11,7 @@ const {
|
|
|
11
11
|
getTaintTrackingNoop,
|
|
12
12
|
lodashTaintTrackingHandler
|
|
13
13
|
} = require('./taint-tracking-impl')
|
|
14
|
-
const { taintObject } = require('./operations-taint-object')
|
|
14
|
+
const { taintObject, taintQueryWithCache } = require('./operations-taint-object')
|
|
15
15
|
|
|
16
16
|
const lodashOperationCh = dc.channel('datadog:lodash:operation')
|
|
17
17
|
|
|
@@ -98,6 +98,7 @@ module.exports = {
|
|
|
98
98
|
newTaintedString,
|
|
99
99
|
newTaintedObject,
|
|
100
100
|
taintObject,
|
|
101
|
+
taintQueryWithCache,
|
|
101
102
|
isTainted,
|
|
102
103
|
getRanges,
|
|
103
104
|
enableTaintOperations,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const { SourceIastPlugin } = require('../iast-plugin')
|
|
4
4
|
const { getIastContext } = require('../iast-context')
|
|
5
5
|
const { storage } = require('../../../../../datadog-core')
|
|
6
|
-
const { taintObject, newTaintedString, getRanges } = require('./operations')
|
|
6
|
+
const { taintObject, newTaintedString, getRanges, taintQueryWithCache } = require('./operations')
|
|
7
7
|
const {
|
|
8
8
|
HTTP_REQUEST_BODY,
|
|
9
9
|
HTTP_REQUEST_COOKIE_VALUE,
|
|
@@ -63,7 +63,12 @@ class TaintTrackingPlugin extends SourceIastPlugin {
|
|
|
63
63
|
|
|
64
64
|
this.addSub(
|
|
65
65
|
{ channelName: 'datadog:express:query:finish', tag: HTTP_REQUEST_PARAMETER },
|
|
66
|
-
({ query }) =>
|
|
66
|
+
({ query }) => {
|
|
67
|
+
const iastContext = getIastContext(storage('legacy').getStore())
|
|
68
|
+
if (!iastContext || !query) return
|
|
69
|
+
|
|
70
|
+
taintQueryWithCache(iastContext, query)
|
|
71
|
+
}
|
|
67
72
|
)
|
|
68
73
|
|
|
69
74
|
this.addSub(
|
|
@@ -37,6 +37,7 @@ const rasp = require('./rasp')
|
|
|
37
37
|
const { isInServerlessEnvironment } = require('../serverless')
|
|
38
38
|
|
|
39
39
|
const responseAnalyzedSet = new WeakSet()
|
|
40
|
+
const storedResponseHeaders = new WeakMap()
|
|
40
41
|
|
|
41
42
|
let isEnabled = false
|
|
42
43
|
let config
|
|
@@ -187,7 +188,13 @@ function incomingHttpEndTranslator ({ req, res }) {
|
|
|
187
188
|
|
|
188
189
|
waf.disposeContext(req)
|
|
189
190
|
|
|
190
|
-
|
|
191
|
+
const storedHeaders = storedResponseHeaders.get(req) || {}
|
|
192
|
+
|
|
193
|
+
Reporter.finishRequest(req, res, storedHeaders)
|
|
194
|
+
|
|
195
|
+
if (storedHeaders) {
|
|
196
|
+
storedResponseHeaders.delete(req)
|
|
197
|
+
}
|
|
191
198
|
}
|
|
192
199
|
|
|
193
200
|
function onPassportVerify ({ framework, login, user, success, abortController }) {
|
|
@@ -285,6 +292,10 @@ function onResponseBody ({ req, res, body }) {
|
|
|
285
292
|
}
|
|
286
293
|
|
|
287
294
|
function onResponseWriteHead ({ req, res, abortController, statusCode, responseHeaders }) {
|
|
295
|
+
if (Object.keys(responseHeaders).length) {
|
|
296
|
+
storedResponseHeaders.set(req, responseHeaders)
|
|
297
|
+
}
|
|
298
|
+
|
|
288
299
|
// avoid "write after end" error
|
|
289
300
|
if (isBlocked(res)) {
|
|
290
301
|
abortController?.abort()
|
|
@@ -140,14 +140,16 @@ function filterExtendedHeaders (headers, excludedHeaderNames, tagPrefix, limit =
|
|
|
140
140
|
return result
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
function getCollectedHeaders (req, res, shouldCollectEventHeaders) {
|
|
143
|
+
function getCollectedHeaders (req, res, shouldCollectEventHeaders, storedResponseHeaders = {}) {
|
|
144
144
|
// Mandatory
|
|
145
145
|
const mandatoryCollectedHeaders = filterHeaders(req.headers, REQUEST_HEADERS_MAP)
|
|
146
146
|
|
|
147
147
|
// Basic collection
|
|
148
148
|
if (!shouldCollectEventHeaders) return mandatoryCollectedHeaders
|
|
149
149
|
|
|
150
|
-
const responseHeaders =
|
|
150
|
+
const responseHeaders = Object.keys(storedResponseHeaders).length === 0
|
|
151
|
+
? res.getHeaders()
|
|
152
|
+
: { ...storedResponseHeaders, ...res.getHeaders() }
|
|
151
153
|
|
|
152
154
|
const requestEventCollectedHeaders = filterHeaders(req.headers, EVENT_HEADERS_MAP)
|
|
153
155
|
const responseEventCollectedHeaders = filterHeaders(responseHeaders, RESPONSE_HEADERS_MAP)
|
|
@@ -399,7 +401,7 @@ function reportDerivatives (derivatives) {
|
|
|
399
401
|
rootSpan.addTags(tags)
|
|
400
402
|
}
|
|
401
403
|
|
|
402
|
-
function finishRequest (req, res) {
|
|
404
|
+
function finishRequest (req, res, storedResponseHeaders) {
|
|
403
405
|
const rootSpan = web.root(req)
|
|
404
406
|
if (!rootSpan) return
|
|
405
407
|
|
|
@@ -453,7 +455,7 @@ function finishRequest (req, res) {
|
|
|
453
455
|
|
|
454
456
|
const tags = rootSpan.context()._tags
|
|
455
457
|
|
|
456
|
-
const newTags = getCollectedHeaders(req, res, shouldCollectEventHeaders(tags))
|
|
458
|
+
const newTags = getCollectedHeaders(req, res, shouldCollectEventHeaders(tags), storedResponseHeaders)
|
|
457
459
|
|
|
458
460
|
if (tags['appsec.event'] === 'true' && typeof req.route?.path === 'string') {
|
|
459
461
|
newTags['http.endpoint'] = req.route.path
|
|
@@ -13,7 +13,7 @@ function getBaggageItem (key) {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
function getAllBaggageItems () {
|
|
16
|
-
return storage('baggage').getStore()
|
|
16
|
+
return storage('baggage').getStore() ?? {}
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
function removeBaggageItem (keyToRemove) {
|
|
@@ -23,7 +23,7 @@ function removeBaggageItem (keyToRemove) {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
function removeAllBaggageItems () {
|
|
26
|
-
storage('baggage').enterWith(
|
|
26
|
+
storage('baggage').enterWith()
|
|
27
27
|
return storage('baggage').getStore()
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -8,8 +8,6 @@ const log = require('./log')
|
|
|
8
8
|
const pkg = require('./pkg')
|
|
9
9
|
const coalesce = require('koalas')
|
|
10
10
|
const tagger = require('./tagger')
|
|
11
|
-
const get = require('../../datadog-core/src/utils/src/get')
|
|
12
|
-
const has = require('../../datadog-core/src/utils/src/has')
|
|
13
11
|
const set = require('../../datadog-core/src/utils/src/set')
|
|
14
12
|
const { isTrue, isFalse, normalizeProfilingEnabledValue } = require('./util')
|
|
15
13
|
const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('./plugins/util/tags')
|
|
@@ -23,6 +21,8 @@ const { getEnvironmentVariable, getEnvironmentVariables } = require('./config-he
|
|
|
23
21
|
|
|
24
22
|
const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
|
|
25
23
|
|
|
24
|
+
const changeTracker = {}
|
|
25
|
+
|
|
26
26
|
const telemetryCounters = {
|
|
27
27
|
'otel.env.hiding': {},
|
|
28
28
|
'otel.env.invalid': {}
|
|
@@ -231,6 +231,16 @@ function reformatSpanSamplingRules (rules) {
|
|
|
231
231
|
})
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
+
const sourcesOrder = [
|
|
235
|
+
{ containerProperty: '_remote', origin: 'remote_config', unprocessedProperty: '_remoteUnprocessed' },
|
|
236
|
+
{ containerProperty: '_options', origin: 'code', unprocessedProperty: '_optsUnprocessed' },
|
|
237
|
+
{ containerProperty: '_fleetStableConfig', origin: 'fleet_stable_config' },
|
|
238
|
+
{ containerProperty: '_env', origin: 'env_var', unprocessedProperty: '_envUnprocessed' },
|
|
239
|
+
{ containerProperty: '_localStableConfig', origin: 'local_stable_config' },
|
|
240
|
+
{ containerProperty: '_calculated', origin: 'calculated' },
|
|
241
|
+
{ containerProperty: '_defaults', origin: 'default' }
|
|
242
|
+
]
|
|
243
|
+
|
|
234
244
|
class Config {
|
|
235
245
|
constructor (options = {}) {
|
|
236
246
|
if (!isInServerlessEnvironment()) {
|
|
@@ -487,6 +497,7 @@ class Config {
|
|
|
487
497
|
this._setValue(defaults, 'dynamicInstrumentation.enabled', false)
|
|
488
498
|
this._setValue(defaults, 'dynamicInstrumentation.redactedIdentifiers', [])
|
|
489
499
|
this._setValue(defaults, 'dynamicInstrumentation.redactionExcludedIdentifiers', [])
|
|
500
|
+
this._setValue(defaults, 'dynamicInstrumentation.uploadIntervalSeconds', 1)
|
|
490
501
|
this._setValue(defaults, 'env')
|
|
491
502
|
this._setValue(defaults, 'experimental.enableGetRumData', false)
|
|
492
503
|
this._setValue(defaults, 'experimental.exporter')
|
|
@@ -670,6 +681,7 @@ class Config {
|
|
|
670
681
|
DD_DYNAMIC_INSTRUMENTATION_ENABLED,
|
|
671
682
|
DD_DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS,
|
|
672
683
|
DD_DYNAMIC_INSTRUMENTATION_REDACTION_EXCLUDED_IDENTIFIERS,
|
|
684
|
+
DD_DYNAMIC_INSTRUMENTATION_UPLOAD_INTERVAL_SECONDS,
|
|
673
685
|
DD_ENV,
|
|
674
686
|
DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED,
|
|
675
687
|
DD_PROFILING_ENABLED,
|
|
@@ -843,6 +855,12 @@ class Config {
|
|
|
843
855
|
'dynamicInstrumentation.redactionExcludedIdentifiers',
|
|
844
856
|
DD_DYNAMIC_INSTRUMENTATION_REDACTION_EXCLUDED_IDENTIFIERS
|
|
845
857
|
)
|
|
858
|
+
this._setValue(
|
|
859
|
+
env,
|
|
860
|
+
'dynamicInstrumentation.uploadIntervalSeconds',
|
|
861
|
+
maybeFloat(DD_DYNAMIC_INSTRUMENTATION_UPLOAD_INTERVAL_SECONDS)
|
|
862
|
+
)
|
|
863
|
+
this._envUnprocessed['dynamicInstrumentation.uploadInterval'] = DD_DYNAMIC_INSTRUMENTATION_UPLOAD_INTERVAL_SECONDS
|
|
846
864
|
this._setString(env, 'env', DD_ENV || tags.env)
|
|
847
865
|
this._setBoolean(env, 'traceEnabled', DD_TRACE_ENABLED)
|
|
848
866
|
this._setBoolean(env, 'experimental.enableGetRumData', DD_TRACE_EXPERIMENTAL_GET_RUM_DATA_ENABLED)
|
|
@@ -1072,6 +1090,13 @@ class Config {
|
|
|
1072
1090
|
'dynamicInstrumentation.redactionExcludedIdentifiers',
|
|
1073
1091
|
options.dynamicInstrumentation?.redactionExcludedIdentifiers
|
|
1074
1092
|
)
|
|
1093
|
+
this._setValue(
|
|
1094
|
+
opts,
|
|
1095
|
+
'dynamicInstrumentation.uploadIntervalSeconds',
|
|
1096
|
+
maybeFloat(options.dynamicInstrumentation?.uploadIntervalSeconds)
|
|
1097
|
+
)
|
|
1098
|
+
this._optsUnprocessed['dynamicInstrumentation.uploadIntervalSeconds'] =
|
|
1099
|
+
options.dynamicInstrumentation?.uploadIntervalSeconds
|
|
1075
1100
|
this._setString(opts, 'env', options.env || tags.env)
|
|
1076
1101
|
this._setBoolean(opts, 'experimental.enableGetRumData', options.experimental?.enableGetRumData)
|
|
1077
1102
|
this._setString(opts, 'experimental.exporter', options.experimental?.exporter)
|
|
@@ -1436,27 +1461,24 @@ class Config {
|
|
|
1436
1461
|
obj[name] = value
|
|
1437
1462
|
}
|
|
1438
1463
|
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
]
|
|
1458
|
-
|
|
1459
|
-
return { containers, origins }
|
|
1464
|
+
_setAndTrackChange ({ name, value, origin, unprocessedValue, changes }) {
|
|
1465
|
+
set(this, name, value)
|
|
1466
|
+
|
|
1467
|
+
if (!changeTracker[name]) {
|
|
1468
|
+
changeTracker[name] = {}
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
const originExists = origin in changeTracker[name]
|
|
1472
|
+
const oldValue = changeTracker[name][origin]
|
|
1473
|
+
|
|
1474
|
+
if (!originExists || oldValue !== value) {
|
|
1475
|
+
changeTracker[name][origin] = value
|
|
1476
|
+
changes.push({
|
|
1477
|
+
name,
|
|
1478
|
+
value: unprocessedValue || value,
|
|
1479
|
+
origin
|
|
1480
|
+
})
|
|
1481
|
+
}
|
|
1460
1482
|
}
|
|
1461
1483
|
|
|
1462
1484
|
// TODO: Report origin changes and errors to telemetry.
|
|
@@ -1465,51 +1487,35 @@ class Config {
|
|
|
1465
1487
|
// for telemetry reporting, `name`s in `containers` need to be keys from:
|
|
1466
1488
|
// https://github.com/DataDog/dd-go/blob/prod/trace/apps/tracer-telemetry-intake/telemetry-payload/static/config_norm_rules.json
|
|
1467
1489
|
_merge () {
|
|
1468
|
-
const { containers, origins } = this._getContainersAndOriginsOrdered()
|
|
1469
|
-
const unprocessedValues = [
|
|
1470
|
-
this._remoteUnprocessed,
|
|
1471
|
-
this._optsUnprocessed,
|
|
1472
|
-
{},
|
|
1473
|
-
this._envUnprocessed,
|
|
1474
|
-
{},
|
|
1475
|
-
{},
|
|
1476
|
-
{}
|
|
1477
|
-
]
|
|
1478
1490
|
const changes = []
|
|
1479
1491
|
|
|
1480
1492
|
for (const name in this._defaults) {
|
|
1481
|
-
|
|
1482
|
-
|
|
1493
|
+
// Use reverse order for merge (lowest priority first)
|
|
1494
|
+
for (let i = sourcesOrder.length - 1; i >= 0; i--) {
|
|
1495
|
+
const { containerProperty, origin, unprocessedProperty } = sourcesOrder[i]
|
|
1496
|
+
const container = this[containerProperty]
|
|
1483
1497
|
const value = container[name]
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
if (get(this, name) === value && has(this, name)) break
|
|
1487
|
-
|
|
1488
|
-
set(this, name, value)
|
|
1489
|
-
|
|
1490
|
-
changes.push({
|
|
1498
|
+
if (value != null || container === this._defaults) {
|
|
1499
|
+
this._setAndTrackChange({
|
|
1491
1500
|
name,
|
|
1492
|
-
value
|
|
1493
|
-
origin
|
|
1501
|
+
value,
|
|
1502
|
+
origin,
|
|
1503
|
+
unprocessedValue: unprocessedProperty === undefined ? undefined : this[unprocessedProperty][name],
|
|
1504
|
+
changes
|
|
1494
1505
|
})
|
|
1495
|
-
|
|
1496
|
-
break
|
|
1497
1506
|
}
|
|
1498
1507
|
}
|
|
1499
1508
|
}
|
|
1500
|
-
|
|
1501
1509
|
this.sampler.sampleRate = this.sampleRate
|
|
1502
1510
|
updateConfig(changes, this)
|
|
1503
1511
|
}
|
|
1504
1512
|
|
|
1505
1513
|
getOrigin (name) {
|
|
1506
|
-
const {
|
|
1507
|
-
|
|
1508
|
-
for (let i = 0; i < containers.length; i++) {
|
|
1509
|
-
const container = containers[i]
|
|
1514
|
+
for (const { containerProperty, origin } of sourcesOrder) {
|
|
1515
|
+
const container = this[containerProperty]
|
|
1510
1516
|
const value = container[name]
|
|
1511
1517
|
if (value != null || container === this._defaults) {
|
|
1512
|
-
return
|
|
1518
|
+
return origin
|
|
1513
1519
|
}
|
|
1514
1520
|
}
|
|
1515
1521
|
}
|
|
@@ -32,7 +32,11 @@ const ddtags = [
|
|
|
32
32
|
|
|
33
33
|
const path = `/debugger/v1/input?${stringify({ ddtags })}`
|
|
34
34
|
|
|
35
|
-
const jsonBuffer = new JSONBuffer({
|
|
35
|
+
const jsonBuffer = new JSONBuffer({
|
|
36
|
+
size: config.maxTotalPayloadSize,
|
|
37
|
+
timeout: config.dynamicInstrumentation.uploadIntervalSeconds * 1000,
|
|
38
|
+
onFlush
|
|
39
|
+
})
|
|
36
40
|
|
|
37
41
|
function send (message, logger, dd, snapshot) {
|
|
38
42
|
const payload = {
|
|
@@ -20,7 +20,11 @@ const runtimeId = config.runtimeId
|
|
|
20
20
|
|
|
21
21
|
const cache = new TTLSet(60 * 60 * 1000) // 1 hour
|
|
22
22
|
|
|
23
|
-
const jsonBuffer = new JSONBuffer({
|
|
23
|
+
const jsonBuffer = new JSONBuffer({
|
|
24
|
+
size: config.maxTotalPayloadSize,
|
|
25
|
+
timeout: config.dynamicInstrumentation.uploadIntervalSeconds * 1000,
|
|
26
|
+
onFlush
|
|
27
|
+
})
|
|
24
28
|
|
|
25
29
|
const STATUSES = {
|
|
26
30
|
RECEIVED: 'RECEIVED',
|
|
@@ -69,7 +69,9 @@ function setHeader (headers, key, value) {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
function getEncoder (protocolVersion) {
|
|
72
|
-
return
|
|
72
|
+
return protocolVersion === '0.5'
|
|
73
|
+
? require('../../encode/0.5').AgentEncoder
|
|
74
|
+
: require('../../encode/0.4').AgentEncoder
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
function makeRequest (version, data, count, url, headers, lookup, needsStartupLog, cb) {
|
|
@@ -136,7 +136,7 @@ class TextMapPropagator {
|
|
|
136
136
|
let itemCounter = 0
|
|
137
137
|
let byteCounter = 0
|
|
138
138
|
|
|
139
|
-
const baggageItems =
|
|
139
|
+
const baggageItems = getAllBaggageItems()
|
|
140
140
|
if (!baggageItems) return
|
|
141
141
|
for (const [key, value] of Object.entries(baggageItems)) {
|
|
142
142
|
const item = `${this._encodeOtelBaggageKey(String(key).trim())}=${encodeURIComponent(String(value).trim())},`
|
|
@@ -355,19 +355,20 @@ class TextMapPropagator {
|
|
|
355
355
|
}
|
|
356
356
|
}
|
|
357
357
|
|
|
358
|
-
this._extractBaggageItems(carrier, context)
|
|
359
|
-
|
|
360
358
|
if (this._config.tracePropagationBehaviorExtract === 'ignore') {
|
|
361
359
|
context._links = []
|
|
362
|
-
} else
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
context
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
360
|
+
} else {
|
|
361
|
+
if (this._config.tracePropagationBehaviorExtract === 'restart') {
|
|
362
|
+
context._links = []
|
|
363
|
+
context._links.push({
|
|
364
|
+
context,
|
|
365
|
+
attributes:
|
|
366
|
+
{
|
|
367
|
+
reason: 'propagation_behavior_extract', context_headers: style
|
|
368
|
+
}
|
|
369
|
+
})
|
|
370
|
+
}
|
|
371
|
+
this._extractBaggageItems(carrier, context)
|
|
371
372
|
}
|
|
372
373
|
|
|
373
374
|
return context || this._extractSqsdContext(carrier)
|
|
@@ -628,33 +629,26 @@ class TextMapPropagator {
|
|
|
628
629
|
_extractBaggageItems (carrier, spanContext) {
|
|
629
630
|
if (!this._hasPropagationStyle('extract', 'baggage')) return
|
|
630
631
|
if (!carrier || !carrier.baggage) return
|
|
631
|
-
if (!spanContext) removeAllBaggageItems()
|
|
632
632
|
const baggages = carrier.baggage.split(',')
|
|
633
633
|
const keysToSpanTag = this._config.baggageTagKeys === '*'
|
|
634
634
|
? undefined
|
|
635
635
|
: new Set(this._config.baggageTagKeys.split(','))
|
|
636
636
|
for (const keyValue of baggages) {
|
|
637
637
|
if (!keyValue.includes('=')) {
|
|
638
|
-
|
|
638
|
+
removeAllBaggageItems()
|
|
639
639
|
return
|
|
640
640
|
}
|
|
641
641
|
let [key, value] = keyValue.split('=')
|
|
642
642
|
key = this._decodeOtelBaggageKey(key.trim())
|
|
643
643
|
value = decodeURIComponent(value.trim())
|
|
644
644
|
if (!key || !value) {
|
|
645
|
-
|
|
645
|
+
removeAllBaggageItems()
|
|
646
646
|
return
|
|
647
647
|
}
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
if (Object.hasOwn(spanContext._baggageItems, key)) continue
|
|
651
|
-
spanContext._baggageItems[key] = value
|
|
652
|
-
if (this._config.baggageTagKeys === '*' || keysToSpanTag.has(key)) {
|
|
653
|
-
spanContext._trace.tags['baggage.' + key] = value
|
|
654
|
-
}
|
|
655
|
-
} else {
|
|
656
|
-
setBaggageItem(key, value)
|
|
648
|
+
if (spanContext && (this._config.baggageTagKeys === '*' || keysToSpanTag.has(key))) {
|
|
649
|
+
spanContext._trace.tags['baggage.' + key] = value
|
|
657
650
|
}
|
|
651
|
+
setBaggageItem(key, value)
|
|
658
652
|
}
|
|
659
653
|
}
|
|
660
654
|
|
|
@@ -291,8 +291,16 @@ class NodeApiEventSource {
|
|
|
291
291
|
|
|
292
292
|
class DatadogInstrumentationEventSource {
|
|
293
293
|
constructor (eventHandler, eventFilter) {
|
|
294
|
-
|
|
295
|
-
|
|
294
|
+
// List all entries explicitly for bundlers to pick up the require calls correctly.
|
|
295
|
+
const plugins = [
|
|
296
|
+
require('./event_plugins/dns_lookup'),
|
|
297
|
+
require('./event_plugins/dns_lookupservice'),
|
|
298
|
+
require('./event_plugins/dns_resolve'),
|
|
299
|
+
require('./event_plugins/dns_reverse'),
|
|
300
|
+
require('./event_plugins/fs'),
|
|
301
|
+
require('./event_plugins/net')
|
|
302
|
+
]
|
|
303
|
+
this.plugins = plugins.map((Plugin) => {
|
|
296
304
|
return new Plugin(eventHandler, eventFilter)
|
|
297
305
|
})
|
|
298
306
|
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"DD_DYNAMIC_INSTRUMENTATION_ENABLED": ["A"],
|
|
57
57
|
"DD_DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS": ["A"],
|
|
58
58
|
"DD_DYNAMIC_INSTRUMENTATION_REDACTION_EXCLUDED_IDENTIFIERS": ["A"],
|
|
59
|
+
"DD_DYNAMIC_INSTRUMENTATION_UPLOAD_INTERVAL_SECONDS": ["A"],
|
|
59
60
|
"DD_ENV": ["A"],
|
|
60
61
|
"DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED": ["A"],
|
|
61
62
|
"DD_EXTERNAL_ENV": ["A"],
|
|
@@ -28,6 +28,8 @@ const extendedHeartbeatPayload = {}
|
|
|
28
28
|
|
|
29
29
|
const sentIntegrations = new Set()
|
|
30
30
|
|
|
31
|
+
let seqId = 0
|
|
32
|
+
|
|
31
33
|
function getRetryData () {
|
|
32
34
|
return retryData
|
|
33
35
|
}
|
|
@@ -337,9 +339,8 @@ function updateConfig (changes, config) {
|
|
|
337
339
|
|
|
338
340
|
for (const change of changes) {
|
|
339
341
|
const name = nameMapping[change.name] || change.name
|
|
340
|
-
|
|
341
342
|
const { origin, value } = change
|
|
342
|
-
const entry = { name, value, origin }
|
|
343
|
+
const entry = { name, value, origin, seq_id: seqId++ }
|
|
343
344
|
|
|
344
345
|
if (namesNeedFormatting.has(entry.name)) {
|
|
345
346
|
entry.value = formatMapForTelemetry(entry.value)
|
|
@@ -352,7 +353,9 @@ function updateConfig (changes, config) {
|
|
|
352
353
|
} else if (Array.isArray(entry.value)) {
|
|
353
354
|
entry.value = value.join(',')
|
|
354
355
|
}
|
|
355
|
-
|
|
356
|
+
|
|
357
|
+
// Use composite key to support multiple origins for same config name
|
|
358
|
+
configWithOrigin.set(`${name}|${origin}`, entry)
|
|
356
359
|
}
|
|
357
360
|
|
|
358
361
|
if (changed) {
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
module.exports = function has (object, path) {
|
|
4
|
-
const pathArr = path.split('.')
|
|
5
|
-
let property = object
|
|
6
|
-
for (const n of pathArr) {
|
|
7
|
-
if (property.hasOwnProperty(n)) {
|
|
8
|
-
property = property[n]
|
|
9
|
-
} else {
|
|
10
|
-
return false
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
return true
|
|
14
|
-
}
|