dd-trace 5.35.0 → 5.37.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 +2 -1
- package/index.d.ts +8 -7
- package/loader-hook.mjs +0 -4
- package/package.json +15 -14
- package/packages/datadog-core/index.js +1 -1
- package/packages/datadog-core/src/storage.js +76 -31
- package/packages/datadog-instrumentations/src/cucumber.js +54 -1
- package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -2
- package/packages/datadog-instrumentations/src/helpers/register.js +2 -2
- package/packages/datadog-instrumentations/src/jest.js +105 -11
- package/packages/datadog-instrumentations/src/mocha/main.js +46 -4
- package/packages/datadog-instrumentations/src/mocha/utils.js +35 -2
- package/packages/datadog-instrumentations/src/mocha/worker.js +7 -0
- package/packages/datadog-instrumentations/src/mysql2.js +3 -3
- package/packages/datadog-instrumentations/src/openai.js +8 -0
- package/packages/datadog-instrumentations/src/playwright.js +70 -22
- package/packages/datadog-instrumentations/src/vitest.js +60 -6
- 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/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 +31 -14
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +72 -7
- package/packages/datadog-plugin-cypress/src/support.js +36 -29
- package/packages/datadog-plugin-dd-trace-api/src/index.js +1 -3
- package/packages/datadog-plugin-graphql/src/utils.js +8 -1
- 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 +17 -12
- 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 +35 -16
- package/packages/datadog-plugin-mongodb-core/src/index.js +28 -2
- package/packages/datadog-plugin-next/src/index.js +4 -4
- package/packages/datadog-plugin-openai/src/tracing.js +2 -3
- package/packages/datadog-plugin-playwright/src/index.js +35 -9
- 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 +36 -12
- package/packages/dd-trace/src/appsec/graphql.js +6 -6
- package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +3 -7
- package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +15 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +17 -30
- 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 +7 -11
- package/packages/dd-trace/src/appsec/iast/analyzers/stored-injection-analyzer.js +11 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/template-injection-analyzer.js +2 -6
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +24 -4
- 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 +4 -2
- package/packages/dd-trace/src/appsec/iast/security-controls/index.js +187 -0
- package/packages/dd-trace/src/appsec/iast/security-controls/parser.js +96 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/constants.js +6 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +2 -2
- 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/secure-marks-generator.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/secure-marks.js +28 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -1
- package/packages/dd-trace/src/appsec/iast/telemetry/iast-metric.js +5 -0
- package/packages/dd-trace/src/appsec/iast/utils.js +24 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +8 -13
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +1 -0
- package/packages/dd-trace/src/appsec/index.js +4 -4
- package/packages/dd-trace/src/appsec/rasp/command_injection.js +5 -5
- package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +5 -5
- package/packages/dd-trace/src/appsec/rasp/lfi.js +3 -3
- package/packages/dd-trace/src/appsec/rasp/sql_injection.js +4 -4
- package/packages/dd-trace/src/appsec/rasp/ssrf.js +3 -3
- package/packages/dd-trace/src/appsec/reporter.js +3 -3
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
- 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 +31 -56
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +20 -2
- package/packages/dd-trace/src/ci-visibility/quarantined-tests/get-quarantined-tests.js +62 -0
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +5 -2
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +3 -3
- package/packages/dd-trace/src/config.js +18 -3
- package/packages/dd-trace/src/data_streams_context.js +2 -2
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +14 -7
- package/packages/dd-trace/src/debugger/devtools_client/source-maps.js +50 -0
- package/packages/dd-trace/src/debugger/devtools_client/state.js +38 -10
- 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/iitm.js +2 -2
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +1 -1
- package/packages/dd-trace/src/llmobs/tagger.js +12 -2
- 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 +3 -3
- package/packages/dd-trace/src/plugin_manager.js +3 -1
- package/packages/dd-trace/src/plugins/apollo.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +51 -4
- package/packages/dd-trace/src/plugins/database.js +14 -4
- 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/inferred_proxy.js +1 -3
- package/packages/dd-trace/src/plugins/util/test.js +10 -4
- 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/proxy.js +5 -1
- package/packages/dd-trace/src/ritm.js +2 -1
- package/packages/dd-trace/src/scope.js +5 -5
- package/packages/dd-trace/src/spanleak.js +0 -1
- package/packages/dd-trace/src/tracer.js +0 -14
- package/packages/memwatch/package.json +0 -9
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const request = require('../../exporters/common/request')
|
|
2
|
+
const id = require('../../id')
|
|
3
|
+
|
|
4
|
+
function getQuarantinedTests ({
|
|
5
|
+
url,
|
|
6
|
+
isEvpProxy,
|
|
7
|
+
evpProxyPrefix,
|
|
8
|
+
isGzipCompatible,
|
|
9
|
+
repositoryUrl
|
|
10
|
+
}, done) {
|
|
11
|
+
const options = {
|
|
12
|
+
path: '/api/v2/test/libraries/test-management/tests',
|
|
13
|
+
method: 'POST',
|
|
14
|
+
headers: {
|
|
15
|
+
'Content-Type': 'application/json'
|
|
16
|
+
},
|
|
17
|
+
timeout: 20000,
|
|
18
|
+
url
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (isGzipCompatible) {
|
|
22
|
+
options.headers['accept-encoding'] = 'gzip'
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (isEvpProxy) {
|
|
26
|
+
options.path = `${evpProxyPrefix}/api/v2/test/libraries/test-management/tests`
|
|
27
|
+
options.headers['X-Datadog-EVP-Subdomain'] = 'api'
|
|
28
|
+
} else {
|
|
29
|
+
const apiKey = process.env.DATADOG_API_KEY || process.env.DD_API_KEY
|
|
30
|
+
if (!apiKey) {
|
|
31
|
+
return done(new Error('Quarantined tests were not fetched because Datadog API key is not defined.'))
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
options.headers['dd-api-key'] = apiKey
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const data = JSON.stringify({
|
|
38
|
+
data: {
|
|
39
|
+
id: id().toString(10),
|
|
40
|
+
type: 'ci_app_libraries_tests_request',
|
|
41
|
+
attributes: {
|
|
42
|
+
repository_url: repositoryUrl
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
request(data, options, (err, res) => {
|
|
48
|
+
if (err) {
|
|
49
|
+
done(err)
|
|
50
|
+
} else {
|
|
51
|
+
try {
|
|
52
|
+
const { data: { attributes: { modules: quarantinedTests } } } = JSON.parse(res)
|
|
53
|
+
|
|
54
|
+
done(null, quarantinedTests)
|
|
55
|
+
} catch (err) {
|
|
56
|
+
done(err)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = { getQuarantinedTests }
|
|
@@ -94,7 +94,8 @@ function getLibraryConfiguration ({
|
|
|
94
94
|
early_flake_detection: earlyFlakeDetectionConfig,
|
|
95
95
|
flaky_test_retries_enabled: isFlakyTestRetriesEnabled,
|
|
96
96
|
di_enabled: isDiEnabled,
|
|
97
|
-
known_tests_enabled: isKnownTestsEnabled
|
|
97
|
+
known_tests_enabled: isKnownTestsEnabled,
|
|
98
|
+
test_management: testManagementConfig
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
101
|
} = JSON.parse(res)
|
|
@@ -111,7 +112,9 @@ function getLibraryConfiguration ({
|
|
|
111
112
|
earlyFlakeDetectionConfig?.faulty_session_threshold ?? DEFAULT_EARLY_FLAKE_DETECTION_ERROR_THRESHOLD,
|
|
112
113
|
isFlakyTestRetriesEnabled,
|
|
113
114
|
isDiEnabled: isDiEnabled && isFlakyTestRetriesEnabled,
|
|
114
|
-
isKnownTestsEnabled
|
|
115
|
+
isKnownTestsEnabled,
|
|
116
|
+
// TODO: should it be test management?
|
|
117
|
+
isQuarantinedTestsEnabled: (testManagementConfig?.enabled ?? false)
|
|
115
118
|
}
|
|
116
119
|
|
|
117
120
|
log.debug(() => `Remote settings: ${JSON.stringify(settings)}`)
|
|
@@ -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)
|
|
@@ -497,6 +497,7 @@ class Config {
|
|
|
497
497
|
this._setValue(defaults, 'iast.redactionNamePattern', null)
|
|
498
498
|
this._setValue(defaults, 'iast.redactionValuePattern', null)
|
|
499
499
|
this._setValue(defaults, 'iast.requestSampling', 30)
|
|
500
|
+
this._setValue(defaults, 'iast.securityControlsConfiguration', null)
|
|
500
501
|
this._setValue(defaults, 'iast.telemetryVerbosity', 'INFORMATION')
|
|
501
502
|
this._setValue(defaults, 'iast.stackTrace.enabled', true)
|
|
502
503
|
this._setValue(defaults, 'injectionEnabled', [])
|
|
@@ -518,6 +519,9 @@ class Config {
|
|
|
518
519
|
this._setValue(defaults, 'ciVisAgentlessLogSubmissionEnabled', false)
|
|
519
520
|
this._setValue(defaults, 'legacyBaggageEnabled', true)
|
|
520
521
|
this._setValue(defaults, 'isTestDynamicInstrumentationEnabled', false)
|
|
522
|
+
this._setValue(defaults, 'isServiceUserProvided', false)
|
|
523
|
+
this._setValue(defaults, 'testManagementAttemptToFixRetries', 20)
|
|
524
|
+
this._setValue(defaults, 'isTestManagementEnabled', false)
|
|
521
525
|
this._setValue(defaults, 'logInjection', false)
|
|
522
526
|
this._setValue(defaults, 'lookup', undefined)
|
|
523
527
|
this._setValue(defaults, 'inferredProxyServicesEnabled', false)
|
|
@@ -624,6 +628,7 @@ class Config {
|
|
|
624
628
|
DD_IAST_REDACTION_NAME_PATTERN,
|
|
625
629
|
DD_IAST_REDACTION_VALUE_PATTERN,
|
|
626
630
|
DD_IAST_REQUEST_SAMPLING,
|
|
631
|
+
DD_IAST_SECURITY_CONTROLS_CONFIGURATION,
|
|
627
632
|
DD_IAST_TELEMETRY_VERBOSITY,
|
|
628
633
|
DD_IAST_STACK_TRACE_ENABLED,
|
|
629
634
|
DD_INJECTION_ENABLED,
|
|
@@ -792,6 +797,7 @@ class Config {
|
|
|
792
797
|
this._setValue(env, 'iast.requestSampling', iastRequestSampling)
|
|
793
798
|
}
|
|
794
799
|
this._envUnprocessed['iast.requestSampling'] = DD_IAST_REQUEST_SAMPLING
|
|
800
|
+
this._setString(env, 'iast.securityControlsConfiguration', DD_IAST_SECURITY_CONTROLS_CONFIGURATION)
|
|
795
801
|
this._setString(env, 'iast.telemetryVerbosity', DD_IAST_TELEMETRY_VERBOSITY)
|
|
796
802
|
this._setBoolean(env, 'iast.stackTrace.enabled', DD_IAST_STACK_TRACE_ENABLED)
|
|
797
803
|
this._setArray(env, 'injectionEnabled', DD_INJECTION_ENABLED)
|
|
@@ -984,14 +990,15 @@ class Config {
|
|
|
984
990
|
this._setValue(opts, 'iast.requestSampling', iastRequestSampling)
|
|
985
991
|
this._optsUnprocessed['iast.requestSampling'] = options.iast?.requestSampling
|
|
986
992
|
}
|
|
987
|
-
this.
|
|
993
|
+
this._setValue(opts, 'iast.securityControlsConfiguration', options.iast?.securityControlsConfiguration)
|
|
988
994
|
this._setBoolean(opts, 'iast.stackTrace.enabled', options.iast?.stackTrace?.enabled)
|
|
995
|
+
this._setString(opts, 'iast.telemetryVerbosity', options.iast && options.iast.telemetryVerbosity)
|
|
989
996
|
this._setBoolean(opts, 'isCiVisibility', options.isCiVisibility)
|
|
990
997
|
this._setBoolean(opts, 'legacyBaggageEnabled', options.legacyBaggageEnabled)
|
|
991
998
|
this._setBoolean(opts, 'llmobs.agentlessEnabled', options.llmobs?.agentlessEnabled)
|
|
992
999
|
this._setString(opts, 'llmobs.mlApp', options.llmobs?.mlApp)
|
|
993
1000
|
this._setBoolean(opts, 'logInjection', options.logInjection)
|
|
994
|
-
this.
|
|
1001
|
+
this._setValue(opts, 'lookup', options.lookup)
|
|
995
1002
|
this._setBoolean(opts, 'middlewareTracingEnabled', options.middlewareTracingEnabled)
|
|
996
1003
|
this._setBoolean(opts, 'openAiLogsEnabled', options.openAiLogsEnabled)
|
|
997
1004
|
this._setValue(opts, 'peerServiceMapping', options.peerServiceMapping)
|
|
@@ -1137,7 +1144,9 @@ class Config {
|
|
|
1137
1144
|
DD_CIVISIBILITY_FLAKY_RETRY_COUNT,
|
|
1138
1145
|
DD_TEST_SESSION_NAME,
|
|
1139
1146
|
DD_AGENTLESS_LOG_SUBMISSION_ENABLED,
|
|
1140
|
-
DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED
|
|
1147
|
+
DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED,
|
|
1148
|
+
DD_TEST_MANAGEMENT_ENABLED,
|
|
1149
|
+
DD_TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES
|
|
1141
1150
|
} = process.env
|
|
1142
1151
|
|
|
1143
1152
|
if (DD_CIVISIBILITY_AGENTLESS_URL) {
|
|
@@ -1156,6 +1165,12 @@ class Config {
|
|
|
1156
1165
|
this._setString(calc, 'ciVisibilityTestSessionName', DD_TEST_SESSION_NAME)
|
|
1157
1166
|
this._setBoolean(calc, 'ciVisAgentlessLogSubmissionEnabled', isTrue(DD_AGENTLESS_LOG_SUBMISSION_ENABLED))
|
|
1158
1167
|
this._setBoolean(calc, 'isTestDynamicInstrumentationEnabled', isTrue(DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED))
|
|
1168
|
+
this._setBoolean(calc, 'isServiceUserProvided', !!this._env.service)
|
|
1169
|
+
this._setBoolean(calc, 'isTestManagementEnabled', !isFalse(DD_TEST_MANAGEMENT_ENABLED))
|
|
1170
|
+
this._setValue(calc,
|
|
1171
|
+
'testManagementAttemptToFixRetries',
|
|
1172
|
+
coalesce(maybeInt(DD_TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES), 20)
|
|
1173
|
+
)
|
|
1159
1174
|
}
|
|
1160
1175
|
this._setString(calc, 'dogstatsd.hostname', this._getHostname())
|
|
1161
1176
|
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 = {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { getGeneratedPosition } = require('./source-maps')
|
|
3
4
|
const session = require('./session')
|
|
4
5
|
const { MAX_SNAPSHOTS_PER_SECOND_PER_PROBE, MAX_NON_SNAPSHOTS_PER_SECOND_PER_PROBE } = require('./defaults')
|
|
5
6
|
const { findScriptFromPartialPath, probes, breakpoints } = require('./state')
|
|
@@ -16,10 +17,11 @@ async function addBreakpoint (probe) {
|
|
|
16
17
|
if (!sessionStarted) await start()
|
|
17
18
|
|
|
18
19
|
const file = probe.where.sourceFile
|
|
19
|
-
|
|
20
|
+
let lineNumber = Number(probe.where.lines[0]) // Tracer doesn't support multiple-line breakpoints
|
|
21
|
+
let columnNumber = 0 // Probes do not contain/support column information
|
|
20
22
|
|
|
21
23
|
// Optimize for sending data to /debugger/v1/input endpoint
|
|
22
|
-
probe.location = { file, lines: [String(
|
|
24
|
+
probe.location = { file, lines: [String(lineNumber)] }
|
|
23
25
|
delete probe.where
|
|
24
26
|
|
|
25
27
|
// Optimize for fast calculations when probe is hit
|
|
@@ -34,17 +36,22 @@ async function addBreakpoint (probe) {
|
|
|
34
36
|
// not continue untill all scripts have been parsed?
|
|
35
37
|
const script = findScriptFromPartialPath(file)
|
|
36
38
|
if (!script) throw new Error(`No loaded script found for ${file} (probe: ${probe.id}, version: ${probe.version})`)
|
|
37
|
-
const
|
|
39
|
+
const { url, scriptId, sourceMapURL, source } = script
|
|
40
|
+
|
|
41
|
+
if (sourceMapURL) {
|
|
42
|
+
({ line: lineNumber, column: columnNumber } = await getGeneratedPosition(url, source, lineNumber, sourceMapURL))
|
|
43
|
+
}
|
|
38
44
|
|
|
39
45
|
log.debug(
|
|
40
|
-
'[debugger:devtools_client] Adding breakpoint at %s:%d (probe: %s, version: %d)',
|
|
41
|
-
|
|
46
|
+
'[debugger:devtools_client] Adding breakpoint at %s:%d:%d (probe: %s, version: %d)',
|
|
47
|
+
url, lineNumber, columnNumber, probe.id, probe.version
|
|
42
48
|
)
|
|
43
49
|
|
|
44
50
|
const { breakpointId } = await session.post('Debugger.setBreakpoint', {
|
|
45
51
|
location: {
|
|
46
52
|
scriptId,
|
|
47
|
-
lineNumber:
|
|
53
|
+
lineNumber: lineNumber - 1, // Beware! lineNumber is zero-indexed
|
|
54
|
+
columnNumber
|
|
48
55
|
}
|
|
49
56
|
})
|
|
50
57
|
|
|
@@ -66,7 +73,7 @@ async function removeBreakpoint ({ id }) {
|
|
|
66
73
|
probes.delete(id)
|
|
67
74
|
breakpoints.delete(breakpointId)
|
|
68
75
|
|
|
69
|
-
if (breakpoints.size === 0)
|
|
76
|
+
if (breakpoints.size === 0) return stop() // return instead of await to reduce number of promises created
|
|
70
77
|
}
|
|
71
78
|
|
|
72
79
|
async function start () {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { join, dirname } = require('path')
|
|
4
|
+
const { readFileSync } = require('fs')
|
|
5
|
+
const { readFile } = require('fs/promises')
|
|
6
|
+
const { SourceMapConsumer } = require('source-map')
|
|
7
|
+
|
|
8
|
+
const cache = new Map()
|
|
9
|
+
let cacheTimer = null
|
|
10
|
+
|
|
11
|
+
const self = module.exports = {
|
|
12
|
+
async loadSourceMap (dir, url) {
|
|
13
|
+
if (url.startsWith('data:')) return loadInlineSourceMap(url)
|
|
14
|
+
const path = join(dir, url)
|
|
15
|
+
if (cache.has(path)) return cache.get(path)
|
|
16
|
+
return cacheIt(path, JSON.parse(await readFile(path, 'utf8')))
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
loadSourceMapSync (dir, url) {
|
|
20
|
+
if (url.startsWith('data:')) return loadInlineSourceMap(url)
|
|
21
|
+
const path = join(dir, url)
|
|
22
|
+
if (cache.has(path)) return cache.get(path)
|
|
23
|
+
return cacheIt(path, JSON.parse(readFileSync(path, 'utf8')))
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
async getGeneratedPosition (url, source, line, sourceMapURL) {
|
|
27
|
+
const dir = dirname(new URL(url).pathname)
|
|
28
|
+
return await SourceMapConsumer.with(
|
|
29
|
+
await self.loadSourceMap(dir, sourceMapURL),
|
|
30
|
+
null,
|
|
31
|
+
(consumer) => consumer.generatedPositionFor({ source, line, column: 0 })
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function cacheIt (key, value) {
|
|
37
|
+
clearTimeout(cacheTimer)
|
|
38
|
+
cacheTimer = setTimeout(function () {
|
|
39
|
+
// Optimize for app boot, where a lot of reads might happen
|
|
40
|
+
// Clear cache a few seconds after it was last used
|
|
41
|
+
cache.clear()
|
|
42
|
+
}, 10_000).unref()
|
|
43
|
+
cache.set(key, value)
|
|
44
|
+
return value
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function loadInlineSourceMap (data) {
|
|
48
|
+
data = data.slice(data.indexOf('base64,') + 7)
|
|
49
|
+
return JSON.parse(Buffer.from(data, 'base64').toString('utf8'))
|
|
50
|
+
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { join, dirname } = require('path')
|
|
4
|
+
const { loadSourceMapSync } = require('./source-maps')
|
|
3
5
|
const session = require('./session')
|
|
6
|
+
const log = require('../../log')
|
|
4
7
|
|
|
5
8
|
const WINDOWS_DRIVE_LETTER_REGEX = /[a-zA-Z]/
|
|
6
9
|
|
|
7
|
-
const
|
|
10
|
+
const loadedScripts = []
|
|
8
11
|
const scriptUrls = new Map()
|
|
9
12
|
|
|
10
13
|
module.exports = {
|
|
@@ -15,18 +18,17 @@ module.exports = {
|
|
|
15
18
|
* Find the script to inspect based on a partial or absolute path. Handles both Windows and POSIX paths.
|
|
16
19
|
*
|
|
17
20
|
* @param {string} path - Partial or absolute path to match against loaded scripts
|
|
18
|
-
* @returns {
|
|
19
|
-
* or null if no match
|
|
21
|
+
* @returns {Object | null} - Object containing `url`, `scriptId`, `sourceMapURL`, and `source` - or null if no match
|
|
20
22
|
*/
|
|
21
23
|
findScriptFromPartialPath (path) {
|
|
22
24
|
if (!path) return null // This shouldn't happen, but better safe than sorry
|
|
23
25
|
|
|
24
26
|
path = path.toLowerCase()
|
|
25
27
|
|
|
26
|
-
const bestMatch =
|
|
28
|
+
const bestMatch = { url: null, scriptId: null, sourceMapURL: null, source: null }
|
|
27
29
|
let maxMatchLength = -1
|
|
28
30
|
|
|
29
|
-
for (const
|
|
31
|
+
for (const { url, sourceUrl, scriptId, sourceMapURL, source } of loadedScripts) {
|
|
30
32
|
let i = url.length - 1
|
|
31
33
|
let j = path.length - 1
|
|
32
34
|
let matchLength = 0
|
|
@@ -75,12 +77,13 @@ module.exports = {
|
|
|
75
77
|
// If we found a valid match and it's better than our previous best
|
|
76
78
|
if (atBoundary && (
|
|
77
79
|
lastBoundaryPos > maxMatchLength ||
|
|
78
|
-
(lastBoundaryPos === maxMatchLength && url.length < bestMatch
|
|
80
|
+
(lastBoundaryPos === maxMatchLength && url.length < bestMatch.url.length) // Prefer shorter paths
|
|
79
81
|
)) {
|
|
80
82
|
maxMatchLength = lastBoundaryPos
|
|
81
|
-
bestMatch
|
|
82
|
-
bestMatch
|
|
83
|
-
bestMatch
|
|
83
|
+
bestMatch.url = sourceUrl || url
|
|
84
|
+
bestMatch.scriptId = scriptId
|
|
85
|
+
bestMatch.sourceMapURL = sourceMapURL
|
|
86
|
+
bestMatch.source = source
|
|
84
87
|
}
|
|
85
88
|
}
|
|
86
89
|
|
|
@@ -112,6 +115,31 @@ module.exports = {
|
|
|
112
115
|
session.on('Debugger.scriptParsed', ({ params }) => {
|
|
113
116
|
scriptUrls.set(params.scriptId, params.url)
|
|
114
117
|
if (params.url.startsWith('file:')) {
|
|
115
|
-
|
|
118
|
+
if (params.sourceMapURL) {
|
|
119
|
+
const dir = dirname(new URL(params.url).pathname)
|
|
120
|
+
let sources
|
|
121
|
+
try {
|
|
122
|
+
sources = loadSourceMapSync(dir, params.sourceMapURL).sources
|
|
123
|
+
} catch (err) {
|
|
124
|
+
if (typeof params.sourceMapURL === 'string' && params.sourceMapURL.startsWith('data:')) {
|
|
125
|
+
log.error('[debugger:devtools_client] could not load inline source map for "%s"', params.url, err)
|
|
126
|
+
} else {
|
|
127
|
+
log.error('[debugger:devtools_client] could not load source map "%s" from "%s" for "%s"',
|
|
128
|
+
params.sourceMapURL, dir, params.url, err)
|
|
129
|
+
}
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
for (const source of sources) {
|
|
133
|
+
// TODO: Take source map `sourceRoot` into account?
|
|
134
|
+
loadedScripts.push({
|
|
135
|
+
...params,
|
|
136
|
+
sourceUrl: params.url,
|
|
137
|
+
url: new URL(join(dir, source), 'file:').href,
|
|
138
|
+
source
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
} else {
|
|
142
|
+
loadedScripts.push(params)
|
|
143
|
+
}
|
|
116
144
|
}
|
|
117
145
|
})
|
|
@@ -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
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const satisfies = require('semifies')
|
|
4
4
|
const logger = require('./log')
|
|
5
5
|
const { addHook } = require('import-in-the-middle')
|
|
6
6
|
const dc = require('dc-polyfill')
|
|
7
7
|
|
|
8
|
-
if (
|
|
8
|
+
if (satisfies(process.versions.node, '>=14.13.1')) {
|
|
9
9
|
const moduleLoadStartChannel = dc.channel('dd-trace:moduleLoadStart')
|
|
10
10
|
addHook((name, namespace) => {
|
|
11
11
|
if (moduleLoadStartChannel.hasSubscribers) {
|
|
@@ -29,7 +29,7 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
|
|
|
29
29
|
if (modelName.includes('embed')) {
|
|
30
30
|
return
|
|
31
31
|
}
|
|
32
|
-
const span = storage.getStore()?.span
|
|
32
|
+
const span = storage('legacy').getStore()?.span
|
|
33
33
|
this.setLLMObsTags({ request, span, response, modelProvider, modelName })
|
|
34
34
|
})
|
|
35
35
|
|
|
@@ -100,7 +100,12 @@ class LLMObsTagger {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
tagMetadata (span, metadata) {
|
|
103
|
-
|
|
103
|
+
const existingMetadata = registry.get(span)?.[METADATA]
|
|
104
|
+
if (existingMetadata) {
|
|
105
|
+
Object.assign(existingMetadata, metadata)
|
|
106
|
+
} else {
|
|
107
|
+
this._setTag(span, METADATA, metadata)
|
|
108
|
+
}
|
|
104
109
|
}
|
|
105
110
|
|
|
106
111
|
tagMetrics (span, metrics) {
|
|
@@ -128,7 +133,12 @@ class LLMObsTagger {
|
|
|
128
133
|
}
|
|
129
134
|
}
|
|
130
135
|
|
|
131
|
-
|
|
136
|
+
const existingMetrics = registry.get(span)?.[METRICS]
|
|
137
|
+
if (existingMetrics) {
|
|
138
|
+
Object.assign(existingMetrics, filterdMetrics)
|
|
139
|
+
} else {
|
|
140
|
+
this._setTag(span, METRICS, filterdMetrics)
|
|
141
|
+
}
|
|
132
142
|
}
|
|
133
143
|
|
|
134
144
|
tagSpanTags (span, tags) {
|
|
@@ -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('=')) {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
const { performance } = require('perf_hooks')
|
|
5
5
|
const now = performance.now.bind(performance)
|
|
6
6
|
const dateNow = Date.now
|
|
7
|
-
const
|
|
7
|
+
const satisfies = require('semifies')
|
|
8
8
|
const SpanContext = require('./span_context')
|
|
9
9
|
const id = require('../id')
|
|
10
10
|
const tagger = require('../tagger')
|
|
@@ -65,7 +65,7 @@ class DatadogSpan {
|
|
|
65
65
|
this._debug = debug
|
|
66
66
|
this._processor = processor
|
|
67
67
|
this._prioritySampler = prioritySampler
|
|
68
|
-
this._store = storage.getHandle()
|
|
68
|
+
this._store = storage('legacy').getHandle()
|
|
69
69
|
this._duration = undefined
|
|
70
70
|
|
|
71
71
|
this._events = []
|
|
@@ -365,7 +365,7 @@ class DatadogSpan {
|
|
|
365
365
|
}
|
|
366
366
|
|
|
367
367
|
function createRegistry (type) {
|
|
368
|
-
if (!
|
|
368
|
+
if (!satisfies(process.version, '>=14.6')) return
|
|
369
369
|
|
|
370
370
|
return new global.FinalizationRegistry(name => {
|
|
371
371
|
runtimeMetrics.decrement(`runtime.node.spans.${type}`)
|
|
@@ -143,6 +143,7 @@ module.exports = class PluginManager {
|
|
|
143
143
|
ciVisibilityTestSessionName,
|
|
144
144
|
ciVisAgentlessLogSubmissionEnabled,
|
|
145
145
|
isTestDynamicInstrumentationEnabled,
|
|
146
|
+
isServiceUserProvided,
|
|
146
147
|
middlewareTracingEnabled
|
|
147
148
|
} = this._tracerConfig
|
|
148
149
|
|
|
@@ -155,7 +156,8 @@ module.exports = class PluginManager {
|
|
|
155
156
|
headers: headerTags || [],
|
|
156
157
|
ciVisibilityTestSessionName,
|
|
157
158
|
ciVisAgentlessLogSubmissionEnabled,
|
|
158
|
-
isTestDynamicInstrumentationEnabled
|
|
159
|
+
isTestDynamicInstrumentationEnabled,
|
|
160
|
+
isServiceUserProvided
|
|
159
161
|
}
|
|
160
162
|
|
|
161
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(), {
|