dd-trace 5.104.0 → 5.105.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 +90 -102
- package/index.d.ts +82 -3
- package/package.json +15 -15
- package/packages/datadog-core/src/storage.js +1 -1
- package/packages/datadog-instrumentations/src/aerospike.js +1 -1
- package/packages/datadog-instrumentations/src/ai.js +8 -7
- package/packages/datadog-instrumentations/src/aws-sdk.js +13 -0
- package/packages/datadog-instrumentations/src/azure-cosmos.js +7 -0
- package/packages/datadog-instrumentations/src/azure-functions.js +3 -0
- package/packages/datadog-instrumentations/src/cucumber.js +78 -5
- package/packages/datadog-instrumentations/src/dns.js +54 -18
- package/packages/datadog-instrumentations/src/fastify.js +142 -82
- package/packages/datadog-instrumentations/src/graphql.js +188 -62
- package/packages/datadog-instrumentations/src/helpers/ai-messages.js +322 -14
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/openai-ai-guard.js +269 -0
- package/packages/datadog-instrumentations/src/helpers/promise-instrumentor.js +42 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-cosmos.js +50 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js +4 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +85 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +37 -236
- package/packages/datadog-instrumentations/src/hono.js +54 -3
- package/packages/datadog-instrumentations/src/http/server.js +9 -4
- package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +163 -0
- package/packages/datadog-instrumentations/src/jest.js +360 -150
- package/packages/datadog-instrumentations/src/kafkajs.js +120 -16
- package/packages/datadog-instrumentations/src/mocha/main.js +128 -17
- package/packages/datadog-instrumentations/src/nats.js +182 -0
- package/packages/datadog-instrumentations/src/nyc.js +38 -1
- package/packages/datadog-instrumentations/src/openai.js +33 -18
- package/packages/datadog-instrumentations/src/oracledb.js +6 -1
- package/packages/datadog-instrumentations/src/pino.js +17 -5
- package/packages/datadog-instrumentations/src/playwright.js +515 -292
- package/packages/datadog-instrumentations/src/router.js +76 -32
- package/packages/datadog-instrumentations/src/stripe.js +1 -1
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-azure-cosmos/src/index.js +144 -0
- package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -1
- package/packages/datadog-plugin-azure-functions/src/index.js +5 -2
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +1 -1
- package/packages/datadog-plugin-bunyan/src/index.js +28 -0
- package/packages/datadog-plugin-cucumber/src/index.js +17 -3
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +199 -28
- package/packages/datadog-plugin-cypress/src/support.js +69 -1
- package/packages/datadog-plugin-dns/src/lookup.js +8 -6
- package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +1 -1
- package/packages/datadog-plugin-graphql/src/execute.js +2 -0
- package/packages/datadog-plugin-graphql/src/resolve.js +64 -67
- package/packages/datadog-plugin-http/src/server.js +40 -15
- package/packages/datadog-plugin-jest/src/index.js +11 -3
- package/packages/datadog-plugin-jest/src/util.js +15 -8
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +1 -1
- package/packages/datadog-plugin-kafkajs/src/producer.js +3 -0
- package/packages/datadog-plugin-langgraph/src/stream.js +1 -1
- package/packages/datadog-plugin-mocha/src/index.js +19 -4
- package/packages/datadog-plugin-mongodb-core/src/index.js +281 -40
- package/packages/datadog-plugin-nats/src/consumer.js +43 -0
- package/packages/datadog-plugin-nats/src/index.js +20 -0
- package/packages/datadog-plugin-nats/src/producer.js +62 -0
- package/packages/datadog-plugin-nats/src/util.js +33 -0
- package/packages/datadog-plugin-next/src/index.js +5 -3
- package/packages/datadog-plugin-openai/src/tracing.js +15 -2
- package/packages/datadog-plugin-oracledb/src/index.js +13 -2
- package/packages/datadog-plugin-pino/src/index.js +42 -0
- package/packages/datadog-plugin-playwright/src/index.js +4 -4
- package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-rhea/src/producer.js +1 -1
- package/packages/datadog-plugin-router/src/index.js +33 -44
- package/packages/datadog-plugin-selenium/src/index.js +1 -1
- package/packages/datadog-plugin-vitest/src/index.js +5 -13
- package/packages/datadog-plugin-winston/src/index.js +30 -0
- package/packages/datadog-shimmer/src/shimmer.js +33 -40
- package/packages/dd-trace/src/aiguard/index.js +1 -1
- package/packages/dd-trace/src/aiguard/sdk.js +1 -1
- package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
- package/packages/dd-trace/src/appsec/index.js +1 -1
- package/packages/dd-trace/src/appsec/reporter.js +5 -6
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
- package/packages/dd-trace/src/appsec/sdk/utils.js +1 -1
- package/packages/dd-trace/src/appsec/user_tracking.js +5 -4
- package/packages/dd-trace/src/baggage.js +7 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +0 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +25 -13
- package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +70 -6
- package/packages/dd-trace/src/config/generated-config-types.d.ts +6 -2
- package/packages/dd-trace/src/config/supported-configurations.json +27 -8
- package/packages/dd-trace/src/datastreams/writer.js +2 -4
- package/packages/dd-trace/src/debugger/devtools_client/condition.js +5 -8
- package/packages/dd-trace/src/encode/0.4.js +124 -108
- package/packages/dd-trace/src/encode/0.5.js +114 -26
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +31 -23
- package/packages/dd-trace/src/encode/agentless-json.js +4 -2
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +32 -13
- package/packages/dd-trace/src/encode/span-stats.js +16 -16
- package/packages/dd-trace/src/encode/tags-processors.js +16 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +9 -7
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +0 -16
- package/packages/dd-trace/src/llmobs/span_processor.js +3 -3
- package/packages/dd-trace/src/llmobs/tagger.js +9 -1
- package/packages/dd-trace/src/llmobs/telemetry.js +1 -1
- package/packages/dd-trace/src/llmobs/util.js +66 -3
- package/packages/dd-trace/src/log/index.js +1 -1
- package/packages/dd-trace/src/msgpack/chunk.js +394 -10
- package/packages/dd-trace/src/msgpack/index.js +96 -2
- package/packages/dd-trace/src/openfeature/encoding.js +70 -0
- package/packages/dd-trace/src/openfeature/flagging_provider.js +20 -0
- package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +143 -0
- package/packages/dd-trace/src/openfeature/span-enrichment.js +149 -0
- package/packages/dd-trace/src/opentelemetry/span-helpers.js +4 -3
- package/packages/dd-trace/src/opentelemetry/span.js +1 -1
- package/packages/dd-trace/src/opentracing/propagation/log.js +18 -7
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +62 -67
- package/packages/dd-trace/src/opentracing/span.js +59 -19
- package/packages/dd-trace/src/opentracing/span_context.js +49 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +20 -20
- package/packages/dd-trace/src/plugins/database.js +7 -6
- package/packages/dd-trace/src/plugins/index.js +4 -0
- package/packages/dd-trace/src/plugins/log_injection.js +56 -0
- package/packages/dd-trace/src/plugins/log_plugin.js +3 -48
- package/packages/dd-trace/src/plugins/outbound.js +1 -1
- package/packages/dd-trace/src/plugins/plugin.js +15 -17
- package/packages/dd-trace/src/plugins/tracing.js +43 -5
- package/packages/dd-trace/src/plugins/util/test.js +236 -13
- package/packages/dd-trace/src/plugins/util/web.js +79 -65
- package/packages/dd-trace/src/priority_sampler.js +2 -2
- package/packages/dd-trace/src/profiling/profiler.js +2 -2
- package/packages/dd-trace/src/profiling/profilers/wall.js +10 -4
- package/packages/dd-trace/src/sampling_rule.js +7 -7
- package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +10 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +8 -0
- package/packages/dd-trace/src/service-naming/source-resolver.js +46 -0
- package/packages/dd-trace/src/span_format.js +190 -58
- package/packages/dd-trace/src/spanleak.js +1 -1
- package/packages/dd-trace/src/standalone/index.js +3 -3
- package/packages/dd-trace/src/tagger.js +0 -2
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +70 -39
- package/vendor/dist/@datadog/sketches-js/LICENSE +10 -36
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/packages/dd-trace/src/msgpack/encoder.js +0 -308
- package/packages/dd-trace/src/plugins/structured_log_plugin.js +0 -9
|
@@ -12,9 +12,9 @@ const {
|
|
|
12
12
|
TEST_BROWSER_NAME,
|
|
13
13
|
TEST_BROWSER_VERSION,
|
|
14
14
|
TEST_CODE_OWNERS,
|
|
15
|
-
TEST_COMMAND,
|
|
16
15
|
TEST_EARLY_FLAKE_ABORT_REASON,
|
|
17
16
|
TEST_EARLY_FLAKE_ENABLED,
|
|
17
|
+
TEST_FRAMEWORK_VERSION,
|
|
18
18
|
TEST_HAS_FAILED_ALL_RETRIES,
|
|
19
19
|
TEST_IS_MODIFIED,
|
|
20
20
|
TEST_IS_NEW,
|
|
@@ -234,7 +234,7 @@ class PlaywrightPlugin extends CiPlugin {
|
|
|
234
234
|
formattedSpan.meta[TEST_SESSION_ID] = this.testSessionSpan.context().toTraceId()
|
|
235
235
|
formattedSpan.meta[TEST_MODULE_ID] = this.testModuleSpan.context().toSpanId()
|
|
236
236
|
Object.assign(formattedSpan.meta, this.getSessionRequestErrorTags())
|
|
237
|
-
formattedSpan.meta[
|
|
237
|
+
formattedSpan.meta[TEST_FRAMEWORK_VERSION] = this.frameworkVersion
|
|
238
238
|
formattedSpan.meta[TEST_MODULE] = this.constructor.id
|
|
239
239
|
// MISSING _trace.startTime and _trace.ticks - because by now the suite is already serialized
|
|
240
240
|
const testSuite = this._testSuiteSpansByTestSuiteAbsolutePath.get(
|
|
@@ -326,7 +326,7 @@ class PlaywrightPlugin extends CiPlugin {
|
|
|
326
326
|
}) => {
|
|
327
327
|
if (!span) return
|
|
328
328
|
|
|
329
|
-
const isRUMActive = span.context().
|
|
329
|
+
const isRUMActive = span.context().getTag(TEST_IS_RUM_ACTIVE)
|
|
330
330
|
|
|
331
331
|
span.setTag(TEST_STATUS, testStatus)
|
|
332
332
|
|
|
@@ -416,7 +416,7 @@ class PlaywrightPlugin extends CiPlugin {
|
|
|
416
416
|
TELEMETRY_EVENT_FINISHED,
|
|
417
417
|
'test',
|
|
418
418
|
{
|
|
419
|
-
hasCodeOwners: !!span.context().
|
|
419
|
+
hasCodeOwners: !!span.context().getTag(TEST_CODE_OWNERS),
|
|
420
420
|
isNew,
|
|
421
421
|
isRum: isRUMActive,
|
|
422
422
|
browserDriver: 'playwright',
|
|
@@ -135,7 +135,7 @@ class SchemaExtractor {
|
|
|
135
135
|
return
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
if (span.context().
|
|
138
|
+
if (span.context().getTag(SCHEMA_TYPE) && operation === 'serialization') {
|
|
139
139
|
// we have already added a schema to this span, this call is an encode of nested schema types
|
|
140
140
|
return
|
|
141
141
|
}
|
|
@@ -42,7 +42,7 @@ function addDeliveryAnnotations (msg, tracer, span) {
|
|
|
42
42
|
tracer.inject(span, 'text_map', msg.delivery_annotations)
|
|
43
43
|
|
|
44
44
|
if (tracer._config.dsmEnabled) {
|
|
45
|
-
const targetName = span.context().
|
|
45
|
+
const targetName = span.context().getTag('amqp.link.target.address')
|
|
46
46
|
const payloadSize = getAmqpMessageSize({ content: msg.body, headers: msg.delivery_annotations })
|
|
47
47
|
const dataStreamsContext = tracer
|
|
48
48
|
.setCheckpoint(['direction:out', `exchange:${targetName}`, 'type:rabbitmq'], span, payloadSize)
|
|
@@ -9,31 +9,35 @@ const { COMPONENT } = require('../../dd-trace/src/constants')
|
|
|
9
9
|
class RouterPlugin extends WebPlugin {
|
|
10
10
|
static id = 'router'
|
|
11
11
|
|
|
12
|
-
#storeStacks = new WeakMap()
|
|
13
12
|
#contexts = new WeakMap()
|
|
14
13
|
|
|
15
14
|
constructor (...args) {
|
|
16
15
|
super(...args)
|
|
17
16
|
|
|
18
17
|
this.addSub(`apm:${this.constructor.id}:middleware:enter`, ({ req, name, route }) => {
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
// One ALS hop covers both the parent-span fallback (when no
|
|
19
|
+
// per-request context exists yet) and the `storeStack` push below.
|
|
20
|
+
// The previous shape paid an ALS read inside `#getStoreSpan` and a
|
|
21
|
+
// second one here for the saved-store push.
|
|
22
|
+
const store = storage('legacy').getStore()
|
|
23
|
+
let context = this.#contexts.get(req)
|
|
24
|
+
let childOf
|
|
25
|
+
if (context !== undefined) {
|
|
26
|
+
const middleware = context.middleware
|
|
27
|
+
childOf = middleware.length === 0 ? context.span : middleware[middleware.length - 1]
|
|
28
|
+
} else if (store) {
|
|
29
|
+
childOf = store.span
|
|
30
|
+
}
|
|
21
31
|
if (!childOf) return
|
|
22
32
|
|
|
23
33
|
const span = this.#getMiddlewareSpan(name, childOf)
|
|
24
|
-
|
|
34
|
+
context = this.#updateContext(req, context, route, childOf)
|
|
25
35
|
|
|
26
36
|
if (childOf !== span) {
|
|
27
37
|
context.middleware.push(span)
|
|
28
38
|
}
|
|
29
39
|
|
|
30
|
-
|
|
31
|
-
let storeStack = this.#storeStacks.get(req)
|
|
32
|
-
if (!storeStack) {
|
|
33
|
-
storeStack = []
|
|
34
|
-
this.#storeStacks.set(req, storeStack)
|
|
35
|
-
}
|
|
36
|
-
storeStack.push(store)
|
|
40
|
+
context.storeStack.push(store)
|
|
37
41
|
this.enter(span, store)
|
|
38
42
|
|
|
39
43
|
web.patch(req)
|
|
@@ -57,11 +61,8 @@ class RouterPlugin extends WebPlugin {
|
|
|
57
61
|
})
|
|
58
62
|
|
|
59
63
|
this.addSub(`apm:${this.constructor.id}:middleware:exit`, ({ req }) => {
|
|
60
|
-
const
|
|
61
|
-
const savedStore =
|
|
62
|
-
if (storeStack && storeStack.length === 0) {
|
|
63
|
-
this.#storeStacks.delete(req)
|
|
64
|
-
}
|
|
64
|
+
const context = this.#contexts.get(req)
|
|
65
|
+
const savedStore = context && context.storeStack.pop()
|
|
65
66
|
const span = savedStore && savedStore.span
|
|
66
67
|
this.enter(span, savedStore)
|
|
67
68
|
})
|
|
@@ -71,8 +72,10 @@ class RouterPlugin extends WebPlugin {
|
|
|
71
72
|
|
|
72
73
|
if (!this.config.middleware) return
|
|
73
74
|
|
|
74
|
-
const
|
|
75
|
-
|
|
75
|
+
const context = this.#contexts.get(req)
|
|
76
|
+
if (!context) return
|
|
77
|
+
const middleware = context.middleware
|
|
78
|
+
const span = middleware.length === 0 ? context.span : middleware[middleware.length - 1]
|
|
76
79
|
if (!span) return
|
|
77
80
|
|
|
78
81
|
span.setTag('error', error)
|
|
@@ -91,21 +94,6 @@ class RouterPlugin extends WebPlugin {
|
|
|
91
94
|
})
|
|
92
95
|
}
|
|
93
96
|
|
|
94
|
-
#getActive (req) {
|
|
95
|
-
const context = this.#contexts.get(req)
|
|
96
|
-
|
|
97
|
-
if (!context) return
|
|
98
|
-
if (context.middleware.length === 0) return context.span
|
|
99
|
-
|
|
100
|
-
return context.middleware.at(-1)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
#getStoreSpan () {
|
|
104
|
-
const store = storage('legacy').getStore()
|
|
105
|
-
|
|
106
|
-
return store && store.span
|
|
107
|
-
}
|
|
108
|
-
|
|
109
97
|
#getMiddlewareSpan (name, childOf) {
|
|
110
98
|
if (this.config.middleware === false) {
|
|
111
99
|
return childOf
|
|
@@ -125,9 +113,7 @@ class RouterPlugin extends WebPlugin {
|
|
|
125
113
|
return span
|
|
126
114
|
}
|
|
127
115
|
|
|
128
|
-
#
|
|
129
|
-
let context = this.#contexts.get(req)
|
|
130
|
-
|
|
116
|
+
#updateContext (req, context, route, span) {
|
|
131
117
|
if (!route || route === '/' || route === '*') {
|
|
132
118
|
route = ''
|
|
133
119
|
}
|
|
@@ -141,17 +127,20 @@ class RouterPlugin extends WebPlugin {
|
|
|
141
127
|
if (isMoreSpecificThan(route, context.route)) {
|
|
142
128
|
context.route = route
|
|
143
129
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
span,
|
|
147
|
-
stack: [route],
|
|
148
|
-
route,
|
|
149
|
-
middleware: [],
|
|
150
|
-
}
|
|
130
|
+
return context
|
|
131
|
+
}
|
|
151
132
|
|
|
152
|
-
|
|
133
|
+
// Five-property shape pinned at allocation so every request shares the
|
|
134
|
+
// same hidden class — no per-field transitions after construction.
|
|
135
|
+
context = {
|
|
136
|
+
span,
|
|
137
|
+
stack: [route],
|
|
138
|
+
route,
|
|
139
|
+
middleware: [],
|
|
140
|
+
storeStack: [],
|
|
153
141
|
}
|
|
154
142
|
|
|
143
|
+
this.#contexts.set(req, context)
|
|
155
144
|
return context
|
|
156
145
|
}
|
|
157
146
|
}
|
|
@@ -15,7 +15,7 @@ const {
|
|
|
15
15
|
TEST_IS_RETRY,
|
|
16
16
|
TEST_CODE_COVERAGE_LINES_PCT,
|
|
17
17
|
TEST_CODE_OWNERS,
|
|
18
|
-
|
|
18
|
+
TEST_COMMAND,
|
|
19
19
|
TEST_SESSION_NAME,
|
|
20
20
|
TEST_SOURCE_START,
|
|
21
21
|
TEST_IS_NEW,
|
|
@@ -323,19 +323,11 @@ class VitestPlugin extends CiPlugin {
|
|
|
323
323
|
const trimmedCommand = DD_MAJOR < 6 ? this.command : 'vitest run'
|
|
324
324
|
// test suites run in a different process, so they also need to init the metadata dictionary
|
|
325
325
|
const testSessionName = getTestSessionName(this.config, trimmedCommand, this.testEnvironmentMetadata)
|
|
326
|
-
const metadataTags = {}
|
|
327
|
-
for (const testLevel of TEST_LEVEL_EVENT_TYPES) {
|
|
328
|
-
metadataTags[testLevel] = {
|
|
329
|
-
[TEST_SESSION_NAME]: testSessionName,
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
326
|
if (this.tracer._exporter.addMetadataTags) {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
}
|
|
338
|
-
this.tracer._exporter.addMetadataTags(metadataTags)
|
|
327
|
+
this.tracer._exporter.addMetadataTags({
|
|
328
|
+
'*': { [TEST_COMMAND]: testCommand, [TEST_SESSION_NAME]: testSessionName },
|
|
329
|
+
test: getLibraryCapabilitiesTags(this.constructor.id),
|
|
330
|
+
})
|
|
339
331
|
}
|
|
340
332
|
|
|
341
333
|
const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
|
|
@@ -1,8 +1,38 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { buildLogHolder, messageProxy } = require('../../dd-trace/src/plugins/log_injection')
|
|
3
4
|
const LogPlugin = require('../../dd-trace/src/plugins/log_plugin')
|
|
4
5
|
|
|
5
6
|
class WinstonPlugin extends LogPlugin {
|
|
6
7
|
static id = 'winston'
|
|
8
|
+
|
|
9
|
+
constructor (...args) {
|
|
10
|
+
super(...args)
|
|
11
|
+
this.addSub('apm:winston:log', (arg) => this.handleLog(arg))
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The prototype + extensibility check is load-bearing. The Proxy
|
|
16
|
+
* fallback keeps `dd` off caller-owned objects (Error, Set, Map, any
|
|
17
|
+
* user class) and out of non-extensible records, where a strict-mode
|
|
18
|
+
* write would throw and `Plugin.addSub` would react by disabling the
|
|
19
|
+
* plugin for the rest of the process.
|
|
20
|
+
*
|
|
21
|
+
* @param {{ message: unknown }} arg
|
|
22
|
+
*/
|
|
23
|
+
handleLog (arg) {
|
|
24
|
+
const info = arg.message
|
|
25
|
+
if (info === null || typeof info !== 'object' || Object.hasOwn(info, 'dd')) return
|
|
26
|
+
|
|
27
|
+
const logHolder = buildLogHolder(this.tracer)
|
|
28
|
+
if (!logHolder) return
|
|
29
|
+
|
|
30
|
+
if (Object.getPrototypeOf(info) === Object.prototype && Object.isExtensible(info)) {
|
|
31
|
+
info.dd = logHolder.dd
|
|
32
|
+
} else {
|
|
33
|
+
arg.message = messageProxy(info, logHolder)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
7
36
|
}
|
|
37
|
+
|
|
8
38
|
module.exports = WinstonPlugin
|
|
@@ -13,11 +13,16 @@ const skipMethodSize = skipMethods.size
|
|
|
13
13
|
|
|
14
14
|
const nonConfigurableModuleExports = new WeakMap()
|
|
15
15
|
|
|
16
|
+
// Reused descriptor scratch space for the `name` and `length` slots that
|
|
17
|
+
// `copyProperties` and `wrapCallback` rewrite per wrap. `Object.defineProperty`
|
|
18
|
+
// reads the descriptor's slots synchronously and does not retain the object,
|
|
19
|
+
// so mutating `value` between calls is safe.
|
|
20
|
+
const lengthDescriptor = { value: 0, configurable: true }
|
|
21
|
+
const nameDescriptor = { value: '', configurable: true }
|
|
22
|
+
|
|
16
23
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* @param {Function} original - The original function.
|
|
20
|
-
* @param {Function} wrapped - The wrapped function.
|
|
24
|
+
* @param {Function} original
|
|
25
|
+
* @param {Function} wrapped
|
|
21
26
|
*/
|
|
22
27
|
function copyProperties (original, wrapped) {
|
|
23
28
|
if (original.constructor !== wrapped.constructor) {
|
|
@@ -26,11 +31,15 @@ function copyProperties (original, wrapped) {
|
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
const ownKeys = Reflect.ownKeys(original)
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
const originalLength = original.length
|
|
35
|
+
if (originalLength !== wrapped.length) {
|
|
36
|
+
lengthDescriptor.value = originalLength
|
|
37
|
+
Object.defineProperty(wrapped, 'length', lengthDescriptor)
|
|
31
38
|
}
|
|
32
|
-
|
|
33
|
-
|
|
39
|
+
const originalName = original.name
|
|
40
|
+
if (originalName !== wrapped.name) {
|
|
41
|
+
nameDescriptor.value = originalName
|
|
42
|
+
Object.defineProperty(wrapped, 'name', nameDescriptor)
|
|
34
43
|
}
|
|
35
44
|
if (ownKeys.length !== 2) {
|
|
36
45
|
for (const key of ownKeys) {
|
|
@@ -46,11 +55,9 @@ function copyProperties (original, wrapped) {
|
|
|
46
55
|
}
|
|
47
56
|
|
|
48
57
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* @param {
|
|
52
|
-
* @param {Record<string | symbol, unknown>} wrapped - The wrapped object.
|
|
53
|
-
* @param {string | symbol} skipKey - The key to skip during copying.
|
|
58
|
+
* @param {Record<string | symbol, unknown>} original
|
|
59
|
+
* @param {Record<string | symbol, unknown>} wrapped
|
|
60
|
+
* @param {string | symbol} skipKey
|
|
54
61
|
*/
|
|
55
62
|
function copyObjectProperties (original, wrapped, skipKey) {
|
|
56
63
|
const ownKeys = Reflect.ownKeys(original)
|
|
@@ -66,11 +73,8 @@ function copyObjectProperties (original, wrapped, skipKey) {
|
|
|
66
73
|
}
|
|
67
74
|
|
|
68
75
|
/**
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* @param {Function} original - The original function to wrap.
|
|
72
|
-
* @param {(original: Function) => Function} wrapper - The wrapper function.
|
|
73
|
-
* @returns {Function} The wrapped function.
|
|
76
|
+
* @param {Function} original
|
|
77
|
+
* @param {(original: Function) => Function} wrapper
|
|
74
78
|
*/
|
|
75
79
|
function wrapFunction (original, wrapper) {
|
|
76
80
|
if (typeof original !== 'function') return original
|
|
@@ -83,24 +87,14 @@ function wrapFunction (original, wrapper) {
|
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
/**
|
|
86
|
-
* Lean variant of `wrapFunction` for
|
|
87
|
-
* user-supplied callback
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
* `assertNotClass` guard, and the `Reflect.ownKeys` descriptor-copy loop.
|
|
92
|
-
* Only `name` and `length` are preserved, and only when the wrapper's
|
|
93
|
-
* autogenerated values differ -- a wrapper whose closure already has the
|
|
94
|
-
* right arity / name pays no overhead.
|
|
95
|
-
*
|
|
96
|
-
* Use `wrapFunction` instead when any of the following is true: the wrapped
|
|
97
|
-
* function needs to keep its prototype, has custom own properties the caller
|
|
98
|
-
* may read, or is `new`-ed.
|
|
90
|
+
* Lean variant of `wrapFunction` for tracer-owned closures wrapping a
|
|
91
|
+
* user-supplied callback. Preserves `name` and `length` only; skips the
|
|
92
|
+
* prototype copy, `assertNotClass`, and the `Reflect.ownKeys` descriptor
|
|
93
|
+
* walk. Use `wrapFunction` instead when the wrapped value needs its
|
|
94
|
+
* prototype, has own properties the caller may read, or is `new`-ed.
|
|
99
95
|
*
|
|
100
|
-
* @param {Function} original
|
|
101
|
-
* @param {(original: Function) => Function} wrapper
|
|
102
|
-
* `original` and returns the wrapper closure.
|
|
103
|
-
* @returns {Function} The wrapper closure with `name` and `length` preserved.
|
|
96
|
+
* @param {Function} original
|
|
97
|
+
* @param {(original: Function) => Function} wrapper
|
|
104
98
|
*/
|
|
105
99
|
function wrapCallback (original, wrapper) {
|
|
106
100
|
if (typeof original !== 'function') {
|
|
@@ -108,10 +102,12 @@ function wrapCallback (original, wrapper) {
|
|
|
108
102
|
}
|
|
109
103
|
const wrapped = wrapper(original)
|
|
110
104
|
if (wrapped.name !== original.name) {
|
|
111
|
-
|
|
105
|
+
nameDescriptor.value = original.name
|
|
106
|
+
Object.defineProperty(wrapped, 'name', nameDescriptor)
|
|
112
107
|
}
|
|
113
108
|
if (wrapped.length !== original.length) {
|
|
114
|
-
|
|
109
|
+
lengthDescriptor.value = original.length
|
|
110
|
+
Object.defineProperty(wrapped, 'length', lengthDescriptor)
|
|
115
111
|
}
|
|
116
112
|
return wrapped
|
|
117
113
|
}
|
|
@@ -174,7 +170,6 @@ function wrap (target, name, wrapper, options) {
|
|
|
174
170
|
copyProperties(original, wrapped)
|
|
175
171
|
|
|
176
172
|
if (descriptor.writable) {
|
|
177
|
-
// Fast path for assigned properties.
|
|
178
173
|
if (descriptor.configurable && descriptor.enumerable) {
|
|
179
174
|
target[name] = wrapped
|
|
180
175
|
return target
|
|
@@ -209,8 +204,6 @@ function wrap (target, name, wrapper, options) {
|
|
|
209
204
|
// with this code. That way it would be possible to directly pass through
|
|
210
205
|
// the entries.
|
|
211
206
|
|
|
212
|
-
// In case more than a single property is not configurable and writable,
|
|
213
|
-
// Just reuse the already created object.
|
|
214
207
|
let moduleExports = nonConfigurableModuleExports.get(target)
|
|
215
208
|
if (!moduleExports) {
|
|
216
209
|
if (typeof target === 'function') {
|
|
@@ -44,7 +44,7 @@ function disable () {
|
|
|
44
44
|
/**
|
|
45
45
|
* Handles channel messages with pre-converted messages.
|
|
46
46
|
*
|
|
47
|
-
* @param {{messages: Array<object>, resolve: Function, reject: Function}} ctx
|
|
47
|
+
* @param {{messages: Array<object>, integration?: string, resolve: Function, reject: Function}} ctx
|
|
48
48
|
*/
|
|
49
49
|
function onEvaluate (ctx) {
|
|
50
50
|
if (!ctx.messages?.length) {
|
|
@@ -148,7 +148,7 @@ class AIGuard extends NoopAIGuard {
|
|
|
148
148
|
#setRootSpanClientIpTags (rootSpan) {
|
|
149
149
|
if (!rootSpan) return
|
|
150
150
|
|
|
151
|
-
const currentTags = rootSpan.context().
|
|
151
|
+
const currentTags = rootSpan.context().getTags()
|
|
152
152
|
const needsHttpClientIp = !Object.hasOwn(currentTags, HTTP_CLIENT_IP)
|
|
153
153
|
const needsNetworkClientIp = !Object.hasOwn(currentTags, NETWORK_CLIENT_IP)
|
|
154
154
|
|
|
@@ -79,7 +79,7 @@ function getRouteOrEndpoint (context, statusCode) {
|
|
|
79
79
|
|
|
80
80
|
// If route is not available, fallback to http.endpoint
|
|
81
81
|
if (statusCode !== 404) {
|
|
82
|
-
const endpoint = context?.span?.context()?.
|
|
82
|
+
const endpoint = context?.span?.context()?.getTag('http.endpoint')
|
|
83
83
|
if (endpoint) {
|
|
84
84
|
return endpoint
|
|
85
85
|
}
|
|
@@ -289,7 +289,7 @@ function onExpressSession ({ req, res, sessionId, abortController }) {
|
|
|
289
289
|
return
|
|
290
290
|
}
|
|
291
291
|
|
|
292
|
-
const isSdkCalled = rootSpan.context().
|
|
292
|
+
const isSdkCalled = rootSpan.context().getTag('usr.session_id')
|
|
293
293
|
if (isSdkCalled) return
|
|
294
294
|
|
|
295
295
|
const results = waf.run({
|
|
@@ -361,18 +361,18 @@ function reportAttack ({ events: attackData, actions }, req) {
|
|
|
361
361
|
const rootSpan = web.root(req)
|
|
362
362
|
if (!rootSpan) return
|
|
363
363
|
|
|
364
|
-
const
|
|
364
|
+
const spanContext = rootSpan.context()
|
|
365
365
|
|
|
366
366
|
const newTags = {
|
|
367
367
|
'appsec.event': 'true',
|
|
368
368
|
}
|
|
369
369
|
|
|
370
370
|
// TODO: maybe add this to format.js later (to take decision as late as possible)
|
|
371
|
-
if (!
|
|
371
|
+
if (!spanContext.getTag('_dd.origin')) {
|
|
372
372
|
newTags['_dd.origin'] = 'appsec'
|
|
373
373
|
}
|
|
374
374
|
|
|
375
|
-
const currentJson =
|
|
375
|
+
const currentJson = spanContext.getTag('_dd.appsec.json')
|
|
376
376
|
|
|
377
377
|
// merge JSON arrays without parsing them
|
|
378
378
|
const attackDataStr = JSON.stringify(attackData)
|
|
@@ -469,8 +469,7 @@ function reportRequestBody (rootSpan, requestBody, comesFromRaspAction = false)
|
|
|
469
469
|
|
|
470
470
|
if (rootSpan.meta_struct['http.request.body']) {
|
|
471
471
|
// If the rasp.exceed metric exists, set also the same for the new tag
|
|
472
|
-
const
|
|
473
|
-
const sizeExceedTagValue = currentTags['_dd.appsec.rasp.request_body_size.exceeded']
|
|
472
|
+
const sizeExceedTagValue = rootSpan.context().getTag('_dd.appsec.rasp.request_body_size.exceeded')
|
|
474
473
|
|
|
475
474
|
if (sizeExceedTagValue) {
|
|
476
475
|
rootSpan.setTag('_dd.appsec.request_body_size.exceeded', sizeExceedTagValue)
|
|
@@ -572,7 +571,7 @@ function finishRequest (req, res, storedResponseHeaders, requestBody) {
|
|
|
572
571
|
|
|
573
572
|
incrementWafRequestsMetric(req)
|
|
574
573
|
|
|
575
|
-
const tags = rootSpan.context().
|
|
574
|
+
const tags = rootSpan.context().getTags()
|
|
576
575
|
|
|
577
576
|
const extendedDataCollection = extendedDataCollectionRequest.get(req)
|
|
578
577
|
const newTags = getCollectedHeaders(
|
|
@@ -91,12 +91,13 @@ function trackLogin (framework, login, user, success, rootSpan) {
|
|
|
91
91
|
[addresses.USER_LOGIN]: login,
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
const
|
|
95
|
-
const
|
|
94
|
+
const spanContext = rootSpan.context()
|
|
95
|
+
const sdkTag = `_dd.appsec.events.users.login.${success ? 'success' : 'failure'}.sdk`
|
|
96
|
+
const isSdkCalled = spanContext.getTag(sdkTag) === 'true'
|
|
96
97
|
|
|
97
98
|
// used to not overwrite tags set by SDK
|
|
98
99
|
function shouldSetTag (tag) {
|
|
99
|
-
return !(isSdkCalled &&
|
|
100
|
+
return !(isSdkCalled && spanContext.getTag(tag))
|
|
100
101
|
}
|
|
101
102
|
|
|
102
103
|
if (success) {
|
|
@@ -167,7 +168,7 @@ function trackUser (user, rootSpan) {
|
|
|
167
168
|
|
|
168
169
|
rootSpan.setTag('_dd.appsec.usr.id', userId)
|
|
169
170
|
|
|
170
|
-
const isSdkCalled = rootSpan.context().
|
|
171
|
+
const isSdkCalled = rootSpan.context().getTag('_dd.appsec.user.collection_mode') === 'sdk'
|
|
171
172
|
// do not override SDK
|
|
172
173
|
if (!isSdkCalled) {
|
|
173
174
|
rootSpan.addTags({
|
|
@@ -62,7 +62,13 @@ function removeBaggageItem (keyToRemove) {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
function removeAllBaggageItems () {
|
|
65
|
-
|
|
65
|
+
// Skip `enterWith` (a real ALS frame switch) when the store is already
|
|
66
|
+
// the empty sentinel. Entry-point services without active baggage hit this
|
|
67
|
+
// on every extract.
|
|
68
|
+
const store = baggageStorage.getStore()
|
|
69
|
+
if (store !== undefined && store !== EMPTY_STORE) {
|
|
70
|
+
baggageStorage.enterWith(EMPTY_STORE)
|
|
71
|
+
}
|
|
66
72
|
return EMPTY_STORE
|
|
67
73
|
}
|
|
68
74
|
|
|
@@ -236,7 +236,6 @@ class CiVisibilityExporter extends BufferingExporter {
|
|
|
236
236
|
testManagementAttemptToFixRetries ?? this._config.testManagementAttemptToFixRetries,
|
|
237
237
|
isImpactedTestsEnabled: isImpactedTestsEnabled && this._config.isImpactedTestsEnabled,
|
|
238
238
|
isCoverageReportUploadEnabled,
|
|
239
|
-
DD_TEST_TIA_KEEP_COV_CONFIG: this._config.DD_TEST_TIA_KEEP_COV_CONFIG,
|
|
240
239
|
}
|
|
241
240
|
}
|
|
242
241
|
|
|
@@ -31,10 +31,11 @@ function getSkippableSuites ({
|
|
|
31
31
|
runtimeVersion,
|
|
32
32
|
custom,
|
|
33
33
|
testLevel = 'suite',
|
|
34
|
+
isCoverageReportUploadEnabled = false,
|
|
34
35
|
}, done) {
|
|
35
36
|
const cacheKey = buildCacheKey('skippable', [
|
|
36
37
|
sha, service, env, repositoryUrl, osPlatform, osVersion, osArchitecture,
|
|
37
|
-
runtimeName, runtimeVersion, testLevel, custom,
|
|
38
|
+
runtimeName, runtimeVersion, testLevel, custom, isCoverageReportUploadEnabled,
|
|
38
39
|
])
|
|
39
40
|
|
|
40
41
|
withCache(cacheKey, (activeCacheKey, cb) => {
|
|
@@ -54,11 +55,12 @@ function getSkippableSuites ({
|
|
|
54
55
|
runtimeVersion,
|
|
55
56
|
custom,
|
|
56
57
|
testLevel,
|
|
58
|
+
isCoverageReportUploadEnabled,
|
|
57
59
|
cacheKey: activeCacheKey,
|
|
58
60
|
}, cb)
|
|
59
61
|
}, (err, data) => {
|
|
60
62
|
if (err) return done(err)
|
|
61
|
-
done(null, data.skippableSuites, data.correlationId)
|
|
63
|
+
done(null, data.skippableSuites, data.correlationId, data.coverage)
|
|
62
64
|
})
|
|
63
65
|
}
|
|
64
66
|
|
|
@@ -81,6 +83,7 @@ function getSkippableSuites ({
|
|
|
81
83
|
* @param {string} params.runtimeVersion
|
|
82
84
|
* @param {object} [params.custom]
|
|
83
85
|
* @param {string} [params.testLevel]
|
|
86
|
+
* @param {boolean} [params.isCoverageReportUploadEnabled]
|
|
84
87
|
* @param {string | null} params.cacheKey
|
|
85
88
|
* @param {Function} done
|
|
86
89
|
*/
|
|
@@ -100,6 +103,7 @@ function fetchFromApi ({
|
|
|
100
103
|
runtimeVersion,
|
|
101
104
|
custom,
|
|
102
105
|
testLevel,
|
|
106
|
+
isCoverageReportUploadEnabled,
|
|
103
107
|
cacheKey,
|
|
104
108
|
}, done) {
|
|
105
109
|
const options = {
|
|
@@ -148,7 +152,6 @@ function fetchFromApi ({
|
|
|
148
152
|
},
|
|
149
153
|
},
|
|
150
154
|
})
|
|
151
|
-
|
|
152
155
|
incrementCountMetric(TELEMETRY_ITR_SKIPPABLE_TESTS)
|
|
153
156
|
|
|
154
157
|
const startTime = Date.now()
|
|
@@ -161,27 +164,36 @@ function fetchFromApi ({
|
|
|
161
164
|
} else {
|
|
162
165
|
try {
|
|
163
166
|
const parsedResponse = JSON.parse(res)
|
|
164
|
-
const
|
|
167
|
+
const coverage = parsedResponse.meta?.coverage || {}
|
|
168
|
+
|
|
169
|
+
const skippableItems = parsedResponse
|
|
165
170
|
.data
|
|
166
171
|
.filter(({ type }) => type === testLevel)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
172
|
+
const skippableSuites = []
|
|
173
|
+
for (const {
|
|
174
|
+
attributes: {
|
|
175
|
+
suite,
|
|
176
|
+
name,
|
|
177
|
+
_is_missing_line_code_coverage: isMissingLineCodeCoverage,
|
|
178
|
+
},
|
|
179
|
+
} of skippableItems) {
|
|
180
|
+
// Only reject candidates without backend line coverage when we need that coverage to backfill reports.
|
|
181
|
+
if (isCoverageReportUploadEnabled && isMissingLineCodeCoverage) continue
|
|
182
|
+
|
|
183
|
+
skippableSuites.push(testLevel === 'suite' ? suite : { suite, name })
|
|
184
|
+
}
|
|
185
|
+
const correlationId = parsedResponse.meta?.correlation_id
|
|
174
186
|
incrementCountMetric(
|
|
175
187
|
testLevel === 'test'
|
|
176
188
|
? TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_TESTS
|
|
177
189
|
: TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_SUITES,
|
|
178
190
|
{},
|
|
179
|
-
|
|
191
|
+
skippableItems.length
|
|
180
192
|
)
|
|
181
193
|
distributionMetric(TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_BYTES, {}, res.length)
|
|
182
194
|
log.debug('Number of received skippable %ss:', testLevel, skippableSuites.length)
|
|
183
195
|
|
|
184
|
-
const result = { skippableSuites, correlationId }
|
|
196
|
+
const result = { skippableSuites, correlationId, coverage }
|
|
185
197
|
writeToCache(cacheKey, result)
|
|
186
198
|
|
|
187
199
|
done(null, result)
|