dd-trace 5.103.0 → 5.104.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/index.d.ts +25 -3
- package/package.json +4 -3
- package/packages/datadog-instrumentations/src/aws-sdk.js +2 -2
- package/packages/datadog-instrumentations/src/cassandra-driver.js +5 -2
- package/packages/datadog-instrumentations/src/cucumber.js +103 -30
- package/packages/datadog-instrumentations/src/elasticsearch.js +4 -4
- package/packages/datadog-instrumentations/src/graphql.js +0 -5
- package/packages/datadog-instrumentations/src/grpc/client.js +48 -32
- package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/kafka.js +17 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +3 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +19 -5
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +14 -13
- package/packages/datadog-instrumentations/src/http/client.js +2 -2
- package/packages/datadog-instrumentations/src/ioredis.js +3 -3
- package/packages/datadog-instrumentations/src/jest.js +33 -36
- package/packages/datadog-instrumentations/src/kafkajs.js +25 -6
- package/packages/datadog-instrumentations/src/mariadb.js +1 -1
- package/packages/datadog-instrumentations/src/memcached.js +2 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +272 -91
- package/packages/datadog-instrumentations/src/mocha/utils.js +48 -8
- package/packages/datadog-instrumentations/src/mongodb-core.js +1 -1
- package/packages/datadog-instrumentations/src/mongoose.js +10 -12
- package/packages/datadog-instrumentations/src/mysql.js +2 -2
- package/packages/datadog-instrumentations/src/mysql2.js +1 -1
- package/packages/datadog-instrumentations/src/pg.js +1 -1
- package/packages/datadog-instrumentations/src/playwright.js +22 -5
- package/packages/datadog-instrumentations/src/router.js +4 -2
- package/packages/datadog-instrumentations/src/vitest.js +246 -149
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +26 -19
- package/packages/datadog-plugin-elasticsearch/src/index.js +28 -8
- package/packages/datadog-plugin-graphql/src/utils.js +4 -1
- package/packages/datadog-plugin-kafkajs/src/producer.js +32 -0
- package/packages/datadog-plugin-mongodb-core/src/index.js +54 -19
- package/packages/datadog-plugin-redis/src/index.js +37 -2
- package/packages/datadog-plugin-undici/src/index.js +19 -0
- package/packages/datadog-plugin-vitest/src/index.js +19 -7
- package/packages/datadog-shimmer/src/shimmer.js +35 -0
- package/packages/dd-trace/src/appsec/blocking.js +2 -2
- package/packages/dd-trace/src/appsec/index.js +10 -3
- package/packages/dd-trace/src/appsec/reporter.js +19 -5
- package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -1
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +5 -3
- package/packages/dd-trace/src/config/generated-config-types.d.ts +1 -0
- package/packages/dd-trace/src/config/supported-configurations.json +9 -0
- package/packages/dd-trace/src/crashtracking/crashtracker.js +15 -3
- package/packages/dd-trace/src/datastreams/context.js +4 -2
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +26 -19
- package/packages/dd-trace/src/exporters/common/agents.js +3 -1
- package/packages/dd-trace/src/exporters/common/request.js +3 -1
- package/packages/dd-trace/src/id.js +17 -4
- package/packages/dd-trace/src/lambda/handler.js +2 -4
- package/packages/dd-trace/src/llmobs/sdk.js +10 -0
- package/packages/dd-trace/src/log/writer.js +3 -1
- package/packages/dd-trace/src/noop/span.js +3 -1
- package/packages/dd-trace/src/openfeature/writers/exposures.js +51 -20
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -1
- package/packages/dd-trace/src/plugins/apollo.js +3 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +3 -13
- package/packages/dd-trace/src/plugins/log_plugin.js +3 -1
- package/packages/dd-trace/src/plugins/tracing.js +5 -3
- package/packages/dd-trace/src/plugins/util/git.js +3 -1
- package/packages/dd-trace/src/plugins/util/test.js +82 -0
- package/packages/dd-trace/src/plugins/util/web.js +11 -0
- package/packages/dd-trace/src/scope.js +7 -5
- package/packages/dd-trace/src/service-naming/extra-services.js +14 -0
- package/vendor/dist/opentracing/LICENSE +0 -201
- package/vendor/dist/opentracing/binary_carrier.d.ts +0 -11
- package/vendor/dist/opentracing/constants.d.ts +0 -61
- package/vendor/dist/opentracing/examples/demo/demo.d.ts +0 -2
- package/vendor/dist/opentracing/ext/tags.d.ts +0 -90
- package/vendor/dist/opentracing/functions.d.ts +0 -20
- package/vendor/dist/opentracing/global_tracer.d.ts +0 -14
- package/vendor/dist/opentracing/index.d.ts +0 -12
- package/vendor/dist/opentracing/index.js +0 -1
- package/vendor/dist/opentracing/mock_tracer/index.d.ts +0 -5
- package/vendor/dist/opentracing/mock_tracer/mock_context.d.ts +0 -13
- package/vendor/dist/opentracing/mock_tracer/mock_report.d.ts +0 -16
- package/vendor/dist/opentracing/mock_tracer/mock_span.d.ts +0 -50
- package/vendor/dist/opentracing/mock_tracer/mock_tracer.d.ts +0 -26
- package/vendor/dist/opentracing/noop.d.ts +0 -8
- package/vendor/dist/opentracing/reference.d.ts +0 -33
- package/vendor/dist/opentracing/span.d.ts +0 -147
- package/vendor/dist/opentracing/span_context.d.ts +0 -26
- package/vendor/dist/opentracing/test/api_compatibility.d.ts +0 -16
- package/vendor/dist/opentracing/test/mocktracer_implemenation.d.ts +0 -3
- package/vendor/dist/opentracing/test/noop_implementation.d.ts +0 -4
- package/vendor/dist/opentracing/test/opentracing_api.d.ts +0 -3
- package/vendor/dist/opentracing/test/unittest.d.ts +0 -2
- package/vendor/dist/opentracing/tracer.d.ts +0 -127
|
@@ -7,6 +7,7 @@ const {
|
|
|
7
7
|
TELEMETRY_ENDPOINT_PAYLOAD_SERIALIZATION_MS,
|
|
8
8
|
TELEMETRY_ENDPOINT_PAYLOAD_EVENTS_COUNT,
|
|
9
9
|
} = require('../ci-visibility/telemetry')
|
|
10
|
+
const { MsgpackChunk } = require('../msgpack')
|
|
10
11
|
const { AgentEncoder } = require('./0.4')
|
|
11
12
|
const { truncateSpan, normalizeSpan } = require('./tags-processors')
|
|
12
13
|
|
|
@@ -20,6 +21,9 @@ const TEST_AND_SPAN_KEYS_LENGTH = 11
|
|
|
20
21
|
|
|
21
22
|
const INTAKE_SOFT_LIMIT = 2 * 1024 * 1024 // 2MB
|
|
22
23
|
|
|
24
|
+
// Prefix is ~1 KB in practice; `MsgpackChunk` resizes on overflow.
|
|
25
|
+
const PREFIX_CHUNK_INITIAL_SIZE = 2048
|
|
26
|
+
|
|
23
27
|
function formatSpan (span) {
|
|
24
28
|
let encodingVersion = ENCODING_VERSION
|
|
25
29
|
if (span.type === 'test' && span.meta && span.meta.test_session_id) {
|
|
@@ -259,10 +263,6 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
259
263
|
}
|
|
260
264
|
|
|
261
265
|
_encode (bytes, trace) {
|
|
262
|
-
if (this._isReset) {
|
|
263
|
-
this._encodePayloadStart(bytes)
|
|
264
|
-
this._isReset = false
|
|
265
|
-
}
|
|
266
266
|
const startTime = Date.now()
|
|
267
267
|
|
|
268
268
|
const events = trace.map(formatSpan)
|
|
@@ -281,20 +281,28 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
281
281
|
|
|
282
282
|
makePayload () {
|
|
283
283
|
distributionMetric(TELEMETRY_ENDPOINT_PAYLOAD_EVENTS_COUNT, { endpoint: 'test_cycle' }, this._eventCount)
|
|
284
|
-
const bytes = this._traceBytes
|
|
285
|
-
const eventsOffset = this._eventsOffset
|
|
286
|
-
const eventsCount = this._eventCount
|
|
287
284
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
285
|
+
// Encode the payload prefix (version + metadata + events-array header) at flush time,
|
|
286
|
+
// not on the first `_encode`. The CI Visibility flow adds metadata across multiple
|
|
287
|
+
// diagnostic channels (`session:start` adds `test_session.name`, the async
|
|
288
|
+
// `library-configuration` callback adds capability tags). Any span finished between
|
|
289
|
+
// those calls would otherwise freeze the prefix with stale metadata.
|
|
290
|
+
const prefixBytes = new MsgpackChunk(PREFIX_CHUNK_INITIAL_SIZE)
|
|
291
|
+
this._encodePayloadStart(prefixBytes)
|
|
293
292
|
|
|
294
|
-
const
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
293
|
+
const eventsOffset = this._eventsOffset
|
|
294
|
+
const eventsCount = this._eventCount
|
|
295
|
+
prefixBytes.buffer[eventsOffset] = 0xDD
|
|
296
|
+
prefixBytes.buffer[eventsOffset + 1] = eventsCount >> 24
|
|
297
|
+
prefixBytes.buffer[eventsOffset + 2] = eventsCount >> 16
|
|
298
|
+
prefixBytes.buffer[eventsOffset + 3] = eventsCount >> 8
|
|
299
|
+
prefixBytes.buffer[eventsOffset + 4] = eventsCount
|
|
300
|
+
|
|
301
|
+
const eventsBytes = this._traceBytes
|
|
302
|
+
const totalSize = prefixBytes.length + eventsBytes.length
|
|
303
|
+
const buffer = Buffer.allocUnsafe(totalSize)
|
|
304
|
+
prefixBytes.buffer.copy(buffer, 0, 0, prefixBytes.length)
|
|
305
|
+
eventsBytes.buffer.copy(buffer, prefixBytes.length, 0, eventsBytes.length)
|
|
298
306
|
|
|
299
307
|
this.reset()
|
|
300
308
|
|
|
@@ -302,7 +310,8 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
302
310
|
}
|
|
303
311
|
|
|
304
312
|
_encodePayloadStart (bytes) {
|
|
305
|
-
//
|
|
313
|
+
// Encodes the payload up to (and including) the `events` array prefix. The 5 reserved
|
|
314
|
+
// bytes for the array length are patched in `makePayload`.
|
|
306
315
|
const payload = {
|
|
307
316
|
version: ENCODING_VERSION,
|
|
308
317
|
metadata: {
|
|
@@ -346,7 +355,6 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
346
355
|
this._encodeMap(bytes, payload.metadata.test_session_end)
|
|
347
356
|
}
|
|
348
357
|
this._encodeString(bytes, 'events')
|
|
349
|
-
// Get offset of the events list to update the length of the array when calling `makePayload`
|
|
350
358
|
this._eventsOffset = bytes.length
|
|
351
359
|
bytes.reserve(5)
|
|
352
360
|
}
|
|
@@ -354,7 +362,6 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
354
362
|
reset () {
|
|
355
363
|
this._reset()
|
|
356
364
|
this._eventCount = 0
|
|
357
|
-
this._isReset = true
|
|
358
365
|
}
|
|
359
366
|
}
|
|
360
367
|
|
|
@@ -4,6 +4,8 @@ const http = require('http')
|
|
|
4
4
|
const https = require('https')
|
|
5
5
|
const { storage } = require('../../../../datadog-core')
|
|
6
6
|
|
|
7
|
+
const legacyStorage = storage('legacy')
|
|
8
|
+
|
|
7
9
|
const keepAlive = true
|
|
8
10
|
const maxSockets = 1
|
|
9
11
|
|
|
@@ -26,7 +28,7 @@ function createAgentClass (BaseAgent) {
|
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
_noop (callback) {
|
|
29
|
-
return
|
|
31
|
+
return legacyStorage.run({ noop: true }, callback)
|
|
30
32
|
}
|
|
31
33
|
}
|
|
32
34
|
|
|
@@ -20,6 +20,8 @@ const {
|
|
|
20
20
|
markEndpointReached,
|
|
21
21
|
} = require('./retry')
|
|
22
22
|
|
|
23
|
+
const legacyStorage = storage('legacy')
|
|
24
|
+
|
|
23
25
|
const maxActiveBufferSize = 1024 * 1024 * 64
|
|
24
26
|
|
|
25
27
|
let activeBufferSize = 0
|
|
@@ -161,7 +163,7 @@ function request (data, options, callback) {
|
|
|
161
163
|
|
|
162
164
|
activeBufferSize += options.headers['Content-Length'] ?? 0
|
|
163
165
|
|
|
164
|
-
|
|
166
|
+
legacyStorage.run({ noop: true }, () => {
|
|
165
167
|
let finished = false
|
|
166
168
|
const finalize = () => {
|
|
167
169
|
if (finished) return
|
|
@@ -13,6 +13,12 @@ let batch = 0
|
|
|
13
13
|
class Identifier {
|
|
14
14
|
/** @type {number[] | Uint8Array} */
|
|
15
15
|
#buffer
|
|
16
|
+
/** @type {bigint | undefined} */
|
|
17
|
+
#bigInt
|
|
18
|
+
/** @type {string | undefined} */
|
|
19
|
+
#stringHex
|
|
20
|
+
/** @type {string | undefined} */
|
|
21
|
+
#stringDecimal
|
|
16
22
|
|
|
17
23
|
/**
|
|
18
24
|
* @param {string} value
|
|
@@ -29,16 +35,23 @@ class Identifier {
|
|
|
29
35
|
* @returns {string}
|
|
30
36
|
*/
|
|
31
37
|
toString (radix = 16) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
if (radix === 16) {
|
|
39
|
+
this.#stringHex ??= Buffer.from(this.#buffer).toString('hex')
|
|
40
|
+
return this.#stringHex
|
|
41
|
+
}
|
|
42
|
+
if (radix === 10) {
|
|
43
|
+
this.#stringDecimal ??= toNumberString(this.#buffer, 10)
|
|
44
|
+
return this.#stringDecimal
|
|
45
|
+
}
|
|
46
|
+
return toNumberString(this.#buffer, radix)
|
|
35
47
|
}
|
|
36
48
|
|
|
37
49
|
/**
|
|
38
50
|
* @returns {bigint}
|
|
39
51
|
*/
|
|
40
52
|
toBigInt () {
|
|
41
|
-
|
|
53
|
+
this.#bigInt ??= Buffer.from(this.#buffer).readBigUInt64BE(0)
|
|
54
|
+
return this.#bigInt
|
|
42
55
|
}
|
|
43
56
|
|
|
44
57
|
/**
|
|
@@ -6,8 +6,6 @@ const { ERROR_MESSAGE, ERROR_TYPE } = require('../constants')
|
|
|
6
6
|
const { ImpendingTimeout } = require('./runtime/errors')
|
|
7
7
|
const { extractContext } = require('./context')
|
|
8
8
|
|
|
9
|
-
const globalTracer = global._ddtrace
|
|
10
|
-
const tracer = globalTracer._tracer
|
|
11
9
|
const timeoutChannel = channel('apm:aws:lambda:timeout')
|
|
12
10
|
// Always crash the flushes when a message is received
|
|
13
11
|
// from this channel.
|
|
@@ -25,8 +23,7 @@ let __lambdaTimeout
|
|
|
25
23
|
*/
|
|
26
24
|
function checkTimeout (context) {
|
|
27
25
|
const remainingTimeInMillis = context.getRemainingTimeInMillis()
|
|
28
|
-
|
|
29
|
-
const apmFlushDeadline = tracer._config.DD_APM_FLUSH_DEADLINE_MILLISECONDS
|
|
26
|
+
const apmFlushDeadline = global._ddtrace._tracer._config.DD_APM_FLUSH_DEADLINE_MILLISECONDS
|
|
30
27
|
|
|
31
28
|
__lambdaTimeout = setTimeout(() => {
|
|
32
29
|
timeoutChannel.publish()
|
|
@@ -42,6 +39,7 @@ function checkTimeout (context) {
|
|
|
42
39
|
* Once that is done, it finishes the last span.
|
|
43
40
|
*/
|
|
44
41
|
function crashFlush () {
|
|
42
|
+
const tracer = global._ddtrace._tracer
|
|
45
43
|
const activeSpan = tracer.scope().active()
|
|
46
44
|
if (activeSpan === null) {
|
|
47
45
|
log.debug('An impending timeout was reached, but no root span was found. No error will be tagged.')
|
|
@@ -55,6 +55,11 @@ class LLMObs extends NoopLLMObs {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
enable (options = {}) {
|
|
58
|
+
logger.warn(
|
|
59
|
+
'Enabling LLM Observability via `llmobs.enable()` is deprecated and will be removed in dd-trace@7.0.0. ' +
|
|
60
|
+
'Please instantiate LLM Observability via DD_LLMOBS_ENABLED or `tracer.init({ llmobs: ...options })`.'
|
|
61
|
+
)
|
|
62
|
+
|
|
58
63
|
if (this.enabled) {
|
|
59
64
|
logger.debug('LLMObs is already enabled.')
|
|
60
65
|
return
|
|
@@ -79,6 +84,11 @@ class LLMObs extends NoopLLMObs {
|
|
|
79
84
|
}
|
|
80
85
|
|
|
81
86
|
disable () {
|
|
87
|
+
logger.warn(
|
|
88
|
+
'Disabling LLM Observability via `llmobs.disable()` is deprecated and will be removed in dd-trace@7.0.0. ' +
|
|
89
|
+
'Set DD_LLMOBS_ENABLED=false to disable LLM Observability.'
|
|
90
|
+
)
|
|
91
|
+
|
|
82
92
|
if (!this.enabled) {
|
|
83
93
|
logger.debug('LLMObs is already disabled.')
|
|
84
94
|
return
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
const { storage } = require('../../../datadog-core')
|
|
4
4
|
const { LogChannel } = require('./channels')
|
|
5
5
|
|
|
6
|
+
const legacyStorage = storage('legacy')
|
|
7
|
+
|
|
6
8
|
const defaultLogger = {
|
|
7
9
|
debug: msg => console.debug(msg), /* eslint-disable-line no-console */
|
|
8
10
|
info: msg => console.info(msg), /* eslint-disable-line no-console */
|
|
@@ -15,7 +17,7 @@ let logger = defaultLogger
|
|
|
15
17
|
let logChannel = new LogChannel()
|
|
16
18
|
|
|
17
19
|
function withNoop (fn) {
|
|
18
|
-
|
|
20
|
+
legacyStorage.run({ noop: true }, fn)
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
function toggleSubscription (enable, level) {
|
|
@@ -4,9 +4,11 @@ const id = require('../id')
|
|
|
4
4
|
const { storage } = require('../../../datadog-core') // TODO: noop storage?
|
|
5
5
|
const NoopSpanContext = require('./span_context')
|
|
6
6
|
|
|
7
|
+
const legacyStorage = storage('legacy')
|
|
8
|
+
|
|
7
9
|
class NoopSpan {
|
|
8
10
|
constructor (tracer, parent) {
|
|
9
|
-
this._store =
|
|
11
|
+
this._store = legacyStorage.getHandle()
|
|
10
12
|
this._noopTracer = tracer
|
|
11
13
|
this._noopContext = this._createContext(parent)
|
|
12
14
|
}
|
|
@@ -8,8 +8,14 @@ const {
|
|
|
8
8
|
EVP_PAYLOAD_SIZE_LIMIT,
|
|
9
9
|
EVP_EVENT_SIZE_LIMIT,
|
|
10
10
|
} = require('../constants/constants')
|
|
11
|
+
const log = require('../../log')
|
|
11
12
|
const BaseFFEWriter = require('./base')
|
|
12
13
|
|
|
14
|
+
// Disabled-state cap. Drops invalidate experiment results because the provider's
|
|
15
|
+
// exposure dedupe cache keeps masking dropped events after recovery. The first
|
|
16
|
+
// drop emits a warning and `droppedEventCount` accumulates the cumulative loss.
|
|
17
|
+
const PENDING_MAX_EVENTS = 1000
|
|
18
|
+
|
|
13
19
|
/**
|
|
14
20
|
* @typedef {object} ExposureEvent
|
|
15
21
|
* @property {number} timestamp - Unix timestamp in milliseconds
|
|
@@ -42,11 +48,21 @@ const BaseFFEWriter = require('./base')
|
|
|
42
48
|
* ExposuresWriter is responsible for sending exposure events to the Datadog Agent.
|
|
43
49
|
*/
|
|
44
50
|
class ExposuresWriter extends BaseFFEWriter {
|
|
51
|
+
// Disabled until the agent strategy probe resolves.
|
|
52
|
+
#enabled = false
|
|
53
|
+
|
|
54
|
+
/** @type {ExposureEvent[]} */
|
|
55
|
+
#pendingEvents = []
|
|
56
|
+
|
|
57
|
+
/** @type {ExposureContext} */
|
|
58
|
+
#context
|
|
59
|
+
|
|
60
|
+
#dropWarned = false
|
|
61
|
+
|
|
45
62
|
/**
|
|
46
63
|
* @param {import('../../config/config-base')} config - Tracer configuration object
|
|
47
64
|
*/
|
|
48
65
|
constructor (config) {
|
|
49
|
-
// Build full EVP endpoint path
|
|
50
66
|
const basePath = EVP_PROXY_AGENT_BASE_PATH.replace(/\/+$/, '')
|
|
51
67
|
const endpoint = EXPOSURES_ENDPOINT.replace(/^\/+/, '')
|
|
52
68
|
const fullEndpoint = `${basePath}/${endpoint}`
|
|
@@ -60,33 +76,33 @@ class ExposuresWriter extends BaseFFEWriter {
|
|
|
60
76
|
[EVP_SUBDOMAIN_HEADER_NAME]: EVP_SUBDOMAIN_VALUE,
|
|
61
77
|
},
|
|
62
78
|
})
|
|
63
|
-
this._enabled = false // Start disabled until agent strategy is set
|
|
64
|
-
this._pendingEvents = [] // Buffer events until enabled
|
|
65
79
|
|
|
80
|
+
/** @type {ExposureContext} */
|
|
66
81
|
const context = {
|
|
67
82
|
service: config.service,
|
|
68
83
|
}
|
|
69
|
-
|
|
84
|
+
|
|
70
85
|
if (config.version !== undefined) {
|
|
71
86
|
context.version = config.version
|
|
72
87
|
}
|
|
88
|
+
|
|
73
89
|
if (config.env !== undefined) {
|
|
74
90
|
context.env = config.env
|
|
75
91
|
}
|
|
76
92
|
|
|
77
|
-
this
|
|
93
|
+
this.#context = context
|
|
78
94
|
}
|
|
79
95
|
|
|
80
96
|
/**
|
|
81
97
|
* @param {boolean} enabled - Whether to enable the writer
|
|
82
98
|
*/
|
|
83
99
|
setEnabled (enabled) {
|
|
84
|
-
this
|
|
100
|
+
this.#enabled = enabled
|
|
85
101
|
|
|
86
|
-
if (enabled && this.
|
|
102
|
+
if (enabled && this.#pendingEvents.length > 0) {
|
|
87
103
|
// Flush all pending events as a batch
|
|
88
|
-
super.append(this
|
|
89
|
-
this
|
|
104
|
+
super.append(this.#pendingEvents)
|
|
105
|
+
this.#pendingEvents = []
|
|
90
106
|
}
|
|
91
107
|
}
|
|
92
108
|
|
|
@@ -95,24 +111,38 @@ class ExposuresWriter extends BaseFFEWriter {
|
|
|
95
111
|
* @param {ExposureEvent|ExposureEvent[]} events - Exposure event(s) to append
|
|
96
112
|
*/
|
|
97
113
|
append (events) {
|
|
98
|
-
if (
|
|
99
|
-
|
|
100
|
-
if (Array.isArray(events)) {
|
|
101
|
-
this._pendingEvents.push(...events)
|
|
102
|
-
} else {
|
|
103
|
-
this._pendingEvents.push(events)
|
|
104
|
-
}
|
|
114
|
+
if (this.#enabled) {
|
|
115
|
+
super.append(events)
|
|
105
116
|
return
|
|
106
117
|
}
|
|
107
|
-
|
|
118
|
+
|
|
119
|
+
const eventArray = Array.isArray(events) ? events : [events]
|
|
120
|
+
this.#pendingEvents.push(...eventArray)
|
|
121
|
+
if (this.#pendingEvents.length > PENDING_MAX_EVENTS) {
|
|
122
|
+
const dropped = this.#pendingEvents.length - PENDING_MAX_EVENTS
|
|
123
|
+
this.#pendingEvents.splice(0, dropped)
|
|
124
|
+
this._droppedEvents += dropped
|
|
125
|
+
if (!this.#dropWarned) {
|
|
126
|
+
this.#dropWarned = true
|
|
127
|
+
log.warn(
|
|
128
|
+
'%s dropped exposure event(s) at cap %d. This may invalidate experiment results.',
|
|
129
|
+
this.constructor.name, PENDING_MAX_EVENTS)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @returns {number} Cumulative number of exposure events dropped due to buffer overflow.
|
|
136
|
+
*/
|
|
137
|
+
get droppedEventCount () {
|
|
138
|
+
return this._droppedEvents
|
|
108
139
|
}
|
|
109
140
|
|
|
110
141
|
/**
|
|
111
142
|
* Flushes buffered exposure events to the agent
|
|
112
143
|
*/
|
|
113
144
|
flush () {
|
|
114
|
-
if (!this
|
|
115
|
-
// Don't flush when disabled
|
|
145
|
+
if (!this.#enabled) {
|
|
116
146
|
return
|
|
117
147
|
}
|
|
118
148
|
super.flush()
|
|
@@ -125,6 +155,7 @@ class ExposuresWriter extends BaseFFEWriter {
|
|
|
125
155
|
*/
|
|
126
156
|
makePayload (events) {
|
|
127
157
|
const formattedEvents = events.map(event => {
|
|
158
|
+
/** @type {ExposureEvent} */
|
|
128
159
|
return {
|
|
129
160
|
timestamp: event.timestamp || Date.now(),
|
|
130
161
|
allocation: {
|
|
@@ -145,7 +176,7 @@ class ExposuresWriter extends BaseFFEWriter {
|
|
|
145
176
|
})
|
|
146
177
|
|
|
147
178
|
return {
|
|
148
|
-
context: this
|
|
179
|
+
context: this.#context,
|
|
149
180
|
exposures: formattedEvents,
|
|
150
181
|
}
|
|
151
182
|
}
|
|
@@ -3,13 +3,15 @@
|
|
|
3
3
|
const { storage } = require('../../../datadog-core')
|
|
4
4
|
const TracingPlugin = require('./tracing')
|
|
5
5
|
|
|
6
|
+
const legacyStorage = storage('legacy')
|
|
7
|
+
|
|
6
8
|
class ApolloBasePlugin extends TracingPlugin {
|
|
7
9
|
static id = 'apollo.gateway'
|
|
8
10
|
static type = 'web'
|
|
9
11
|
static kind = 'server'
|
|
10
12
|
|
|
11
13
|
bindStart (ctx) {
|
|
12
|
-
const store =
|
|
14
|
+
const store = legacyStorage.getStore()
|
|
13
15
|
const childOf = store ? /** @type {import('../opentracing/span') | undefined} */ (store.span) : null
|
|
14
16
|
|
|
15
17
|
const span = this.startSpan(this.getOperationName(), {
|
|
@@ -82,6 +82,8 @@ const {
|
|
|
82
82
|
DD_CAPABILITIES_TEST_IMPACT_ANALYSIS,
|
|
83
83
|
} = require('./util/test')
|
|
84
84
|
|
|
85
|
+
const legacyStorage = storage('legacy')
|
|
86
|
+
|
|
85
87
|
const FRAMEWORK_TO_TRIMMED_COMMAND = {
|
|
86
88
|
vitest: 'vitest run',
|
|
87
89
|
mocha: 'mocha',
|
|
@@ -147,7 +149,7 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
147
149
|
|
|
148
150
|
this.addSub(`ci:${this.constructor.id}:library-configuration`, (ctx) => {
|
|
149
151
|
const { onDone, frameworkVersion } = ctx
|
|
150
|
-
ctx.currentStore =
|
|
152
|
+
ctx.currentStore = legacyStorage.getStore()
|
|
151
153
|
|
|
152
154
|
if (!this.tracer._exporter || !this.tracer._exporter.getLibraryConfiguration) {
|
|
153
155
|
return onDone({ err: new Error('Test optimization was not initialized correctly') })
|
|
@@ -249,18 +251,6 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
249
251
|
integrationName: this.constructor.id,
|
|
250
252
|
})
|
|
251
253
|
setItrSkippingEnabledTagFromLibraryConfig(this, frameworkVersion)
|
|
252
|
-
// only for vitest
|
|
253
|
-
// These are added for the worker threads to use
|
|
254
|
-
if (this.constructor.id === 'vitest') {
|
|
255
|
-
// TODO: Figure out alternative ways to pass this information to the worker threads
|
|
256
|
-
// eslint-disable-next-line eslint-rules/eslint-process-env
|
|
257
|
-
process.env.DD_CIVISIBILITY_TEST_SESSION_ID = this.testSessionSpan.context().toTraceId()
|
|
258
|
-
// eslint-disable-next-line eslint-rules/eslint-process-env
|
|
259
|
-
process.env.DD_CIVISIBILITY_TEST_MODULE_ID = this.testModuleSpan.context().toSpanId()
|
|
260
|
-
// eslint-disable-next-line eslint-rules/eslint-process-env
|
|
261
|
-
process.env.DD_CIVISIBILITY_TEST_COMMAND = this.command
|
|
262
|
-
}
|
|
263
|
-
|
|
264
254
|
this.telemetry.ciVisEvent(TELEMETRY_EVENT_CREATED, 'module')
|
|
265
255
|
})
|
|
266
256
|
|
|
@@ -4,6 +4,8 @@ const { LOG } = require('../../../../ext/formats')
|
|
|
4
4
|
const { storage } = require('../../../datadog-core')
|
|
5
5
|
const Plugin = require('./plugin')
|
|
6
6
|
|
|
7
|
+
const legacyStorage = storage('legacy')
|
|
8
|
+
|
|
7
9
|
function messageProxy (message, holder) {
|
|
8
10
|
return new Proxy(message, {
|
|
9
11
|
get (target, key) {
|
|
@@ -38,7 +40,7 @@ module.exports = class LogPlugin extends Plugin {
|
|
|
38
40
|
super(...args)
|
|
39
41
|
|
|
40
42
|
this.addSub(`apm:${this.constructor.id}:log`, (arg) => {
|
|
41
|
-
const span =
|
|
43
|
+
const span = legacyStorage.getStore()?.span
|
|
42
44
|
|
|
43
45
|
// NOTE: This needs to run whether or not there is a span
|
|
44
46
|
// so service, version, and env will always get injected.
|
|
@@ -5,6 +5,8 @@ const analyticsSampler = require('../analytics_sampler')
|
|
|
5
5
|
const { COMPONENT, SVC_SRC_KEY } = require('../constants')
|
|
6
6
|
const Plugin = require('./plugin')
|
|
7
7
|
|
|
8
|
+
const legacyStorage = storage('legacy')
|
|
9
|
+
|
|
8
10
|
class TracingPlugin extends Plugin {
|
|
9
11
|
constructor (...args) {
|
|
10
12
|
super(...args)
|
|
@@ -16,7 +18,7 @@ class TracingPlugin extends Plugin {
|
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
get activeSpan () {
|
|
19
|
-
const store = /** @type {{ span?: import('../../../..').Span }} */ (
|
|
21
|
+
const store = /** @type {{ span?: import('../../../..').Span }} */ (legacyStorage.getStore())
|
|
20
22
|
|
|
21
23
|
return store?.span
|
|
22
24
|
}
|
|
@@ -193,7 +195,7 @@ class TracingPlugin extends Plugin {
|
|
|
193
195
|
serviceSource = service ? 'opt.plugin' : undefined
|
|
194
196
|
}
|
|
195
197
|
|
|
196
|
-
const store =
|
|
198
|
+
const store = legacyStorage.getStore()
|
|
197
199
|
if (store && childOf === undefined) {
|
|
198
200
|
childOf = /** @type {import('../opentracing/span') | undefined} */ (store.span)
|
|
199
201
|
}
|
|
@@ -226,7 +228,7 @@ class TracingPlugin extends Plugin {
|
|
|
226
228
|
|
|
227
229
|
// TODO: Remove this after migration to TracingChannel is done.
|
|
228
230
|
if (enterOrCtx === true) {
|
|
229
|
-
|
|
231
|
+
legacyStorage.enterWith({ ...store, span })
|
|
230
232
|
} else if (enterOrCtx) {
|
|
231
233
|
enterOrCtx.parentStore = store
|
|
232
234
|
enterOrCtx.currentStore = { ...store, span }
|
|
@@ -37,6 +37,8 @@ const {
|
|
|
37
37
|
const { filterSensitiveInfoFromRepository } = require('./url')
|
|
38
38
|
const { cachedExec } = require('./git-cache')
|
|
39
39
|
|
|
40
|
+
const legacyStorage = storage('legacy')
|
|
41
|
+
|
|
40
42
|
const GIT_REV_LIST_MAX_BUFFER = 12 * 1024 * 1024 // 12MB
|
|
41
43
|
|
|
42
44
|
function sanitizedExec (
|
|
@@ -47,7 +49,7 @@ function sanitizedExec (
|
|
|
47
49
|
errorMetric,
|
|
48
50
|
shouldTrim = true
|
|
49
51
|
) {
|
|
50
|
-
return
|
|
52
|
+
return legacyStorage.run({ noop: true }, () => {
|
|
51
53
|
let startTime
|
|
52
54
|
if (operationMetric) {
|
|
53
55
|
incrementCountMetric(operationMetric.name, operationMetric.tags)
|
|
@@ -267,6 +267,87 @@ function getSessionItrSkippingEnabledTags (sessionSpan) {
|
|
|
267
267
|
return {}
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
+
/**
|
|
271
|
+
* Starts supported test optimization requests together when each feature is enabled.
|
|
272
|
+
*
|
|
273
|
+
* @param {{
|
|
274
|
+
* isKnownTestsEnabled: boolean,
|
|
275
|
+
* isTestManagementTestsEnabled: boolean,
|
|
276
|
+
* isSuitesSkippingEnabled?: boolean,
|
|
277
|
+
* getKnownTests: () => Promise<object>,
|
|
278
|
+
* getTestManagementTests: () => Promise<object>,
|
|
279
|
+
* getSkippableSuites?: () => Promise<object>
|
|
280
|
+
* }} options - Test optimization request factories.
|
|
281
|
+
* @returns {Promise<{
|
|
282
|
+
* knownTestsResponse?: object,
|
|
283
|
+
* testManagementTestsResponse?: object,
|
|
284
|
+
* skippableSuitesResponse?: object
|
|
285
|
+
* }>}
|
|
286
|
+
*/
|
|
287
|
+
function getTestOptimizationRequestResults ({
|
|
288
|
+
isKnownTestsEnabled,
|
|
289
|
+
isTestManagementTestsEnabled,
|
|
290
|
+
isSuitesSkippingEnabled,
|
|
291
|
+
getKnownTests,
|
|
292
|
+
getTestManagementTests,
|
|
293
|
+
getSkippableSuites,
|
|
294
|
+
}) {
|
|
295
|
+
const requestPromises = []
|
|
296
|
+
const responseNames = []
|
|
297
|
+
|
|
298
|
+
if (isKnownTestsEnabled) {
|
|
299
|
+
addTestOptimizationRequest(requestPromises, responseNames, 'knownTestsResponse', getKnownTests)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (isTestManagementTestsEnabled) {
|
|
303
|
+
addTestOptimizationRequest(
|
|
304
|
+
requestPromises,
|
|
305
|
+
responseNames,
|
|
306
|
+
'testManagementTestsResponse',
|
|
307
|
+
getTestManagementTests
|
|
308
|
+
)
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (isSuitesSkippingEnabled && getSkippableSuites) {
|
|
312
|
+
addTestOptimizationRequest(requestPromises, responseNames, 'skippableSuitesResponse', getSkippableSuites)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (!requestPromises.length) {
|
|
316
|
+
return Promise.resolve({})
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return Promise.allSettled(requestPromises).then(requestResults => {
|
|
320
|
+
const responses = {}
|
|
321
|
+
|
|
322
|
+
for (let index = 0; index < requestResults.length; index++) {
|
|
323
|
+
const requestResult = requestResults[index]
|
|
324
|
+
responses[responseNames[index]] = requestResult.status === 'fulfilled'
|
|
325
|
+
? requestResult.value
|
|
326
|
+
: { err: requestResult.reason }
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return responses
|
|
330
|
+
})
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Starts a test optimization request.
|
|
335
|
+
*
|
|
336
|
+
* @param {Promise<object>[]} requestPromises - Test optimization request promises.
|
|
337
|
+
* @param {string[]} responseNames - Response keys matching request promises.
|
|
338
|
+
* @param {string} responseName - Response key for this request.
|
|
339
|
+
* @param {() => Promise<object>} getRequest - Test optimization request factory.
|
|
340
|
+
*/
|
|
341
|
+
function addTestOptimizationRequest (requestPromises, responseNames, responseName, getRequest) {
|
|
342
|
+
responseNames.push(responseName)
|
|
343
|
+
|
|
344
|
+
try {
|
|
345
|
+
requestPromises.push(Promise.resolve(getRequest()))
|
|
346
|
+
} catch (err) {
|
|
347
|
+
requestPromises.push(Promise.reject(err))
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
270
351
|
module.exports = {
|
|
271
352
|
TEST_CODE_OWNERS,
|
|
272
353
|
TEST_SESSION_NAME,
|
|
@@ -383,6 +464,7 @@ module.exports = {
|
|
|
383
464
|
DD_CI_LIBRARY_CONFIGURATION_ERROR_KNOWN_TESTS,
|
|
384
465
|
DD_CI_LIBRARY_CONFIGURATION_ERROR_TEST_MANAGEMENT_TESTS,
|
|
385
466
|
getSessionItrSkippingEnabledTags,
|
|
467
|
+
getTestOptimizationRequestResults,
|
|
386
468
|
checkShaDiscrepancies,
|
|
387
469
|
getPullRequestDiff,
|
|
388
470
|
getPullRequestBaseBranch,
|
|
@@ -400,6 +400,17 @@ function addRequestTags (context, spanType) {
|
|
|
400
400
|
}
|
|
401
401
|
}
|
|
402
402
|
|
|
403
|
+
// Datadog scan/test markers, tagged unconditionally so the API endpoint
|
|
404
|
+
// reducer can keep scan/test traffic out of the API inventory.
|
|
405
|
+
const endpointScan = req.headers['x-datadog-endpoint-scan']
|
|
406
|
+
if (endpointScan !== undefined) {
|
|
407
|
+
span.setTag(`${HTTP_REQUEST_HEADERS}.x-datadog-endpoint-scan`, endpointScan)
|
|
408
|
+
}
|
|
409
|
+
const securityTest = req.headers['x-datadog-security-test']
|
|
410
|
+
if (securityTest !== undefined) {
|
|
411
|
+
span.setTag(`${HTTP_REQUEST_HEADERS}.x-datadog-security-test`, securityTest)
|
|
412
|
+
}
|
|
413
|
+
|
|
403
414
|
addHeaders(context)
|
|
404
415
|
}
|
|
405
416
|
|