dd-trace 5.104.0 → 5.106.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 +16 -2
- 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-worker-threads.js +19 -0
- package/packages/datadog-instrumentations/src/cucumber.js +390 -157
- 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-aws-sdk/src/services/bedrockruntime/tracing.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +218 -4
- 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/id.js +15 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +92 -6
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +43 -21
- 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/opentelemetry/trace/otlp_transformer.js +22 -3
- package/packages/dd-trace/src/opentracing/propagation/log.js +18 -7
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +64 -77
- package/packages/dd-trace/src/opentracing/span.js +59 -19
- package/packages/dd-trace/src/opentracing/span_context.js +50 -3
- 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/config.js +10 -23
- package/packages/dd-trace/src/profiling/exporters/agent.js +11 -10
- package/packages/dd-trace/src/profiling/profiler.js +21 -11
- package/packages/dd-trace/src/profiling/profilers/wall.js +12 -7
- 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
|
@@ -4,6 +4,7 @@ const plugins = {
|
|
|
4
4
|
get '@anthropic-ai/sdk' () { return require('../../../datadog-plugin-anthropic/src') },
|
|
5
5
|
get '@apollo/gateway' () { return require('../../../datadog-plugin-apollo/src') },
|
|
6
6
|
get '@aws-sdk/smithy-client' () { return require('../../../datadog-plugin-aws-sdk/src') },
|
|
7
|
+
get '@azure/cosmos' () { return require('../../../datadog-plugin-azure-cosmos/src') },
|
|
7
8
|
get '@azure/event-hubs' () { return require('../../../datadog-plugin-azure-event-hubs/src') },
|
|
8
9
|
get '@azure/functions' () { return require('../../../datadog-plugin-azure-functions/src') },
|
|
9
10
|
get '@modelcontextprotocol/sdk' () { return require('../../../datadog-plugin-modelcontextprotocol-sdk/src') },
|
|
@@ -30,6 +31,7 @@ const plugins = {
|
|
|
30
31
|
get '@prisma/client' () { return require('../../../datadog-plugin-prisma/src') },
|
|
31
32
|
get './runtime/library.js' () { return require('../../../datadog-plugin-prisma/src') },
|
|
32
33
|
get '@redis/client' () { return require('../../../datadog-plugin-redis/src') },
|
|
34
|
+
get '@smithy/core' () { return require('../../../datadog-plugin-aws-sdk/src') },
|
|
33
35
|
get '@smithy/smithy-client' () { return require('../../../datadog-plugin-aws-sdk/src') },
|
|
34
36
|
get '@vitest/runner' () { return require('../../../datadog-plugin-vitest/src') },
|
|
35
37
|
get '@langchain/langgraph' () { return require('../../../datadog-plugin-langgraph/src') },
|
|
@@ -90,6 +92,8 @@ const plugins = {
|
|
|
90
92
|
get mongoose () { return require('../../../datadog-plugin-mongoose/src') },
|
|
91
93
|
get mysql () { return require('../../../datadog-plugin-mysql/src') },
|
|
92
94
|
get mysql2 () { return require('../../../datadog-plugin-mysql2/src') },
|
|
95
|
+
get '@nats-io/nats-core' () { return require('../../../datadog-plugin-nats/src') },
|
|
96
|
+
get '@nats-io/transport-node' () { return require('../../../datadog-plugin-nats/src') },
|
|
93
97
|
get net () { return require('../../../datadog-plugin-net/src') },
|
|
94
98
|
get next () { return require('../../../datadog-plugin-next/src') },
|
|
95
99
|
get 'node:dns' () { return require('../../../datadog-plugin-dns/src') },
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { LOG } = require('../../../../ext/formats')
|
|
4
|
+
const { storage } = require('../../../datadog-core')
|
|
5
|
+
|
|
6
|
+
const legacyStorage = storage('legacy')
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Runs the tracer's log injector and returns the populated log holder, or
|
|
10
|
+
* `undefined` when the propagator emitted no `dd` field (no span, no
|
|
11
|
+
* service / version / env). Hot-path callers gate on the return.
|
|
12
|
+
*
|
|
13
|
+
* @param {object} tracer
|
|
14
|
+
* @returns {{ dd: object } | undefined}
|
|
15
|
+
*/
|
|
16
|
+
function buildLogHolder (tracer) {
|
|
17
|
+
const logHolder = {}
|
|
18
|
+
tracer.inject(legacyStorage.getStore()?.span, LOG, logHolder)
|
|
19
|
+
return logHolder.dd ? logHolder : undefined
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {object} message Caller-owned log record; never mutated.
|
|
24
|
+
* @param {{ dd: object }} logHolder Holds the dd fields injected by the tracer.
|
|
25
|
+
*/
|
|
26
|
+
function messageProxy (message, logHolder) {
|
|
27
|
+
return new Proxy(message, {
|
|
28
|
+
get (target, key) {
|
|
29
|
+
if (shouldOverride(target, key)) return logHolder.dd
|
|
30
|
+
return target[key]
|
|
31
|
+
},
|
|
32
|
+
set (target, key, value) {
|
|
33
|
+
return Reflect.set(target, key, value)
|
|
34
|
+
},
|
|
35
|
+
ownKeys (target) {
|
|
36
|
+
const ownKeys = Reflect.ownKeys(target)
|
|
37
|
+
if (!Object.hasOwn(target, 'dd') && Reflect.isExtensible(target)) {
|
|
38
|
+
ownKeys.push('dd')
|
|
39
|
+
}
|
|
40
|
+
return ownKeys
|
|
41
|
+
},
|
|
42
|
+
getOwnPropertyDescriptor (target, p) {
|
|
43
|
+
return Reflect.getOwnPropertyDescriptor(shouldOverride(target, p) ? logHolder : target, p)
|
|
44
|
+
},
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @param {object} target
|
|
50
|
+
* @param {string | symbol} p
|
|
51
|
+
*/
|
|
52
|
+
function shouldOverride (target, p) {
|
|
53
|
+
return p === 'dd' && !Object.hasOwn(target, p) && Reflect.isExtensible(target)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = { buildLogHolder, messageProxy }
|
|
@@ -1,55 +1,8 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { LOG } = require('../../../../ext/formats')
|
|
4
|
-
const { storage } = require('../../../datadog-core')
|
|
5
3
|
const Plugin = require('./plugin')
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
function messageProxy (message, holder) {
|
|
10
|
-
return new Proxy(message, {
|
|
11
|
-
get (target, key) {
|
|
12
|
-
if (shouldOverride(target, key)) {
|
|
13
|
-
return holder.dd
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
return target[key]
|
|
17
|
-
},
|
|
18
|
-
set (target, key, value) {
|
|
19
|
-
return Reflect.set(target, key, value)
|
|
20
|
-
},
|
|
21
|
-
ownKeys (target) {
|
|
22
|
-
const ownKeys = Reflect.ownKeys(target)
|
|
23
|
-
if (!Object.hasOwn(target, 'dd') && Reflect.isExtensible(target)) {
|
|
24
|
-
ownKeys.push('dd')
|
|
25
|
-
}
|
|
26
|
-
return ownKeys
|
|
27
|
-
},
|
|
28
|
-
getOwnPropertyDescriptor (target, p) {
|
|
29
|
-
return Reflect.getOwnPropertyDescriptor(shouldOverride(target, p) ? holder : target, p)
|
|
30
|
-
},
|
|
31
|
-
})
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function shouldOverride (target, p) {
|
|
35
|
-
return p === 'dd' && !Object.hasOwn(target, p) && Reflect.isExtensible(target)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
module.exports = class LogPlugin extends Plugin {
|
|
39
|
-
constructor (...args) {
|
|
40
|
-
super(...args)
|
|
41
|
-
|
|
42
|
-
this.addSub(`apm:${this.constructor.id}:log`, (arg) => {
|
|
43
|
-
const span = legacyStorage.getStore()?.span
|
|
44
|
-
|
|
45
|
-
// NOTE: This needs to run whether or not there is a span
|
|
46
|
-
// so service, version, and env will always get injected.
|
|
47
|
-
const holder = {}
|
|
48
|
-
this.tracer.inject(span, LOG, holder)
|
|
49
|
-
arg.message = messageProxy(arg.message, holder)
|
|
50
|
-
})
|
|
51
|
-
}
|
|
52
|
-
|
|
5
|
+
class LogPlugin extends Plugin {
|
|
53
6
|
configure (config) {
|
|
54
7
|
return super.configure({
|
|
55
8
|
...config,
|
|
@@ -57,3 +10,5 @@ module.exports = class LogPlugin extends Plugin {
|
|
|
57
10
|
})
|
|
58
11
|
}
|
|
59
12
|
}
|
|
13
|
+
|
|
14
|
+
module.exports = LogPlugin
|
|
@@ -125,7 +125,7 @@ class OutboundPlugin extends TracingPlugin {
|
|
|
125
125
|
*/
|
|
126
126
|
tagPeerService (span) {
|
|
127
127
|
if (this._tracerConfig.spanComputePeerService) {
|
|
128
|
-
const peerData = this.getPeerService(span.context().
|
|
128
|
+
const peerData = this.getPeerService(span.context().getTags())
|
|
129
129
|
if (peerData !== undefined) {
|
|
130
130
|
span.addTags(this.getPeerServiceRemap(peerData))
|
|
131
131
|
}
|
|
@@ -6,6 +6,8 @@ const dc = require('dc-polyfill')
|
|
|
6
6
|
const logger = require('../log')
|
|
7
7
|
const { storage } = require('../../../datadog-core')
|
|
8
8
|
|
|
9
|
+
const legacyStorage = storage('legacy')
|
|
10
|
+
|
|
9
11
|
/**
|
|
10
12
|
* Base class for all Datadog plugins.
|
|
11
13
|
*
|
|
@@ -28,8 +30,7 @@ class Subscription {
|
|
|
28
30
|
constructor (event, handler) {
|
|
29
31
|
this._channel = dc.channel(event)
|
|
30
32
|
this._handler = (message, name) => {
|
|
31
|
-
|
|
32
|
-
if (!store || !store.noop) {
|
|
33
|
+
if (!legacyStorage.getHandle()?.noop) {
|
|
33
34
|
handler(message, name)
|
|
34
35
|
}
|
|
35
36
|
}
|
|
@@ -50,20 +51,20 @@ class StoreBinding {
|
|
|
50
51
|
constructor (event, transform) {
|
|
51
52
|
this._channel = dc.channel(event)
|
|
52
53
|
this._transform = data => {
|
|
53
|
-
const
|
|
54
|
+
const handle = legacyStorage.getHandle()
|
|
54
55
|
|
|
55
|
-
return !
|
|
56
|
+
return !handle?.noop || (data && Object.hasOwn(data, 'currentStore'))
|
|
56
57
|
? transform(data)
|
|
57
|
-
:
|
|
58
|
+
: legacyStorage.getStore()
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
enable () {
|
|
62
|
-
this._channel.bindStore(
|
|
63
|
+
this._channel.bindStore(legacyStorage, this._transform)
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
disable () {
|
|
66
|
-
this._channel.unbindStore(
|
|
67
|
+
this._channel.unbindStore(legacyStorage)
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
70
|
|
|
@@ -102,24 +103,21 @@ module.exports = class Plugin {
|
|
|
102
103
|
* @returns {void}
|
|
103
104
|
*/
|
|
104
105
|
enter (span, store) {
|
|
105
|
-
store = store ||
|
|
106
|
-
|
|
106
|
+
store = store || legacyStorage.getStore()
|
|
107
|
+
legacyStorage.enterWith({ ...store, span })
|
|
107
108
|
}
|
|
108
109
|
|
|
109
110
|
/**
|
|
110
111
|
* Subscribe to a diagnostic channel with automatic error handling and enable/disable lifecycle.
|
|
111
112
|
*
|
|
112
113
|
* @param {string} channelName Diagnostic channel name.
|
|
113
|
-
* @param {(
|
|
114
|
+
* @param {(message: unknown, name: string) => unknown} handler Handler invoked on messages.
|
|
114
115
|
* @returns {void}
|
|
115
116
|
*/
|
|
116
117
|
addSub (channelName, handler) {
|
|
117
|
-
|
|
118
|
-
* @type {typeof handler}
|
|
119
|
-
*/
|
|
120
|
-
const wrappedHandler = (...args) => {
|
|
118
|
+
const wrappedHandler = (message, name) => {
|
|
121
119
|
try {
|
|
122
|
-
return handler.
|
|
120
|
+
return handler.call(this, message, name)
|
|
123
121
|
} catch (error) {
|
|
124
122
|
logger.error('Error in plugin handler:', error)
|
|
125
123
|
logger.info('Disabling plugin: %s', this.constructor.name)
|
|
@@ -147,12 +145,12 @@ module.exports = class Plugin {
|
|
|
147
145
|
* @returns {void}
|
|
148
146
|
*/
|
|
149
147
|
addError (error) {
|
|
150
|
-
const store =
|
|
148
|
+
const store = legacyStorage.getStore()
|
|
151
149
|
|
|
152
150
|
if (!store || !store.span) return
|
|
153
151
|
|
|
154
152
|
const span = /** @type {import('../opentracing/span')} */ (store.span)
|
|
155
|
-
if (!span.
|
|
153
|
+
if (!span.context().getTag('error')) {
|
|
156
154
|
span.setTag('error', error || 1)
|
|
157
155
|
}
|
|
158
156
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const { storage } = require('../../../datadog-core')
|
|
4
4
|
const analyticsSampler = require('../analytics_sampler')
|
|
5
5
|
const { COMPONENT, SVC_SRC_KEY } = require('../constants')
|
|
6
|
+
const { INTEGRATION_SERVICE } = require('../service-naming/source-resolver')
|
|
6
7
|
const Plugin = require('./plugin')
|
|
7
8
|
|
|
8
9
|
const legacyStorage = storage('legacy')
|
|
@@ -99,13 +100,11 @@ class TracingPlugin extends Plugin {
|
|
|
99
100
|
const bindName = `bind${event.charAt(0).toUpperCase()}${event.slice(1)}`
|
|
100
101
|
|
|
101
102
|
if (this[event]) {
|
|
102
|
-
this.addTraceSub(event,
|
|
103
|
-
this[event](message)
|
|
104
|
-
})
|
|
103
|
+
this.addTraceSub(event, this[event].bind(this))
|
|
105
104
|
}
|
|
106
105
|
|
|
107
106
|
if (this[bindName]) {
|
|
108
|
-
this.addTraceBind(event,
|
|
107
|
+
this.addTraceBind(event, this[bindName].bind(this))
|
|
109
108
|
}
|
|
110
109
|
}
|
|
111
110
|
}
|
|
@@ -128,12 +127,49 @@ class TracingPlugin extends Plugin {
|
|
|
128
127
|
this.addBind(`${prefix}:${eventName}`, transform)
|
|
129
128
|
}
|
|
130
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Record the integration's intended `service.name` on a span without writing the tag.
|
|
132
|
+
*
|
|
133
|
+
* Use this when the plugin has already set `service.name` directly on the span (e.g. via
|
|
134
|
+
* the `tracer.startSpan` tags object) and only needs to stamp the marker so
|
|
135
|
+
* `Span#finish` can later detect user overrides and re-attribute the source.
|
|
136
|
+
*
|
|
137
|
+
* Prefer {@link TracingPlugin#setServiceName} when the tag itself also needs to be written.
|
|
138
|
+
*
|
|
139
|
+
* No-op when there is nothing meaningful to record
|
|
140
|
+
*
|
|
141
|
+
* @param {import('../opentracing/span')} span Internal DatadogSpan instance.
|
|
142
|
+
* @param {string|undefined} name Service name the integration is claiming.
|
|
143
|
+
*/
|
|
144
|
+
stampIntegrationService (span, name) {
|
|
145
|
+
if (name === undefined) return
|
|
146
|
+
span[INTEGRATION_SERVICE] = name
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Set `service.name` on a span on behalf of this integration and stamp the marker.
|
|
151
|
+
*
|
|
152
|
+
* Use this for late-binding cases where the service is not known at startSpan time
|
|
153
|
+
* (e.g. web framework config applied after the span is already open).
|
|
154
|
+
*
|
|
155
|
+
* For spans started via {@link TracingPlugin#startSpan}, pass `service` as an option
|
|
156
|
+
* instead — it sets the tag and stamps the marker in one step.
|
|
157
|
+
*
|
|
158
|
+
* @param {import('../opentracing/span')} span Internal DatadogSpan instance.
|
|
159
|
+
* @param {string} name Service name the integration is claiming.
|
|
160
|
+
*/
|
|
161
|
+
setServiceName (span, name) {
|
|
162
|
+
// eslint-disable-next-line eslint-rules/eslint-prefer-set-service-name -- this is the implementation
|
|
163
|
+
span._spanContext.setTag('service.name', name)
|
|
164
|
+
this.stampIntegrationService(span, name)
|
|
165
|
+
}
|
|
166
|
+
|
|
131
167
|
/**
|
|
132
168
|
* @param {unknown} error
|
|
133
169
|
* @param {import('../../../..').Span} [span]
|
|
134
170
|
*/
|
|
135
171
|
addError (error, span = this.activeSpan) {
|
|
136
|
-
if (span && !span.
|
|
172
|
+
if (span && !span.context().getTag('error')) {
|
|
137
173
|
// Errors may be wrapped in a context.
|
|
138
174
|
span.setTag('error', error?.error || error || 1)
|
|
139
175
|
}
|
|
@@ -224,6 +260,8 @@ class TracingPlugin extends Plugin {
|
|
|
224
260
|
links: childOf?._links,
|
|
225
261
|
})
|
|
226
262
|
|
|
263
|
+
this.stampIntegrationService(span, serviceName)
|
|
264
|
+
|
|
227
265
|
analyticsSampler.sample(span, config.measured)
|
|
228
266
|
|
|
229
267
|
// TODO: Remove this after migration to TracingChannel is done.
|
|
@@ -229,11 +229,11 @@ const BASE_LIKE_BRANCH_FILTER = /^(main|master|preprod|prod|dev|development|trun
|
|
|
229
229
|
|
|
230
230
|
/**
|
|
231
231
|
* Returns request error tags from a test session span for propagation to child events.
|
|
232
|
-
* @param {{ context: () => {
|
|
232
|
+
* @param {{ context: () => { getTag?: (key: string) => string } } | undefined} sessionSpan
|
|
233
233
|
* @returns {Record<string, string>}
|
|
234
234
|
*/
|
|
235
235
|
function getSessionRequestErrorTags (sessionSpan) {
|
|
236
|
-
const tags = sessionSpan?.context()
|
|
236
|
+
const tags = sessionSpan?.context()?.getTags?.()
|
|
237
237
|
const sessionRequestErrorTags = {}
|
|
238
238
|
if (!tags || typeof tags !== 'object') return {}
|
|
239
239
|
if (tags[DD_CI_LIBRARY_CONFIGURATION_ERROR_SETTINGS] === 'true') {
|
|
@@ -253,11 +253,11 @@ function getSessionRequestErrorTags (sessionSpan) {
|
|
|
253
253
|
|
|
254
254
|
/**
|
|
255
255
|
* Returns ITR skipping-enabled tags from a test session span for propagation to child events.
|
|
256
|
-
* @param {{ context: () => {
|
|
256
|
+
* @param {{ context: () => { getTags?: () => Record<string, string> } } | undefined} sessionSpan
|
|
257
257
|
* @returns {Record<string, string>}
|
|
258
258
|
*/
|
|
259
259
|
function getSessionItrSkippingEnabledTags (sessionSpan) {
|
|
260
|
-
const tags = sessionSpan?.context()
|
|
260
|
+
const tags = sessionSpan?.context()?.getTags?.()
|
|
261
261
|
if (!tags || typeof tags !== 'object') return {}
|
|
262
262
|
if (tags[TEST_ITR_SKIPPING_ENABLED] !== undefined) {
|
|
263
263
|
return {
|
|
@@ -418,6 +418,12 @@ module.exports = {
|
|
|
418
418
|
ITR_CORRELATION_ID,
|
|
419
419
|
addIntelligentTestRunnerSpanTags,
|
|
420
420
|
getCoveredFilenamesFromCoverage,
|
|
421
|
+
getCoveredFilesFromCoverage,
|
|
422
|
+
getExecutableFilesFromCoverage,
|
|
423
|
+
getRelativeCoverageFiles,
|
|
424
|
+
getLineCoverageBitmap,
|
|
425
|
+
applySkippedCoverageToCoverage,
|
|
426
|
+
getTestCoverageLinesPercentage,
|
|
421
427
|
resetCoverage,
|
|
422
428
|
mergeCoverage,
|
|
423
429
|
fromCoverageMapToCoverage,
|
|
@@ -952,7 +958,6 @@ function getTestLevelCommonTags (command, testFrameworkVersion, testFramework) {
|
|
|
952
958
|
return {
|
|
953
959
|
[TEST_FRAMEWORK_VERSION]: testFrameworkVersion,
|
|
954
960
|
[LIBRARY_VERSION]: ddTraceVersion,
|
|
955
|
-
[TEST_COMMAND]: command,
|
|
956
961
|
[TEST_TYPE]: getTestTypeFromFramework(testFramework),
|
|
957
962
|
}
|
|
958
963
|
}
|
|
@@ -1030,15 +1035,233 @@ function addIntelligentTestRunnerSpanTags (
|
|
|
1030
1035
|
}
|
|
1031
1036
|
|
|
1032
1037
|
function getCoveredFilenamesFromCoverage (coverage) {
|
|
1033
|
-
|
|
1038
|
+
return getCoveredFilesFromCoverage(coverage).map(({ filename }) => filename)
|
|
1039
|
+
}
|
|
1034
1040
|
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1041
|
+
function getCoverageMap (coverage) {
|
|
1042
|
+
if (coverage?.files && coverage?.fileCoverageFor) {
|
|
1043
|
+
return coverage
|
|
1044
|
+
}
|
|
1045
|
+
return istanbul.createCoverageMap(coverage)
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
function getCoveredFilesFromCoverage (coverage) {
|
|
1049
|
+
const coverageMap = getCoverageMap(coverage)
|
|
1050
|
+
const coverageFiles = []
|
|
1051
|
+
|
|
1052
|
+
for (const filename of coverageMap.files()) {
|
|
1053
|
+
const fileCoverage = coverageMap.fileCoverageFor(filename)
|
|
1054
|
+
const bitmap = getLineCoverageBitmap(fileCoverage.getLineCoverage(), true)
|
|
1055
|
+
if (bitmap) {
|
|
1056
|
+
coverageFiles.push({ filename, bitmap })
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
return coverageFiles
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
function getExecutableFilesFromCoverage (coverage) {
|
|
1064
|
+
const coverageMap = getCoverageMap(coverage)
|
|
1065
|
+
const coverageFiles = []
|
|
1066
|
+
|
|
1067
|
+
for (const filename of coverageMap.files()) {
|
|
1068
|
+
const fileCoverage = coverageMap.fileCoverageFor(filename)
|
|
1069
|
+
const bitmap = getLineCoverageBitmap(fileCoverage.getLineCoverage())
|
|
1070
|
+
if (bitmap) {
|
|
1071
|
+
coverageFiles.push({ filename, bitmap })
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
return coverageFiles
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
function getRelativeCoverageFiles (coverageFiles, rootDir) {
|
|
1079
|
+
return coverageFiles.map(({ filename, bitmap }) => ({
|
|
1080
|
+
filename: getTestSuitePath(filename, rootDir),
|
|
1081
|
+
bitmap,
|
|
1082
|
+
}))
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
function getLineCoverageBitmap (lineCoverage, onlyCoveredLines = false) {
|
|
1086
|
+
let maxLine = 0
|
|
1087
|
+
const lines = []
|
|
1088
|
+
|
|
1089
|
+
for (const [line, hits] of Object.entries(lineCoverage)) {
|
|
1090
|
+
if (onlyCoveredLines && !hits) continue
|
|
1091
|
+
|
|
1092
|
+
const lineNumber = Number(line)
|
|
1093
|
+
if (!Number.isSafeInteger(lineNumber) || lineNumber <= 0) continue
|
|
1094
|
+
|
|
1095
|
+
lines.push(lineNumber)
|
|
1096
|
+
if (lineNumber > maxLine) {
|
|
1097
|
+
maxLine = lineNumber
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
if (maxLine === 0) return
|
|
1102
|
+
|
|
1103
|
+
const bitmap = Buffer.alloc(Math.ceil((maxLine + 1) / 8))
|
|
1104
|
+
for (const lineNumber of lines) {
|
|
1105
|
+
bitmap[lineNumber >> 3] |= 1 << (lineNumber % 8)
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
return bitmap
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
function mergeCoverageBitmaps (targetBitmap, bitmap) {
|
|
1112
|
+
if (!targetBitmap) {
|
|
1113
|
+
return Buffer.from(bitmap)
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
if (targetBitmap.length < bitmap.length) {
|
|
1117
|
+
const biggerBitmap = Buffer.alloc(bitmap.length)
|
|
1118
|
+
targetBitmap.copy(biggerBitmap)
|
|
1119
|
+
targetBitmap = biggerBitmap
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
for (let i = 0; i < bitmap.length; i++) {
|
|
1123
|
+
targetBitmap[i] |= bitmap[i]
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
return targetBitmap
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
function countBitmapBits (bitmap) {
|
|
1130
|
+
let count = 0
|
|
1131
|
+
|
|
1132
|
+
for (const byte of bitmap) {
|
|
1133
|
+
let value = byte
|
|
1134
|
+
while (value) {
|
|
1135
|
+
value &= value - 1
|
|
1136
|
+
count++
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
return count
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
function countCoveredExecutableBits (coveredBitmap, executableBitmap) {
|
|
1144
|
+
if (!coveredBitmap) return 0
|
|
1145
|
+
|
|
1146
|
+
let count = 0
|
|
1147
|
+
const length = Math.min(coveredBitmap.length, executableBitmap.length)
|
|
1148
|
+
|
|
1149
|
+
for (let i = 0; i < length; i++) {
|
|
1150
|
+
let value = coveredBitmap[i] & executableBitmap[i]
|
|
1151
|
+
while (value) {
|
|
1152
|
+
value &= value - 1
|
|
1153
|
+
count++
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
return count
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
function getCoverageFileBitmap (bitmap) {
|
|
1161
|
+
if (!bitmap) return
|
|
1162
|
+
if (Buffer.isBuffer(bitmap)) return bitmap
|
|
1163
|
+
if (ArrayBuffer.isView(bitmap)) {
|
|
1164
|
+
return Buffer.from(bitmap.buffer, bitmap.byteOffset, bitmap.byteLength)
|
|
1165
|
+
}
|
|
1166
|
+
if (typeof bitmap === 'string') {
|
|
1167
|
+
return Buffer.from(bitmap, 'base64')
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
function addCoverageFilesToMap (files, targetMap, rootDir) {
|
|
1172
|
+
for (const file of files) {
|
|
1173
|
+
const bitmap = getCoverageFileBitmap(file.bitmap)
|
|
1174
|
+
if (!bitmap) continue
|
|
1175
|
+
|
|
1176
|
+
const filename = rootDir ? getTestSuitePath(file.filename, rootDir) : file.filename
|
|
1177
|
+
targetMap.set(filename, mergeCoverageBitmaps(targetMap.get(filename), bitmap))
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
function addSkippedCoverageToMap (skippedCoverage, targetMap) {
|
|
1182
|
+
if (!skippedCoverage) return
|
|
1183
|
+
|
|
1184
|
+
for (const [filename, bitmap] of Object.entries(skippedCoverage)) {
|
|
1185
|
+
const coverageBitmap = getCoverageFileBitmap(bitmap)
|
|
1186
|
+
if (!coverageBitmap) continue
|
|
1187
|
+
targetMap.set(filename, mergeCoverageBitmaps(targetMap.get(filename), coverageBitmap))
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
function hasSkippedCoverage (skippedCoverage) {
|
|
1192
|
+
return skippedCoverage && typeof skippedCoverage === 'object' && Object.keys(skippedCoverage).length > 0
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
function getTestCoverageLinesPercentage (coverage, skippedCoverage, rootDir) {
|
|
1196
|
+
const executableLinesByFile = new Map()
|
|
1197
|
+
const coveredLinesByFile = new Map()
|
|
1198
|
+
|
|
1199
|
+
addCoverageFilesToMap(getExecutableFilesFromCoverage(coverage), executableLinesByFile, rootDir)
|
|
1200
|
+
addCoverageFilesToMap(getCoveredFilesFromCoverage(coverage), coveredLinesByFile, rootDir)
|
|
1201
|
+
addSkippedCoverageToMap(skippedCoverage, coveredLinesByFile)
|
|
1202
|
+
|
|
1203
|
+
let totalExecutableLines = 0
|
|
1204
|
+
let totalCoveredLines = 0
|
|
1205
|
+
|
|
1206
|
+
for (const [filename, executableLines] of executableLinesByFile) {
|
|
1207
|
+
totalExecutableLines += countBitmapBits(executableLines)
|
|
1208
|
+
totalCoveredLines += countCoveredExecutableBits(coveredLinesByFile.get(filename), executableLines)
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
return totalExecutableLines === 0 ? 0 : Math.floor((totalCoveredLines / totalExecutableLines) * 10_000) / 100
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
function isLineCoveredByBitmap (bitmap, line) {
|
|
1215
|
+
if (!Number.isSafeInteger(line) || line <= 0) return false
|
|
1216
|
+
|
|
1217
|
+
const byteIndex = line >> 3
|
|
1218
|
+
return byteIndex < bitmap.length && !!(bitmap[byteIndex] & (1 << (line % 8)))
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
function getSkippedCoverageByFilename (skippedCoverage) {
|
|
1222
|
+
const skippedCoverageByFilename = new Map()
|
|
1223
|
+
addSkippedCoverageToMap(skippedCoverage, skippedCoverageByFilename)
|
|
1224
|
+
return skippedCoverageByFilename
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
function applySkippedCoverageToFileCoverage (fileCoverage, skippedBitmap) {
|
|
1228
|
+
let updated = false
|
|
1229
|
+
for (const [statementId, statementLocation] of Object.entries(fileCoverage.data.statementMap)) {
|
|
1230
|
+
const startLine = statementLocation?.start?.line
|
|
1231
|
+
if (!isLineCoveredByBitmap(skippedBitmap, startLine)) continue
|
|
1232
|
+
if (fileCoverage.data.s[statementId] > 0) continue
|
|
1233
|
+
|
|
1234
|
+
fileCoverage.data.s[statementId] = 1
|
|
1235
|
+
updated = true
|
|
1236
|
+
}
|
|
1237
|
+
return updated
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
/**
|
|
1241
|
+
* Applies backend skipped-suite coverage to an Istanbul coverage map.
|
|
1242
|
+
* @param {object} coverage
|
|
1243
|
+
* @param {object} skippedCoverage
|
|
1244
|
+
* @param {string} [rootDir]
|
|
1245
|
+
* @returns {boolean}
|
|
1246
|
+
*/
|
|
1247
|
+
function applySkippedCoverageToCoverage (coverage, skippedCoverage, rootDir) {
|
|
1248
|
+
if (!hasSkippedCoverage(skippedCoverage)) return false
|
|
1249
|
+
|
|
1250
|
+
const coverageMap = getCoverageMap(coverage)
|
|
1251
|
+
const skippedCoverageByFilename = getSkippedCoverageByFilename(skippedCoverage)
|
|
1252
|
+
let matched = false
|
|
1253
|
+
|
|
1254
|
+
for (const filename of coverageMap.files()) {
|
|
1255
|
+
const relativeFilename = rootDir ? getTestSuitePath(filename, rootDir) : filename
|
|
1256
|
+
const skippedBitmap = skippedCoverageByFilename.get(relativeFilename)
|
|
1257
|
+
if (!skippedBitmap) continue
|
|
1258
|
+
|
|
1259
|
+
const fileCoverage = coverageMap.fileCoverageFor(filename)
|
|
1260
|
+
applySkippedCoverageToFileCoverage(fileCoverage, skippedBitmap)
|
|
1261
|
+
matched = true
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
return matched
|
|
1042
1265
|
}
|
|
1043
1266
|
|
|
1044
1267
|
function resetCoverage (coverage) {
|