dd-trace 5.86.0 → 5.88.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 +60 -32
- package/ext/exporters.d.ts +1 -0
- package/ext/exporters.js +1 -0
- package/index.d.ts +243 -7
- package/package.json +9 -6
- package/packages/datadog-instrumentations/src/ai.js +54 -90
- package/packages/datadog-instrumentations/src/cucumber.js +14 -0
- package/packages/datadog-instrumentations/src/helpers/hook.js +17 -11
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +55 -14
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +15 -13
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +103 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/bullmq.js +108 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/transformer.js +21 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +138 -12
- package/packages/datadog-instrumentations/src/http/client.js +119 -1
- package/packages/datadog-instrumentations/src/jest.js +179 -15
- package/packages/datadog-instrumentations/src/kafkajs.js +20 -17
- package/packages/datadog-instrumentations/src/mocha/utils.js +6 -0
- package/packages/datadog-instrumentations/src/mysql2.js +131 -64
- package/packages/datadog-instrumentations/src/playwright.js +9 -1
- package/packages/datadog-instrumentations/src/stripe.js +92 -0
- package/packages/datadog-instrumentations/src/vitest.js +11 -0
- package/packages/datadog-plugin-amqplib/src/consumer.js +14 -10
- package/packages/datadog-plugin-amqplib/src/producer.js +23 -19
- package/packages/datadog-plugin-azure-functions/src/index.js +53 -37
- package/packages/datadog-plugin-bullmq/src/consumer.js +33 -11
- package/packages/datadog-plugin-bullmq/src/producer.js +60 -31
- package/packages/datadog-plugin-cucumber/src/index.js +9 -6
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +33 -0
- package/packages/datadog-plugin-cypress/src/support.js +48 -8
- package/packages/datadog-plugin-jest/src/index.js +12 -2
- package/packages/datadog-plugin-jest/src/util.js +2 -1
- package/packages/datadog-plugin-kafkajs/src/consumer.js +22 -12
- package/packages/datadog-plugin-kafkajs/src/producer.js +33 -22
- package/packages/datadog-plugin-mocha/src/index.js +9 -6
- package/packages/datadog-plugin-playwright/src/index.js +10 -6
- package/packages/datadog-plugin-vitest/src/index.js +13 -8
- package/packages/dd-trace/src/appsec/addresses.js +11 -0
- package/packages/dd-trace/src/appsec/channels.js +5 -1
- package/packages/dd-trace/src/appsec/downstream_requests.js +302 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/ssrf-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +4 -5
- package/packages/dd-trace/src/appsec/iast/path-line.js +36 -25
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -4
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +3 -2
- package/packages/dd-trace/src/appsec/index.js +103 -0
- package/packages/dd-trace/src/appsec/rasp/ssrf.js +66 -4
- package/packages/dd-trace/src/azure_metadata.js +0 -2
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +14 -1
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +2 -0
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +1 -1
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -1
- package/packages/dd-trace/src/ci-visibility/requests/request.js +236 -0
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +1 -1
- package/packages/dd-trace/src/config/defaults.js +148 -195
- package/packages/dd-trace/src/config/helper.js +43 -1
- package/packages/dd-trace/src/config/index.js +42 -14
- package/packages/dd-trace/src/config/supported-configurations.json +4115 -510
- package/packages/dd-trace/src/constants.js +0 -2
- package/packages/dd-trace/src/crashtracking/crashtracker.js +10 -3
- package/packages/dd-trace/src/datastreams/pathway.js +22 -3
- package/packages/dd-trace/src/datastreams/processor.js +14 -1
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +47 -2
- package/packages/dd-trace/src/debugger/devtools_client/index.js +75 -23
- package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +23 -1
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +3 -3
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +168 -36
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +18 -0
- package/packages/dd-trace/src/encode/agentless-json.js +141 -0
- package/packages/dd-trace/src/exporter.js +2 -0
- package/packages/dd-trace/src/exporters/agent/writer.js +22 -8
- package/packages/dd-trace/src/exporters/agentless/index.js +89 -0
- package/packages/dd-trace/src/exporters/agentless/writer.js +184 -0
- package/packages/dd-trace/src/exporters/common/agents.js +1 -1
- package/packages/dd-trace/src/exporters/common/request.js +4 -4
- package/packages/dd-trace/src/llmobs/constants/writers.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/index.js +5 -3
- package/packages/dd-trace/src/llmobs/sdk.js +34 -5
- package/packages/dd-trace/src/opentelemetry/context_manager.js +19 -46
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +3 -4
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +3 -5
- package/packages/dd-trace/src/opentracing/span.js +6 -4
- package/packages/dd-trace/src/plugins/ci_plugin.js +57 -5
- package/packages/dd-trace/src/plugins/database.js +57 -45
- package/packages/dd-trace/src/plugins/outbound.js +27 -2
- package/packages/dd-trace/src/plugins/tracing.js +39 -4
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +7 -0
- package/packages/dd-trace/src/plugins/util/test.js +48 -0
- package/packages/dd-trace/src/plugins/util/web.js +8 -7
- package/packages/dd-trace/src/profiling/exporter_cli.js +1 -0
- package/packages/dd-trace/src/propagation-hash/index.js +145 -0
- package/packages/dd-trace/src/proxy.js +4 -0
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +1 -1
- package/packages/dd-trace/src/startup-log.js +3 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/bullmq.json +0 -106
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +0 -741
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-regex.js +0 -11
- package/packages/dd-trace/src/plugins/util/serverless.js +0 -8
- package/packages/dd-trace/src/scope/noop/scope.js +0 -21
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { trace, ROOT_CONTEXT, propagation } = require('@opentelemetry/api')
|
|
4
4
|
const { storage } = require('../../../datadog-core')
|
|
5
|
+
const { getAllBaggageItems, setBaggageItem, removeAllBaggageItems } = require('../baggage')
|
|
5
6
|
|
|
6
7
|
const tracer = require('../../')
|
|
7
8
|
const SpanContext = require('./span_context')
|
|
@@ -19,31 +20,26 @@ class ContextManager {
|
|
|
19
20
|
|
|
20
21
|
const storedSpan = store ? trace.getSpan(store) : null
|
|
21
22
|
|
|
23
|
+
// Convert DD baggage to OTel format
|
|
24
|
+
const baggages = getAllBaggageItems()
|
|
25
|
+
const hasBaggage = Object.keys(baggages).length > 0
|
|
26
|
+
let otelBaggages
|
|
27
|
+
if (hasBaggage) {
|
|
28
|
+
const entries = {}
|
|
29
|
+
for (const [key, value] of Object.entries(baggages)) {
|
|
30
|
+
entries[key] = { value }
|
|
31
|
+
}
|
|
32
|
+
otelBaggages = propagation.createBaggage(entries)
|
|
33
|
+
}
|
|
34
|
+
|
|
22
35
|
// If stored span wraps the active DD span, prefer the stored context
|
|
23
36
|
if (storedSpan && storedSpan._ddSpan === activeSpan) {
|
|
24
|
-
|
|
25
|
-
if (Object.keys(baggages).length > 0) {
|
|
26
|
-
const entries = {}
|
|
27
|
-
for (const [key, value] of Object.entries(baggages)) {
|
|
28
|
-
entries[key] = { value }
|
|
29
|
-
}
|
|
30
|
-
const otelBaggages = propagation.createBaggage(entries)
|
|
31
|
-
return propagation.setBaggage(store, otelBaggages)
|
|
32
|
-
}
|
|
37
|
+
if (otelBaggages) return propagation.setBaggage(store, otelBaggages)
|
|
33
38
|
return store
|
|
34
39
|
}
|
|
35
40
|
|
|
36
41
|
if (!activeSpan) {
|
|
37
|
-
|
|
38
|
-
if (storedBaggageItems) {
|
|
39
|
-
const baggages = storedBaggageItems
|
|
40
|
-
const entries = {}
|
|
41
|
-
for (const [key, value] of Object.entries(baggages)) {
|
|
42
|
-
entries[key] = { value }
|
|
43
|
-
}
|
|
44
|
-
const otelBaggages = propagation.createBaggage(entries)
|
|
45
|
-
return propagation.setBaggage(baseContext, otelBaggages)
|
|
46
|
-
}
|
|
42
|
+
if (otelBaggages) return propagation.setBaggage(baseContext, otelBaggages)
|
|
47
43
|
return baseContext
|
|
48
44
|
}
|
|
49
45
|
|
|
@@ -53,18 +49,6 @@ class ContextManager {
|
|
|
53
49
|
ddContext._otelSpanContext = new SpanContext(ddContext)
|
|
54
50
|
}
|
|
55
51
|
|
|
56
|
-
// Convert DD baggage to OTel format
|
|
57
|
-
const baggages = JSON.parse(activeSpan.getAllBaggageItems())
|
|
58
|
-
const hasBaggage = Object.keys(baggages).length > 0
|
|
59
|
-
let otelBaggages
|
|
60
|
-
if (hasBaggage) {
|
|
61
|
-
const entries = {}
|
|
62
|
-
for (const [key, value] of Object.entries(baggages)) {
|
|
63
|
-
entries[key] = { value }
|
|
64
|
-
}
|
|
65
|
-
otelBaggages = propagation.createBaggage(entries)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
52
|
if (store && trace.getSpanContext(store) === ddContext._otelSpanContext) {
|
|
69
53
|
return otelBaggages ? propagation.setBaggage(store, otelBaggages) : store
|
|
70
54
|
}
|
|
@@ -86,22 +70,11 @@ class ContextManager {
|
|
|
86
70
|
if (baggages) {
|
|
87
71
|
baggageItems = baggages.getAllEntries()
|
|
88
72
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
for (const baggage of baggageItems) {
|
|
93
|
-
span._ddSpan.setBaggageItem(baggage[0], baggage[1].value)
|
|
94
|
-
}
|
|
95
|
-
return ddScope.activate(span._ddSpan, run)
|
|
96
|
-
}
|
|
97
|
-
// span instanceof NonRecordingSpan
|
|
98
|
-
const ddContext = span?._spanContext?._ddContext
|
|
99
|
-
if (ddContext && ddContext._baggageItems) {
|
|
100
|
-
ddContext._baggageItems = {}
|
|
101
|
-
for (const baggage of baggageItems) {
|
|
102
|
-
ddContext._baggageItems[baggage[0]] = baggage[1].value
|
|
103
|
-
}
|
|
73
|
+
removeAllBaggageItems()
|
|
74
|
+
for (const baggage of baggageItems) {
|
|
75
|
+
setBaggageItem(baggage[0], baggage[1].value)
|
|
104
76
|
}
|
|
77
|
+
if (span && span._ddSpan) return ddScope.activate(span._ddSpan, run)
|
|
105
78
|
return run()
|
|
106
79
|
}
|
|
107
80
|
|
|
@@ -20,7 +20,7 @@ class OtlpHttpExporterBase {
|
|
|
20
20
|
* Creates a new OtlpHttpExporterBase instance.
|
|
21
21
|
*
|
|
22
22
|
* @param {string} url - OTLP endpoint URL
|
|
23
|
-
* @param {string} headers - Additional HTTP headers as comma-separated key=value string
|
|
23
|
+
* @param {string|undefined} headers - Additional HTTP headers as comma-separated key=value string
|
|
24
24
|
* @param {number} timeout - Request timeout in milliseconds
|
|
25
25
|
* @param {string} protocol - OTLP protocol (http/protobuf or http/json)
|
|
26
26
|
* @param {string} defaultPath - Default path to use if URL has no path
|
|
@@ -117,11 +117,10 @@ class OtlpHttpExporterBase {
|
|
|
117
117
|
|
|
118
118
|
/**
|
|
119
119
|
* Parses additional HTTP headers from a comma-separated string.
|
|
120
|
-
* @param {string} headersString - Comma-separated key=value pairs
|
|
120
|
+
* @param {string} [headersString=''] - Comma-separated key=value pairs
|
|
121
121
|
* @returns {Record<string, string>} Parsed headers object
|
|
122
|
-
* @private
|
|
123
122
|
*/
|
|
124
|
-
#parseAdditionalHeaders (headersString) {
|
|
123
|
+
#parseAdditionalHeaders (headersString = '') {
|
|
125
124
|
const headers = {}
|
|
126
125
|
let key = ''
|
|
127
126
|
let value = ''
|
|
@@ -670,10 +670,8 @@ class TextMapPropagator {
|
|
|
670
670
|
if (!this._hasPropagationStyle('extract', 'baggage')) return
|
|
671
671
|
if (!carrier?.baggage) return
|
|
672
672
|
const baggages = carrier.baggage.split(',')
|
|
673
|
-
const
|
|
674
|
-
const
|
|
675
|
-
? undefined
|
|
676
|
-
: new Set(this._config.baggageTagKeys.split(','))
|
|
673
|
+
const baggageTagKeys = new Set(this._config.baggageTagKeys)
|
|
674
|
+
const tagAllKeys = baggageTagKeys.has('*')
|
|
677
675
|
for (const keyValue of baggages) {
|
|
678
676
|
if (!keyValue) continue
|
|
679
677
|
|
|
@@ -707,7 +705,7 @@ class TextMapPropagator {
|
|
|
707
705
|
return
|
|
708
706
|
}
|
|
709
707
|
|
|
710
|
-
if (spanContext && (tagAllKeys ||
|
|
708
|
+
if (spanContext && (tagAllKeys || baggageTagKeys.has(key))) {
|
|
711
709
|
spanContext._trace.tags['baggage.' + key] = value
|
|
712
710
|
}
|
|
713
711
|
setBaggageItem(key, value)
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
// TODO (new internal tracer): use DC events for lifecycle metrics and test them
|
|
4
4
|
const { performance } = require('perf_hooks')
|
|
5
5
|
const now = performance.now.bind(performance)
|
|
6
|
-
const dateNow = Date.now
|
|
7
6
|
const util = require('util')
|
|
8
7
|
const { channel } = require('dc-polyfill')
|
|
9
8
|
const id = require('../id')
|
|
@@ -13,12 +12,15 @@ const log = require('../log')
|
|
|
13
12
|
const { storage } = require('../../../datadog-core')
|
|
14
13
|
const telemetryMetrics = require('../telemetry/metrics')
|
|
15
14
|
const { getValueFromEnvSources } = require('../config/helper')
|
|
15
|
+
const { isTrue } = require('../util')
|
|
16
16
|
const SpanContext = require('./span_context')
|
|
17
17
|
|
|
18
|
+
const dateNow = Date.now
|
|
19
|
+
|
|
18
20
|
const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
|
|
19
21
|
|
|
20
|
-
const DD_TRACE_EXPERIMENTAL_STATE_TRACKING = getValueFromEnvSources('DD_TRACE_EXPERIMENTAL_STATE_TRACKING')
|
|
21
|
-
const DD_TRACE_EXPERIMENTAL_SPAN_COUNTS = getValueFromEnvSources('DD_TRACE_EXPERIMENTAL_SPAN_COUNTS')
|
|
22
|
+
const DD_TRACE_EXPERIMENTAL_STATE_TRACKING = isTrue(getValueFromEnvSources('DD_TRACE_EXPERIMENTAL_STATE_TRACKING'))
|
|
23
|
+
const DD_TRACE_EXPERIMENTAL_SPAN_COUNTS = isTrue(getValueFromEnvSources('DD_TRACE_EXPERIMENTAL_SPAN_COUNTS'))
|
|
22
24
|
|
|
23
25
|
const unfinishedRegistry = createRegistry('unfinished')
|
|
24
26
|
const finishedRegistry = createRegistry('finished')
|
|
@@ -251,7 +253,7 @@ class DatadogSpan {
|
|
|
251
253
|
return
|
|
252
254
|
}
|
|
253
255
|
|
|
254
|
-
if (DD_TRACE_EXPERIMENTAL_STATE_TRACKING
|
|
256
|
+
if (DD_TRACE_EXPERIMENTAL_STATE_TRACKING && !this._spanContext._tags['service.name']) {
|
|
255
257
|
log.error('Finishing invalid span: %s', this)
|
|
256
258
|
}
|
|
257
259
|
|
|
@@ -63,6 +63,8 @@ const {
|
|
|
63
63
|
getPullRequestDiff,
|
|
64
64
|
getModifiedFilesFromDiff,
|
|
65
65
|
getPullRequestBaseBranch,
|
|
66
|
+
getSessionRequestErrorTags,
|
|
67
|
+
DD_CI_LIBRARY_CONFIGURATION_ERROR,
|
|
66
68
|
TEST_IS_TEST_FRAMEWORK_WORKER,
|
|
67
69
|
TEST_IS_NEW,
|
|
68
70
|
TEST_IS_RUM_ACTIVE,
|
|
@@ -120,6 +122,7 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
120
122
|
this.fileLineToProbeId = new Map()
|
|
121
123
|
this.rootDir = process.cwd() // fallback in case :session:start events are not emitted
|
|
122
124
|
this._testSuiteSpansByTestSuite = new Map()
|
|
125
|
+
this._pendingRequestErrorTags = []
|
|
123
126
|
|
|
124
127
|
this.addSub(`ci:${this.constructor.id}:library-configuration`, (ctx) => {
|
|
125
128
|
const { onDone, isParallel, frameworkVersion } = ctx
|
|
@@ -131,10 +134,15 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
131
134
|
this.tracer._exporter.getLibraryConfiguration(this.testConfiguration, (err, libraryConfig) => {
|
|
132
135
|
if (err) {
|
|
133
136
|
log.error('Library configuration could not be fetched. %s', err.message)
|
|
137
|
+
this._addRequestErrorTag(DD_CI_LIBRARY_CONFIGURATION_ERROR, err)
|
|
134
138
|
} else {
|
|
135
139
|
this.libraryConfig = libraryConfig
|
|
136
140
|
}
|
|
137
141
|
|
|
142
|
+
const requestErrorTags = this.testSessionSpan
|
|
143
|
+
? getSessionRequestErrorTags(this.testSessionSpan)
|
|
144
|
+
: Object.fromEntries(this._pendingRequestErrorTags.map(({ tag, value }) => [tag, value]))
|
|
145
|
+
|
|
138
146
|
const libraryCapabilitiesTags = getLibraryCapabilitiesTags(this.constructor.id, isParallel, frameworkVersion)
|
|
139
147
|
const metadataTags = {
|
|
140
148
|
test: {
|
|
@@ -142,7 +150,7 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
142
150
|
},
|
|
143
151
|
}
|
|
144
152
|
this.tracer._exporter.addMetadataTags(metadataTags)
|
|
145
|
-
onDone({ err, libraryConfig })
|
|
153
|
+
onDone({ err, libraryConfig, requestErrorTags })
|
|
146
154
|
})
|
|
147
155
|
})
|
|
148
156
|
|
|
@@ -200,6 +208,10 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
200
208
|
},
|
|
201
209
|
integrationName: this.constructor.id,
|
|
202
210
|
})
|
|
211
|
+
for (const { tag, value } of this._pendingRequestErrorTags) {
|
|
212
|
+
this.testSessionSpan.setTag(tag, value)
|
|
213
|
+
}
|
|
214
|
+
this._pendingRequestErrorTags = []
|
|
203
215
|
// TODO: add telemetry tag when we can add `is_agentless_log_submission_enabled` for agentless log submission
|
|
204
216
|
this.telemetry.ciVisEvent(TELEMETRY_EVENT_CREATED, 'session')
|
|
205
217
|
|
|
@@ -209,6 +221,7 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
209
221
|
[COMPONENT]: this.constructor.id,
|
|
210
222
|
...this.testEnvironmentMetadata,
|
|
211
223
|
...testModuleSpanMetadata,
|
|
224
|
+
...getSessionRequestErrorTags(this.testSessionSpan),
|
|
212
225
|
},
|
|
213
226
|
integrationName: this.constructor.id,
|
|
214
227
|
})
|
|
@@ -230,7 +243,10 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
230
243
|
this.addSub(`ci:${this.constructor.id}:itr:skipped-suites`, ({ skippedSuites, frameworkVersion }) => {
|
|
231
244
|
const testCommand = this.testSessionSpan.context()._tags[TEST_COMMAND]
|
|
232
245
|
for (const testSuite of skippedSuites) {
|
|
233
|
-
const testSuiteMetadata =
|
|
246
|
+
const testSuiteMetadata = {
|
|
247
|
+
...getTestSuiteCommonTags(testCommand, frameworkVersion, testSuite, this.constructor.id),
|
|
248
|
+
...getSessionRequestErrorTags(this.testSessionSpan),
|
|
249
|
+
}
|
|
234
250
|
if (this.itrCorrelationId) {
|
|
235
251
|
testSuiteMetadata[ITR_CORRELATION_ID] = this.itrCorrelationId
|
|
236
252
|
}
|
|
@@ -261,8 +277,10 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
261
277
|
this.tracer._exporter.getKnownTests(this.testConfiguration, (err, knownTests) => {
|
|
262
278
|
if (err) {
|
|
263
279
|
log.error('Known tests could not be fetched. %s', err.message)
|
|
264
|
-
this.libraryConfig
|
|
265
|
-
|
|
280
|
+
if (this.libraryConfig) {
|
|
281
|
+
this.libraryConfig.isEarlyFlakeDetectionEnabled = false
|
|
282
|
+
this.libraryConfig.isKnownTestsEnabled = false
|
|
283
|
+
}
|
|
266
284
|
}
|
|
267
285
|
onDone({ err, knownTests })
|
|
268
286
|
})
|
|
@@ -279,7 +297,9 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
279
297
|
this.tracer._exporter.getTestManagementTests(this.testConfiguration, (err, testManagementTests) => {
|
|
280
298
|
if (err) {
|
|
281
299
|
log.error('Test management tests could not be fetched. %s', err.message)
|
|
282
|
-
this.libraryConfig
|
|
300
|
+
if (this.libraryConfig) {
|
|
301
|
+
this.libraryConfig.isTestManagementEnabled = false
|
|
302
|
+
}
|
|
283
303
|
}
|
|
284
304
|
onDone({ err, testManagementTests })
|
|
285
305
|
})
|
|
@@ -346,8 +366,15 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
346
366
|
span.meta = {
|
|
347
367
|
...span.meta,
|
|
348
368
|
...testSuiteTags,
|
|
369
|
+
...getSessionRequestErrorTags(this.testSessionSpan),
|
|
349
370
|
}
|
|
350
371
|
}
|
|
372
|
+
|
|
373
|
+
// Jest and Vitest worker test spans are serialized in the worker and may not include
|
|
374
|
+
// request error tags; add them from the session span in the main process.
|
|
375
|
+
if ((span.name === 'jest.test' || span.name === 'vitest.test') && this.testSessionSpan) {
|
|
376
|
+
Object.assign(span.meta, getSessionRequestErrorTags(this.testSessionSpan))
|
|
377
|
+
}
|
|
351
378
|
}
|
|
352
379
|
this.tracer._exporter.export(trace)
|
|
353
380
|
}
|
|
@@ -418,6 +445,30 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
418
445
|
}
|
|
419
446
|
}
|
|
420
447
|
|
|
448
|
+
/**
|
|
449
|
+
* Adds a hidden _dd tag to the test session span when a test-optimization request fails.
|
|
450
|
+
* If the session span does not exist yet (e.g. library-configuration failed before session:start),
|
|
451
|
+
* the tag is queued and applied when the span is created.
|
|
452
|
+
* @param {string} tag - Tag name (e.g. DD_CI_LIBRARY_CONFIGURATION_ERROR)
|
|
453
|
+
* @param {Error} err - Request error
|
|
454
|
+
*/
|
|
455
|
+
_addRequestErrorTag (tag, err) {
|
|
456
|
+
const value = 'true'
|
|
457
|
+
if (this.testSessionSpan) {
|
|
458
|
+
this.testSessionSpan.setTag(tag, value)
|
|
459
|
+
} else {
|
|
460
|
+
this._pendingRequestErrorTags.push({ tag, value })
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Returns request error tags from the test session span for propagation to module, suite and test spans.
|
|
466
|
+
* @returns {Record<string, string>}
|
|
467
|
+
*/
|
|
468
|
+
getSessionRequestErrorTags () {
|
|
469
|
+
return getSessionRequestErrorTags(this.testSessionSpan)
|
|
470
|
+
}
|
|
471
|
+
|
|
421
472
|
configure (config, shouldGetEnvironmentData = true) {
|
|
422
473
|
super.configure(config)
|
|
423
474
|
|
|
@@ -529,6 +580,7 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
529
580
|
[TEST_SESSION_ID]: testSuiteSpan.context().toTraceId(),
|
|
530
581
|
[TEST_COMMAND]: testSuiteSpan.context()._tags[TEST_COMMAND],
|
|
531
582
|
[TEST_MODULE]: this.constructor.id,
|
|
583
|
+
...getSessionRequestErrorTags(this.testSessionSpan),
|
|
532
584
|
}
|
|
533
585
|
if (testSuiteSpan.context()._parentId) {
|
|
534
586
|
suiteTags[TEST_MODULE_ID] = testSuiteSpan.context()._parentId.toString(10)
|
|
@@ -1,88 +1,94 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { PEER_SERVICE_KEY, PEER_SERVICE_SOURCE_KEY } = require('../constants')
|
|
4
|
+
const propagationHash = require('../propagation-hash')
|
|
4
5
|
const StoragePlugin = require('./storage')
|
|
5
6
|
|
|
6
7
|
class DatabasePlugin extends StoragePlugin {
|
|
7
8
|
static operation = 'query'
|
|
8
9
|
static peerServicePrecursors = ['db.name']
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
encodingServiceTags (serviceTag, encodeATag, spanConfig) {
|
|
25
|
-
if (serviceTag !== spanConfig) {
|
|
26
|
-
this.serviceTags[serviceTag] = spanConfig
|
|
27
|
-
this.serviceTags[encodeATag] = encodeURIComponent(spanConfig)
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
createDBMPropagationCommentService (serviceName, span) {
|
|
32
|
-
this.encodingServiceTags('dddbs', 'encodedDddbs', serviceName)
|
|
33
|
-
this.encodingServiceTags('dde', 'encodedDde', this.tracer._env)
|
|
34
|
-
this.encodingServiceTags('ddps', 'encodedDdps', this.tracer._service)
|
|
35
|
-
this.encodingServiceTags('ddpv', 'encodedDdpv', this.tracer._version)
|
|
36
|
-
if (span.context()._tags['out.host']) {
|
|
37
|
-
this.encodingServiceTags('ddh', 'encodedDdh', span._spanContext._tags['out.host'])
|
|
38
|
-
}
|
|
39
|
-
if (span.context()._tags['db.name']) {
|
|
40
|
-
this.encodingServiceTags('dddb', 'encodedDddb', span._spanContext._tags['db.name'])
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const { encodedDddb, encodedDddbs, encodedDde, encodedDdh, encodedDdps, encodedDdpv } = this.serviceTags
|
|
11
|
+
/**
|
|
12
|
+
* @param {string} serviceName
|
|
13
|
+
* @param {import('../../../..').Span} span
|
|
14
|
+
* @param {object} peerData
|
|
15
|
+
* @returns {string}
|
|
16
|
+
*/
|
|
17
|
+
#createDBMPropagationCommentService (serviceName, span, peerData) {
|
|
18
|
+
const spanTags = span.context()._tags
|
|
19
|
+
const encodedDddb = encode(spanTags['db.name'])
|
|
20
|
+
const encodedDddbs = encode(serviceName)
|
|
21
|
+
const encodedDde = encode(this.tracer._env)
|
|
22
|
+
const encodedDdh = encode(spanTags['out.host'])
|
|
23
|
+
const encodedDdps = this.tracer._service ?? ''
|
|
24
|
+
const encodedDdpv = this.tracer._version
|
|
44
25
|
|
|
45
26
|
let dbmComment = `dddb='${encodedDddb}',dddbs='${encodedDddbs}',dde='${encodedDde}',ddh='${encodedDdh}',` +
|
|
46
27
|
`ddps='${encodedDdps}',ddpv='${encodedDdpv}'`
|
|
47
28
|
|
|
48
|
-
const peerData = this.getPeerService(span.context()._tags)
|
|
49
29
|
if (peerData !== undefined && peerData[PEER_SERVICE_SOURCE_KEY] === PEER_SERVICE_KEY) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const { encodedDdprs } = this.serviceTags
|
|
53
|
-
dbmComment += `,ddprs='${encodedDdprs}'`
|
|
30
|
+
dbmComment += `,ddprs='${encode(peerData[PEER_SERVICE_KEY])}'`
|
|
54
31
|
}
|
|
55
32
|
return dbmComment
|
|
56
33
|
}
|
|
57
34
|
|
|
58
|
-
|
|
35
|
+
/**
|
|
36
|
+
* @param {string} tracerService
|
|
37
|
+
* @param {object} peerData
|
|
38
|
+
* @returns {string}
|
|
39
|
+
*/
|
|
40
|
+
#getDbmServiceName (tracerService, peerData) {
|
|
59
41
|
if (this._tracerConfig.spanComputePeerService) {
|
|
60
|
-
const peerData = this.getPeerService(span.context()._tags)
|
|
61
42
|
return this.getPeerServiceRemap(peerData)[PEER_SERVICE_KEY] || tracerService
|
|
62
43
|
}
|
|
63
44
|
return tracerService
|
|
64
45
|
}
|
|
65
46
|
|
|
47
|
+
/**
|
|
48
|
+
* @param {import('../../../..').Span} span
|
|
49
|
+
* @param {string} serviceName
|
|
50
|
+
* @param {boolean} disableFullMode
|
|
51
|
+
*/
|
|
66
52
|
createDbmComment (span, serviceName, disableFullMode = false) {
|
|
67
53
|
const mode = this.config.dbmPropagationMode
|
|
68
|
-
const dbmService = this.getDbmServiceName(span, serviceName)
|
|
69
54
|
|
|
70
55
|
if (mode === 'disabled') {
|
|
71
56
|
return null
|
|
72
57
|
}
|
|
73
58
|
|
|
74
|
-
const
|
|
59
|
+
const peerData = this.getPeerService(span.context()._tags)
|
|
60
|
+
const dbmService = this.#getDbmServiceName(serviceName, peerData)
|
|
61
|
+
const servicePropagation = this.#createDBMPropagationCommentService(dbmService, span, peerData)
|
|
62
|
+
|
|
63
|
+
let dbmComment = servicePropagation
|
|
64
|
+
|
|
65
|
+
// Add propagation hash if both process tags and SQL base hash injection are enabled
|
|
66
|
+
if (propagationHash.isEnabled() && this.config['dbm.injectSqlBaseHash']) {
|
|
67
|
+
const hashBase64 = propagationHash.getHashBase64()
|
|
68
|
+
if (hashBase64) {
|
|
69
|
+
dbmComment += `,ddsh='${hashBase64}'`
|
|
70
|
+
// Add hash to span meta as a tag
|
|
71
|
+
span.setTag('_dd.dbm.propagation_hash', hashBase64)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
75
74
|
|
|
76
75
|
if (disableFullMode || mode === 'service') {
|
|
77
|
-
return
|
|
76
|
+
return dbmComment
|
|
78
77
|
} else if (mode === 'full') {
|
|
79
78
|
span.setTag('_dd.dbm_trace_injected', 'true')
|
|
80
79
|
span._processor.sample(span)
|
|
81
80
|
const traceparent = span._spanContext.toTraceparent()
|
|
82
|
-
return `${
|
|
81
|
+
return `${dbmComment},traceparent='${traceparent}'`
|
|
83
82
|
}
|
|
84
83
|
}
|
|
85
84
|
|
|
85
|
+
/**
|
|
86
|
+
* @param {import('../../../..').Span} span
|
|
87
|
+
* @param {string} query
|
|
88
|
+
* @param {string} serviceName
|
|
89
|
+
* @param {boolean} disableFullMode
|
|
90
|
+
* @returns {string}
|
|
91
|
+
*/
|
|
86
92
|
injectDbmQuery (span, query, serviceName, disableFullMode = false) {
|
|
87
93
|
const dbmTraceComment = this.createDbmComment(span, serviceName, disableFullMode)
|
|
88
94
|
|
|
@@ -95,6 +101,10 @@ class DatabasePlugin extends StoragePlugin {
|
|
|
95
101
|
: `/*${dbmTraceComment}*/ ${query}`
|
|
96
102
|
}
|
|
97
103
|
|
|
104
|
+
/**
|
|
105
|
+
* @param {string} query
|
|
106
|
+
* @returns {string}
|
|
107
|
+
*/
|
|
98
108
|
maybeTruncate (query) {
|
|
99
109
|
const maxLength = typeof this.config.truncate === 'number'
|
|
100
110
|
? this.config.truncate
|
|
@@ -108,4 +118,6 @@ class DatabasePlugin extends StoragePlugin {
|
|
|
108
118
|
}
|
|
109
119
|
}
|
|
110
120
|
|
|
121
|
+
const encode = value => value ? encodeURIComponent(value) : ''
|
|
122
|
+
|
|
111
123
|
module.exports = DatabasePlugin
|
|
@@ -18,6 +18,10 @@ const COMMON_PEER_SVC_SOURCE_TAGS = [
|
|
|
18
18
|
|
|
19
19
|
// TODO: Exit span on finish when AsyncResource instances are removed.
|
|
20
20
|
class OutboundPlugin extends TracingPlugin {
|
|
21
|
+
/**
|
|
22
|
+
*
|
|
23
|
+
* @type {string[]}
|
|
24
|
+
*/
|
|
21
25
|
static peerServicePrecursors = []
|
|
22
26
|
|
|
23
27
|
constructor (...args) {
|
|
@@ -28,12 +32,15 @@ class OutboundPlugin extends TracingPlugin {
|
|
|
28
32
|
})
|
|
29
33
|
}
|
|
30
34
|
|
|
35
|
+
/**
|
|
36
|
+
* @param {{ parentStore?: { span: import('../../../..').Span } }} ctx
|
|
37
|
+
*/
|
|
31
38
|
bindFinish (ctx) {
|
|
32
39
|
return ctx.parentStore
|
|
33
40
|
}
|
|
34
41
|
|
|
35
|
-
startSpan (
|
|
36
|
-
const span = super.startSpan(
|
|
42
|
+
startSpan (name, options, enterOrCtx) {
|
|
43
|
+
const span = super.startSpan(name, options, enterOrCtx)
|
|
37
44
|
if (
|
|
38
45
|
this._tracerConfig.codeOriginForSpans.enabled &&
|
|
39
46
|
this._tracerConfig.codeOriginForSpans.experimental.exit_spans.enabled
|
|
@@ -43,6 +50,9 @@ class OutboundPlugin extends TracingPlugin {
|
|
|
43
50
|
return span
|
|
44
51
|
}
|
|
45
52
|
|
|
53
|
+
/**
|
|
54
|
+
* @param {Record<string, string>} tags
|
|
55
|
+
*/
|
|
46
56
|
getPeerService (tags) {
|
|
47
57
|
/**
|
|
48
58
|
* Compute `peer.service` and associated metadata from available tags, based
|
|
@@ -75,6 +85,9 @@ class OutboundPlugin extends TracingPlugin {
|
|
|
75
85
|
}
|
|
76
86
|
}
|
|
77
87
|
|
|
88
|
+
/**
|
|
89
|
+
* @param {Record<string, string>} peerData
|
|
90
|
+
*/
|
|
78
91
|
getPeerServiceRemap (peerData) {
|
|
79
92
|
/**
|
|
80
93
|
* If DD_TRACE_PEER_SERVICE_MAPPING is matched, we need to override the existing
|
|
@@ -92,6 +105,9 @@ class OutboundPlugin extends TracingPlugin {
|
|
|
92
105
|
return peerData
|
|
93
106
|
}
|
|
94
107
|
|
|
108
|
+
/**
|
|
109
|
+
* @param {{ currentStore?: { span: import('../../../..').Span } }} ctx
|
|
110
|
+
*/
|
|
95
111
|
finish (ctx) {
|
|
96
112
|
const span = ctx?.currentStore?.span || this.activeSpan
|
|
97
113
|
this.tagPeerService(span)
|
|
@@ -104,6 +120,9 @@ class OutboundPlugin extends TracingPlugin {
|
|
|
104
120
|
super.finish(...arguments)
|
|
105
121
|
}
|
|
106
122
|
|
|
123
|
+
/**
|
|
124
|
+
* @param {import('../../../..').Span} span
|
|
125
|
+
*/
|
|
107
126
|
tagPeerService (span) {
|
|
108
127
|
if (this._tracerConfig.spanComputePeerService) {
|
|
109
128
|
const peerData = this.getPeerService(span.context()._tags)
|
|
@@ -113,10 +132,16 @@ class OutboundPlugin extends TracingPlugin {
|
|
|
113
132
|
}
|
|
114
133
|
}
|
|
115
134
|
|
|
135
|
+
/**
|
|
136
|
+
* @param {object} ctx
|
|
137
|
+
*/
|
|
116
138
|
connect (ctx) {
|
|
117
139
|
this.addHost(ctx)
|
|
118
140
|
}
|
|
119
141
|
|
|
142
|
+
/**
|
|
143
|
+
* @param {{ hostname: string, port: number, currentStore?: { span: import('../../../..').Span } }} ctx
|
|
144
|
+
*/
|
|
120
145
|
addHost (ctx) {
|
|
121
146
|
const { hostname, port } = ctx
|
|
122
147
|
|
|
@@ -16,11 +16,18 @@ class TracingPlugin extends Plugin {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
get activeSpan () {
|
|
19
|
-
const store = storage('legacy').getStore()
|
|
19
|
+
const store = /** @type {{ span?: import('../../../..').Span }} */ (storage('legacy').getStore())
|
|
20
20
|
|
|
21
|
-
return store
|
|
21
|
+
return store?.span
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* @param {object} opts
|
|
26
|
+
* @param {string} [opts.type]
|
|
27
|
+
* @param {string} [opts.id]
|
|
28
|
+
* @param {string} [opts.kind]
|
|
29
|
+
* @returns {string}
|
|
30
|
+
*/
|
|
24
31
|
serviceName (opts = {}) {
|
|
25
32
|
const {
|
|
26
33
|
type = this.constructor.type,
|
|
@@ -31,6 +38,13 @@ class TracingPlugin extends Plugin {
|
|
|
31
38
|
return this._tracer._nomenclature.serviceName(type, kind, id, opts)
|
|
32
39
|
}
|
|
33
40
|
|
|
41
|
+
/**
|
|
42
|
+
* @param {object} opts
|
|
43
|
+
* @param {string} [opts.type]
|
|
44
|
+
* @param {string} [opts.id]
|
|
45
|
+
* @param {string} [opts.kind]
|
|
46
|
+
* @returns {string}
|
|
47
|
+
*/
|
|
34
48
|
operationName (opts = {}) {
|
|
35
49
|
const {
|
|
36
50
|
type = this.constructor.type,
|
|
@@ -41,6 +55,10 @@ class TracingPlugin extends Plugin {
|
|
|
41
55
|
return this._tracer._nomenclature.opName(type, kind, id, opts)
|
|
42
56
|
}
|
|
43
57
|
|
|
58
|
+
/**
|
|
59
|
+
* @param {object} config
|
|
60
|
+
* @returns {object}
|
|
61
|
+
*/
|
|
44
62
|
configure (config) {
|
|
45
63
|
return super.configure({
|
|
46
64
|
...config,
|
|
@@ -53,11 +71,17 @@ class TracingPlugin extends Plugin {
|
|
|
53
71
|
|
|
54
72
|
start () {} // implemented by individual plugins
|
|
55
73
|
|
|
74
|
+
/**
|
|
75
|
+
* @param {{ currentStore?: { span: import('../../../..').Span } }} ctx
|
|
76
|
+
*/
|
|
56
77
|
finish (ctx) {
|
|
57
78
|
const span = ctx?.currentStore?.span || this.activeSpan
|
|
58
79
|
span?.finish()
|
|
59
80
|
}
|
|
60
81
|
|
|
82
|
+
/**
|
|
83
|
+
* @param {{ currentStore?: { span: import('../../../..').Span }, error?: unknown }} ctxOrError
|
|
84
|
+
*/
|
|
61
85
|
error (ctxOrError) {
|
|
62
86
|
if (ctxOrError?.currentStore) {
|
|
63
87
|
ctxOrError.currentStore?.span.setTag('error', ctxOrError?.error)
|
|
@@ -84,21 +108,32 @@ class TracingPlugin extends Plugin {
|
|
|
84
108
|
}
|
|
85
109
|
}
|
|
86
110
|
|
|
111
|
+
/**
|
|
112
|
+
* @param {string} eventName
|
|
113
|
+
* @param {Function} handler
|
|
114
|
+
*/
|
|
87
115
|
addTraceSub (eventName, handler) {
|
|
88
116
|
const prefix = this.constructor.prefix || `apm:${this.component}:${this.operation}`
|
|
89
117
|
this.addSub(`${prefix}:${eventName}`, handler)
|
|
90
118
|
}
|
|
91
119
|
|
|
120
|
+
/**
|
|
121
|
+
* @param {string} eventName
|
|
122
|
+
* @param {Function} transform
|
|
123
|
+
*/
|
|
92
124
|
addTraceBind (eventName, transform) {
|
|
93
125
|
const prefix = this.constructor.prefix || `apm:${this.component}:${this.operation}`
|
|
94
126
|
this.addBind(`${prefix}:${eventName}`, transform)
|
|
95
127
|
}
|
|
96
128
|
|
|
129
|
+
/**
|
|
130
|
+
* @param {unknown} error
|
|
131
|
+
* @param {import('../../../..').Span} [span]
|
|
132
|
+
*/
|
|
97
133
|
addError (error, span = this.activeSpan) {
|
|
98
134
|
if (span && !span._spanContext._tags.error) {
|
|
99
135
|
// Errors may be wrapped in a context.
|
|
100
|
-
error
|
|
101
|
-
span.setTag('error', error || 1)
|
|
136
|
+
span.setTag('error', error?.error || error || 1)
|
|
102
137
|
}
|
|
103
138
|
}
|
|
104
139
|
|