dd-trace 5.43.0 → 5.44.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/package.json +4 -4
- package/packages/datadog-instrumentations/src/cucumber.js +61 -23
- package/packages/datadog-instrumentations/src/dd-trace-api.js +7 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/jest.js +134 -48
- package/packages/datadog-instrumentations/src/mocha/main.js +20 -4
- package/packages/datadog-instrumentations/src/mocha/utils.js +89 -30
- package/packages/datadog-instrumentations/src/mocha/worker.js +3 -1
- package/packages/datadog-instrumentations/src/playwright.js +97 -17
- package/packages/datadog-instrumentations/src/router.js +1 -0
- package/packages/datadog-instrumentations/src/tedious.js +13 -10
- package/packages/datadog-instrumentations/src/vitest.js +77 -17
- package/packages/datadog-plugin-cucumber/src/index.js +24 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +69 -20
- package/packages/datadog-plugin-cypress/src/support.js +39 -10
- package/packages/datadog-plugin-google-cloud-vertexai/src/index.js +8 -186
- package/packages/datadog-plugin-google-cloud-vertexai/src/tracing.js +186 -0
- package/packages/datadog-plugin-google-cloud-vertexai/src/utils.js +19 -0
- package/packages/datadog-plugin-jest/src/index.js +38 -5
- package/packages/datadog-plugin-mocha/src/index.js +28 -5
- package/packages/datadog-plugin-playwright/src/index.js +22 -2
- package/packages/datadog-plugin-tedious/src/index.js +14 -9
- package/packages/datadog-plugin-vitest/src/index.js +46 -14
- package/packages/dd-trace/src/appsec/blocking.js +2 -0
- package/packages/dd-trace/src/appsec/graphql.js +3 -1
- package/packages/dd-trace/src/appsec/reporter.js +13 -8
- package/packages/dd-trace/src/appsec/telemetry/common.js +6 -3
- package/packages/dd-trace/src/appsec/telemetry/index.js +20 -4
- package/packages/dd-trace/src/appsec/telemetry/waf.js +29 -9
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +16 -7
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +5 -2
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +3 -1
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +4 -2
- package/packages/dd-trace/src/llmobs/constants/tags.js +2 -0
- package/packages/dd-trace/src/llmobs/noop.js +3 -3
- package/packages/dd-trace/src/llmobs/plugins/base.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +2 -1
- package/packages/dd-trace/src/llmobs/plugins/vertexai.js +196 -0
- package/packages/dd-trace/src/llmobs/sdk.js +2 -0
- package/packages/dd-trace/src/llmobs/span_processor.js +6 -0
- package/packages/dd-trace/src/llmobs/tagger.js +8 -2
- package/packages/dd-trace/src/llmobs/telemetry.js +82 -1
- package/packages/dd-trace/src/llmobs/writers/spans/base.js +10 -1
- package/packages/dd-trace/src/plugin_manager.js +0 -3
- package/packages/dd-trace/src/plugins/ci_plugin.js +16 -26
- package/packages/dd-trace/src/plugins/database.js +4 -4
- package/packages/dd-trace/src/plugins/plugin.js +2 -0
- package/packages/dd-trace/src/plugins/util/test.js +62 -1
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +7 -6
- package/packages/dd-trace/src/telemetry/send-data.js +5 -1
|
@@ -1,195 +1,17 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const makeUtilities = require('../../dd-trace/src/plugins/util/llm')
|
|
3
|
+
const CompositePlugin = require('../../dd-trace/src/plugins/composite')
|
|
4
|
+
const GoogleVertexAITracingPlugin = require('./tracing')
|
|
5
|
+
const VertexAILLMObsPlugin = require('../../dd-trace/src/llmobs/plugins/vertexai')
|
|
7
6
|
|
|
8
|
-
class GoogleCloudVertexAIPlugin extends
|
|
7
|
+
class GoogleCloudVertexAIPlugin extends CompositePlugin {
|
|
9
8
|
static get id () { return 'google-cloud-vertexai' }
|
|
10
|
-
static get
|
|
11
|
-
return
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
constructor () {
|
|
15
|
-
super(...arguments)
|
|
16
|
-
|
|
17
|
-
Object.assign(this, makeUtilities('vertexai', this._tracerConfig))
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
bindStart (ctx) {
|
|
21
|
-
const { instance, request, resource, stream } = ctx
|
|
22
|
-
|
|
23
|
-
const tags = this.tagRequest(request, instance, stream)
|
|
24
|
-
|
|
25
|
-
const span = this.startSpan('vertexai.request', {
|
|
26
|
-
service: this.config.service,
|
|
27
|
-
resource,
|
|
28
|
-
kind: 'client',
|
|
29
|
-
meta: {
|
|
30
|
-
[MEASURED]: 1,
|
|
31
|
-
...tags
|
|
32
|
-
}
|
|
33
|
-
}, false)
|
|
34
|
-
|
|
35
|
-
const store = storage('legacy').getStore() || {}
|
|
36
|
-
ctx.currentStore = { ...store, span }
|
|
37
|
-
|
|
38
|
-
return ctx.currentStore
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
asyncEnd (ctx) {
|
|
42
|
-
const span = ctx.currentStore?.span
|
|
43
|
-
if (!span) return
|
|
44
|
-
|
|
45
|
-
const { result } = ctx
|
|
46
|
-
|
|
47
|
-
const response = result?.response
|
|
48
|
-
if (response) {
|
|
49
|
-
const tags = this.tagResponse(response)
|
|
50
|
-
span.addTags(tags)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
span.finish()
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
tagRequest (request, instance, stream) {
|
|
57
|
-
const model = extractModel(instance)
|
|
58
|
-
const tags = {
|
|
59
|
-
'vertexai.request.model': model
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const history = instance.historyInternal
|
|
63
|
-
let contents = typeof request === 'string' || Array.isArray(request) ? request : request.contents
|
|
64
|
-
if (history) {
|
|
65
|
-
contents = [...history, ...(Array.isArray(contents) ? contents : [contents])]
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const generationConfig = instance.generationConfig || {}
|
|
69
|
-
for (const key of Object.keys(generationConfig)) {
|
|
70
|
-
const transformedKey = key.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase()
|
|
71
|
-
tags[`vertexai.request.generation_config.${transformedKey}`] = JSON.stringify(generationConfig[key])
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (stream) {
|
|
75
|
-
tags['vertexai.request.stream'] = true
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (!this.isPromptCompletionSampled()) return tags
|
|
79
|
-
|
|
80
|
-
const systemInstructions = extractSystemInstructions(instance)
|
|
81
|
-
|
|
82
|
-
for (const [idx, systemInstruction] of systemInstructions.entries()) {
|
|
83
|
-
tags[`vertexai.request.system_instruction.${idx}.text`] = systemInstruction
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (typeof contents === 'string') {
|
|
87
|
-
tags['vertexai.request.contents.0.text'] = contents
|
|
88
|
-
return tags
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
for (const [contentIdx, content] of contents.entries()) {
|
|
92
|
-
this.tagRequestContent(tags, content, contentIdx)
|
|
9
|
+
static get plugins () {
|
|
10
|
+
return {
|
|
11
|
+
llmobs: VertexAILLMObsPlugin,
|
|
12
|
+
tracing: GoogleVertexAITracingPlugin
|
|
93
13
|
}
|
|
94
|
-
|
|
95
|
-
return tags
|
|
96
14
|
}
|
|
97
|
-
|
|
98
|
-
tagRequestPart (part, tags, partIdx, contentIdx) {
|
|
99
|
-
tags[`vertexai.request.contents.${contentIdx}.parts.${partIdx}.text`] = this.normalize(part.text)
|
|
100
|
-
|
|
101
|
-
const functionCall = part.functionCall
|
|
102
|
-
const functionResponse = part.functionResponse
|
|
103
|
-
|
|
104
|
-
if (functionCall) {
|
|
105
|
-
tags[`vertexai.request.contents.${contentIdx}.parts.${partIdx}.function_call.name`] = functionCall.name
|
|
106
|
-
tags[`vertexai.request.contents.${contentIdx}.parts.${partIdx}.function_call.args`] =
|
|
107
|
-
this.normalize(JSON.stringify(functionCall.args))
|
|
108
|
-
}
|
|
109
|
-
if (functionResponse) {
|
|
110
|
-
tags[`vertexai.request.contents.${contentIdx}.parts.${partIdx}.function_response.name`] =
|
|
111
|
-
functionResponse.name
|
|
112
|
-
tags[`vertexai.request.contents.${contentIdx}.parts.${partIdx}.function_response.response`] =
|
|
113
|
-
this.normalize(JSON.stringify(functionResponse.response))
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
tagRequestContent (tags, content, contentIdx) {
|
|
118
|
-
if (typeof content === 'string') {
|
|
119
|
-
tags[`vertexai.request.contents.${contentIdx}.text`] = this.normalize(content)
|
|
120
|
-
return
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (content.text || content.functionCall || content.functionResponse) {
|
|
124
|
-
this.tagRequestPart(content, tags, 0, contentIdx)
|
|
125
|
-
return
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const { role, parts } = content
|
|
129
|
-
if (role) {
|
|
130
|
-
tags[`vertexai.request.contents.${contentIdx}.role`] = role
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
for (const [partIdx, part] of parts.entries()) {
|
|
134
|
-
this.tagRequestPart(part, tags, partIdx, contentIdx)
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
tagResponse (response) {
|
|
139
|
-
const tags = {}
|
|
140
|
-
|
|
141
|
-
const candidates = response.candidates
|
|
142
|
-
for (const [candidateIdx, candidate] of candidates.entries()) {
|
|
143
|
-
const finishReason = candidate.finishReason
|
|
144
|
-
if (finishReason) {
|
|
145
|
-
tags[`vertexai.response.candidates.${candidateIdx}.finish_reason`] = finishReason
|
|
146
|
-
}
|
|
147
|
-
const candidateContent = candidate.content
|
|
148
|
-
const role = candidateContent.role
|
|
149
|
-
tags[`vertexai.response.candidates.${candidateIdx}.content.role`] = role
|
|
150
|
-
|
|
151
|
-
if (!this.isPromptCompletionSampled()) continue
|
|
152
|
-
|
|
153
|
-
const parts = candidateContent.parts
|
|
154
|
-
for (const [partIdx, part] of parts.entries()) {
|
|
155
|
-
const text = part.text
|
|
156
|
-
tags[`vertexai.response.candidates.${candidateIdx}.content.parts.${partIdx}.text`] =
|
|
157
|
-
this.normalize(String(text))
|
|
158
|
-
|
|
159
|
-
const functionCall = part.functionCall
|
|
160
|
-
if (!functionCall) continue
|
|
161
|
-
|
|
162
|
-
tags[`vertexai.response.candidates.${candidateIdx}.content.parts.${partIdx}.function_call.name`] =
|
|
163
|
-
functionCall.name
|
|
164
|
-
tags[`vertexai.response.candidates.${candidateIdx}.content.parts.${partIdx}.function_call.args`] =
|
|
165
|
-
this.normalize(JSON.stringify(functionCall.args))
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const tokenCounts = response.usageMetadata
|
|
170
|
-
if (tokenCounts) {
|
|
171
|
-
tags['vertexai.response.usage.prompt_tokens'] = tokenCounts.promptTokenCount
|
|
172
|
-
tags['vertexai.response.usage.completion_tokens'] = tokenCounts.candidatesTokenCount
|
|
173
|
-
tags['vertexai.response.usage.total_tokens'] = tokenCounts.totalTokenCount
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return tags
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function extractModel (instance) {
|
|
181
|
-
const model = instance.model || instance.resourcePath || instance.publisherModelEndpoint
|
|
182
|
-
return model?.split('/').pop()
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function extractSystemInstructions (instance) {
|
|
186
|
-
// systemInstruction is either a string or a Content object
|
|
187
|
-
// Content objects have parts (Part[]) and a role
|
|
188
|
-
const systemInstruction = instance.systemInstruction
|
|
189
|
-
if (!systemInstruction) return []
|
|
190
|
-
if (typeof systemInstruction === 'string') return [systemInstruction]
|
|
191
|
-
|
|
192
|
-
return systemInstruction.parts?.map(part => part.text)
|
|
193
15
|
}
|
|
194
16
|
|
|
195
17
|
module.exports = GoogleCloudVertexAIPlugin
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { MEASURED } = require('../../../ext/tags')
|
|
4
|
+
const { storage } = require('../../datadog-core')
|
|
5
|
+
const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
|
|
6
|
+
const makeUtilities = require('../../dd-trace/src/plugins/util/llm')
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
extractModel,
|
|
10
|
+
extractSystemInstructions
|
|
11
|
+
} = require('./utils')
|
|
12
|
+
|
|
13
|
+
class GoogleCloudVertexAITracingPlugin extends TracingPlugin {
|
|
14
|
+
static get id () { return 'google-cloud-vertexai' }
|
|
15
|
+
static get prefix () {
|
|
16
|
+
return 'tracing:apm:vertexai:request'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
constructor () {
|
|
20
|
+
super(...arguments)
|
|
21
|
+
|
|
22
|
+
Object.assign(this, makeUtilities('vertexai', this._tracerConfig))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
bindStart (ctx) {
|
|
26
|
+
const { instance, request, resource, stream } = ctx
|
|
27
|
+
|
|
28
|
+
const tags = this.tagRequest(request, instance, stream)
|
|
29
|
+
|
|
30
|
+
const span = this.startSpan('vertexai.request', {
|
|
31
|
+
service: this.config.service,
|
|
32
|
+
resource,
|
|
33
|
+
kind: 'client',
|
|
34
|
+
meta: {
|
|
35
|
+
[MEASURED]: 1,
|
|
36
|
+
...tags
|
|
37
|
+
}
|
|
38
|
+
}, false)
|
|
39
|
+
|
|
40
|
+
const store = storage('legacy').getStore() || {}
|
|
41
|
+
ctx.currentStore = { ...store, span }
|
|
42
|
+
|
|
43
|
+
return ctx.currentStore
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
asyncEnd (ctx) {
|
|
47
|
+
const span = ctx.currentStore?.span
|
|
48
|
+
if (!span) return
|
|
49
|
+
|
|
50
|
+
const { result } = ctx
|
|
51
|
+
|
|
52
|
+
const response = result?.response
|
|
53
|
+
if (response) {
|
|
54
|
+
const tags = this.tagResponse(response)
|
|
55
|
+
span.addTags(tags)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
span.finish()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
tagRequest (request, instance, stream) {
|
|
62
|
+
const model = extractModel(instance)
|
|
63
|
+
const tags = {
|
|
64
|
+
'vertexai.request.model': model
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const history = instance.historyInternal
|
|
68
|
+
|
|
69
|
+
let contents = typeof request === 'string' || Array.isArray(request) ? request : request.contents
|
|
70
|
+
if (history) {
|
|
71
|
+
contents = [...history, ...(Array.isArray(contents) ? contents : [contents])]
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const generationConfig = instance.generationConfig || {}
|
|
75
|
+
for (const key of Object.keys(generationConfig)) {
|
|
76
|
+
const transformedKey = key.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase()
|
|
77
|
+
tags[`vertexai.request.generation_config.${transformedKey}`] = JSON.stringify(generationConfig[key])
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (stream) {
|
|
81
|
+
tags['vertexai.request.stream'] = true
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (!this.isPromptCompletionSampled()) return tags
|
|
85
|
+
|
|
86
|
+
const systemInstructions = extractSystemInstructions(instance)
|
|
87
|
+
|
|
88
|
+
for (const [idx, systemInstruction] of systemInstructions.entries()) {
|
|
89
|
+
tags[`vertexai.request.system_instruction.${idx}.text`] = systemInstruction
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (typeof contents === 'string') {
|
|
93
|
+
tags['vertexai.request.contents.0.text'] = contents
|
|
94
|
+
return tags
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
for (const [contentIdx, content] of contents.entries()) {
|
|
98
|
+
this.tagRequestContent(tags, content, contentIdx)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return tags
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
tagRequestPart (part, tags, partIdx, contentIdx) {
|
|
105
|
+
tags[`vertexai.request.contents.${contentIdx}.parts.${partIdx}.text`] = this.normalize(part.text)
|
|
106
|
+
|
|
107
|
+
const functionCall = part.functionCall
|
|
108
|
+
const functionResponse = part.functionResponse
|
|
109
|
+
|
|
110
|
+
if (functionCall) {
|
|
111
|
+
tags[`vertexai.request.contents.${contentIdx}.parts.${partIdx}.function_call.name`] = functionCall.name
|
|
112
|
+
tags[`vertexai.request.contents.${contentIdx}.parts.${partIdx}.function_call.args`] =
|
|
113
|
+
this.normalize(JSON.stringify(functionCall.args))
|
|
114
|
+
}
|
|
115
|
+
if (functionResponse) {
|
|
116
|
+
tags[`vertexai.request.contents.${contentIdx}.parts.${partIdx}.function_response.name`] =
|
|
117
|
+
functionResponse.name
|
|
118
|
+
tags[`vertexai.request.contents.${contentIdx}.parts.${partIdx}.function_response.response`] =
|
|
119
|
+
this.normalize(JSON.stringify(functionResponse.response))
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
tagRequestContent (tags, content, contentIdx) {
|
|
124
|
+
if (typeof content === 'string') {
|
|
125
|
+
tags[`vertexai.request.contents.${contentIdx}.text`] = this.normalize(content)
|
|
126
|
+
return
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (content.text || content.functionCall || content.functionResponse) {
|
|
130
|
+
this.tagRequestPart(content, tags, 0, contentIdx)
|
|
131
|
+
return
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const { role, parts } = content
|
|
135
|
+
if (role) {
|
|
136
|
+
tags[`vertexai.request.contents.${contentIdx}.role`] = role
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
for (const [partIdx, part] of parts.entries()) {
|
|
140
|
+
this.tagRequestPart(part, tags, partIdx, contentIdx)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
tagResponse (response) {
|
|
145
|
+
const tags = {}
|
|
146
|
+
|
|
147
|
+
const candidates = response.candidates
|
|
148
|
+
for (const [candidateIdx, candidate] of candidates.entries()) {
|
|
149
|
+
const finishReason = candidate.finishReason
|
|
150
|
+
if (finishReason) {
|
|
151
|
+
tags[`vertexai.response.candidates.${candidateIdx}.finish_reason`] = finishReason
|
|
152
|
+
}
|
|
153
|
+
const candidateContent = candidate.content
|
|
154
|
+
const role = candidateContent.role
|
|
155
|
+
tags[`vertexai.response.candidates.${candidateIdx}.content.role`] = role
|
|
156
|
+
|
|
157
|
+
if (!this.isPromptCompletionSampled()) continue
|
|
158
|
+
|
|
159
|
+
const parts = candidateContent.parts
|
|
160
|
+
for (const [partIdx, part] of parts.entries()) {
|
|
161
|
+
const text = part.text
|
|
162
|
+
tags[`vertexai.response.candidates.${candidateIdx}.content.parts.${partIdx}.text`] =
|
|
163
|
+
this.normalize(String(text))
|
|
164
|
+
|
|
165
|
+
const functionCall = part.functionCall
|
|
166
|
+
if (!functionCall) continue
|
|
167
|
+
|
|
168
|
+
tags[`vertexai.response.candidates.${candidateIdx}.content.parts.${partIdx}.function_call.name`] =
|
|
169
|
+
functionCall.name
|
|
170
|
+
tags[`vertexai.response.candidates.${candidateIdx}.content.parts.${partIdx}.function_call.args`] =
|
|
171
|
+
this.normalize(JSON.stringify(functionCall.args))
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const tokenCounts = response.usageMetadata
|
|
176
|
+
if (tokenCounts) {
|
|
177
|
+
tags['vertexai.response.usage.prompt_tokens'] = tokenCounts.promptTokenCount
|
|
178
|
+
tags['vertexai.response.usage.completion_tokens'] = tokenCounts.candidatesTokenCount
|
|
179
|
+
tags['vertexai.response.usage.total_tokens'] = tokenCounts.totalTokenCount
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return tags
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
module.exports = GoogleCloudVertexAITracingPlugin
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
function extractModel (instance) {
|
|
2
|
+
const model = instance.model || instance.resourcePath || instance.publisherModelEndpoint
|
|
3
|
+
return model?.split('/').pop()
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
function extractSystemInstructions (instance) {
|
|
7
|
+
// systemInstruction is either a string or a Content object
|
|
8
|
+
// Content objects have parts (Part[]) and a role
|
|
9
|
+
const systemInstruction = instance.systemInstruction
|
|
10
|
+
if (!systemInstruction) return []
|
|
11
|
+
if (typeof systemInstruction === 'string') return [systemInstruction]
|
|
12
|
+
|
|
13
|
+
return systemInstruction.parts?.map(part => part.text)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
extractModel,
|
|
18
|
+
extractSystemInstructions
|
|
19
|
+
}
|
|
@@ -27,7 +27,10 @@ const {
|
|
|
27
27
|
TEST_RETRY_REASON,
|
|
28
28
|
TEST_MANAGEMENT_ENABLED,
|
|
29
29
|
TEST_MANAGEMENT_IS_QUARANTINED,
|
|
30
|
-
TEST_MANAGEMENT_IS_DISABLED
|
|
30
|
+
TEST_MANAGEMENT_IS_DISABLED,
|
|
31
|
+
TEST_MANAGEMENT_IS_ATTEMPT_TO_FIX,
|
|
32
|
+
TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED,
|
|
33
|
+
TEST_HAS_FAILED_ALL_RETRIES
|
|
31
34
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
32
35
|
const { COMPONENT } = require('../../dd-trace/src/constants')
|
|
33
36
|
const id = require('../../dd-trace/src/id')
|
|
@@ -177,6 +180,7 @@ class JestPlugin extends CiPlugin {
|
|
|
177
180
|
config._ddRepositoryRoot = this.repositoryRoot
|
|
178
181
|
config._ddIsFlakyTestRetriesEnabled = this.libraryConfig?.isFlakyTestRetriesEnabled ?? false
|
|
179
182
|
config._ddIsTestManagementTestsEnabled = this.libraryConfig?.isTestManagementEnabled ?? false
|
|
183
|
+
config._ddTestManagementAttemptToFixRetries = this.libraryConfig?.testManagementAttemptToFixRetries ?? 0
|
|
180
184
|
config._ddFlakyTestRetriesCount = this.libraryConfig?.flakyTestRetriesCount
|
|
181
185
|
config._ddIsDiEnabled = this.libraryConfig?.isDiEnabled ?? false
|
|
182
186
|
config._ddIsKnownTestsEnabled = this.libraryConfig?.isKnownTestsEnabled ?? false
|
|
@@ -336,14 +340,22 @@ class JestPlugin extends CiPlugin {
|
|
|
336
340
|
this.activeTestSpan = span
|
|
337
341
|
})
|
|
338
342
|
|
|
339
|
-
this.addSub('ci:jest:test:finish', ({
|
|
343
|
+
this.addSub('ci:jest:test:finish', ({
|
|
344
|
+
status,
|
|
345
|
+
testStartLine,
|
|
346
|
+
attemptToFixPassed,
|
|
347
|
+
failedAllTests
|
|
348
|
+
}) => {
|
|
340
349
|
const span = storage('legacy').getStore().span
|
|
341
350
|
span.setTag(TEST_STATUS, status)
|
|
342
351
|
if (testStartLine) {
|
|
343
352
|
span.setTag(TEST_SOURCE_START, testStartLine)
|
|
344
353
|
}
|
|
345
|
-
if (
|
|
346
|
-
span.setTag(
|
|
354
|
+
if (attemptToFixPassed) {
|
|
355
|
+
span.setTag(TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED, 'true')
|
|
356
|
+
}
|
|
357
|
+
if (failedAllTests) {
|
|
358
|
+
span.setTag(TEST_HAS_FAILED_ALL_RETRIES, 'true')
|
|
347
359
|
}
|
|
348
360
|
|
|
349
361
|
const spanTags = span.context()._tags
|
|
@@ -407,7 +419,11 @@ class JestPlugin extends CiPlugin {
|
|
|
407
419
|
testSourceFile,
|
|
408
420
|
isNew,
|
|
409
421
|
isEfdRetry,
|
|
410
|
-
|
|
422
|
+
isAttemptToFix,
|
|
423
|
+
isAttemptToFixRetry,
|
|
424
|
+
isJestRetry,
|
|
425
|
+
isDisabled,
|
|
426
|
+
isQuarantined
|
|
411
427
|
} = test
|
|
412
428
|
|
|
413
429
|
const extraTags = {
|
|
@@ -425,6 +441,23 @@ class JestPlugin extends CiPlugin {
|
|
|
425
441
|
extraTags[JEST_DISPLAY_NAME] = displayName
|
|
426
442
|
}
|
|
427
443
|
|
|
444
|
+
if (isAttemptToFix) {
|
|
445
|
+
extraTags[TEST_MANAGEMENT_IS_ATTEMPT_TO_FIX] = 'true'
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (isAttemptToFixRetry) {
|
|
449
|
+
extraTags[TEST_IS_RETRY] = 'true'
|
|
450
|
+
extraTags[TEST_RETRY_REASON] = 'attempt_to_fix'
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (isDisabled) {
|
|
454
|
+
extraTags[TEST_MANAGEMENT_IS_DISABLED] = 'true'
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
if (isQuarantined) {
|
|
458
|
+
extraTags[TEST_MANAGEMENT_IS_QUARANTINED] = 'true'
|
|
459
|
+
}
|
|
460
|
+
|
|
428
461
|
if (isNew) {
|
|
429
462
|
extraTags[TEST_IS_NEW] = 'true'
|
|
430
463
|
if (isEfdRetry) {
|
|
@@ -17,7 +17,6 @@ const {
|
|
|
17
17
|
TEST_CODE_OWNERS,
|
|
18
18
|
ITR_CORRELATION_ID,
|
|
19
19
|
TEST_SOURCE_FILE,
|
|
20
|
-
removeEfdStringFromTestName,
|
|
21
20
|
TEST_IS_NEW,
|
|
22
21
|
TEST_IS_RETRY,
|
|
23
22
|
TEST_EARLY_FLAKE_ENABLED,
|
|
@@ -34,7 +33,10 @@ const {
|
|
|
34
33
|
TEST_RETRY_REASON,
|
|
35
34
|
TEST_MANAGEMENT_ENABLED,
|
|
36
35
|
TEST_MANAGEMENT_IS_QUARANTINED,
|
|
37
|
-
TEST_MANAGEMENT_IS_DISABLED
|
|
36
|
+
TEST_MANAGEMENT_IS_DISABLED,
|
|
37
|
+
TEST_MANAGEMENT_IS_ATTEMPT_TO_FIX,
|
|
38
|
+
TEST_HAS_FAILED_ALL_RETRIES,
|
|
39
|
+
TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED
|
|
38
40
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
39
41
|
const { COMPONENT } = require('../../dd-trace/src/constants')
|
|
40
42
|
const {
|
|
@@ -199,7 +201,14 @@ class MochaPlugin extends CiPlugin {
|
|
|
199
201
|
this.tracer._exporter.flush()
|
|
200
202
|
})
|
|
201
203
|
|
|
202
|
-
this.addSub('ci:mocha:test:finish', ({
|
|
204
|
+
this.addSub('ci:mocha:test:finish', ({
|
|
205
|
+
status,
|
|
206
|
+
hasBeenRetried,
|
|
207
|
+
isLastRetry,
|
|
208
|
+
hasFailedAllRetries,
|
|
209
|
+
attemptToFixPassed,
|
|
210
|
+
isAttemptToFixRetry
|
|
211
|
+
}) => {
|
|
203
212
|
const store = storage('legacy').getStore()
|
|
204
213
|
const span = store?.span
|
|
205
214
|
|
|
@@ -208,6 +217,16 @@ class MochaPlugin extends CiPlugin {
|
|
|
208
217
|
if (hasBeenRetried) {
|
|
209
218
|
span.setTag(TEST_IS_RETRY, 'true')
|
|
210
219
|
}
|
|
220
|
+
if (hasFailedAllRetries) {
|
|
221
|
+
span.setTag(TEST_HAS_FAILED_ALL_RETRIES, 'true')
|
|
222
|
+
}
|
|
223
|
+
if (attemptToFixPassed) {
|
|
224
|
+
span.setTag(TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED, 'true')
|
|
225
|
+
}
|
|
226
|
+
if (isAttemptToFixRetry) {
|
|
227
|
+
span.setTag(TEST_IS_RETRY, 'true')
|
|
228
|
+
span.setTag(TEST_RETRY_REASON, 'attempt_to_fix')
|
|
229
|
+
}
|
|
211
230
|
|
|
212
231
|
const spanTags = span.context()._tags
|
|
213
232
|
this.telemetry.ciVisEvent(
|
|
@@ -403,18 +422,18 @@ class MochaPlugin extends CiPlugin {
|
|
|
403
422
|
|
|
404
423
|
startTestSpan (testInfo) {
|
|
405
424
|
const {
|
|
425
|
+
testName,
|
|
406
426
|
testSuiteAbsolutePath,
|
|
407
427
|
title,
|
|
408
428
|
isNew,
|
|
409
429
|
isEfdRetry,
|
|
410
430
|
testStartLine,
|
|
411
431
|
isParallel,
|
|
432
|
+
isAttemptToFix,
|
|
412
433
|
isDisabled,
|
|
413
434
|
isQuarantined
|
|
414
435
|
} = testInfo
|
|
415
436
|
|
|
416
|
-
const testName = removeEfdStringFromTestName(testInfo.testName)
|
|
417
|
-
|
|
418
437
|
const extraTags = {}
|
|
419
438
|
const testParametersString = getTestParametersString(this._testTitleToParams, title)
|
|
420
439
|
if (testParametersString) {
|
|
@@ -429,6 +448,10 @@ class MochaPlugin extends CiPlugin {
|
|
|
429
448
|
extraTags[MOCHA_IS_PARALLEL] = 'true'
|
|
430
449
|
}
|
|
431
450
|
|
|
451
|
+
if (isAttemptToFix) {
|
|
452
|
+
extraTags[TEST_MANAGEMENT_IS_ATTEMPT_TO_FIX] = 'true'
|
|
453
|
+
}
|
|
454
|
+
|
|
432
455
|
if (isDisabled) {
|
|
433
456
|
extraTags[TEST_MANAGEMENT_IS_DISABLED] = 'true'
|
|
434
457
|
}
|
|
@@ -20,7 +20,10 @@ const {
|
|
|
20
20
|
TEST_MANAGEMENT_IS_QUARANTINED,
|
|
21
21
|
TEST_MANAGEMENT_ENABLED,
|
|
22
22
|
TEST_BROWSER_NAME,
|
|
23
|
-
TEST_MANAGEMENT_IS_DISABLED
|
|
23
|
+
TEST_MANAGEMENT_IS_DISABLED,
|
|
24
|
+
TEST_MANAGEMENT_IS_ATTEMPT_TO_FIX,
|
|
25
|
+
TEST_HAS_FAILED_ALL_RETRIES,
|
|
26
|
+
TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED
|
|
24
27
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
25
28
|
const { RESOURCE_NAME } = require('../../../ext/tags')
|
|
26
29
|
const { COMPONENT } = require('../../dd-trace/src/constants')
|
|
@@ -162,7 +165,11 @@ class PlaywrightPlugin extends CiPlugin {
|
|
|
162
165
|
isNew,
|
|
163
166
|
isEfdRetry,
|
|
164
167
|
isRetry,
|
|
165
|
-
|
|
168
|
+
isAttemptToFix,
|
|
169
|
+
isQuarantined,
|
|
170
|
+
isAttemptToFixRetry,
|
|
171
|
+
hasFailedAllRetries,
|
|
172
|
+
hasPassedAttemptToFixRetries
|
|
166
173
|
}) => {
|
|
167
174
|
const store = storage('legacy').getStore()
|
|
168
175
|
const span = store && store.span
|
|
@@ -186,6 +193,19 @@ class PlaywrightPlugin extends CiPlugin {
|
|
|
186
193
|
if (isRetry) {
|
|
187
194
|
span.setTag(TEST_IS_RETRY, 'true')
|
|
188
195
|
}
|
|
196
|
+
if (hasFailedAllRetries) {
|
|
197
|
+
span.setTag(TEST_HAS_FAILED_ALL_RETRIES, 'true')
|
|
198
|
+
}
|
|
199
|
+
if (isAttemptToFix) {
|
|
200
|
+
span.setTag(TEST_MANAGEMENT_IS_ATTEMPT_TO_FIX, 'true')
|
|
201
|
+
}
|
|
202
|
+
if (isAttemptToFixRetry) {
|
|
203
|
+
span.setTag(TEST_IS_RETRY, 'true')
|
|
204
|
+
span.setTag(TEST_RETRY_REASON, 'attempt_to_fix')
|
|
205
|
+
}
|
|
206
|
+
if (hasPassedAttemptToFixRetries) {
|
|
207
|
+
span.setTag(TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED, 'true')
|
|
208
|
+
}
|
|
189
209
|
if (isQuarantined) {
|
|
190
210
|
span.setTag(TEST_MANAGEMENT_IS_QUARANTINED, 'true')
|
|
191
211
|
}
|
|
@@ -8,22 +8,27 @@ class TediousPlugin extends DatabasePlugin {
|
|
|
8
8
|
static get operation () { return 'request' } // TODO: change to match other database plugins
|
|
9
9
|
static get system () { return 'mssql' }
|
|
10
10
|
|
|
11
|
-
start (
|
|
12
|
-
this.
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
start (payload) {
|
|
12
|
+
const service = this.serviceName({ pluginConfig: this.config, system: this.system })
|
|
13
|
+
const span = this.startSpan(this.operationName(), {
|
|
14
|
+
service,
|
|
15
|
+
resource: payload.queryOrProcedure,
|
|
15
16
|
type: 'sql',
|
|
16
17
|
kind: 'client',
|
|
17
18
|
meta: {
|
|
18
19
|
'db.type': 'mssql',
|
|
19
20
|
component: 'tedious',
|
|
20
|
-
'out.host': connectionConfig.server,
|
|
21
|
-
[CLIENT_PORT_KEY]: connectionConfig.options.port,
|
|
22
|
-
'db.user': connectionConfig.userName || connectionConfig.authentication.options.userName,
|
|
23
|
-
'db.name': connectionConfig.options.database,
|
|
24
|
-
'db.instance': connectionConfig.options.instanceName
|
|
21
|
+
'out.host': payload.connectionConfig.server,
|
|
22
|
+
[CLIENT_PORT_KEY]: payload.connectionConfig.options.port,
|
|
23
|
+
'db.user': payload.connectionConfig.userName || payload.connectionConfig.authentication.options.userName,
|
|
24
|
+
'db.name': payload.connectionConfig.options.database,
|
|
25
|
+
'db.instance': payload.connectionConfig.options.instanceName
|
|
25
26
|
}
|
|
26
27
|
})
|
|
28
|
+
|
|
29
|
+
// SQL Server includes comments when caching queries
|
|
30
|
+
// For that reason we allow service mode but not full mode
|
|
31
|
+
payload.sql = this.injectDbmQuery(span, payload.queryOrProcedure, service, true)
|
|
27
32
|
}
|
|
28
33
|
}
|
|
29
34
|
|