dd-trace 5.21.0 → 5.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-3rdparty.csv +2 -0
- package/index.d.ts +20 -8
- package/package.json +11 -5
- package/packages/datadog-instrumentations/src/aerospike.js +1 -1
- package/packages/datadog-instrumentations/src/apollo-server.js +1 -1
- package/packages/datadog-instrumentations/src/aws-sdk.js +4 -4
- package/packages/datadog-instrumentations/src/body-parser.js +4 -4
- package/packages/datadog-instrumentations/src/cassandra-driver.js +2 -2
- package/packages/datadog-instrumentations/src/child_process.js +2 -2
- package/packages/datadog-instrumentations/src/connect.js +4 -4
- package/packages/datadog-instrumentations/src/cookie-parser.js +4 -4
- package/packages/datadog-instrumentations/src/couchbase.js +12 -12
- package/packages/datadog-instrumentations/src/cucumber.js +294 -56
- package/packages/datadog-instrumentations/src/dns.js +10 -10
- package/packages/datadog-instrumentations/src/elasticsearch.js +4 -4
- package/packages/datadog-instrumentations/src/express-mongo-sanitize.js +3 -3
- package/packages/datadog-instrumentations/src/express.js +4 -4
- package/packages/datadog-instrumentations/src/fastify.js +6 -6
- package/packages/datadog-instrumentations/src/fetch.js +1 -1
- package/packages/datadog-instrumentations/src/find-my-way.js +2 -2
- package/packages/datadog-instrumentations/src/fs.js +2 -2
- package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +2 -2
- package/packages/datadog-instrumentations/src/grpc/client.js +4 -6
- package/packages/datadog-instrumentations/src/grpc/server.js +2 -2
- package/packages/datadog-instrumentations/src/hapi.js +10 -13
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/http/client.js +3 -3
- package/packages/datadog-instrumentations/src/jest.js +8 -5
- package/packages/datadog-instrumentations/src/kafkajs.js +67 -31
- package/packages/datadog-instrumentations/src/knex.js +2 -2
- package/packages/datadog-instrumentations/src/koa.js +5 -5
- package/packages/datadog-instrumentations/src/ldapjs.js +1 -1
- package/packages/datadog-instrumentations/src/mariadb.js +8 -8
- package/packages/datadog-instrumentations/src/memcached.js +2 -2
- package/packages/datadog-instrumentations/src/microgateway-core.js +7 -5
- package/packages/datadog-instrumentations/src/mocha/common.js +1 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +139 -53
- package/packages/datadog-instrumentations/src/mocha/utils.js +37 -18
- package/packages/datadog-instrumentations/src/mocha/worker.js +29 -1
- package/packages/datadog-instrumentations/src/mocha.js +4 -0
- package/packages/datadog-instrumentations/src/moleculer/server.js +2 -2
- package/packages/datadog-instrumentations/src/mongodb-core.js +7 -7
- package/packages/datadog-instrumentations/src/mongoose.js +5 -6
- package/packages/datadog-instrumentations/src/mysql.js +3 -3
- package/packages/datadog-instrumentations/src/mysql2.js +6 -6
- package/packages/datadog-instrumentations/src/net.js +2 -2
- package/packages/datadog-instrumentations/src/next.js +5 -5
- package/packages/datadog-instrumentations/src/openai.js +62 -71
- package/packages/datadog-instrumentations/src/oracledb.js +8 -8
- package/packages/datadog-instrumentations/src/passport-http.js +1 -1
- package/packages/datadog-instrumentations/src/passport-local.js +1 -1
- package/packages/datadog-instrumentations/src/passport-utils.js +1 -1
- package/packages/datadog-instrumentations/src/pg.js +60 -5
- package/packages/datadog-instrumentations/src/pino.js +4 -4
- package/packages/datadog-instrumentations/src/playwright.js +6 -4
- package/packages/datadog-instrumentations/src/redis.js +2 -2
- package/packages/datadog-instrumentations/src/restify.js +4 -4
- package/packages/datadog-instrumentations/src/rhea.js +4 -4
- package/packages/datadog-instrumentations/src/router.js +5 -5
- package/packages/datadog-instrumentations/src/sharedb.js +2 -2
- package/packages/datadog-instrumentations/src/vitest.js +188 -12
- package/packages/datadog-instrumentations/src/winston.js +2 -3
- package/packages/datadog-plugin-amqplib/src/consumer.js +1 -3
- package/packages/datadog-plugin-aws-sdk/src/base.js +33 -0
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +2 -0
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -1
- package/packages/datadog-plugin-cucumber/src/index.js +24 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +39 -10
- package/packages/datadog-plugin-cypress/src/support.js +4 -1
- package/packages/datadog-plugin-hapi/src/index.js +2 -2
- package/packages/datadog-plugin-http/src/client.js +1 -42
- package/packages/datadog-plugin-http2/src/client.js +1 -26
- package/packages/datadog-plugin-jest/src/index.js +18 -1
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +20 -0
- package/packages/datadog-plugin-kafkajs/src/consumer.js +1 -2
- package/packages/datadog-plugin-kafkajs/src/index.js +3 -1
- package/packages/datadog-plugin-mocha/src/index.js +18 -0
- package/packages/datadog-plugin-openai/src/index.js +85 -65
- package/packages/datadog-plugin-playwright/src/index.js +9 -0
- package/packages/datadog-plugin-rhea/src/consumer.js +1 -3
- package/packages/datadog-plugin-vitest/src/index.js +68 -3
- package/packages/datadog-shimmer/src/shimmer.js +144 -10
- package/packages/dd-trace/src/appsec/addresses.js +3 -1
- package/packages/dd-trace/src/appsec/blocking.js +23 -17
- package/packages/dd-trace/src/appsec/channels.js +4 -2
- package/packages/dd-trace/src/appsec/graphql.js +3 -1
- package/packages/dd-trace/src/appsec/iast/iast-log.js +2 -1
- package/packages/dd-trace/src/appsec/rasp/index.js +103 -0
- package/packages/dd-trace/src/appsec/rasp/sql_injection.js +86 -0
- package/packages/dd-trace/src/appsec/rasp/ssrf.js +37 -0
- package/packages/dd-trace/src/appsec/rasp/utils.js +63 -0
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -0
- package/packages/dd-trace/src/appsec/remote_config/index.js +16 -7
- package/packages/dd-trace/src/appsec/remote_config/manager.js +93 -52
- package/packages/dd-trace/src/appsec/rule_manager.js +8 -0
- package/packages/dd-trace/src/appsec/telemetry.js +3 -3
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +33 -14
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +2 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +4 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +15 -1
- package/packages/dd-trace/src/config.js +100 -40
- package/packages/dd-trace/src/constants.js +11 -1
- package/packages/dd-trace/src/data_streams_context.js +3 -0
- package/packages/dd-trace/src/datastreams/fnv.js +23 -0
- package/packages/dd-trace/src/datastreams/pathway.js +12 -5
- package/packages/dd-trace/src/datastreams/processor.js +35 -0
- package/packages/dd-trace/src/datastreams/schemas/schema.js +8 -0
- package/packages/dd-trace/src/datastreams/schemas/schema_builder.js +125 -0
- package/packages/dd-trace/src/datastreams/schemas/schema_sampler.js +29 -0
- package/packages/dd-trace/src/debugger/devtools_client/config.js +24 -0
- package/packages/dd-trace/src/debugger/devtools_client/index.js +57 -0
- package/packages/dd-trace/src/debugger/devtools_client/inspector_promises_polyfill.js +23 -0
- package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +164 -0
- package/packages/dd-trace/src/debugger/devtools_client/send.js +28 -0
- package/packages/dd-trace/src/debugger/devtools_client/session.js +7 -0
- package/packages/dd-trace/src/debugger/devtools_client/state.js +47 -0
- package/packages/dd-trace/src/debugger/devtools_client/status.js +109 -0
- package/packages/dd-trace/src/debugger/index.js +92 -0
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +29 -2
- package/packages/dd-trace/src/exporters/common/request.js +1 -1
- package/packages/dd-trace/src/lambda/handler.js +1 -0
- package/packages/dd-trace/src/lambda/index.js +12 -1
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +1 -6
- package/packages/dd-trace/src/payload-tagging/config/aws.json +30 -0
- package/packages/dd-trace/src/payload-tagging/config/index.js +30 -0
- package/packages/dd-trace/src/payload-tagging/index.js +93 -0
- package/packages/dd-trace/src/payload-tagging/tagging.js +83 -0
- package/packages/dd-trace/src/plugin_manager.js +11 -10
- package/packages/dd-trace/src/plugins/ci_plugin.js +33 -8
- package/packages/dd-trace/src/plugins/util/env.js +5 -2
- package/packages/dd-trace/src/plugins/util/test.js +24 -4
- package/packages/dd-trace/src/profiler.js +15 -5
- package/packages/dd-trace/src/profiling/config.js +7 -4
- package/packages/dd-trace/src/profiling/exporter_cli.js +13 -1
- package/packages/dd-trace/src/profiling/exporters/agent.js +8 -2
- package/packages/dd-trace/src/profiling/profiler.js +0 -9
- package/packages/dd-trace/src/profiling/profilers/event_plugins/dns.js +13 -0
- package/packages/dd-trace/src/profiling/profilers/event_plugins/dns_lookup.js +16 -0
- package/packages/dd-trace/src/profiling/profilers/event_plugins/dns_lookupservice.js +16 -0
- package/packages/dd-trace/src/profiling/profilers/event_plugins/dns_resolve.js +24 -0
- package/packages/dd-trace/src/profiling/profilers/event_plugins/dns_reverse.js +16 -0
- package/packages/dd-trace/src/profiling/profilers/event_plugins/event.js +48 -0
- package/packages/dd-trace/src/profiling/profilers/event_plugins/net.js +24 -0
- package/packages/dd-trace/src/profiling/profilers/events.js +108 -32
- package/packages/dd-trace/src/profiling/profilers/shared.js +5 -0
- package/packages/dd-trace/src/profiling/profilers/wall.js +9 -3
- package/packages/dd-trace/src/profiling/ssi-heuristics.js +59 -60
- package/packages/dd-trace/src/proxy.js +31 -24
- package/packages/dd-trace/src/span_stats.js +4 -2
- package/packages/dd-trace/src/telemetry/index.js +23 -6
- package/packages/dd-trace/src/telemetry/logs/index.js +20 -0
- package/packages/dd-trace/src/appsec/rasp.js +0 -176
|
@@ -58,7 +58,7 @@ class HttpClientPlugin extends ClientPlugin {
|
|
|
58
58
|
span._spanContext._trace.record = false
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
if (this.
|
|
61
|
+
if (this.config.propagationFilter(uri)) {
|
|
62
62
|
this.tracer.inject(span, HTTP_HEADERS, options.headers)
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -71,18 +71,6 @@ class HttpClientPlugin extends ClientPlugin {
|
|
|
71
71
|
return message.currentStore
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
shouldInjectTraceHeaders (options, uri) {
|
|
75
|
-
if (hasAmazonSignature(options) && !this.config.enablePropagationWithAmazonHeaders) {
|
|
76
|
-
return false
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (!this.config.propagationFilter(uri)) {
|
|
80
|
-
return false
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return true
|
|
84
|
-
}
|
|
85
|
-
|
|
86
74
|
bindAsyncStart ({ parentStore }) {
|
|
87
75
|
return parentStore
|
|
88
76
|
}
|
|
@@ -212,31 +200,6 @@ function getHooks (config) {
|
|
|
212
200
|
return { request }
|
|
213
201
|
}
|
|
214
202
|
|
|
215
|
-
function hasAmazonSignature (options) {
|
|
216
|
-
if (!options) {
|
|
217
|
-
return false
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (options.headers) {
|
|
221
|
-
const headers = Object.keys(options.headers)
|
|
222
|
-
.reduce((prev, next) => Object.assign(prev, {
|
|
223
|
-
[next.toLowerCase()]: options.headers[next]
|
|
224
|
-
}), {})
|
|
225
|
-
|
|
226
|
-
if (headers['x-amz-signature']) {
|
|
227
|
-
return true
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if ([].concat(headers.authorization).some(startsWith('AWS4-HMAC-SHA256'))) {
|
|
231
|
-
return true
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const search = options.search || options.path
|
|
236
|
-
|
|
237
|
-
return search && search.toLowerCase().indexOf('x-amz-signature=') !== -1
|
|
238
|
-
}
|
|
239
|
-
|
|
240
203
|
function extractSessionDetails (options) {
|
|
241
204
|
if (typeof options === 'string') {
|
|
242
205
|
return new URL(options).host
|
|
@@ -248,8 +211,4 @@ function extractSessionDetails (options) {
|
|
|
248
211
|
return { host, port }
|
|
249
212
|
}
|
|
250
213
|
|
|
251
|
-
function startsWith (searchString) {
|
|
252
|
-
return value => String(value).startsWith(searchString)
|
|
253
|
-
}
|
|
254
|
-
|
|
255
214
|
module.exports = HttpClientPlugin
|
|
@@ -62,9 +62,7 @@ class Http2ClientPlugin extends ClientPlugin {
|
|
|
62
62
|
|
|
63
63
|
addHeaderTags(span, headers, HTTP_REQUEST_HEADERS, this.config)
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
this.tracer.inject(span, HTTP_HEADERS, headers)
|
|
67
|
-
}
|
|
65
|
+
this.tracer.inject(span, HTTP_HEADERS, headers)
|
|
68
66
|
|
|
69
67
|
message.parentStore = store
|
|
70
68
|
message.currentStore = { ...store, span }
|
|
@@ -134,29 +132,6 @@ function extractSessionDetails (authority, options) {
|
|
|
134
132
|
return { protocol, port, host }
|
|
135
133
|
}
|
|
136
134
|
|
|
137
|
-
function hasAmazonSignature (headers, path) {
|
|
138
|
-
if (headers) {
|
|
139
|
-
headers = Object.keys(headers)
|
|
140
|
-
.reduce((prev, next) => Object.assign(prev, {
|
|
141
|
-
[next.toLowerCase()]: headers[next]
|
|
142
|
-
}), {})
|
|
143
|
-
|
|
144
|
-
if (headers['x-amz-signature']) {
|
|
145
|
-
return true
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if ([].concat(headers.authorization).some(startsWith('AWS4-HMAC-SHA256'))) {
|
|
149
|
-
return true
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return path && path.toLowerCase().indexOf('x-amz-signature=') !== -1
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function startsWith (searchString) {
|
|
157
|
-
return value => String(value).startsWith(searchString)
|
|
158
|
-
}
|
|
159
|
-
|
|
160
135
|
function getStatusValidator (config) {
|
|
161
136
|
if (typeof config.validateStatus === 'function') {
|
|
162
137
|
return config.validateStatus
|
|
@@ -154,10 +154,17 @@ class JestPlugin extends CiPlugin {
|
|
|
154
154
|
config._ddEarlyFlakeDetectionNumRetries = this.libraryConfig?.earlyFlakeDetectionNumRetries ?? 0
|
|
155
155
|
config._ddRepositoryRoot = this.repositoryRoot
|
|
156
156
|
config._ddIsFlakyTestRetriesEnabled = this.libraryConfig?.isFlakyTestRetriesEnabled ?? false
|
|
157
|
+
config._ddFlakyTestRetriesCount = this.libraryConfig?.flakyTestRetriesCount
|
|
157
158
|
})
|
|
158
159
|
})
|
|
159
160
|
|
|
160
|
-
this.addSub('ci:jest:test-suite:start', ({
|
|
161
|
+
this.addSub('ci:jest:test-suite:start', ({
|
|
162
|
+
testSuite,
|
|
163
|
+
testSourceFile,
|
|
164
|
+
testEnvironmentOptions,
|
|
165
|
+
frameworkVersion,
|
|
166
|
+
displayName
|
|
167
|
+
}) => {
|
|
161
168
|
const {
|
|
162
169
|
_ddTestSessionId: testSessionId,
|
|
163
170
|
_ddTestCommand: testCommand,
|
|
@@ -195,6 +202,16 @@ class JestPlugin extends CiPlugin {
|
|
|
195
202
|
if (displayName) {
|
|
196
203
|
testSuiteMetadata[JEST_DISPLAY_NAME] = displayName
|
|
197
204
|
}
|
|
205
|
+
if (testSourceFile) {
|
|
206
|
+
testSuiteMetadata[TEST_SOURCE_FILE] = testSourceFile
|
|
207
|
+
// Test suite is the whole test file, so we can use the first line as the start
|
|
208
|
+
testSuiteMetadata[TEST_SOURCE_START] = 1
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const codeOwners = this.getCodeOwners(testSuiteMetadata)
|
|
212
|
+
if (codeOwners) {
|
|
213
|
+
testSuiteMetadata[TEST_CODE_OWNERS] = codeOwners
|
|
214
|
+
}
|
|
198
215
|
|
|
199
216
|
this.testSuiteSpan = this.tracer.startSpan('jest.test_suite', {
|
|
200
217
|
childOf: testSessionSpanContext,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const ConsumerPlugin = require('../../dd-trace/src/plugins/consumer')
|
|
2
|
+
const { getMessageSize } = require('../../dd-trace/src/datastreams/processor')
|
|
3
|
+
|
|
4
|
+
class KafkajsBatchConsumerPlugin extends ConsumerPlugin {
|
|
5
|
+
static get id () { return 'kafkajs' }
|
|
6
|
+
static get operation () { return 'consume-batch' }
|
|
7
|
+
|
|
8
|
+
start ({ topic, partition, messages, groupId }) {
|
|
9
|
+
if (!this.config.dsmEnabled) return
|
|
10
|
+
for (const message of messages) {
|
|
11
|
+
if (!message || !message.headers) continue
|
|
12
|
+
const payloadSize = getMessageSize(message)
|
|
13
|
+
this.tracer.decodeDataStreamsContext(message.headers)
|
|
14
|
+
this.tracer
|
|
15
|
+
.setCheckpoint(['direction:in', `group:${groupId}`, `topic:${topic}`, 'type:kafka'], null, payloadSize)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = KafkajsBatchConsumerPlugin
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const dc = require('dc-polyfill')
|
|
4
4
|
const { getMessageSize } = require('../../dd-trace/src/datastreams/processor')
|
|
5
|
-
const { DsmPathwayCodec } = require('../../dd-trace/src/datastreams/pathway')
|
|
6
5
|
const ConsumerPlugin = require('../../dd-trace/src/plugins/consumer')
|
|
7
6
|
|
|
8
7
|
const afterStartCh = dc.channel('dd-trace:kafkajs:consumer:afterStart')
|
|
@@ -78,7 +77,7 @@ class KafkajsConsumerPlugin extends ConsumerPlugin {
|
|
|
78
77
|
'kafka.partition': partition
|
|
79
78
|
}
|
|
80
79
|
})
|
|
81
|
-
if (this.config.dsmEnabled && message?.headers
|
|
80
|
+
if (this.config.dsmEnabled && message?.headers) {
|
|
82
81
|
const payloadSize = getMessageSize(message)
|
|
83
82
|
this.tracer.decodeDataStreamsContext(message.headers)
|
|
84
83
|
this.tracer
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const ProducerPlugin = require('./producer')
|
|
4
4
|
const ConsumerPlugin = require('./consumer')
|
|
5
|
+
const BatchConsumerPlugin = require('./batch-consumer')
|
|
5
6
|
const CompositePlugin = require('../../dd-trace/src/plugins/composite')
|
|
6
7
|
|
|
7
8
|
class KafkajsPlugin extends CompositePlugin {
|
|
@@ -9,7 +10,8 @@ class KafkajsPlugin extends CompositePlugin {
|
|
|
9
10
|
static get plugins () {
|
|
10
11
|
return {
|
|
11
12
|
producer: ProducerPlugin,
|
|
12
|
-
consumer: ConsumerPlugin
|
|
13
|
+
consumer: ConsumerPlugin,
|
|
14
|
+
batchConsumer: BatchConsumerPlugin
|
|
13
15
|
}
|
|
14
16
|
}
|
|
15
17
|
}
|
|
@@ -21,6 +21,7 @@ const {
|
|
|
21
21
|
TEST_IS_NEW,
|
|
22
22
|
TEST_IS_RETRY,
|
|
23
23
|
TEST_EARLY_FLAKE_ENABLED,
|
|
24
|
+
TEST_EARLY_FLAKE_ABORT_REASON,
|
|
24
25
|
TEST_SESSION_ID,
|
|
25
26
|
TEST_MODULE_ID,
|
|
26
27
|
TEST_MODULE,
|
|
@@ -124,6 +125,19 @@ class MochaPlugin extends CiPlugin {
|
|
|
124
125
|
testSuiteMetadata[TEST_ITR_FORCED_RUN] = 'true'
|
|
125
126
|
this.telemetry.count(TELEMETRY_ITR_FORCED_TO_RUN, { testLevel: 'suite' })
|
|
126
127
|
}
|
|
128
|
+
if (this.repositoryRoot !== this.sourceRoot && !!this.repositoryRoot) {
|
|
129
|
+
testSuiteMetadata[TEST_SOURCE_FILE] = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
|
|
130
|
+
} else {
|
|
131
|
+
testSuiteMetadata[TEST_SOURCE_FILE] = testSuite
|
|
132
|
+
}
|
|
133
|
+
if (testSuiteMetadata[TEST_SOURCE_FILE]) {
|
|
134
|
+
testSuiteMetadata[TEST_SOURCE_START] = 1
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const codeOwners = this.getCodeOwners(testSuiteMetadata)
|
|
138
|
+
if (codeOwners) {
|
|
139
|
+
testSuiteMetadata[TEST_CODE_OWNERS] = codeOwners
|
|
140
|
+
}
|
|
127
141
|
|
|
128
142
|
const testSuiteSpan = this.tracer.startSpan('mocha.test_suite', {
|
|
129
143
|
childOf: this.testModuleSpan,
|
|
@@ -267,6 +281,7 @@ class MochaPlugin extends CiPlugin {
|
|
|
267
281
|
hasUnskippableSuites,
|
|
268
282
|
error,
|
|
269
283
|
isEarlyFlakeDetectionEnabled,
|
|
284
|
+
isEarlyFlakeDetectionFaulty,
|
|
270
285
|
isParallel
|
|
271
286
|
}) => {
|
|
272
287
|
if (this.testSessionSpan) {
|
|
@@ -301,6 +316,9 @@ class MochaPlugin extends CiPlugin {
|
|
|
301
316
|
if (isEarlyFlakeDetectionEnabled) {
|
|
302
317
|
this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ENABLED, 'true')
|
|
303
318
|
}
|
|
319
|
+
if (isEarlyFlakeDetectionFaulty) {
|
|
320
|
+
this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ABORT_REASON, 'faulty')
|
|
321
|
+
}
|
|
304
322
|
|
|
305
323
|
this.testModuleSpan.finish()
|
|
306
324
|
this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'module')
|
|
@@ -31,6 +31,9 @@ class OpenApiPlugin extends TracingPlugin {
|
|
|
31
31
|
static get id () { return 'openai' }
|
|
32
32
|
static get operation () { return 'request' }
|
|
33
33
|
static get system () { return 'openai' }
|
|
34
|
+
static get prefix () {
|
|
35
|
+
return 'tracing:apm:openai:request'
|
|
36
|
+
}
|
|
34
37
|
|
|
35
38
|
constructor (...args) {
|
|
36
39
|
super(...args)
|
|
@@ -55,8 +58,10 @@ class OpenApiPlugin extends TracingPlugin {
|
|
|
55
58
|
super.configure(config)
|
|
56
59
|
}
|
|
57
60
|
|
|
58
|
-
|
|
61
|
+
bindStart (ctx) {
|
|
62
|
+
const { methodName, args, basePath, apiKey } = ctx
|
|
59
63
|
const payload = normalizeRequestPayload(methodName, args)
|
|
64
|
+
const store = storage.getStore() || {}
|
|
60
65
|
|
|
61
66
|
const span = this.startSpan('openai.request', {
|
|
62
67
|
service: this.config.service,
|
|
@@ -87,18 +92,16 @@ class OpenApiPlugin extends TracingPlugin {
|
|
|
87
92
|
'openai.request.user': payload.user,
|
|
88
93
|
'openai.request.file_id': payload.file_id // deleteFile, retrieveFile, downloadFile
|
|
89
94
|
}
|
|
90
|
-
})
|
|
95
|
+
}, false)
|
|
91
96
|
|
|
92
|
-
const
|
|
93
|
-
const store = Object.create(null)
|
|
94
|
-
fullStore.openai = store // namespacing these fields
|
|
97
|
+
const openaiStore = Object.create(null)
|
|
95
98
|
|
|
96
99
|
const tags = {} // The remaining tags are added one at a time
|
|
97
100
|
|
|
98
101
|
// createChatCompletion, createCompletion, createImage, createImageEdit, createTranscription, createTranslation
|
|
99
102
|
if (payload.prompt) {
|
|
100
103
|
const prompt = payload.prompt
|
|
101
|
-
|
|
104
|
+
openaiStore.prompt = prompt
|
|
102
105
|
if (typeof prompt === 'string' || (Array.isArray(prompt) && typeof prompt[0] === 'number')) {
|
|
103
106
|
// This is a single prompt, either String or [Number]
|
|
104
107
|
tags['openai.request.prompt'] = normalizeStringOrTokenArray(prompt, true)
|
|
@@ -114,7 +117,7 @@ class OpenApiPlugin extends TracingPlugin {
|
|
|
114
117
|
if (payload.input) {
|
|
115
118
|
const normalized = normalizeStringOrTokenArray(payload.input, false)
|
|
116
119
|
tags['openai.request.input'] = truncateText(normalized)
|
|
117
|
-
|
|
120
|
+
openaiStore.input = normalized
|
|
118
121
|
}
|
|
119
122
|
|
|
120
123
|
// createChatCompletion, createCompletion
|
|
@@ -141,12 +144,12 @@ class OpenApiPlugin extends TracingPlugin {
|
|
|
141
144
|
case 'images.edit':
|
|
142
145
|
case 'createImageVariation':
|
|
143
146
|
case 'images.createVariation':
|
|
144
|
-
commonCreateImageRequestExtraction(tags, payload,
|
|
147
|
+
commonCreateImageRequestExtraction(tags, payload, openaiStore)
|
|
145
148
|
break
|
|
146
149
|
|
|
147
150
|
case 'createChatCompletion':
|
|
148
151
|
case 'chat.completions.create':
|
|
149
|
-
createChatCompletionRequestExtraction(tags, payload,
|
|
152
|
+
createChatCompletionRequestExtraction(tags, payload, openaiStore)
|
|
150
153
|
break
|
|
151
154
|
|
|
152
155
|
case 'createFile':
|
|
@@ -160,7 +163,7 @@ class OpenApiPlugin extends TracingPlugin {
|
|
|
160
163
|
case 'audio.transcriptions.create':
|
|
161
164
|
case 'createTranslation':
|
|
162
165
|
case 'audio.translations.create':
|
|
163
|
-
commonCreateAudioRequestExtraction(tags, payload,
|
|
166
|
+
commonCreateAudioRequestExtraction(tags, payload, openaiStore)
|
|
164
167
|
break
|
|
165
168
|
|
|
166
169
|
case 'retrieveModel':
|
|
@@ -184,23 +187,32 @@ class OpenApiPlugin extends TracingPlugin {
|
|
|
184
187
|
|
|
185
188
|
case 'createEdit':
|
|
186
189
|
case 'edits.create':
|
|
187
|
-
createEditRequestExtraction(tags, payload,
|
|
190
|
+
createEditRequestExtraction(tags, payload, openaiStore)
|
|
188
191
|
break
|
|
189
192
|
}
|
|
190
193
|
|
|
191
194
|
span.addTags(tags)
|
|
195
|
+
|
|
196
|
+
ctx.currentStore = { ...store, span, openai: openaiStore }
|
|
197
|
+
|
|
198
|
+
return ctx.currentStore
|
|
192
199
|
}
|
|
193
200
|
|
|
194
|
-
|
|
195
|
-
const
|
|
201
|
+
asyncEnd (ctx) {
|
|
202
|
+
const { result } = ctx
|
|
203
|
+
const store = ctx.currentStore
|
|
204
|
+
|
|
205
|
+
const span = store?.span
|
|
206
|
+
if (!span) return
|
|
207
|
+
|
|
196
208
|
const error = !!span.context()._tags.error
|
|
197
209
|
|
|
198
210
|
let headers, body, method, path
|
|
199
211
|
if (!error) {
|
|
200
|
-
headers =
|
|
201
|
-
body =
|
|
202
|
-
method =
|
|
203
|
-
path =
|
|
212
|
+
headers = result.headers
|
|
213
|
+
body = result.data
|
|
214
|
+
method = result.request.method
|
|
215
|
+
path = result.request.path
|
|
204
216
|
}
|
|
205
217
|
|
|
206
218
|
if (!error && headers?.constructor.name === 'Headers') {
|
|
@@ -210,10 +222,9 @@ class OpenApiPlugin extends TracingPlugin {
|
|
|
210
222
|
|
|
211
223
|
body = coerceResponseBody(body, methodName)
|
|
212
224
|
|
|
213
|
-
const
|
|
214
|
-
const store = fullStore.openai
|
|
225
|
+
const openaiStore = store.openai
|
|
215
226
|
|
|
216
|
-
if (!error && (path
|
|
227
|
+
if (!error && (path?.startsWith('https://') || path?.startsWith('http://'))) {
|
|
217
228
|
// basic checking for if the path was set as a full URL
|
|
218
229
|
// not using a full regex as it will likely be "https://api.openai.com/..."
|
|
219
230
|
path = new URL(path).pathname
|
|
@@ -239,11 +250,11 @@ class OpenApiPlugin extends TracingPlugin {
|
|
|
239
250
|
'openai.response.created_at': body.created_at
|
|
240
251
|
}
|
|
241
252
|
|
|
242
|
-
responseDataExtractionByMethod(methodName, tags, body,
|
|
253
|
+
responseDataExtractionByMethod(methodName, tags, body, openaiStore)
|
|
243
254
|
span.addTags(tags)
|
|
244
255
|
|
|
245
|
-
|
|
246
|
-
this.sendLog(methodName, span, tags,
|
|
256
|
+
span.finish()
|
|
257
|
+
this.sendLog(methodName, span, tags, openaiStore, error)
|
|
247
258
|
this.sendMetrics(headers, body, endpoint, span._duration, error, tags)
|
|
248
259
|
}
|
|
249
260
|
|
|
@@ -265,25 +276,34 @@ class OpenApiPlugin extends TracingPlugin {
|
|
|
265
276
|
const completionTokens = spanTags['openai.response.usage.completion_tokens']
|
|
266
277
|
const completionTokensEstimated = spanTags['openai.response.usage.completion_tokens_estimated']
|
|
267
278
|
|
|
279
|
+
const totalTokens = spanTags['openai.response.usage.total_tokens']
|
|
280
|
+
|
|
268
281
|
if (!error) {
|
|
269
|
-
if (
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
282
|
+
if (promptTokens != null) {
|
|
283
|
+
if (promptTokensEstimated) {
|
|
284
|
+
this.metrics.distribution(
|
|
285
|
+
'openai.tokens.prompt', promptTokens, [...tags, 'openai.estimated:true'])
|
|
286
|
+
} else {
|
|
287
|
+
this.metrics.distribution('openai.tokens.prompt', promptTokens, tags)
|
|
288
|
+
}
|
|
274
289
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
290
|
+
|
|
291
|
+
if (completionTokens != null) {
|
|
292
|
+
if (completionTokensEstimated) {
|
|
293
|
+
this.metrics.distribution(
|
|
294
|
+
'openai.tokens.completion', completionTokens, [...tags, 'openai.estimated:true'])
|
|
295
|
+
} else {
|
|
296
|
+
this.metrics.distribution('openai.tokens.completion', completionTokens, tags)
|
|
297
|
+
}
|
|
280
298
|
}
|
|
281
299
|
|
|
282
|
-
if (
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
300
|
+
if (totalTokens != null) {
|
|
301
|
+
if (promptTokensEstimated || completionTokensEstimated) {
|
|
302
|
+
this.metrics.distribution(
|
|
303
|
+
'openai.tokens.total', totalTokens, [...tags, 'openai.estimated:true'])
|
|
304
|
+
} else {
|
|
305
|
+
this.metrics.distribution('openai.tokens.total', totalTokens, tags)
|
|
306
|
+
}
|
|
287
307
|
}
|
|
288
308
|
}
|
|
289
309
|
|
|
@@ -308,15 +328,15 @@ class OpenApiPlugin extends TracingPlugin {
|
|
|
308
328
|
}
|
|
309
329
|
}
|
|
310
330
|
|
|
311
|
-
sendLog (methodName, span, tags,
|
|
312
|
-
if (!
|
|
313
|
-
if (!Object.keys(
|
|
331
|
+
sendLog (methodName, span, tags, openaiStore, error) {
|
|
332
|
+
if (!openaiStore) return
|
|
333
|
+
if (!Object.keys(openaiStore).length) return
|
|
314
334
|
if (!this.sampler.isSampled()) return
|
|
315
335
|
|
|
316
336
|
const log = {
|
|
317
337
|
status: error ? 'error' : 'info',
|
|
318
338
|
message: `sampled ${methodName}`,
|
|
319
|
-
...
|
|
339
|
+
...openaiStore
|
|
320
340
|
}
|
|
321
341
|
|
|
322
342
|
this.logger.log(log, span, tags)
|
|
@@ -400,21 +420,21 @@ function countTokens (content, model) {
|
|
|
400
420
|
}
|
|
401
421
|
}
|
|
402
422
|
|
|
403
|
-
function createEditRequestExtraction (tags, payload,
|
|
423
|
+
function createEditRequestExtraction (tags, payload, openaiStore) {
|
|
404
424
|
const instruction = payload.instruction
|
|
405
425
|
tags['openai.request.instruction'] = instruction
|
|
406
|
-
|
|
426
|
+
openaiStore.instruction = instruction
|
|
407
427
|
}
|
|
408
428
|
|
|
409
429
|
function retrieveModelRequestExtraction (tags, payload) {
|
|
410
430
|
tags['openai.request.id'] = payload.id
|
|
411
431
|
}
|
|
412
432
|
|
|
413
|
-
function createChatCompletionRequestExtraction (tags, payload,
|
|
433
|
+
function createChatCompletionRequestExtraction (tags, payload, openaiStore) {
|
|
414
434
|
const messages = payload.messages
|
|
415
435
|
if (!defensiveArrayLength(messages)) return
|
|
416
436
|
|
|
417
|
-
|
|
437
|
+
openaiStore.messages = payload.messages
|
|
418
438
|
for (let i = 0; i < payload.messages.length; i++) {
|
|
419
439
|
const message = payload.messages[i]
|
|
420
440
|
tagChatCompletionRequestContent(message.content, i, tags)
|
|
@@ -424,20 +444,20 @@ function createChatCompletionRequestExtraction (tags, payload, store) {
|
|
|
424
444
|
}
|
|
425
445
|
}
|
|
426
446
|
|
|
427
|
-
function commonCreateImageRequestExtraction (tags, payload,
|
|
447
|
+
function commonCreateImageRequestExtraction (tags, payload, openaiStore) {
|
|
428
448
|
// createImageEdit, createImageVariation
|
|
429
449
|
const img = payload.file || payload.image
|
|
430
450
|
if (img !== null && typeof img === 'object' && img.path) {
|
|
431
451
|
const file = path.basename(img.path)
|
|
432
452
|
tags['openai.request.image'] = file
|
|
433
|
-
|
|
453
|
+
openaiStore.file = file
|
|
434
454
|
}
|
|
435
455
|
|
|
436
456
|
// createImageEdit
|
|
437
457
|
if (payload.mask !== null && typeof payload.mask === 'object' && payload.mask.path) {
|
|
438
458
|
const mask = path.basename(payload.mask.path)
|
|
439
459
|
tags['openai.request.mask'] = mask
|
|
440
|
-
|
|
460
|
+
openaiStore.mask = mask
|
|
441
461
|
}
|
|
442
462
|
|
|
443
463
|
tags['openai.request.size'] = payload.size
|
|
@@ -445,7 +465,7 @@ function commonCreateImageRequestExtraction (tags, payload, store) {
|
|
|
445
465
|
tags['openai.request.language'] = payload.language
|
|
446
466
|
}
|
|
447
467
|
|
|
448
|
-
function responseDataExtractionByMethod (methodName, tags, body,
|
|
468
|
+
function responseDataExtractionByMethod (methodName, tags, body, openaiStore) {
|
|
449
469
|
switch (methodName) {
|
|
450
470
|
case 'createModeration':
|
|
451
471
|
case 'moderations.create':
|
|
@@ -458,7 +478,7 @@ function responseDataExtractionByMethod (methodName, tags, body, store) {
|
|
|
458
478
|
case 'chat.completions.create':
|
|
459
479
|
case 'createEdit':
|
|
460
480
|
case 'edits.create':
|
|
461
|
-
commonCreateResponseExtraction(tags, body,
|
|
481
|
+
commonCreateResponseExtraction(tags, body, openaiStore, methodName)
|
|
462
482
|
break
|
|
463
483
|
|
|
464
484
|
case 'listFiles':
|
|
@@ -474,7 +494,7 @@ function responseDataExtractionByMethod (methodName, tags, body, store) {
|
|
|
474
494
|
|
|
475
495
|
case 'createEmbedding':
|
|
476
496
|
case 'embeddings.create':
|
|
477
|
-
createEmbeddingResponseExtraction(tags, body)
|
|
497
|
+
createEmbeddingResponseExtraction(tags, body, openaiStore)
|
|
478
498
|
break
|
|
479
499
|
|
|
480
500
|
case 'createFile':
|
|
@@ -629,14 +649,14 @@ function deleteFileResponseExtraction (tags, body) {
|
|
|
629
649
|
tags['openai.response.id'] = body.id
|
|
630
650
|
}
|
|
631
651
|
|
|
632
|
-
function commonCreateAudioRequestExtraction (tags, body,
|
|
652
|
+
function commonCreateAudioRequestExtraction (tags, body, openaiStore) {
|
|
633
653
|
tags['openai.request.response_format'] = body.response_format
|
|
634
654
|
tags['openai.request.language'] = body.language
|
|
635
655
|
|
|
636
656
|
if (body.file !== null && typeof body.file === 'object' && body.file.path) {
|
|
637
657
|
const filename = path.basename(body.file.path)
|
|
638
658
|
tags['openai.request.filename'] = filename
|
|
639
|
-
|
|
659
|
+
openaiStore.file = filename
|
|
640
660
|
}
|
|
641
661
|
}
|
|
642
662
|
|
|
@@ -659,8 +679,8 @@ function createRetrieveFileResponseExtraction (tags, body) {
|
|
|
659
679
|
tags['openai.response.status_details'] = body.status_details
|
|
660
680
|
}
|
|
661
681
|
|
|
662
|
-
function createEmbeddingResponseExtraction (tags, body) {
|
|
663
|
-
usageExtraction(tags, body)
|
|
682
|
+
function createEmbeddingResponseExtraction (tags, body, openaiStore) {
|
|
683
|
+
usageExtraction(tags, body, openaiStore)
|
|
664
684
|
|
|
665
685
|
if (!body.data) return
|
|
666
686
|
|
|
@@ -694,14 +714,14 @@ function createModerationResponseExtraction (tags, body) {
|
|
|
694
714
|
}
|
|
695
715
|
|
|
696
716
|
// createCompletion, createChatCompletion, createEdit
|
|
697
|
-
function commonCreateResponseExtraction (tags, body,
|
|
698
|
-
usageExtraction(tags, body, methodName)
|
|
717
|
+
function commonCreateResponseExtraction (tags, body, openaiStore, methodName) {
|
|
718
|
+
usageExtraction(tags, body, methodName, openaiStore)
|
|
699
719
|
|
|
700
720
|
if (!body.choices) return
|
|
701
721
|
|
|
702
722
|
tags['openai.response.choices_count'] = body.choices.length
|
|
703
723
|
|
|
704
|
-
|
|
724
|
+
openaiStore.choices = body.choices
|
|
705
725
|
|
|
706
726
|
for (let choiceIdx = 0; choiceIdx < body.choices.length; choiceIdx++) {
|
|
707
727
|
const choice = body.choices[choiceIdx]
|
|
@@ -735,7 +755,7 @@ function commonCreateResponseExtraction (tags, body, store, methodName) {
|
|
|
735
755
|
}
|
|
736
756
|
|
|
737
757
|
// createCompletion, createChatCompletion, createEdit, createEmbedding
|
|
738
|
-
function usageExtraction (tags, body, methodName) {
|
|
758
|
+
function usageExtraction (tags, body, methodName, openaiStore) {
|
|
739
759
|
let promptTokens = 0
|
|
740
760
|
let completionTokens = 0
|
|
741
761
|
let totalTokens = 0
|
|
@@ -743,14 +763,14 @@ function usageExtraction (tags, body, methodName) {
|
|
|
743
763
|
promptTokens = body.usage.prompt_tokens
|
|
744
764
|
completionTokens = body.usage.completion_tokens
|
|
745
765
|
totalTokens = body.usage.total_tokens
|
|
746
|
-
} else if (['chat.completions.create', 'completions.create'].includes(methodName)) {
|
|
766
|
+
} else if (body.model && ['chat.completions.create', 'completions.create'].includes(methodName)) {
|
|
747
767
|
// estimate tokens based on method name for completions and chat completions
|
|
748
768
|
const { model } = body
|
|
749
769
|
let promptEstimated = false
|
|
750
770
|
let completionEstimated = false
|
|
751
771
|
|
|
752
772
|
// prompt tokens
|
|
753
|
-
const payload =
|
|
773
|
+
const payload = openaiStore
|
|
754
774
|
const promptTokensCount = countPromptTokens(methodName, payload, model)
|
|
755
775
|
promptTokens = promptTokensCount.promptTokens
|
|
756
776
|
promptEstimated = promptTokensCount.promptEstimated
|
|
@@ -766,9 +786,9 @@ function usageExtraction (tags, body, methodName) {
|
|
|
766
786
|
if (completionEstimated) tags['openai.response.usage.completion_tokens_estimated'] = true
|
|
767
787
|
}
|
|
768
788
|
|
|
769
|
-
if (promptTokens) tags['openai.response.usage.prompt_tokens'] = promptTokens
|
|
770
|
-
if (completionTokens) tags['openai.response.usage.completion_tokens'] = completionTokens
|
|
771
|
-
if (totalTokens) tags['openai.response.usage.total_tokens'] = totalTokens
|
|
789
|
+
if (promptTokens != null) tags['openai.response.usage.prompt_tokens'] = promptTokens
|
|
790
|
+
if (completionTokens != null) tags['openai.response.usage.completion_tokens'] = completionTokens
|
|
791
|
+
if (totalTokens != null) tags['openai.response.usage.total_tokens'] = totalTokens
|
|
772
792
|
}
|
|
773
793
|
|
|
774
794
|
function truncateApiKey (apiKey) {
|
|
@@ -69,6 +69,7 @@ class PlaywrightPlugin extends CiPlugin {
|
|
|
69
69
|
this.addSub('ci:playwright:test-suite:start', (testSuiteAbsolutePath) => {
|
|
70
70
|
const store = storage.getStore()
|
|
71
71
|
const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.rootDir)
|
|
72
|
+
const testSourceFile = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
|
|
72
73
|
|
|
73
74
|
const testSuiteMetadata = getTestSuiteCommonTags(
|
|
74
75
|
this.command,
|
|
@@ -76,6 +77,14 @@ class PlaywrightPlugin extends CiPlugin {
|
|
|
76
77
|
testSuite,
|
|
77
78
|
'playwright'
|
|
78
79
|
)
|
|
80
|
+
if (testSourceFile) {
|
|
81
|
+
testSuiteMetadata[TEST_SOURCE_FILE] = testSourceFile
|
|
82
|
+
testSuiteMetadata[TEST_SOURCE_START] = 1
|
|
83
|
+
}
|
|
84
|
+
const codeOwners = this.getCodeOwners(testSuiteMetadata)
|
|
85
|
+
if (codeOwners) {
|
|
86
|
+
testSuiteMetadata[TEST_CODE_OWNERS] = codeOwners
|
|
87
|
+
}
|
|
79
88
|
|
|
80
89
|
const testSuiteSpan = this.tracer.startSpan('playwright.test_suite', {
|
|
81
90
|
childOf: this.testModuleSpan,
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
const ConsumerPlugin = require('../../dd-trace/src/plugins/consumer')
|
|
4
4
|
const { storage } = require('../../datadog-core')
|
|
5
5
|
const { getAmqpMessageSize } = require('../../dd-trace/src/datastreams/processor')
|
|
6
|
-
const { DsmPathwayCodec } = require('../../dd-trace/src/datastreams/pathway')
|
|
7
6
|
|
|
8
7
|
class RheaConsumerPlugin extends ConsumerPlugin {
|
|
9
8
|
static get id () { return 'rhea' }
|
|
@@ -34,8 +33,7 @@ class RheaConsumerPlugin extends ConsumerPlugin {
|
|
|
34
33
|
|
|
35
34
|
if (
|
|
36
35
|
this.config.dsmEnabled &&
|
|
37
|
-
msgObj?.message?.delivery_annotations
|
|
38
|
-
DsmPathwayCodec.contextExists(msgObj.message.delivery_annotations)
|
|
36
|
+
msgObj?.message?.delivery_annotations
|
|
39
37
|
) {
|
|
40
38
|
const payloadSize = getAmqpMessageSize(
|
|
41
39
|
{ headers: msgObj.message.delivery_annotations, content: msgObj.message.body }
|