dd-trace 5.34.0 → 5.36.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/index.d.ts +3 -7
- package/package.json +4 -4
- package/packages/datadog-core/index.js +1 -1
- package/packages/datadog-core/src/storage.js +76 -31
- package/packages/datadog-instrumentations/src/aws-sdk.js +16 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/jest.js +3 -7
- package/packages/datadog-instrumentations/src/passport.js +45 -0
- package/packages/datadog-plugin-aerospike/src/index.js +1 -1
- package/packages/datadog-plugin-apollo/src/gateway/fetch.js +1 -1
- package/packages/datadog-plugin-apollo/src/gateway/index.js +1 -1
- package/packages/datadog-plugin-apollo/src/gateway/request.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/base.js +3 -3
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +33 -6
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +4 -4
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -2
- package/packages/datadog-plugin-azure-functions/src/index.js +1 -1
- package/packages/datadog-plugin-couchbase/src/index.js +2 -2
- package/packages/datadog-plugin-cucumber/src/index.js +11 -11
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +6 -1
- package/packages/datadog-plugin-cypress/src/support.js +36 -29
- package/packages/datadog-plugin-dd-trace-api/src/index.js +120 -0
- package/packages/datadog-plugin-grpc/src/client.js +1 -1
- package/packages/datadog-plugin-grpc/src/server.js +1 -1
- package/packages/datadog-plugin-hapi/src/index.js +1 -1
- package/packages/datadog-plugin-http/src/client.js +1 -1
- package/packages/datadog-plugin-http/src/server.js +1 -1
- package/packages/datadog-plugin-http2/src/client.js +3 -3
- package/packages/datadog-plugin-http2/src/server.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +6 -11
- package/packages/datadog-plugin-langchain/src/tracing.js +1 -1
- package/packages/datadog-plugin-mariadb/src/index.js +3 -3
- package/packages/datadog-plugin-mocha/src/index.js +13 -13
- package/packages/datadog-plugin-next/src/index.js +4 -4
- package/packages/datadog-plugin-openai/src/tracing.js +1 -1
- package/packages/datadog-plugin-playwright/src/index.js +4 -4
- package/packages/datadog-plugin-rhea/src/consumer.js +1 -1
- package/packages/datadog-plugin-router/src/index.js +2 -2
- package/packages/datadog-plugin-selenium/src/index.js +1 -1
- package/packages/datadog-plugin-vitest/src/index.js +11 -11
- package/packages/dd-trace/src/appsec/blocking.js +4 -1
- package/packages/dd-trace/src/appsec/channels.js +1 -0
- package/packages/dd-trace/src/appsec/graphql.js +6 -6
- package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +6 -6
- package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +2 -2
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +5 -5
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +2 -2
- package/packages/dd-trace/src/appsec/iast/analyzers/weak-hash-analyzer.js +2 -1
- package/packages/dd-trace/src/appsec/iast/context/context-plugin.js +2 -2
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +2 -2
- package/packages/dd-trace/src/appsec/iast/index.js +2 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/constants.js +6 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +8 -8
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-esm.mjs +65 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-telemetry.js +14 -5
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +80 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -1
- package/packages/dd-trace/src/appsec/index.js +20 -3
- package/packages/dd-trace/src/appsec/rasp/command_injection.js +1 -1
- package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +5 -5
- package/packages/dd-trace/src/appsec/rasp/lfi.js +1 -1
- package/packages/dd-trace/src/appsec/rasp/sql_injection.js +2 -2
- package/packages/dd-trace/src/appsec/rasp/ssrf.js +1 -1
- package/packages/dd-trace/src/appsec/reporter.js +3 -3
- package/packages/dd-trace/src/appsec/sdk/set_user.js +9 -0
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +2 -1
- package/packages/dd-trace/src/appsec/telemetry.js +10 -0
- package/packages/dd-trace/src/appsec/user_tracking.js +32 -6
- package/packages/dd-trace/src/appsec/waf/index.js +1 -1
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +2 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +17 -10
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +3 -3
- package/packages/dd-trace/src/config.js +2 -0
- package/packages/dd-trace/src/data_streams_context.js +2 -2
- package/packages/dd-trace/src/debugger/devtools_client/state.js +8 -3
- package/packages/dd-trace/src/exporters/common/agents.js +1 -1
- package/packages/dd-trace/src/exporters/common/request.js +3 -3
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +49 -4
- package/packages/dd-trace/src/log/writer.js +3 -3
- package/packages/dd-trace/src/noop/span.js +1 -1
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +5 -4
- package/packages/dd-trace/src/opentracing/span.js +1 -1
- package/packages/dd-trace/src/plugin_manager.js +6 -1
- package/packages/dd-trace/src/plugins/apollo.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +35 -1
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/log_plugin.js +1 -1
- package/packages/dd-trace/src/plugins/plugin.js +8 -8
- package/packages/dd-trace/src/plugins/tracing.js +3 -3
- package/packages/dd-trace/src/plugins/util/git.js +3 -3
- package/packages/dd-trace/src/plugins/util/test.js +5 -1
- package/packages/dd-trace/src/profiling/exporters/agent.js +3 -3
- package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
- package/packages/dd-trace/src/scope.js +5 -5
- package/packages/dd-trace/src/tracer.js +0 -14
|
@@ -14,9 +14,9 @@ const enabledFor = {
|
|
|
14
14
|
|
|
15
15
|
let fsPlugin
|
|
16
16
|
|
|
17
|
-
function enterWith (fsProps, store = storage.getStore()) {
|
|
17
|
+
function enterWith (fsProps, store = storage('legacy').getStore()) {
|
|
18
18
|
if (store && !store.fs?.opExcluded) {
|
|
19
|
-
storage.enterWith({
|
|
19
|
+
storage('legacy').enterWith({
|
|
20
20
|
...store,
|
|
21
21
|
fs: {
|
|
22
22
|
...store.fs,
|
|
@@ -42,7 +42,7 @@ class AppsecFsPlugin extends Plugin {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
_onFsOperationStart () {
|
|
45
|
-
const store = storage.getStore()
|
|
45
|
+
const store = storage('legacy').getStore()
|
|
46
46
|
if (store) {
|
|
47
47
|
enterWith({ root: store.fs?.root === undefined }, store)
|
|
48
48
|
}
|
|
@@ -53,9 +53,9 @@ class AppsecFsPlugin extends Plugin {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
_onFsOperationFinishOrRenderEnd () {
|
|
56
|
-
const store = storage.getStore()
|
|
56
|
+
const store = storage('legacy').getStore()
|
|
57
57
|
if (store?.fs?.parentStore) {
|
|
58
|
-
storage.enterWith(store.fs.parentStore)
|
|
58
|
+
storage('legacy').enterWith(store.fs.parentStore)
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -49,7 +49,7 @@ function analyzePgSqlInjection (ctx) {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
function analyzeSqlInjection (query, dbSystem, abortController) {
|
|
52
|
-
const store = storage.getStore()
|
|
52
|
+
const store = storage('legacy').getStore()
|
|
53
53
|
if (!store) return
|
|
54
54
|
|
|
55
55
|
const { req, res } = store
|
|
@@ -91,7 +91,7 @@ function hasAddressesObjectInputAddress (addressesObject) {
|
|
|
91
91
|
function clearQuerySet ({ payload }) {
|
|
92
92
|
if (!payload) return
|
|
93
93
|
|
|
94
|
-
const store = storage.getStore()
|
|
94
|
+
const store = storage('legacy').getStore()
|
|
95
95
|
if (!store) return
|
|
96
96
|
|
|
97
97
|
const { req } = store
|
|
@@ -19,7 +19,7 @@ function disable () {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
function analyzeSsrf (ctx) {
|
|
22
|
-
const store = storage.getStore()
|
|
22
|
+
const store = storage('legacy').getStore()
|
|
23
23
|
const req = store?.req
|
|
24
24
|
const outgoingUrl = (ctx.args.options?.uri && format(ctx.args.options.uri)) ?? ctx.args.uri
|
|
25
25
|
|
|
@@ -102,7 +102,7 @@ function reportWafInit (wafVersion, rulesVersion, diagnosticsRules = {}) {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
function reportMetrics (metrics, raspRule) {
|
|
105
|
-
const store = storage.getStore()
|
|
105
|
+
const store = storage('legacy').getStore()
|
|
106
106
|
const rootSpan = store?.req && web.root(store.req)
|
|
107
107
|
if (!rootSpan) return
|
|
108
108
|
|
|
@@ -117,7 +117,7 @@ function reportMetrics (metrics, raspRule) {
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
function reportAttack (attackData) {
|
|
120
|
-
const store = storage.getStore()
|
|
120
|
+
const store = storage('legacy').getStore()
|
|
121
121
|
const req = store?.req
|
|
122
122
|
const rootSpan = web.root(req)
|
|
123
123
|
if (!rootSpan) return
|
|
@@ -162,7 +162,7 @@ function isFingerprintDerivative (derivative) {
|
|
|
162
162
|
function reportDerivatives (derivatives) {
|
|
163
163
|
if (!derivatives) return
|
|
164
164
|
|
|
165
|
-
const req = storage.getStore()?.req
|
|
165
|
+
const req = storage('legacy').getStore()?.req
|
|
166
166
|
const rootSpan = web.root(req)
|
|
167
167
|
|
|
168
168
|
if (!rootSpan) return
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const { getRootSpan } = require('./utils')
|
|
4
4
|
const log = require('../../log')
|
|
5
|
+
const waf = require('../waf')
|
|
6
|
+
const addresses = require('../addresses')
|
|
5
7
|
|
|
6
8
|
function setUserTags (user, rootSpan) {
|
|
7
9
|
for (const k of Object.keys(user)) {
|
|
@@ -22,6 +24,13 @@ function setUser (tracer, user) {
|
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
setUserTags(user, rootSpan)
|
|
27
|
+
rootSpan.setTag('_dd.appsec.user.collection_mode', 'sdk')
|
|
28
|
+
|
|
29
|
+
waf.run({
|
|
30
|
+
persistent: {
|
|
31
|
+
[addresses.USER_ID]: '' + user.id
|
|
32
|
+
}
|
|
33
|
+
})
|
|
25
34
|
}
|
|
26
35
|
|
|
27
36
|
module.exports = {
|
|
@@ -23,6 +23,7 @@ function checkUserAndSetUser (tracer, user) {
|
|
|
23
23
|
if (rootSpan) {
|
|
24
24
|
if (!rootSpan.context()._tags['usr.id']) {
|
|
25
25
|
setUserTags(user, rootSpan)
|
|
26
|
+
rootSpan.setTag('_dd.appsec.user.collection_mode', 'sdk')
|
|
26
27
|
}
|
|
27
28
|
} else {
|
|
28
29
|
log.warn('[ASM] Root span not available in isUserBlocked')
|
|
@@ -33,7 +34,7 @@ function checkUserAndSetUser (tracer, user) {
|
|
|
33
34
|
|
|
34
35
|
function blockRequest (tracer, req, res) {
|
|
35
36
|
if (!req || !res) {
|
|
36
|
-
const store = storage.getStore()
|
|
37
|
+
const store = storage('legacy').getStore()
|
|
37
38
|
if (store) {
|
|
38
39
|
req = req || store.req
|
|
39
40
|
res = res || store.res
|
|
@@ -186,6 +186,15 @@ function incrementMissingUserLoginMetric (framework, eventType) {
|
|
|
186
186
|
}).inc()
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
+
function incrementMissingUserIdMetric (framework, eventType) {
|
|
190
|
+
if (!enabled) return
|
|
191
|
+
|
|
192
|
+
appsecMetrics.count('instrum.user_auth.missing_user_id', {
|
|
193
|
+
framework,
|
|
194
|
+
event_type: eventType
|
|
195
|
+
}).inc()
|
|
196
|
+
}
|
|
197
|
+
|
|
189
198
|
function getRequestMetrics (req) {
|
|
190
199
|
if (req) {
|
|
191
200
|
const store = getStore(req)
|
|
@@ -203,6 +212,7 @@ module.exports = {
|
|
|
203
212
|
incrementWafUpdatesMetric,
|
|
204
213
|
incrementWafRequestsMetric,
|
|
205
214
|
incrementMissingUserLoginMetric,
|
|
215
|
+
incrementMissingUserIdMetric,
|
|
206
216
|
|
|
207
217
|
getRequestMetrics
|
|
208
218
|
}
|
|
@@ -53,6 +53,8 @@ function obfuscateIfNeeded (str) {
|
|
|
53
53
|
function getUserId (user) {
|
|
54
54
|
if (!user) return
|
|
55
55
|
|
|
56
|
+
// should we iterate on user keys instead to be case insensitive ?
|
|
57
|
+
// but if we iterate over user then we're missing the inherited props ?
|
|
56
58
|
for (const field of USER_ID_FIELDS) {
|
|
57
59
|
let id = user[field]
|
|
58
60
|
|
|
@@ -73,11 +75,6 @@ function getUserId (user) {
|
|
|
73
75
|
function trackLogin (framework, login, user, success, rootSpan) {
|
|
74
76
|
if (!collectionMode || collectionMode === 'disabled') return
|
|
75
77
|
|
|
76
|
-
if (!rootSpan) {
|
|
77
|
-
log.error('[ASM] No rootSpan found in AppSec trackLogin')
|
|
78
|
-
return
|
|
79
|
-
}
|
|
80
|
-
|
|
81
78
|
if (typeof login !== 'string') {
|
|
82
79
|
log.error('[ASM] Invalid login provided to AppSec trackLogin')
|
|
83
80
|
|
|
@@ -162,7 +159,36 @@ function trackLogin (framework, login, user, success, rootSpan) {
|
|
|
162
159
|
return waf.run({ persistent })
|
|
163
160
|
}
|
|
164
161
|
|
|
162
|
+
function trackUser (user, rootSpan) {
|
|
163
|
+
if (!collectionMode || collectionMode === 'disabled') return
|
|
164
|
+
|
|
165
|
+
const userId = getUserId(user)
|
|
166
|
+
if (!userId) {
|
|
167
|
+
log.error('[ASM] No valid user ID found in AppSec trackUser')
|
|
168
|
+
telemetry.incrementMissingUserIdMetric('passport', 'authenticated_request')
|
|
169
|
+
return
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
rootSpan.setTag('_dd.appsec.usr.id', userId)
|
|
173
|
+
|
|
174
|
+
const isSdkCalled = rootSpan.context()._tags['_dd.appsec.user.collection_mode'] === 'sdk'
|
|
175
|
+
// do not override SDK
|
|
176
|
+
if (!isSdkCalled) {
|
|
177
|
+
rootSpan.addTags({
|
|
178
|
+
'usr.id': userId,
|
|
179
|
+
'_dd.appsec.user.collection_mode': collectionMode
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
return waf.run({
|
|
183
|
+
persistent: {
|
|
184
|
+
[addresses.USER_ID]: userId
|
|
185
|
+
}
|
|
186
|
+
})
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
165
190
|
module.exports = {
|
|
166
191
|
setCollectionMode,
|
|
167
|
-
trackLogin
|
|
192
|
+
trackLogin,
|
|
193
|
+
trackUser
|
|
168
194
|
}
|
|
@@ -48,7 +48,7 @@ function update (newRules) {
|
|
|
48
48
|
|
|
49
49
|
function run (data, req, raspRule) {
|
|
50
50
|
if (!req) {
|
|
51
|
-
const store = storage.getStore()
|
|
51
|
+
const store = storage('legacy').getStore()
|
|
52
52
|
if (!store || !store.req) {
|
|
53
53
|
log.warn('[ASM] Request object not available in waf.run')
|
|
54
54
|
return
|
|
@@ -93,11 +93,14 @@ async function addBreakpoint (probe) {
|
|
|
93
93
|
probe.location = { file, lines: [String(line)] }
|
|
94
94
|
|
|
95
95
|
const script = findScriptFromPartialPath(file)
|
|
96
|
-
if (!script)
|
|
96
|
+
if (!script) {
|
|
97
|
+
log.error(`No loaded script found for ${file}`)
|
|
98
|
+
throw new Error(`No loaded script found for ${file}`)
|
|
99
|
+
}
|
|
97
100
|
|
|
98
101
|
const [path, scriptId, sourceMapURL] = script
|
|
99
102
|
|
|
100
|
-
log.
|
|
103
|
+
log.warn(`Adding breakpoint at ${path}:${line}`)
|
|
101
104
|
|
|
102
105
|
let lineNumber = line
|
|
103
106
|
|
|
@@ -109,15 +112,19 @@ async function addBreakpoint (probe) {
|
|
|
109
112
|
}
|
|
110
113
|
}
|
|
111
114
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
try {
|
|
116
|
+
const { breakpointId } = await session.post('Debugger.setBreakpoint', {
|
|
117
|
+
location: {
|
|
118
|
+
scriptId,
|
|
119
|
+
lineNumber: lineNumber - 1
|
|
120
|
+
}
|
|
121
|
+
})
|
|
118
122
|
|
|
119
|
-
|
|
120
|
-
|
|
123
|
+
breakpointIdToProbe.set(breakpointId, probe)
|
|
124
|
+
probeIdToBreakpointId.set(probe.id, breakpointId)
|
|
125
|
+
} catch (e) {
|
|
126
|
+
log.error(`Error setting breakpoint at ${path}:${line}:`, e)
|
|
127
|
+
}
|
|
121
128
|
}
|
|
122
129
|
|
|
123
130
|
function start () {
|
|
@@ -17,13 +17,13 @@ class TestApiManualPlugin extends CiPlugin {
|
|
|
17
17
|
this.sourceRoot = process.cwd()
|
|
18
18
|
|
|
19
19
|
this.unconfiguredAddSub('dd-trace:ci:manual:test:start', ({ testName, testSuite }) => {
|
|
20
|
-
const store = storage.getStore()
|
|
20
|
+
const store = storage('legacy').getStore()
|
|
21
21
|
const testSuiteRelative = getTestSuitePath(testSuite, this.sourceRoot)
|
|
22
22
|
const testSpan = this.startTestSpan(testName, testSuiteRelative)
|
|
23
23
|
this.enter(testSpan, store)
|
|
24
24
|
})
|
|
25
25
|
this.unconfiguredAddSub('dd-trace:ci:manual:test:finish', ({ status, error }) => {
|
|
26
|
-
const store = storage.getStore()
|
|
26
|
+
const store = storage('legacy').getStore()
|
|
27
27
|
const testSpan = store && store.span
|
|
28
28
|
if (testSpan) {
|
|
29
29
|
testSpan.setTag(TEST_STATUS, status)
|
|
@@ -35,7 +35,7 @@ class TestApiManualPlugin extends CiPlugin {
|
|
|
35
35
|
}
|
|
36
36
|
})
|
|
37
37
|
this.unconfiguredAddSub('dd-trace:ci:manual:test:addTags', (tags) => {
|
|
38
|
-
const store = storage.getStore()
|
|
38
|
+
const store = storage('legacy').getStore()
|
|
39
39
|
const testSpan = store && store.span
|
|
40
40
|
if (testSpan) {
|
|
41
41
|
testSpan.addTags(tags)
|
|
@@ -518,6 +518,7 @@ class Config {
|
|
|
518
518
|
this._setValue(defaults, 'ciVisAgentlessLogSubmissionEnabled', false)
|
|
519
519
|
this._setValue(defaults, 'legacyBaggageEnabled', true)
|
|
520
520
|
this._setValue(defaults, 'isTestDynamicInstrumentationEnabled', false)
|
|
521
|
+
this._setValue(defaults, 'isServiceUserProvided', false)
|
|
521
522
|
this._setValue(defaults, 'logInjection', false)
|
|
522
523
|
this._setValue(defaults, 'lookup', undefined)
|
|
523
524
|
this._setValue(defaults, 'inferredProxyServicesEnabled', false)
|
|
@@ -1156,6 +1157,7 @@ class Config {
|
|
|
1156
1157
|
this._setString(calc, 'ciVisibilityTestSessionName', DD_TEST_SESSION_NAME)
|
|
1157
1158
|
this._setBoolean(calc, 'ciVisAgentlessLogSubmissionEnabled', isTrue(DD_AGENTLESS_LOG_SUBMISSION_ENABLED))
|
|
1158
1159
|
this._setBoolean(calc, 'isTestDynamicInstrumentationEnabled', isTrue(DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED))
|
|
1160
|
+
this._setBoolean(calc, 'isServiceUserProvided', !!this._env.service)
|
|
1159
1161
|
}
|
|
1160
1162
|
this._setString(calc, 'dogstatsd.hostname', this._getHostname())
|
|
1161
1163
|
this._setBoolean(calc, 'isGitUploadEnabled',
|
|
@@ -2,14 +2,14 @@ const { storage } = require('../../datadog-core')
|
|
|
2
2
|
const log = require('./log')
|
|
3
3
|
|
|
4
4
|
function getDataStreamsContext () {
|
|
5
|
-
const store = storage.getStore()
|
|
5
|
+
const store = storage('legacy').getStore()
|
|
6
6
|
return (store && store.dataStreamsContext) || null
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
function setDataStreamsContext (dataStreamsContext) {
|
|
10
10
|
log.debug(() => `Setting new DSM Context: ${JSON.stringify(dataStreamsContext)}.`)
|
|
11
11
|
|
|
12
|
-
if (dataStreamsContext) storage.enterWith({ ...(storage.getStore()), dataStreamsContext })
|
|
12
|
+
if (dataStreamsContext) storage('legacy').enterWith({ ...(storage('legacy').getStore()), dataStreamsContext })
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
module.exports = {
|
|
@@ -21,6 +21,8 @@ module.exports = {
|
|
|
21
21
|
findScriptFromPartialPath (path) {
|
|
22
22
|
if (!path) return null // This shouldn't happen, but better safe than sorry
|
|
23
23
|
|
|
24
|
+
path = path.toLowerCase()
|
|
25
|
+
|
|
24
26
|
const bestMatch = new Array(3)
|
|
25
27
|
let maxMatchLength = -1
|
|
26
28
|
|
|
@@ -33,7 +35,7 @@ module.exports = {
|
|
|
33
35
|
|
|
34
36
|
// Compare characters from the end
|
|
35
37
|
while (i >= 0 && j >= 0) {
|
|
36
|
-
const urlChar = url[i]
|
|
38
|
+
const urlChar = url[i].toLowerCase()
|
|
37
39
|
const pathChar = path[j]
|
|
38
40
|
|
|
39
41
|
// Check if both characters is a path boundary
|
|
@@ -43,8 +45,8 @@ module.exports = {
|
|
|
43
45
|
// If both are boundaries, or if characters match exactly
|
|
44
46
|
if (isBoundary || urlChar === pathChar) {
|
|
45
47
|
if (isBoundary) {
|
|
46
|
-
lastBoundaryPos = matchLength
|
|
47
48
|
atBoundary = true
|
|
49
|
+
lastBoundaryPos = matchLength
|
|
48
50
|
} else {
|
|
49
51
|
atBoundary = false
|
|
50
52
|
}
|
|
@@ -71,7 +73,10 @@ module.exports = {
|
|
|
71
73
|
}
|
|
72
74
|
|
|
73
75
|
// If we found a valid match and it's better than our previous best
|
|
74
|
-
if (atBoundary &&
|
|
76
|
+
if (atBoundary && (
|
|
77
|
+
lastBoundaryPos > maxMatchLength ||
|
|
78
|
+
(lastBoundaryPos === maxMatchLength && url.length < bestMatch[0].length) // Prefer shorter paths
|
|
79
|
+
)) {
|
|
75
80
|
maxMatchLength = lastBoundaryPos
|
|
76
81
|
bestMatch[0] = url
|
|
77
82
|
bestMatch[1] = scriptId
|
|
@@ -126,9 +126,9 @@ function request (data, options, callback) {
|
|
|
126
126
|
|
|
127
127
|
activeRequests++
|
|
128
128
|
|
|
129
|
-
const store = storage.getStore()
|
|
129
|
+
const store = storage('legacy').getStore()
|
|
130
130
|
|
|
131
|
-
storage.enterWith({ noop: true })
|
|
131
|
+
storage('legacy').enterWith({ noop: true })
|
|
132
132
|
|
|
133
133
|
const req = client.request(options, onResponse)
|
|
134
134
|
|
|
@@ -146,7 +146,7 @@ function request (data, options, callback) {
|
|
|
146
146
|
req.end()
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
storage.enterWith(store)
|
|
149
|
+
storage('legacy').enterWith(store)
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
// TODO: Figure out why setTimeout is needed to avoid losing the async context
|
|
@@ -8,7 +8,9 @@ const {
|
|
|
8
8
|
parseModelId
|
|
9
9
|
} = require('../../../../datadog-plugin-aws-sdk/src/services/bedrockruntime/utils')
|
|
10
10
|
|
|
11
|
-
const
|
|
11
|
+
const ENABLED_OPERATIONS = ['invokeModel']
|
|
12
|
+
|
|
13
|
+
const requestIdsToTokens = {}
|
|
12
14
|
|
|
13
15
|
class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
|
|
14
16
|
constructor () {
|
|
@@ -18,7 +20,7 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
|
|
|
18
20
|
const request = response.request
|
|
19
21
|
const operation = request.operation
|
|
20
22
|
// avoids instrumenting other non supported runtime operations
|
|
21
|
-
if (!
|
|
23
|
+
if (!ENABLED_OPERATIONS.includes(operation)) {
|
|
22
24
|
return
|
|
23
25
|
}
|
|
24
26
|
const { modelProvider, modelName } = parseModelId(request.params.modelId)
|
|
@@ -27,9 +29,20 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
|
|
|
27
29
|
if (modelName.includes('embed')) {
|
|
28
30
|
return
|
|
29
31
|
}
|
|
30
|
-
const span = storage.getStore()?.span
|
|
32
|
+
const span = storage('legacy').getStore()?.span
|
|
31
33
|
this.setLLMObsTags({ request, span, response, modelProvider, modelName })
|
|
32
34
|
})
|
|
35
|
+
|
|
36
|
+
this.addSub('apm:aws:response:deserialize:bedrockruntime', ({ headers }) => {
|
|
37
|
+
const requestId = headers['x-amzn-requestid']
|
|
38
|
+
const inputTokenCount = headers['x-amzn-bedrock-input-token-count']
|
|
39
|
+
const outputTokenCount = headers['x-amzn-bedrock-output-token-count']
|
|
40
|
+
|
|
41
|
+
requestIdsToTokens[requestId] = {
|
|
42
|
+
inputTokensFromHeaders: inputTokenCount && parseInt(inputTokenCount),
|
|
43
|
+
outputTokensFromHeaders: outputTokenCount && parseInt(outputTokenCount)
|
|
44
|
+
}
|
|
45
|
+
})
|
|
33
46
|
}
|
|
34
47
|
|
|
35
48
|
setLLMObsTags ({ request, span, response, modelProvider, modelName }) {
|
|
@@ -52,7 +65,39 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
|
|
|
52
65
|
})
|
|
53
66
|
|
|
54
67
|
// add I/O tags
|
|
55
|
-
this._tagger.tagLLMIO(
|
|
68
|
+
this._tagger.tagLLMIO(
|
|
69
|
+
span,
|
|
70
|
+
requestParams.prompt,
|
|
71
|
+
[{ content: textAndResponseReason.message, role: textAndResponseReason.role }]
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
// add token metrics
|
|
75
|
+
const { inputTokens, outputTokens, totalTokens } = extractTokens({
|
|
76
|
+
requestId: response.$metadata.requestId,
|
|
77
|
+
usage: textAndResponseReason.usage
|
|
78
|
+
})
|
|
79
|
+
this._tagger.tagMetrics(span, {
|
|
80
|
+
inputTokens,
|
|
81
|
+
outputTokens,
|
|
82
|
+
totalTokens
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function extractTokens ({ requestId, usage }) {
|
|
88
|
+
const {
|
|
89
|
+
inputTokensFromHeaders,
|
|
90
|
+
outputTokensFromHeaders
|
|
91
|
+
} = requestIdsToTokens[requestId] || {}
|
|
92
|
+
delete requestIdsToTokens[requestId]
|
|
93
|
+
|
|
94
|
+
const inputTokens = usage.inputTokens || inputTokensFromHeaders || 0
|
|
95
|
+
const outputTokens = usage.outputTokens || outputTokensFromHeaders || 0
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
inputTokens,
|
|
99
|
+
outputTokens,
|
|
100
|
+
totalTokens: inputTokens + outputTokens
|
|
56
101
|
}
|
|
57
102
|
}
|
|
58
103
|
|
|
@@ -15,11 +15,11 @@ let logger = defaultLogger
|
|
|
15
15
|
let logChannel = new LogChannel()
|
|
16
16
|
|
|
17
17
|
function withNoop (fn) {
|
|
18
|
-
const store = storage.getStore()
|
|
18
|
+
const store = storage('legacy').getStore()
|
|
19
19
|
|
|
20
|
-
storage.enterWith({ noop: true })
|
|
20
|
+
storage('legacy').enterWith({ noop: true })
|
|
21
21
|
fn()
|
|
22
|
-
storage.enterWith(store)
|
|
22
|
+
storage('legacy').enterWith(store)
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
function unsubscribeAll () {
|
|
@@ -6,7 +6,7 @@ const { storage } = require('../../../datadog-core') // TODO: noop storage?
|
|
|
6
6
|
|
|
7
7
|
class NoopSpan {
|
|
8
8
|
constructor (tracer, parent) {
|
|
9
|
-
this._store = storage.getHandle()
|
|
9
|
+
this._store = storage('legacy').getHandle()
|
|
10
10
|
this._noopTracer = tracer
|
|
11
11
|
this._noopContext = this._createContext(parent)
|
|
12
12
|
}
|
|
@@ -325,6 +325,7 @@ class TextMapPropagator {
|
|
|
325
325
|
if (context === null) {
|
|
326
326
|
context = extractedContext
|
|
327
327
|
if (this._config.tracePropagationExtractFirst) {
|
|
328
|
+
this._extractBaggageItems(carrier, context)
|
|
328
329
|
return context
|
|
329
330
|
}
|
|
330
331
|
} else {
|
|
@@ -344,10 +345,7 @@ class TextMapPropagator {
|
|
|
344
345
|
}
|
|
345
346
|
}
|
|
346
347
|
|
|
347
|
-
|
|
348
|
-
context = context || new DatadogSpanContext()
|
|
349
|
-
this._extractBaggageItems(carrier, context)
|
|
350
|
-
}
|
|
348
|
+
this._extractBaggageItems(carrier, context)
|
|
351
349
|
|
|
352
350
|
return context || this._extractSqsdContext(carrier)
|
|
353
351
|
}
|
|
@@ -596,6 +594,9 @@ class TextMapPropagator {
|
|
|
596
594
|
}
|
|
597
595
|
|
|
598
596
|
_extractBaggageItems (carrier, spanContext) {
|
|
597
|
+
if (!this._hasPropagationStyle('extract', 'baggage')) return
|
|
598
|
+
if (!carrier || !carrier.baggage) return
|
|
599
|
+
if (!spanContext) return
|
|
599
600
|
const baggages = carrier.baggage.split(',')
|
|
600
601
|
for (const keyValue of baggages) {
|
|
601
602
|
if (!keyValue.includes('=')) {
|
|
@@ -31,6 +31,9 @@ loadChannel.subscribe(({ name }) => {
|
|
|
31
31
|
// Globals
|
|
32
32
|
maybeEnable(require('../../datadog-plugin-fetch/src'))
|
|
33
33
|
|
|
34
|
+
// Always enabled
|
|
35
|
+
maybeEnable(require('../../datadog-plugin-dd-trace-api/src'))
|
|
36
|
+
|
|
34
37
|
function maybeEnable (Plugin) {
|
|
35
38
|
if (!Plugin || typeof Plugin !== 'function') return
|
|
36
39
|
if (!pluginClasses[Plugin.id]) {
|
|
@@ -140,6 +143,7 @@ module.exports = class PluginManager {
|
|
|
140
143
|
ciVisibilityTestSessionName,
|
|
141
144
|
ciVisAgentlessLogSubmissionEnabled,
|
|
142
145
|
isTestDynamicInstrumentationEnabled,
|
|
146
|
+
isServiceUserProvided,
|
|
143
147
|
middlewareTracingEnabled
|
|
144
148
|
} = this._tracerConfig
|
|
145
149
|
|
|
@@ -152,7 +156,8 @@ module.exports = class PluginManager {
|
|
|
152
156
|
headers: headerTags || [],
|
|
153
157
|
ciVisibilityTestSessionName,
|
|
154
158
|
ciVisAgentlessLogSubmissionEnabled,
|
|
155
|
-
isTestDynamicInstrumentationEnabled
|
|
159
|
+
isTestDynamicInstrumentationEnabled,
|
|
160
|
+
isServiceUserProvided
|
|
156
161
|
}
|
|
157
162
|
|
|
158
163
|
if (logInjection !== undefined) {
|
|
@@ -7,7 +7,7 @@ class ApolloBasePlugin extends TracingPlugin {
|
|
|
7
7
|
static get kind () { return 'server' }
|
|
8
8
|
|
|
9
9
|
bindStart (ctx) {
|
|
10
|
-
const store = storage.getStore()
|
|
10
|
+
const store = storage('legacy').getStore()
|
|
11
11
|
const childOf = store ? store.span : null
|
|
12
12
|
|
|
13
13
|
const span = this.startSpan(this.getOperationName(), {
|
|
@@ -45,6 +45,7 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
45
45
|
constructor (...args) {
|
|
46
46
|
super(...args)
|
|
47
47
|
|
|
48
|
+
this.fileLineToProbeId = new Map()
|
|
48
49
|
this.rootDir = process.cwd() // fallback in case :session:start events are not emitted
|
|
49
50
|
|
|
50
51
|
this.addSub(`ci:${this.constructor.id}:library-configuration`, ({ onDone }) => {
|
|
@@ -335,7 +336,22 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
335
336
|
})
|
|
336
337
|
}
|
|
337
338
|
|
|
338
|
-
|
|
339
|
+
removeAllDiProbes () {
|
|
340
|
+
if (this.fileLineToProbeId.size === 0) {
|
|
341
|
+
return Promise.resolve()
|
|
342
|
+
}
|
|
343
|
+
log.debug('Removing all Dynamic Instrumentation probes')
|
|
344
|
+
return Promise.all(Array.from(this.fileLineToProbeId.keys())
|
|
345
|
+
.map((fileLine) => {
|
|
346
|
+
const [file, line] = fileLine.split(':')
|
|
347
|
+
return this.removeDiProbe({ file, line })
|
|
348
|
+
}))
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
removeDiProbe ({ file, line }) {
|
|
352
|
+
const probeId = this.fileLineToProbeId.get(`${file}:${line}`)
|
|
353
|
+
log.warn(`Removing probe from ${file}:${line}, with id: ${probeId}`)
|
|
354
|
+
this.fileLineToProbeId.delete(probeId)
|
|
339
355
|
return this.di.removeProbe(probeId)
|
|
340
356
|
}
|
|
341
357
|
|
|
@@ -346,9 +362,27 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
346
362
|
log.warn('Could not add breakpoint for dynamic instrumentation')
|
|
347
363
|
return
|
|
348
364
|
}
|
|
365
|
+
log.debug('Adding breakpoint for Dynamic Instrumentation')
|
|
366
|
+
|
|
367
|
+
this.testErrorStackIndex = stackIndex
|
|
368
|
+
const activeProbeKey = `${file}:${line}`
|
|
369
|
+
|
|
370
|
+
if (this.fileLineToProbeId.has(activeProbeKey)) {
|
|
371
|
+
log.warn('Probe already set for this line')
|
|
372
|
+
const oldProbeId = this.fileLineToProbeId.get(activeProbeKey)
|
|
373
|
+
return {
|
|
374
|
+
probeId: oldProbeId,
|
|
375
|
+
setProbePromise: Promise.resolve(),
|
|
376
|
+
stackIndex,
|
|
377
|
+
file,
|
|
378
|
+
line
|
|
379
|
+
}
|
|
380
|
+
}
|
|
349
381
|
|
|
350
382
|
const [probeId, setProbePromise] = this.di.addLineProbe({ file, line }, this.onDiBreakpointHit.bind(this))
|
|
351
383
|
|
|
384
|
+
this.fileLineToProbeId.set(activeProbeKey, probeId)
|
|
385
|
+
|
|
352
386
|
return {
|
|
353
387
|
probeId,
|
|
354
388
|
setProbePromise,
|