dd-trace 5.71.0 → 5.73.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 +7 -0
- package/index.d.ts +114 -1
- package/package.json +25 -4
- package/packages/datadog-esbuild/index.js +8 -0
- package/packages/datadog-instrumentations/src/azure-event-hubs.js +37 -0
- package/packages/datadog-instrumentations/src/azure-functions.js +3 -0
- package/packages/datadog-instrumentations/src/azure-service-bus.js +49 -22
- package/packages/datadog-instrumentations/src/cookie-parser.js +2 -0
- package/packages/datadog-instrumentations/src/cucumber.js +7 -7
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/jest.js +85 -47
- package/packages/datadog-instrumentations/src/mocha/main.js +8 -9
- package/packages/datadog-instrumentations/src/mocha/utils.js +4 -5
- package/packages/datadog-instrumentations/src/mocha/worker.js +2 -2
- package/packages/datadog-instrumentations/src/pg.js +1 -1
- package/packages/datadog-instrumentations/src/playwright.js +5 -5
- package/packages/datadog-instrumentations/src/vitest.js +8 -8
- package/packages/datadog-plugin-amqplib/src/consumer.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +73 -27
- package/packages/datadog-plugin-azure-event-hubs/src/index.js +15 -0
- package/packages/datadog-plugin-azure-event-hubs/src/producer.js +82 -0
- package/packages/datadog-plugin-azure-functions/src/index.js +50 -3
- package/packages/datadog-plugin-azure-service-bus/src/index.js +1 -1
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +60 -12
- package/packages/datadog-plugin-cucumber/src/index.js +3 -3
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +9 -9
- package/packages/datadog-plugin-jest/src/index.js +53 -18
- package/packages/datadog-plugin-jest/src/util.js +10 -2
- package/packages/datadog-plugin-mocha/src/index.js +2 -2
- package/packages/datadog-plugin-playwright/src/index.js +2 -2
- package/packages/datadog-plugin-vitest/src/index.js +2 -2
- package/packages/datadog-plugin-ws/src/close.js +1 -1
- package/packages/datadog-plugin-ws/src/producer.js +1 -1
- package/packages/datadog-plugin-ws/src/receiver.js +1 -1
- package/packages/datadog-plugin-ws/src/server.js +5 -3
- package/packages/dd-trace/src/appsec/index.js +9 -1
- package/packages/dd-trace/src/appsec/reporter.js +2 -3
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +5 -0
- package/packages/dd-trace/src/config.js +108 -26
- package/packages/dd-trace/src/config_defaults.js +12 -0
- package/packages/dd-trace/src/git_properties.js +90 -5
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +8 -3
- package/packages/dd-trace/src/llmobs/plugins/base.js +11 -12
- package/packages/dd-trace/src/llmobs/sdk.js +20 -4
- package/packages/dd-trace/src/llmobs/tagger.js +12 -0
- package/packages/dd-trace/src/noop/proxy.js +3 -0
- package/packages/dd-trace/src/openfeature/constants/constants.js +51 -0
- package/packages/dd-trace/src/openfeature/flagging_provider.js +45 -0
- package/packages/dd-trace/src/openfeature/index.js +77 -0
- package/packages/dd-trace/src/openfeature/noop.js +101 -0
- package/packages/dd-trace/src/openfeature/writers/base.js +181 -0
- package/packages/dd-trace/src/openfeature/writers/exposures.js +173 -0
- package/packages/dd-trace/src/openfeature/writers/util.js +43 -0
- package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +100 -0
- package/packages/dd-trace/src/opentelemetry/logs/index.js +87 -0
- package/packages/dd-trace/src/opentelemetry/logs/logger.js +77 -0
- package/packages/dd-trace/src/opentelemetry/logs/logger_provider.js +126 -0
- package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +53 -0
- package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +252 -0
- package/packages/dd-trace/src/opentelemetry/otlp/common.proto +116 -0
- package/packages/dd-trace/src/opentelemetry/otlp/logs.proto +226 -0
- package/packages/dd-trace/src/opentelemetry/otlp/logs_service.proto +78 -0
- package/packages/dd-trace/src/opentelemetry/otlp/metrics.proto +720 -0
- package/packages/dd-trace/src/opentelemetry/otlp/metrics_service.proto +78 -0
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +177 -0
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +163 -0
- package/packages/dd-trace/src/opentelemetry/otlp/protobuf_loader.js +66 -0
- package/packages/dd-trace/src/opentelemetry/otlp/resource.proto +45 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +7 -6
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/util/test.js +6 -5
- package/packages/dd-trace/src/profiling/config.js +21 -1
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +3 -2
- package/packages/dd-trace/src/profiling/profiler.js +44 -22
- package/packages/dd-trace/src/profiling/profilers/events.js +12 -3
- package/packages/dd-trace/src/profiling/profilers/space.js +35 -24
- package/packages/dd-trace/src/profiling/profilers/wall.js +14 -6
- package/packages/dd-trace/src/proxy.js +22 -1
- package/packages/dd-trace/src/remote_config/capabilities.js +1 -0
- package/packages/dd-trace/src/remote_config/index.js +1 -0
- package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +4 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +8 -0
- package/packages/dd-trace/src/supported-configurations.json +18 -0
- package/packages/dd-trace/src/telemetry/telemetry.js +13 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const ProducerPlugin = require('./producer')
|
|
4
|
+
const CompositePlugin = require('../../dd-trace/src/plugins/composite')
|
|
5
|
+
|
|
6
|
+
class AzureEventHubsPlugin extends CompositePlugin {
|
|
7
|
+
static get id () { return 'azure-event-hubs' }
|
|
8
|
+
static get plugins () {
|
|
9
|
+
return {
|
|
10
|
+
producer: ProducerPlugin
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = AzureEventHubsPlugin
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { getEnvironmentVariable } = require('../../dd-trace/src/config-helper')
|
|
4
|
+
const ProducerPlugin = require('../../dd-trace/src/plugins/producer')
|
|
5
|
+
|
|
6
|
+
class AzureEventHubsProducerPlugin extends ProducerPlugin {
|
|
7
|
+
static get id () { return 'azure-event-hubs' }
|
|
8
|
+
static get operation () { return 'send' }
|
|
9
|
+
static get prefix () { return 'tracing:apm:azure-event-hubs:send' }
|
|
10
|
+
|
|
11
|
+
bindStart (ctx) {
|
|
12
|
+
// we do not want to make these spans when batch linking is disabled.
|
|
13
|
+
if (!batchLinksAreEnabled() && ctx.functionName === 'tryAdd') {
|
|
14
|
+
return ctx.currentStore
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const qualifiedNamespace = ctx.config.endpoint.replace('sb://', '').replace('/', '')
|
|
18
|
+
const entityPath = ctx.config.entityPath
|
|
19
|
+
const span = this.startSpan({
|
|
20
|
+
resource: entityPath,
|
|
21
|
+
type: 'messaging',
|
|
22
|
+
meta: {
|
|
23
|
+
component: 'azure-event-hubs',
|
|
24
|
+
'messaging.system': 'eventhubs',
|
|
25
|
+
'messaging.destination.name': entityPath,
|
|
26
|
+
'network.destination.name': qualifiedNamespace,
|
|
27
|
+
}
|
|
28
|
+
}, ctx)
|
|
29
|
+
|
|
30
|
+
if (ctx.functionName === 'tryAdd') {
|
|
31
|
+
span._spanContext._name = 'azure.eventhubs.create'
|
|
32
|
+
span.setTag('messaging.operation', 'create')
|
|
33
|
+
|
|
34
|
+
if (ctx.eventData.messageID !== undefined) {
|
|
35
|
+
span.setTag('message.id', ctx.eventData.messageID)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (batchLinksAreEnabled()) {
|
|
39
|
+
ctx.batch._spanContexts.push(span.context())
|
|
40
|
+
injectTraceContext(this.tracer, span, ctx.eventData)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (ctx.functionName === 'sendBatch') {
|
|
45
|
+
const eventData = ctx.eventData
|
|
46
|
+
const eventDataLength = eventData.length || eventData._context.connection._eventsCount
|
|
47
|
+
span.setTag('messaging.operation', 'send')
|
|
48
|
+
span.setTag('messaging.batch.message_count', eventDataLength)
|
|
49
|
+
|
|
50
|
+
if (eventData.constructor.name !== 'EventDataBatchImpl' && Array.isArray(eventData)) {
|
|
51
|
+
eventData.forEach(event => {
|
|
52
|
+
injectTraceContext(this.tracer, span, event)
|
|
53
|
+
})
|
|
54
|
+
} else {
|
|
55
|
+
if (batchLinksAreEnabled()) {
|
|
56
|
+
eventData._spanContexts.forEach(spanContext => {
|
|
57
|
+
span.addLink(spanContext)
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return ctx.currentStore
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
asyncEnd (ctx) {
|
|
66
|
+
super.finish()
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function injectTraceContext (tracer, span, event) {
|
|
71
|
+
if (!event.properties) {
|
|
72
|
+
event.properties = {}
|
|
73
|
+
}
|
|
74
|
+
tracer.inject(span, 'text_map', event.properties)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function batchLinksAreEnabled () {
|
|
78
|
+
const eh = getEnvironmentVariable('DD_TRACE_AZURE_EVENTHUBS_BATCH_LINKS_ENABLED')
|
|
79
|
+
return eh !== 'false'
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module.exports = AzureEventHubsProducerPlugin
|
|
@@ -13,6 +13,7 @@ const triggerMap = {
|
|
|
13
13
|
put: 'Http',
|
|
14
14
|
serviceBusQueue: 'ServiceBus',
|
|
15
15
|
serviceBusTopic: 'ServiceBus',
|
|
16
|
+
eventHub: 'EventHubs',
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
class AzureFunctionsPlugin extends TracingPlugin {
|
|
@@ -23,8 +24,10 @@ class AzureFunctionsPlugin extends TracingPlugin {
|
|
|
23
24
|
static prefix = 'tracing:datadog:azure:functions:invoke'
|
|
24
25
|
|
|
25
26
|
bindStart (ctx) {
|
|
26
|
-
const childOf = extractTraceContext(this._tracer, ctx)
|
|
27
27
|
const meta = getMetaForTrigger(ctx)
|
|
28
|
+
const triggerType = triggerMap[ctx.methodName]
|
|
29
|
+
const isMessagingService = (triggerType === 'ServiceBus' || triggerType === 'EventHubs')
|
|
30
|
+
const childOf = isMessagingService ? null : extractTraceContext(this._tracer, ctx)
|
|
28
31
|
const span = this.startSpan(this.operationName(), {
|
|
29
32
|
childOf,
|
|
30
33
|
service: this.serviceName(),
|
|
@@ -32,6 +35,10 @@ class AzureFunctionsPlugin extends TracingPlugin {
|
|
|
32
35
|
meta,
|
|
33
36
|
}, ctx)
|
|
34
37
|
|
|
38
|
+
if (isMessagingService) {
|
|
39
|
+
setSpanLinks(triggerType, this.tracer, span, ctx)
|
|
40
|
+
}
|
|
41
|
+
|
|
35
42
|
ctx.span = span
|
|
36
43
|
return ctx.currentStore
|
|
37
44
|
}
|
|
@@ -86,6 +93,16 @@ function getMetaForTrigger ({ functionName, methodName, invocationContext }) {
|
|
|
86
93
|
'resource.name': `ServiceBus ${functionName}`,
|
|
87
94
|
'span.kind': 'consumer'
|
|
88
95
|
}
|
|
96
|
+
} else if (triggerMap[methodName] === 'EventHubs') {
|
|
97
|
+
const partitionContext = invocationContext.triggerMetadata.triggerPartitionContext
|
|
98
|
+
meta = {
|
|
99
|
+
...meta,
|
|
100
|
+
'messaging.destination.name': partitionContext.eventHubName,
|
|
101
|
+
'messaging.operation': 'receive',
|
|
102
|
+
'messaging.system': 'eventhubs',
|
|
103
|
+
'resource.name': `EventHubs ${functionName}`,
|
|
104
|
+
'span.kind': 'consumer'
|
|
105
|
+
}
|
|
89
106
|
}
|
|
90
107
|
|
|
91
108
|
return meta
|
|
@@ -99,8 +116,38 @@ function extractTraceContext (tracer, ctx) {
|
|
|
99
116
|
switch (String(triggerMap[ctx.methodName])) {
|
|
100
117
|
case 'Http':
|
|
101
118
|
return tracer.extract('http_headers', Object.fromEntries(ctx.httpRequest.headers))
|
|
102
|
-
|
|
103
|
-
|
|
119
|
+
default:
|
|
120
|
+
null
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// message & messages & batch with cardinality of 1 == applicationProperties
|
|
125
|
+
// messages with cardinality of many == applicationPropertiesArray
|
|
126
|
+
function setSpanLinks (triggerType, tracer, span, ctx) {
|
|
127
|
+
const cardinality = ctx.invocationContext.options.trigger.cardinality
|
|
128
|
+
const triggerMetadata = ctx.invocationContext.triggerMetadata
|
|
129
|
+
const isServiceBus = triggerType === 'ServiceBus'
|
|
130
|
+
|
|
131
|
+
const properties = isServiceBus
|
|
132
|
+
? triggerMetadata.applicationProperties
|
|
133
|
+
: triggerMetadata.properties
|
|
134
|
+
|
|
135
|
+
const propertiesArray = isServiceBus
|
|
136
|
+
? triggerMetadata.applicationPropertiesArray
|
|
137
|
+
: triggerMetadata.propertiesArray
|
|
138
|
+
|
|
139
|
+
const addLinkFromProperties = (props) => {
|
|
140
|
+
if (!props || Object.keys(props).length === 0) return
|
|
141
|
+
const spanContext = tracer.extract('text_map', props)
|
|
142
|
+
if (spanContext) {
|
|
143
|
+
span.addLink(spanContext)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (cardinality === 'many' && propertiesArray?.length > 0) {
|
|
148
|
+
propertiesArray.forEach(addLinkFromProperties)
|
|
149
|
+
} else if (cardinality === 'one') {
|
|
150
|
+
addLinkFromProperties(properties)
|
|
104
151
|
}
|
|
105
152
|
}
|
|
106
153
|
|
|
@@ -4,7 +4,7 @@ const ProducerPlugin = require('./producer')
|
|
|
4
4
|
const CompositePlugin = require('../../dd-trace/src/plugins/composite')
|
|
5
5
|
|
|
6
6
|
class AzureServiceBusPlugin extends CompositePlugin {
|
|
7
|
-
static id
|
|
7
|
+
static get id () { return 'azure-service-bus' }
|
|
8
8
|
static get plugins () {
|
|
9
9
|
return {
|
|
10
10
|
producer: ProducerPlugin
|
|
@@ -1,36 +1,84 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { getEnvironmentVariable } = require('../../dd-trace/src/config-helper')
|
|
3
4
|
const ProducerPlugin = require('../../dd-trace/src/plugins/producer')
|
|
4
5
|
|
|
5
6
|
class AzureServiceBusProducerPlugin extends ProducerPlugin {
|
|
6
|
-
static id
|
|
7
|
-
static operation
|
|
7
|
+
static get id () { return 'azure-service-bus' }
|
|
8
|
+
static get operation () { return 'send' }
|
|
9
|
+
static get prefix () { return 'tracing:apm:azure-service-bus:send' }
|
|
8
10
|
|
|
9
11
|
bindStart (ctx) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
// we do not want to make these spans when batch linking is disabled.
|
|
13
|
+
if (!batchLinksAreEnabled() && ctx.functionName === 'tryAddMessage') {
|
|
14
|
+
return ctx.currentStore
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const qualifiedSenderNamespace = ctx.config.host
|
|
12
18
|
const span = this.startSpan({
|
|
13
|
-
resource:
|
|
19
|
+
resource: ctx.entityPath,
|
|
14
20
|
type: 'messaging',
|
|
15
21
|
meta: {
|
|
16
22
|
component: 'azure-service-bus',
|
|
17
|
-
'messaging.destination.name':
|
|
23
|
+
'messaging.destination.name': ctx.entityPath,
|
|
18
24
|
'messaging.operation': 'send',
|
|
19
25
|
'messaging.system': 'servicebus',
|
|
20
26
|
'network.destination.name': qualifiedSenderNamespace,
|
|
21
27
|
}
|
|
22
28
|
}, ctx)
|
|
23
29
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
msg.applicationProperties = {}
|
|
28
|
-
}
|
|
30
|
+
if (ctx.functionName === 'tryAddMessage') {
|
|
31
|
+
span._spanContext._name = 'azure.servicebus.create'
|
|
32
|
+
span.setTag('messaging.operation', 'create')
|
|
29
33
|
|
|
30
|
-
|
|
34
|
+
if (ctx.msg.messageID !== undefined) {
|
|
35
|
+
span.setTag('message.id', ctx.msg)
|
|
36
|
+
}
|
|
31
37
|
|
|
38
|
+
if (batchLinksAreEnabled()) {
|
|
39
|
+
ctx.batch._spanContexts.push(span.context())
|
|
40
|
+
injectTraceContext(this.tracer, span, ctx.msg)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (ctx.functionName === 'send' || ctx.functionName === 'sendBatch' || ctx.functionName === 'scheduleMessages') {
|
|
45
|
+
const messages = ctx.msg
|
|
46
|
+
const isBatch = messages.constructor?.name === 'ServiceBusMessageBatchImpl'
|
|
47
|
+
if (isBatch) {
|
|
48
|
+
span.setTag('messaging.batch.message_count', messages.count)
|
|
49
|
+
if (batchLinksAreEnabled()) {
|
|
50
|
+
messages._spanContexts.forEach(spanContext => {
|
|
51
|
+
span.addLink(spanContext)
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
} else if (Array.isArray(messages)) {
|
|
55
|
+
span.setTag('messaging.batch.message_count', messages.length)
|
|
56
|
+
messages.forEach(event => {
|
|
57
|
+
injectTraceContext(this.tracer, span, event)
|
|
58
|
+
})
|
|
59
|
+
} else {
|
|
60
|
+
injectTraceContext(this.tracer, span, messages)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
32
63
|
return ctx.currentStore
|
|
33
64
|
}
|
|
65
|
+
|
|
66
|
+
asyncEnd (ctx) {
|
|
67
|
+
super.finish()
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function injectTraceContext (tracer, span, msg) {
|
|
72
|
+
if (!msg.applicationProperties) {
|
|
73
|
+
msg.applicationProperties = {}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
tracer.inject(span, 'text_map', msg.applicationProperties)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function batchLinksAreEnabled () {
|
|
80
|
+
const sb = getEnvironmentVariable('DD_TRACE_AZURE_SERVICEBUS_BATCH_LINKS_ENABLED')
|
|
81
|
+
return sb !== 'false'
|
|
34
82
|
}
|
|
35
83
|
|
|
36
84
|
module.exports = AzureServiceBusProducerPlugin
|
|
@@ -407,7 +407,7 @@ class CucumberPlugin extends CiPlugin {
|
|
|
407
407
|
this.addSub('ci:cucumber:is-modified-test', ({
|
|
408
408
|
scenarios,
|
|
409
409
|
testFileAbsolutePath,
|
|
410
|
-
|
|
410
|
+
modifiedFiles,
|
|
411
411
|
stepIds,
|
|
412
412
|
stepDefinitions,
|
|
413
413
|
setIsModified
|
|
@@ -418,7 +418,7 @@ class CucumberPlugin extends CiPlugin {
|
|
|
418
418
|
testScenarioPath,
|
|
419
419
|
scenario.location.line,
|
|
420
420
|
scenario.steps[scenario.steps.length - 1].location.line,
|
|
421
|
-
|
|
421
|
+
modifiedFiles,
|
|
422
422
|
'cucumber'
|
|
423
423
|
)
|
|
424
424
|
if (isModified) {
|
|
@@ -436,7 +436,7 @@ class CucumberPlugin extends CiPlugin {
|
|
|
436
436
|
stepDefinition.uri,
|
|
437
437
|
testStartLineStep,
|
|
438
438
|
testEndLineStep,
|
|
439
|
-
|
|
439
|
+
modifiedFiles,
|
|
440
440
|
'cucumber'
|
|
441
441
|
)
|
|
442
442
|
if (isModified) {
|
|
@@ -45,7 +45,7 @@ const {
|
|
|
45
45
|
getLibraryCapabilitiesTags,
|
|
46
46
|
TEST_RETRY_REASON_TYPES,
|
|
47
47
|
getPullRequestDiff,
|
|
48
|
-
|
|
48
|
+
getModifiedFilesFromDiff,
|
|
49
49
|
TEST_IS_MODIFIED,
|
|
50
50
|
getPullRequestBaseBranch
|
|
51
51
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
@@ -188,7 +188,7 @@ function getTestManagementTests (tracer, testConfiguration) {
|
|
|
188
188
|
})
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
-
function
|
|
191
|
+
function getModifiedFiles (testEnvironmentMetadata) {
|
|
192
192
|
const {
|
|
193
193
|
[GIT_PULL_REQUEST_BASE_BRANCH]: pullRequestBaseBranch,
|
|
194
194
|
[GIT_PULL_REQUEST_BASE_BRANCH_SHA]: pullRequestBaseBranchSha,
|
|
@@ -199,9 +199,9 @@ function getModifiedTests (testEnvironmentMetadata) {
|
|
|
199
199
|
|
|
200
200
|
if (baseBranchSha) {
|
|
201
201
|
const diff = getPullRequestDiff(baseBranchSha, commitHeadSha)
|
|
202
|
-
const
|
|
203
|
-
if (
|
|
204
|
-
return
|
|
202
|
+
const modifiedFiles = getModifiedFilesFromDiff(diff)
|
|
203
|
+
if (modifiedFiles) {
|
|
204
|
+
return modifiedFiles
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
207
|
|
|
@@ -245,7 +245,7 @@ class CypressPlugin {
|
|
|
245
245
|
isTestManagementTestsEnabled = false
|
|
246
246
|
testManagementAttemptToFixRetries = 0
|
|
247
247
|
isImpactedTestsEnabled = false
|
|
248
|
-
|
|
248
|
+
modifiedFiles = []
|
|
249
249
|
|
|
250
250
|
constructor () {
|
|
251
251
|
const {
|
|
@@ -339,10 +339,10 @@ class CypressPlugin {
|
|
|
339
339
|
|
|
340
340
|
getIsTestModified (testSuiteAbsolutePath) {
|
|
341
341
|
const relativeTestSuitePath = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
|
|
342
|
-
if (!this.
|
|
342
|
+
if (!this.modifiedFiles) {
|
|
343
343
|
return false
|
|
344
344
|
}
|
|
345
|
-
const lines = this.
|
|
345
|
+
const lines = this.modifiedFiles[relativeTestSuitePath]
|
|
346
346
|
if (!lines) {
|
|
347
347
|
return false
|
|
348
348
|
}
|
|
@@ -520,7 +520,7 @@ class CypressPlugin {
|
|
|
520
520
|
|
|
521
521
|
if (this.isImpactedTestsEnabled) {
|
|
522
522
|
try {
|
|
523
|
-
this.
|
|
523
|
+
this.modifiedFiles = getModifiedFiles(this.testEnvironmentMetadata)
|
|
524
524
|
} catch (error) {
|
|
525
525
|
log.error(error)
|
|
526
526
|
this.isImpactedTestsEnabled = false
|
|
@@ -50,6 +50,7 @@ const {
|
|
|
50
50
|
TELEMETRY_CODE_COVERAGE_NUM_FILES,
|
|
51
51
|
TELEMETRY_TEST_SESSION
|
|
52
52
|
} = require('../../dd-trace/src/ci-visibility/telemetry')
|
|
53
|
+
const log = require('../../dd-trace/src/log')
|
|
53
54
|
|
|
54
55
|
const isJestWorker = !!getEnvironmentVariable('JEST_WORKER_ID')
|
|
55
56
|
|
|
@@ -102,6 +103,7 @@ class JestPlugin extends CiPlugin {
|
|
|
102
103
|
}
|
|
103
104
|
process.on('message', handler)
|
|
104
105
|
}
|
|
106
|
+
this.testSuiteSpanPerTestSuiteAbsolutePath = new Map()
|
|
105
107
|
|
|
106
108
|
this.addSub('ci:jest:session:finish', ({
|
|
107
109
|
status,
|
|
@@ -196,7 +198,8 @@ class JestPlugin extends CiPlugin {
|
|
|
196
198
|
testSourceFile,
|
|
197
199
|
testEnvironmentOptions,
|
|
198
200
|
frameworkVersion,
|
|
199
|
-
displayName
|
|
201
|
+
displayName,
|
|
202
|
+
testSuiteAbsolutePath
|
|
200
203
|
}) => {
|
|
201
204
|
const {
|
|
202
205
|
_ddTestSessionId: testSessionId,
|
|
@@ -259,6 +262,7 @@ class JestPlugin extends CiPlugin {
|
|
|
259
262
|
if (_ddTestCodeCoverageEnabled) {
|
|
260
263
|
this.telemetry.ciVisEvent(TELEMETRY_CODE_COVERAGE_STARTED, 'suite', { library: 'istanbul' })
|
|
261
264
|
}
|
|
265
|
+
this.testSuiteSpanPerTestSuiteAbsolutePath.set(testSuiteAbsolutePath, this.testSuiteSpan)
|
|
262
266
|
})
|
|
263
267
|
|
|
264
268
|
this.addSub('ci:jest:worker-report:coverage', data => {
|
|
@@ -272,25 +276,54 @@ class JestPlugin extends CiPlugin {
|
|
|
272
276
|
})
|
|
273
277
|
})
|
|
274
278
|
|
|
275
|
-
this.addSub('ci:jest:test-suite:finish', ({ status, errorMessage, error }) => {
|
|
276
|
-
this.
|
|
279
|
+
this.addSub('ci:jest:test-suite:finish', ({ status, errorMessage, error, testSuiteAbsolutePath }) => {
|
|
280
|
+
const testSuiteSpan = this.testSuiteSpanPerTestSuiteAbsolutePath.get(testSuiteAbsolutePath)
|
|
281
|
+
if (!testSuiteSpan) {
|
|
282
|
+
log.warn('"ci:jest:test-suite:finish": no span found for test suite absolute path %s', testSuiteAbsolutePath)
|
|
283
|
+
return
|
|
284
|
+
}
|
|
285
|
+
const hasStatus = testSuiteSpan.context()._tags[TEST_STATUS]
|
|
286
|
+
if (!hasStatus) {
|
|
287
|
+
// The status may have been set in 'ci:jest:test-suite:error'
|
|
288
|
+
testSuiteSpan.setTag(TEST_STATUS, status)
|
|
289
|
+
}
|
|
277
290
|
if (error) {
|
|
278
|
-
|
|
291
|
+
testSuiteSpan.setTag('error', error)
|
|
292
|
+
testSuiteSpan.setTag(TEST_STATUS, 'fail')
|
|
279
293
|
} else if (errorMessage) {
|
|
280
|
-
|
|
294
|
+
testSuiteSpan.setTag('error', new Error(errorMessage))
|
|
295
|
+
testSuiteSpan.setTag(TEST_STATUS, 'fail')
|
|
281
296
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
297
|
+
// We need to give the potential error in 'ci:jest:test-suite:error' time to be published
|
|
298
|
+
process.nextTick(() => {
|
|
299
|
+
testSuiteSpan.finish()
|
|
300
|
+
this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'suite')
|
|
301
|
+
// Suites potentially run in a different process than the session,
|
|
302
|
+
// so calling finishAllTraceSpans on the session span is not enough
|
|
303
|
+
finishAllTraceSpans(testSuiteSpan)
|
|
304
|
+
// Flushing within jest workers is cheap, as it's just interprocess communication
|
|
305
|
+
// We do not want to flush after every suite if jest is running tests serially,
|
|
306
|
+
// as every flush is an HTTP request.
|
|
307
|
+
if (isJestWorker) {
|
|
308
|
+
this.tracer._exporter.flush()
|
|
309
|
+
}
|
|
310
|
+
this.removeAllDiProbes()
|
|
311
|
+
this.testSuiteSpanPerTestSuiteAbsolutePath.delete(testSuiteAbsolutePath)
|
|
312
|
+
})
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
this.addSub('ci:jest:test-suite:error', ({ error, errorMessage, testSuiteAbsolutePath }) => {
|
|
316
|
+
const runningTestSuiteSpan = this.testSuiteSpanPerTestSuiteAbsolutePath.get(testSuiteAbsolutePath)
|
|
317
|
+
if (!runningTestSuiteSpan) {
|
|
318
|
+
log.warn('"ci:jest:test-suite:error": no span found for test suite absolute path %s', testSuiteAbsolutePath)
|
|
319
|
+
return
|
|
320
|
+
}
|
|
321
|
+
if (error) {
|
|
322
|
+
runningTestSuiteSpan.setTag('error', error)
|
|
323
|
+
} else if (errorMessage) {
|
|
324
|
+
runningTestSuiteSpan.setTag('error', new Error(errorMessage))
|
|
292
325
|
}
|
|
293
|
-
|
|
326
|
+
runningTestSuiteSpan.setTag(TEST_STATUS, 'fail')
|
|
294
327
|
})
|
|
295
328
|
|
|
296
329
|
/**
|
|
@@ -420,7 +453,8 @@ class JestPlugin extends CiPlugin {
|
|
|
420
453
|
isJestRetry,
|
|
421
454
|
isDisabled,
|
|
422
455
|
isQuarantined,
|
|
423
|
-
isModified
|
|
456
|
+
isModified,
|
|
457
|
+
testSuiteAbsolutePath
|
|
424
458
|
} = test
|
|
425
459
|
|
|
426
460
|
const extraTags = {
|
|
@@ -468,8 +502,9 @@ class JestPlugin extends CiPlugin {
|
|
|
468
502
|
if (isNew) {
|
|
469
503
|
extraTags[TEST_IS_NEW] = 'true'
|
|
470
504
|
}
|
|
505
|
+
const testSuiteSpan = this.testSuiteSpanPerTestSuiteAbsolutePath.get(testSuiteAbsolutePath) || this.testSuiteSpan
|
|
471
506
|
|
|
472
|
-
return super.startTestSpan(name, suite,
|
|
507
|
+
return super.startTestSpan(name, suite, testSuiteSpan, extraTags)
|
|
473
508
|
}
|
|
474
509
|
}
|
|
475
510
|
|
|
@@ -41,8 +41,11 @@ function getFormattedJestTestParameters (testParameters) {
|
|
|
41
41
|
return formattedParameters
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
// Support for `@fast-check/jest`: this library modifies the test name to include the seed
|
|
45
|
+
// A test name that keeps changing breaks some Test Optimization's features.
|
|
46
|
+
const SEED_SUFFIX_RE = /\s*\(with seed=-?\d+\)\s*$/i
|
|
44
47
|
// https://github.com/facebook/jest/blob/3e38157ad5f23fb7d24669d24fae8ded06a7ab75/packages/jest-circus/src/utils.ts#L396
|
|
45
|
-
function getJestTestName (test) {
|
|
48
|
+
function getJestTestName (test, shouldStripSeed = false) {
|
|
46
49
|
const titles = []
|
|
47
50
|
let parent = test
|
|
48
51
|
do {
|
|
@@ -50,7 +53,12 @@ function getJestTestName (test) {
|
|
|
50
53
|
} while ((parent = parent.parent))
|
|
51
54
|
|
|
52
55
|
titles.shift() // remove TOP_DESCRIBE_BLOCK_NAME
|
|
53
|
-
|
|
56
|
+
|
|
57
|
+
const testName = titles.join(' ')
|
|
58
|
+
if (shouldStripSeed) {
|
|
59
|
+
return testName.replace(SEED_SUFFIX_RE, '')
|
|
60
|
+
}
|
|
61
|
+
return testName
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
function isMarkedAsUnskippable (test) {
|
|
@@ -169,13 +169,13 @@ class MochaPlugin extends CiPlugin {
|
|
|
169
169
|
return ctx.currentStore
|
|
170
170
|
})
|
|
171
171
|
|
|
172
|
-
this.addSub('ci:mocha:test:is-modified', ({
|
|
172
|
+
this.addSub('ci:mocha:test:is-modified', ({ modifiedFiles, file, onDone }) => {
|
|
173
173
|
const testPath = getTestSuitePath(file, this.repositoryRoot)
|
|
174
174
|
const isModified = isModifiedTest(
|
|
175
175
|
testPath,
|
|
176
176
|
null,
|
|
177
177
|
null,
|
|
178
|
-
|
|
178
|
+
modifiedFiles,
|
|
179
179
|
this.constructor.id
|
|
180
180
|
)
|
|
181
181
|
|
|
@@ -60,11 +60,11 @@ class PlaywrightPlugin extends CiPlugin {
|
|
|
60
60
|
|
|
61
61
|
this.addSub('ci:playwright:test:is-modified', ({
|
|
62
62
|
filePath,
|
|
63
|
-
|
|
63
|
+
modifiedFiles,
|
|
64
64
|
onDone
|
|
65
65
|
}) => {
|
|
66
66
|
const testSuite = getTestSuitePath(filePath, this.repositoryRoot)
|
|
67
|
-
const isModified = isModifiedTest(testSuite, 0, 0,
|
|
67
|
+
const isModified = isModifiedTest(testSuite, 0, 0, modifiedFiles, this.constructor.id)
|
|
68
68
|
onDone({ isModified })
|
|
69
69
|
})
|
|
70
70
|
|
|
@@ -90,9 +90,9 @@ class VitestPlugin extends CiPlugin {
|
|
|
90
90
|
onDone(isQuarantined)
|
|
91
91
|
})
|
|
92
92
|
|
|
93
|
-
this.addSub('ci:vitest:test:is-modified', ({
|
|
93
|
+
this.addSub('ci:vitest:test:is-modified', ({ modifiedFiles, testSuiteAbsolutePath, onDone }) => {
|
|
94
94
|
const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
|
|
95
|
-
const isModified = isModifiedTest(testSuite, 0, 0,
|
|
95
|
+
const isModified = isModifiedTest(testSuite, 0, 0, modifiedFiles, this.constructor.id)
|
|
96
96
|
|
|
97
97
|
onDone(isModified)
|
|
98
98
|
})
|
|
@@ -58,7 +58,7 @@ class WSClosePlugin extends TracingPlugin {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
end (ctx) {
|
|
61
|
-
if (!Object.hasOwn(ctx, 'result')) return
|
|
61
|
+
if (!Object.hasOwn(ctx, 'result') || !ctx.span) return
|
|
62
62
|
|
|
63
63
|
if (ctx.socket.spanContext) ctx.span.addLink({ context: ctx.socket.spanContext })
|
|
64
64
|
|
|
@@ -21,8 +21,10 @@ class WSServerPlugin extends TracingPlugin {
|
|
|
21
21
|
|
|
22
22
|
const protocol = `${getRequestProtocol(req)}:`
|
|
23
23
|
const host = options.headers.host
|
|
24
|
-
const
|
|
25
|
-
const
|
|
24
|
+
const url = req.url
|
|
25
|
+
const indexOfParam = url.indexOf('?')
|
|
26
|
+
const route = indexOfParam === -1 ? url : url.slice(0, indexOfParam)
|
|
27
|
+
const uri = `${protocol}//${host}${route}`
|
|
26
28
|
|
|
27
29
|
ctx.args = { options }
|
|
28
30
|
|
|
@@ -34,7 +36,7 @@ class WSServerPlugin extends TracingPlugin {
|
|
|
34
36
|
'http.upgraded': 'websocket',
|
|
35
37
|
'http.method': options.method,
|
|
36
38
|
'http.url': uri,
|
|
37
|
-
'resource.name': `${options.method} ${
|
|
39
|
+
'resource.name': `${options.method} ${route}`,
|
|
38
40
|
'span.kind': 'server'
|
|
39
41
|
|
|
40
42
|
}
|
|
@@ -43,6 +43,7 @@ const { isInServerlessEnvironment } = require('../serverless')
|
|
|
43
43
|
|
|
44
44
|
const responseAnalyzedSet = new WeakSet()
|
|
45
45
|
const storedResponseHeaders = new WeakMap()
|
|
46
|
+
const storedBodies = new WeakMap()
|
|
46
47
|
|
|
47
48
|
let isEnabled = false
|
|
48
49
|
let config
|
|
@@ -114,6 +115,11 @@ function onRequestBodyParsed ({ req, res, body, abortController }) {
|
|
|
114
115
|
const rootSpan = web.root(req)
|
|
115
116
|
if (!rootSpan) return
|
|
116
117
|
|
|
118
|
+
if (!req.body) {
|
|
119
|
+
// do not store body if it is in req.body
|
|
120
|
+
storedBodies.set(req, body)
|
|
121
|
+
}
|
|
122
|
+
|
|
117
123
|
const results = waf.run({
|
|
118
124
|
persistent: {
|
|
119
125
|
[addresses.HTTP_INCOMING_BODY]: body
|
|
@@ -200,11 +206,13 @@ function incomingHttpEndTranslator ({ req, res }) {
|
|
|
200
206
|
|
|
201
207
|
const storedHeaders = storedResponseHeaders.get(req) || {}
|
|
202
208
|
|
|
203
|
-
|
|
209
|
+
const body = req.body || storedBodies.get(req)
|
|
210
|
+
Reporter.finishRequest(req, res, storedHeaders, body)
|
|
204
211
|
|
|
205
212
|
if (storedHeaders) {
|
|
206
213
|
storedResponseHeaders.delete(req)
|
|
207
214
|
}
|
|
215
|
+
storedBodies.delete(req)
|
|
208
216
|
}
|
|
209
217
|
|
|
210
218
|
function onPassportVerify ({ framework, login, user, success, abortController }) {
|