dd-trace 5.94.0 → 5.96.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 +46 -44
- package/index.d.ts +191 -13
- package/package.json +2 -2
- package/packages/datadog-instrumentations/src/ai.js +112 -0
- package/packages/datadog-instrumentations/src/anthropic.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/ai-messages.js +182 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/{orchestrion/compiler.js → compiler.js} +4 -13
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +16 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +25 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js +2 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/{orchestrion/transforms.js → transforms.js} +3 -89
- package/packages/datadog-instrumentations/src/mocha/utils.js +10 -0
- package/packages/datadog-plugin-dd-trace-api/src/index.js +1 -4
- package/packages/dd-trace/src/aiguard/index.js +64 -0
- package/packages/dd-trace/src/azure_metadata.js +15 -15
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +73 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +76 -1
- package/packages/dd-trace/src/ci-visibility/lage.js +39 -0
- package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +259 -0
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +56 -0
- package/packages/dd-trace/src/config/config-base.d.ts +7 -0
- package/packages/dd-trace/src/config/config-base.js +5 -0
- package/packages/dd-trace/src/config/config-types.d.ts +78 -0
- package/packages/dd-trace/src/config/generated-config-types.d.ts +582 -0
- package/packages/dd-trace/src/config/index.js +5 -2
- package/packages/dd-trace/src/config/supported-configurations.json +24 -0
- package/packages/dd-trace/src/constants.js +1 -0
- package/packages/dd-trace/src/exporter.js +5 -2
- package/packages/dd-trace/src/llmobs/constants/tags.js +1 -0
- package/packages/dd-trace/src/llmobs/constants/text.js +4 -1
- package/packages/dd-trace/src/llmobs/constants/writers.js +1 -1
- package/packages/dd-trace/src/llmobs/index.js +9 -4
- package/packages/dd-trace/src/llmobs/plugins/anthropic.js +11 -2
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +4 -1
- package/packages/dd-trace/src/llmobs/writers/spans.js +1 -1
- package/packages/dd-trace/src/plugins/util/test.js +5 -0
- package/packages/dd-trace/src/priority_sampler.js +1 -1
- package/packages/dd-trace/src/proxy.js +4 -0
- package/packages/dd-trace/src/rate_limiter.js +2 -1
- package/packages/dd-trace/src/startup-log.js +9 -0
- package/packages/dd-trace/src/tagger.js +31 -35
- package/vendor/dist/@apm-js-collab/code-transformer/LICENSE +28 -0
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +133 -0
- package/vendor/dist/@opentelemetry/core/index.js +1 -1
- package/vendor/dist/@opentelemetry/resources/index.js +1 -1
- package/vendor/dist/esquery/index.js +1 -1
- package/vendor/dist/meriyah/index.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/orchestrion/index.js +0 -43
- package/packages/datadog-instrumentations/src/helpers/rewriter/orchestrion/matcher.js +0 -49
- package/packages/datadog-instrumentations/src/helpers/rewriter/orchestrion/transformer.js +0 -121
- package/vendor/dist/astring/LICENSE +0 -19
- package/vendor/dist/astring/index.js +0 -1
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Converts a LanguageModelV2FilePart with an image mediaType to an AI guard style image_url content part.
|
|
5
|
+
*
|
|
6
|
+
* @param {{type: 'file', data: URL|string|Uint8Array, mediaType: string}} part
|
|
7
|
+
* @returns {{type: 'image_url', image_url: {url: string}}|undefined}
|
|
8
|
+
*/
|
|
9
|
+
function convertFilePartToImageUrl (part) {
|
|
10
|
+
const { data, mediaType } = part
|
|
11
|
+
|
|
12
|
+
if (data instanceof URL) {
|
|
13
|
+
return { type: 'image_url', image_url: { url: data.toString() } }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (typeof data === 'string') {
|
|
17
|
+
if (data.startsWith('http') || data.startsWith('data:')) {
|
|
18
|
+
return { type: 'image_url', image_url: { url: data } }
|
|
19
|
+
}
|
|
20
|
+
return { type: 'image_url', image_url: { url: `data:${mediaType};base64,${data}` } }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (data instanceof Uint8Array) {
|
|
24
|
+
return { type: 'image_url', image_url: { url: `data:${mediaType};base64,${Buffer.from(data).toString('base64')}` } }
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Converts a LanguageModelV2Prompt to the AI guard style message format.
|
|
30
|
+
*
|
|
31
|
+
* Vercel AI v2 prompt entries use content arrays with typed parts (e.g. { type: 'text', text },
|
|
32
|
+
* { type: 'file', data, mediaType }). This function converts them to AI guard style messages.
|
|
33
|
+
* When file parts with image media types are present, the content is an array of text and
|
|
34
|
+
* image_url parts; otherwise it is a plain string.
|
|
35
|
+
*
|
|
36
|
+
* @param {Array<{role: string, content: string|Array<{type: string}>}>} prompt
|
|
37
|
+
* @returns {Array<{role: string, content?: string|Array<{type: string}>, tool_calls?: Array, tool_call_id?: string}>}
|
|
38
|
+
*/
|
|
39
|
+
function convertVercelPromptToMessages (prompt) {
|
|
40
|
+
if (!Array.isArray(prompt)) return []
|
|
41
|
+
|
|
42
|
+
const messages = []
|
|
43
|
+
for (const msg of prompt) {
|
|
44
|
+
switch (msg.role) {
|
|
45
|
+
case 'system':
|
|
46
|
+
messages.push({ role: 'system', content: typeof msg.content === 'string' ? msg.content : '' })
|
|
47
|
+
break
|
|
48
|
+
|
|
49
|
+
case 'user': {
|
|
50
|
+
if (!Array.isArray(msg.content)) break
|
|
51
|
+
|
|
52
|
+
const contentParts = []
|
|
53
|
+
for (const part of msg.content) {
|
|
54
|
+
if (part.type === 'text') {
|
|
55
|
+
contentParts.push({ type: 'text', text: part.text })
|
|
56
|
+
} else if (part.type === 'file' && part.mediaType?.startsWith('image/')) {
|
|
57
|
+
const converted = convertFilePartToImageUrl(part)
|
|
58
|
+
if (converted) contentParts.push(converted)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (contentParts.length === 0) break
|
|
63
|
+
|
|
64
|
+
const hasImages = contentParts.some(p => p.type === 'image_url')
|
|
65
|
+
if (hasImages) {
|
|
66
|
+
messages.push({ role: 'user', content: contentParts })
|
|
67
|
+
} else {
|
|
68
|
+
messages.push({ role: 'user', content: contentParts.map(p => p.text).join('\n') })
|
|
69
|
+
}
|
|
70
|
+
break
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
case 'assistant': {
|
|
74
|
+
const textParts = []
|
|
75
|
+
const toolCalls = []
|
|
76
|
+
if (!Array.isArray(msg.content)) break
|
|
77
|
+
|
|
78
|
+
for (const part of msg.content) {
|
|
79
|
+
if (part.type === 'text') {
|
|
80
|
+
textParts.push(part.text)
|
|
81
|
+
} else if (part.type === 'tool-call') {
|
|
82
|
+
const args = part.args ?? part.input
|
|
83
|
+
toolCalls.push({
|
|
84
|
+
id: part.toolCallId,
|
|
85
|
+
function: {
|
|
86
|
+
name: part.toolName,
|
|
87
|
+
arguments: typeof args === 'string' ? args : JSON.stringify(args),
|
|
88
|
+
},
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (toolCalls.length > 0) {
|
|
94
|
+
messages.push({ role: 'assistant', tool_calls: toolCalls })
|
|
95
|
+
} else if (textParts.length > 0) {
|
|
96
|
+
messages.push({ role: 'assistant', content: textParts.join('\n') })
|
|
97
|
+
}
|
|
98
|
+
break
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
case 'tool': {
|
|
102
|
+
if (!Array.isArray(msg.content)) break
|
|
103
|
+
|
|
104
|
+
for (const part of msg.content) {
|
|
105
|
+
if (part.type === 'tool-result') {
|
|
106
|
+
const result = part.result ?? part.output
|
|
107
|
+
messages.push({
|
|
108
|
+
role: 'tool',
|
|
109
|
+
tool_call_id: part.toolCallId,
|
|
110
|
+
content: typeof result === 'string' ? result : JSON.stringify(result),
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
break
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return messages
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Converts LLM output tool calls to AI guard style message format.
|
|
123
|
+
*
|
|
124
|
+
* @param {Array<object>} inputMessages - The input messages already in AI guard style format
|
|
125
|
+
* @param {Array<{toolCallId: string, toolName: string, args?: unknown, input?: unknown}>} toolCalls
|
|
126
|
+
* @returns {Array<object>}
|
|
127
|
+
*/
|
|
128
|
+
function buildToolCallOutputMessages (inputMessages, toolCalls) {
|
|
129
|
+
return [
|
|
130
|
+
...inputMessages,
|
|
131
|
+
{
|
|
132
|
+
role: 'assistant',
|
|
133
|
+
tool_calls: toolCalls.map(tc => {
|
|
134
|
+
const args = tc.args ?? tc.input
|
|
135
|
+
return {
|
|
136
|
+
id: tc.toolCallId,
|
|
137
|
+
function: {
|
|
138
|
+
name: tc.toolName,
|
|
139
|
+
arguments: typeof args === 'string' ? args : JSON.stringify(args),
|
|
140
|
+
},
|
|
141
|
+
}
|
|
142
|
+
}),
|
|
143
|
+
},
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Builds OpenAI-style output messages for the assistant's text response.
|
|
149
|
+
*
|
|
150
|
+
* @param {Array<object>} inputMessages - The input messages already in AI guard style format
|
|
151
|
+
* @param {string} text - The assistant's text response
|
|
152
|
+
* @returns {Array<object>}
|
|
153
|
+
*/
|
|
154
|
+
function buildTextOutputMessages (inputMessages, text) {
|
|
155
|
+
return [
|
|
156
|
+
...inputMessages,
|
|
157
|
+
{ role: 'assistant', content: text },
|
|
158
|
+
]
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Parses a Vercel AI content array and dispatches to the appropriate output message builder.
|
|
163
|
+
*
|
|
164
|
+
* @param {Array<object>} inputMessages - The input messages already in AI guard style format
|
|
165
|
+
* @param {Array<{type: string}>} content - Vercel AI content array from doGenerate/doStream result
|
|
166
|
+
* @returns {Array<object>}
|
|
167
|
+
*/
|
|
168
|
+
function buildOutputMessages (inputMessages, content) {
|
|
169
|
+
const toolCalls = content.filter(c => c.type === 'tool-call')
|
|
170
|
+
const text = content.filter(c => c.type === 'text').map(c => c.text).join('\n')
|
|
171
|
+
if (toolCalls.length) return buildToolCallOutputMessages(inputMessages, toolCalls)
|
|
172
|
+
if (text) return buildTextOutputMessages(inputMessages, text)
|
|
173
|
+
return inputMessages
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
module.exports = {
|
|
177
|
+
convertVercelPromptToMessages,
|
|
178
|
+
convertFilePartToImageUrl,
|
|
179
|
+
buildToolCallOutputMessages,
|
|
180
|
+
buildTextOutputMessages,
|
|
181
|
+
buildOutputMessages,
|
|
182
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const log = require('
|
|
3
|
+
const log = require('../../../../dd-trace/src/log')
|
|
4
4
|
|
|
5
5
|
// eslint-disable-next-line camelcase, no-undef
|
|
6
6
|
const runtimeRequire = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
|
|
@@ -25,7 +25,7 @@ const compiler = {
|
|
|
25
25
|
log.error(e)
|
|
26
26
|
|
|
27
27
|
// Fallback for when OXC is not available.
|
|
28
|
-
const meriyah = require('
|
|
28
|
+
const meriyah = require('../../../../../vendor/dist/meriyah')
|
|
29
29
|
|
|
30
30
|
compiler.parse = (sourceText, { range, sourceType } = {}) => {
|
|
31
31
|
return meriyah.parse(sourceText.toString(), {
|
|
@@ -39,16 +39,8 @@ const compiler = {
|
|
|
39
39
|
return compiler.parse(sourceText, options)
|
|
40
40
|
},
|
|
41
41
|
|
|
42
|
-
generate: (...args) => {
|
|
43
|
-
const astring = require('../../../../../../vendor/dist/astring')
|
|
44
|
-
|
|
45
|
-
compiler.generate = astring.generate
|
|
46
|
-
|
|
47
|
-
return compiler.generate(...args)
|
|
48
|
-
},
|
|
49
|
-
|
|
50
42
|
traverse: (ast, query, visitor) => {
|
|
51
|
-
const esquery = require('
|
|
43
|
+
const esquery = require('../../../../../vendor/dist/esquery')
|
|
52
44
|
|
|
53
45
|
compiler.traverse = (ast, query, visitor) => {
|
|
54
46
|
return esquery.traverse(ast, esquery.parse(query), visitor)
|
|
@@ -58,7 +50,7 @@ const compiler = {
|
|
|
58
50
|
},
|
|
59
51
|
|
|
60
52
|
query: (ast, query) => {
|
|
61
|
-
const esquery = require('
|
|
53
|
+
const esquery = require('../../../../../vendor/dist/esquery')
|
|
62
54
|
|
|
63
55
|
compiler.query = esquery.query
|
|
64
56
|
|
|
@@ -68,7 +60,6 @@ const compiler = {
|
|
|
68
60
|
|
|
69
61
|
module.exports = {
|
|
70
62
|
parse: (...args) => compiler.parse(...args),
|
|
71
|
-
generate: (...args) => compiler.generate(...args),
|
|
72
63
|
traverse: (...args) => compiler.traverse(...args),
|
|
73
64
|
query: (...args) => compiler.query(...args),
|
|
74
65
|
}
|
|
@@ -3,13 +3,27 @@
|
|
|
3
3
|
const { readFileSync } = require('fs')
|
|
4
4
|
const { join } = require('path')
|
|
5
5
|
const log = require('../../../../dd-trace/src/log')
|
|
6
|
+
const { create } = require('../../../../../vendor/dist/@apm-js-collab/code-transformer')
|
|
7
|
+
const { traceAsyncIterator, traceIterator } = require('./transforms')
|
|
6
8
|
const instrumentations = require('./instrumentations')
|
|
7
|
-
|
|
9
|
+
|
|
10
|
+
let dcPolyfill
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
dcPolyfill = require.resolve('dc-polyfill').replaceAll('\\', '/')
|
|
14
|
+
} catch {
|
|
15
|
+
// The `dc-polyfill` module is unavailable for some reason (like bundling).
|
|
16
|
+
// Let's just keep the default of using `diagnostics-channel` as a fallback
|
|
17
|
+
// which works for most Node versions.
|
|
18
|
+
}
|
|
8
19
|
|
|
9
20
|
/** @type {Record<string, string>} map of module base name to version */
|
|
10
21
|
const moduleVersions = {}
|
|
11
22
|
const disabled = new Set()
|
|
12
|
-
const matcher = create(instrumentations,
|
|
23
|
+
const matcher = create(instrumentations, dcPolyfill)
|
|
24
|
+
|
|
25
|
+
matcher.addTransform('traceIterator', traceIterator)
|
|
26
|
+
matcher.addTransform('traceAsyncIterator', traceAsyncIterator)
|
|
13
27
|
|
|
14
28
|
function rewrite (content, filename, format) {
|
|
15
29
|
if (!content) return content
|
|
@@ -75,6 +75,31 @@ module.exports = [
|
|
|
75
75
|
},
|
|
76
76
|
channelName: 'selectTelemetryAttributes',
|
|
77
77
|
},
|
|
78
|
+
// resolveLanguageModel called by all LLM entry points, its result is the resolved model instance.
|
|
79
|
+
{
|
|
80
|
+
module: {
|
|
81
|
+
name: 'ai',
|
|
82
|
+
versionRange: '>=6.0.0',
|
|
83
|
+
filePath: 'dist/index.js',
|
|
84
|
+
},
|
|
85
|
+
functionQuery: {
|
|
86
|
+
functionName: 'resolveLanguageModel',
|
|
87
|
+
kind: 'Sync',
|
|
88
|
+
},
|
|
89
|
+
channelName: 'resolveLanguageModel',
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
module: {
|
|
93
|
+
name: 'ai',
|
|
94
|
+
versionRange: '>=6.0.0',
|
|
95
|
+
filePath: 'dist/index.mjs',
|
|
96
|
+
},
|
|
97
|
+
functionQuery: {
|
|
98
|
+
functionName: 'resolveLanguageModel',
|
|
99
|
+
kind: 'Sync',
|
|
100
|
+
},
|
|
101
|
+
channelName: 'resolveLanguageModel',
|
|
102
|
+
},
|
|
78
103
|
// tool
|
|
79
104
|
{
|
|
80
105
|
module: {
|
package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js
CHANGED
|
@@ -10,9 +10,9 @@ module.exports = [
|
|
|
10
10
|
functionQuery: {
|
|
11
11
|
methodName: 'stream',
|
|
12
12
|
className: 'Pregel',
|
|
13
|
-
kind: 'AsyncIterator',
|
|
14
13
|
},
|
|
15
14
|
channelName: 'Pregel_stream',
|
|
15
|
+
transform: 'traceAsyncIterator',
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
18
|
module: {
|
|
@@ -23,8 +23,8 @@ module.exports = [
|
|
|
23
23
|
functionQuery: {
|
|
24
24
|
methodName: 'stream',
|
|
25
25
|
className: 'Pregel',
|
|
26
|
-
kind: 'AsyncIterator',
|
|
27
26
|
},
|
|
28
27
|
channelName: 'Pregel_stream',
|
|
28
|
+
transform: 'traceAsyncIterator',
|
|
29
29
|
},
|
|
30
30
|
]
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
// TODO: Move traceIterator to Orchestrion.
|
|
4
|
+
|
|
3
5
|
const { parse, query, traverse } = require('./compiler')
|
|
4
6
|
|
|
5
7
|
const tracingChannelPredicate = (node) => (
|
|
@@ -36,10 +38,7 @@ const transforms = module.exports = {
|
|
|
36
38
|
},
|
|
37
39
|
|
|
38
40
|
traceAsyncIterator: traceAny,
|
|
39
|
-
traceCallback: traceAny,
|
|
40
41
|
traceIterator: traceAny,
|
|
41
|
-
tracePromise: traceAny,
|
|
42
|
-
traceSync: traceAny,
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
function traceAny (state, node, _parent, ancestry) {
|
|
@@ -117,33 +116,10 @@ function traceInstanceMethod (state, node, program) {
|
|
|
117
116
|
}
|
|
118
117
|
|
|
119
118
|
function wrap (state, node, program) {
|
|
120
|
-
const {
|
|
119
|
+
const { operator } = state
|
|
121
120
|
|
|
122
121
|
if (operator === 'traceAsyncIterator') return wrapIterator(state, node, program)
|
|
123
|
-
if (operator === 'traceCallback') return wrapCallback(state, node)
|
|
124
122
|
if (operator === 'traceIterator') return wrapIterator(state, node, program)
|
|
125
|
-
|
|
126
|
-
const async = operator === 'tracePromise' ? 'async' : ''
|
|
127
|
-
const channelVariable = 'tr_ch_apm$' + channelName.replaceAll(':', '_')
|
|
128
|
-
const wrapper = parse(`
|
|
129
|
-
function wrapper () {
|
|
130
|
-
const __apm$traced = ${async} () => {
|
|
131
|
-
const __apm$wrapped = () => {};
|
|
132
|
-
return __apm$wrapped.apply(this, arguments);
|
|
133
|
-
};
|
|
134
|
-
if (!${channelVariable}.hasSubscribers) return __apm$traced();
|
|
135
|
-
return ${channelVariable}.${operator}(__apm$traced, {
|
|
136
|
-
arguments,
|
|
137
|
-
self: this,
|
|
138
|
-
moduleVersion: "1.0.0"
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
`).body[0].body // Extract only block statement of function body.
|
|
142
|
-
|
|
143
|
-
// Replace the right-hand side assignment of `const __apm$wrapped = () => {}`.
|
|
144
|
-
query(wrapper, '[id.name=__apm$wrapped]')[0].init = node
|
|
145
|
-
|
|
146
|
-
return wrapper
|
|
147
123
|
}
|
|
148
124
|
|
|
149
125
|
function wrapSuper (_state, node) {
|
|
@@ -195,68 +171,6 @@ function wrapSuper (_state, node) {
|
|
|
195
171
|
}
|
|
196
172
|
}
|
|
197
173
|
|
|
198
|
-
function wrapCallback (state, node) {
|
|
199
|
-
const { channelName, functionQuery: { callbackIndex = -1 } } = state
|
|
200
|
-
const channelVariable = 'tr_ch_apm$' + channelName.replaceAll(':', '_')
|
|
201
|
-
const wrapper = parse(`
|
|
202
|
-
function wrapper () {
|
|
203
|
-
const __apm$cb = Array.prototype.at.call(arguments, ${callbackIndex});
|
|
204
|
-
const __apm$ctx = {
|
|
205
|
-
arguments,
|
|
206
|
-
self: this,
|
|
207
|
-
moduleVersion: "1.0.0"
|
|
208
|
-
};
|
|
209
|
-
const __apm$traced = () => {
|
|
210
|
-
const __apm$wrapped = () => {};
|
|
211
|
-
return __apm$wrapped.apply(this, arguments);
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
if (!${channelVariable}.start.hasSubscribers) return __apm$traced();
|
|
215
|
-
|
|
216
|
-
function __apm$wrappedCb(err, res) {
|
|
217
|
-
if (err) {
|
|
218
|
-
__apm$ctx.error = err;
|
|
219
|
-
${channelVariable}.error.publish(__apm$ctx);
|
|
220
|
-
} else {
|
|
221
|
-
__apm$ctx.result = res;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
${channelVariable}.asyncStart.runStores(__apm$ctx, () => {
|
|
225
|
-
try {
|
|
226
|
-
if (__apm$cb) {
|
|
227
|
-
return __apm$cb.apply(this, arguments);
|
|
228
|
-
}
|
|
229
|
-
} finally {
|
|
230
|
-
${channelVariable}.asyncEnd.publish(__apm$ctx);
|
|
231
|
-
}
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
if (typeof __apm$cb !== 'function') {
|
|
236
|
-
return __apm$traced();
|
|
237
|
-
}
|
|
238
|
-
Array.prototype.splice.call(arguments, ${callbackIndex}, 1, __apm$wrappedCb);
|
|
239
|
-
|
|
240
|
-
return ${channelVariable}.start.runStores(__apm$ctx, () => {
|
|
241
|
-
try {
|
|
242
|
-
return __apm$traced();
|
|
243
|
-
} catch (err) {
|
|
244
|
-
__apm$ctx.error = err;
|
|
245
|
-
${channelVariable}.error.publish(__apm$ctx);
|
|
246
|
-
throw err;
|
|
247
|
-
} finally {
|
|
248
|
-
${channelVariable}.end.publish(__apm$ctx);
|
|
249
|
-
}
|
|
250
|
-
});
|
|
251
|
-
}
|
|
252
|
-
`).body[0].body // Extract only block statement of function body.
|
|
253
|
-
|
|
254
|
-
// Replace the right-hand side assignment of `const __apm$wrapped = () => {}`.
|
|
255
|
-
query(wrapper, '[id.name=__apm$wrapped]')[0].init = node
|
|
256
|
-
|
|
257
|
-
return wrapper
|
|
258
|
-
}
|
|
259
|
-
|
|
260
174
|
function wrapIterator (state, node, program) {
|
|
261
175
|
const { channelName, operator } = state
|
|
262
176
|
const baseChannel = channelName.replaceAll(':', '_')
|
|
@@ -384,6 +384,11 @@ function getOnTestEndHandler (config) {
|
|
|
384
384
|
})
|
|
385
385
|
} else if (ctx) { // if there is an afterEach to run, let's store the finalStatus for getOnHookEndHandler
|
|
386
386
|
ctx.finalStatus = finalStatus
|
|
387
|
+
ctx.hasFailedAllRetries = hasFailedAllRetries
|
|
388
|
+
ctx.attemptToFixPassed = attemptToFixPassed
|
|
389
|
+
ctx.attemptToFixFailed = attemptToFixFailed
|
|
390
|
+
ctx.isAttemptToFixRetry = isAttemptToFixRetry
|
|
391
|
+
ctx.isAtrRetry = isAtrRetry
|
|
387
392
|
}
|
|
388
393
|
}
|
|
389
394
|
}
|
|
@@ -404,6 +409,11 @@ function getOnHookEndHandler () {
|
|
|
404
409
|
status,
|
|
405
410
|
hasBeenRetried: isMochaRetry(test),
|
|
406
411
|
isLastRetry: getIsLastRetry(test),
|
|
412
|
+
hasFailedAllRetries: ctx.hasFailedAllRetries,
|
|
413
|
+
attemptToFixPassed: ctx.attemptToFixPassed,
|
|
414
|
+
attemptToFixFailed: ctx.attemptToFixFailed,
|
|
415
|
+
isAttemptToFixRetry: ctx.isAttemptToFixRetry,
|
|
416
|
+
isAtrRetry: ctx.isAtrRetry,
|
|
407
417
|
...ctx.currentStore,
|
|
408
418
|
finalStatus: ctx.finalStatus,
|
|
409
419
|
})
|
|
@@ -3,14 +3,10 @@
|
|
|
3
3
|
const Plugin = require('../../dd-trace/src/plugins/plugin')
|
|
4
4
|
const telemetryMetrics = require('../../dd-trace/src/telemetry/metrics')
|
|
5
5
|
const apiMetrics = telemetryMetrics.manager.namespace('tracers')
|
|
6
|
-
const { getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
|
|
7
6
|
|
|
8
7
|
// api ==> here
|
|
9
8
|
const objectMap = new WeakMap()
|
|
10
9
|
|
|
11
|
-
const injectionEnabledTag =
|
|
12
|
-
`injection_enabled:${getValueFromEnvSources('DD_INJECTION_ENABLED') ? 'yes' : 'no'}`
|
|
13
|
-
|
|
14
10
|
module.exports = class DdTraceApiPlugin extends Plugin {
|
|
15
11
|
static id = 'dd-trace-api'
|
|
16
12
|
|
|
@@ -18,6 +14,7 @@ module.exports = class DdTraceApiPlugin extends Plugin {
|
|
|
18
14
|
super(...args)
|
|
19
15
|
|
|
20
16
|
const tracer = this._tracer
|
|
17
|
+
const injectionEnabledTag = `injection_enabled:${this._tracerConfig.injectionEnabled ? 'yes' : 'no'}`
|
|
21
18
|
|
|
22
19
|
this.addSub('datadog-api:v1:tracerinit', ({ proxy }) => {
|
|
23
20
|
const proxyVal = proxy()
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { channel } = require('dc-polyfill')
|
|
4
|
+
const log = require('../log')
|
|
5
|
+
const AIGuard = require('./sdk')
|
|
6
|
+
|
|
7
|
+
const aiguardChannel = channel('dd-trace:ai:aiguard')
|
|
8
|
+
|
|
9
|
+
let isEnabled = false
|
|
10
|
+
let aiguard
|
|
11
|
+
let block
|
|
12
|
+
|
|
13
|
+
function enable (tracer, config) {
|
|
14
|
+
if (isEnabled) return
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
aiguard = new AIGuard(tracer, config)
|
|
18
|
+
block = config.experimental?.aiguard?.block !== false
|
|
19
|
+
|
|
20
|
+
aiguardChannel.subscribe(onEvaluate)
|
|
21
|
+
|
|
22
|
+
isEnabled = true
|
|
23
|
+
} catch (err) {
|
|
24
|
+
log.error('AIGuard: unexpected error during initialization: %s', err.message)
|
|
25
|
+
disable()
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function disable () {
|
|
30
|
+
if (!isEnabled) return
|
|
31
|
+
|
|
32
|
+
aiguardChannel.unsubscribe(onEvaluate)
|
|
33
|
+
|
|
34
|
+
aiguard = undefined
|
|
35
|
+
isEnabled = false
|
|
36
|
+
block = false
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Handles channel messages with pre-converted messages.
|
|
41
|
+
*
|
|
42
|
+
* @param {{messages: Array<object>, resolve: Function, reject: Function}} ctx
|
|
43
|
+
*/
|
|
44
|
+
function onEvaluate (ctx) {
|
|
45
|
+
if (!ctx.messages?.length) {
|
|
46
|
+
ctx.resolve()
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
aiguard.evaluate(ctx.messages, { block })
|
|
51
|
+
.then(() => {
|
|
52
|
+
ctx.resolve()
|
|
53
|
+
})
|
|
54
|
+
.catch(err => {
|
|
55
|
+
if (err.name === 'AIGuardAbortError') {
|
|
56
|
+
ctx.reject(err)
|
|
57
|
+
} else {
|
|
58
|
+
log.error('AIGuard: unexpected error during evaluation: %s', err.message)
|
|
59
|
+
ctx.resolve()
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
module.exports = { enable, disable }
|
|
@@ -5,10 +5,9 @@
|
|
|
5
5
|
const os = require('os')
|
|
6
6
|
const {
|
|
7
7
|
getEnvironmentVariable,
|
|
8
|
-
getEnvironmentVariables,
|
|
9
8
|
getValueFromEnvSources,
|
|
10
9
|
} = require('./config/helper')
|
|
11
|
-
const { getIsAzureFunction
|
|
10
|
+
const { getIsAzureFunction } = require('./serverless')
|
|
12
11
|
|
|
13
12
|
function extractSubscriptionID (ownerName) {
|
|
14
13
|
if (ownerName !== undefined) {
|
|
@@ -46,32 +45,33 @@ function trimObject (obj) {
|
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
function buildMetadata () {
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
} = getEnvironmentVariables()
|
|
48
|
+
const COMPUTERNAME = getEnvironmentVariable('COMPUTERNAME')
|
|
49
|
+
const FUNCTIONS_EXTENSION_VERSION = getEnvironmentVariable('FUNCTIONS_EXTENSION_VERSION')
|
|
50
|
+
const FUNCTIONS_WORKER_RUNTIME = getEnvironmentVariable('FUNCTIONS_WORKER_RUNTIME')
|
|
51
|
+
const FUNCTIONS_WORKER_RUNTIME_VERSION = getEnvironmentVariable('FUNCTIONS_WORKER_RUNTIME_VERSION')
|
|
52
|
+
const WEBSITE_INSTANCE_ID = getEnvironmentVariable('WEBSITE_INSTANCE_ID')
|
|
53
|
+
const WEBSITE_OWNER_NAME = getEnvironmentVariable('WEBSITE_OWNER_NAME')
|
|
54
|
+
const WEBSITE_OS = getEnvironmentVariable('WEBSITE_OS')
|
|
55
|
+
const WEBSITE_RESOURCE_GROUP = getEnvironmentVariable('WEBSITE_RESOURCE_GROUP')
|
|
56
|
+
const WEBSITE_SITE_NAME = getEnvironmentVariable('WEBSITE_SITE_NAME')
|
|
57
|
+
const WEBSITE_SKU = getEnvironmentVariable('WEBSITE_SKU')
|
|
60
58
|
|
|
61
59
|
const DD_AZURE_RESOURCE_GROUP = getValueFromEnvSources('DD_AZURE_RESOURCE_GROUP')
|
|
60
|
+
const isAzureFunction = FUNCTIONS_EXTENSION_VERSION !== undefined && FUNCTIONS_WORKER_RUNTIME !== undefined
|
|
61
|
+
const isFlexConsumptionAzureFunction = isAzureFunction && WEBSITE_SKU === 'FlexConsumption'
|
|
62
62
|
|
|
63
63
|
const subscriptionID = extractSubscriptionID(WEBSITE_OWNER_NAME)
|
|
64
64
|
|
|
65
65
|
const siteName = WEBSITE_SITE_NAME
|
|
66
66
|
|
|
67
|
-
const [siteKind, siteType] =
|
|
67
|
+
const [siteKind, siteType] = isAzureFunction
|
|
68
68
|
? ['functionapp', 'function']
|
|
69
69
|
: ['app', 'app']
|
|
70
70
|
|
|
71
71
|
// Azure Functions on Flex Consumption plans require the `DD_AZURE_RESOURCE_GROUP` env var.
|
|
72
72
|
// If this logic ever changes, update the logic in `libdatadog`, `serverless-components/src/datadog-trace-agent`,
|
|
73
73
|
// and the serverless compat layers accordingly.
|
|
74
|
-
const resourceGroup =
|
|
74
|
+
const resourceGroup = isFlexConsumptionAzureFunction
|
|
75
75
|
? (DD_AZURE_RESOURCE_GROUP ?? WEBSITE_RESOURCE_GROUP ?? extractResourceGroup(WEBSITE_OWNER_NAME))
|
|
76
76
|
: (WEBSITE_RESOURCE_GROUP ?? extractResourceGroup(WEBSITE_OWNER_NAME))
|
|
77
77
|
|