dd-trace 5.96.0 → 5.98.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 +60 -2
- package/package.json +9 -7
- package/packages/datadog-esbuild/index.js +20 -9
- package/packages/datadog-instrumentations/src/child_process.js +7 -17
- package/packages/datadog-instrumentations/src/crypto.js +1 -2
- package/packages/datadog-instrumentations/src/cucumber.js +69 -4
- package/packages/datadog-instrumentations/src/cypress-config.js +318 -0
- package/packages/datadog-instrumentations/src/cypress.js +86 -4
- package/packages/datadog-instrumentations/src/dns.js +1 -2
- package/packages/datadog-instrumentations/src/express.js +4 -4
- package/packages/datadog-instrumentations/src/fs.js +27 -29
- package/packages/datadog-instrumentations/src/graphql.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +41 -13
- package/packages/datadog-instrumentations/src/helpers/hook.js +31 -6
- package/packages/datadog-instrumentations/src/helpers/hooks.js +12 -19
- package/packages/datadog-instrumentations/src/helpers/instrument.js +27 -13
- package/packages/datadog-instrumentations/src/helpers/register.js +103 -142
- package/packages/datadog-instrumentations/src/http/client.js +2 -3
- package/packages/datadog-instrumentations/src/http/server.js +2 -5
- package/packages/datadog-instrumentations/src/http2/client.js +1 -3
- package/packages/datadog-instrumentations/src/http2/server.js +1 -3
- package/packages/datadog-instrumentations/src/jest.js +117 -16
- package/packages/datadog-instrumentations/src/limitd-client.js +1 -1
- package/packages/datadog-instrumentations/src/mocha/utils.js +12 -1
- package/packages/datadog-instrumentations/src/net.js +2 -8
- package/packages/datadog-instrumentations/src/pino.js +1 -1
- package/packages/datadog-instrumentations/src/playwright.js +4 -1
- package/packages/datadog-instrumentations/src/prisma.js +1 -2
- package/packages/datadog-instrumentations/src/redis.js +12 -6
- package/packages/datadog-instrumentations/src/selenium.js +4 -1
- package/packages/datadog-instrumentations/src/sequelize.js +1 -1
- package/packages/datadog-instrumentations/src/url.js +1 -3
- package/packages/datadog-instrumentations/src/vitest.js +5 -1
- package/packages/datadog-instrumentations/src/vm.js +1 -3
- package/packages/datadog-plugin-aws-sdk/src/base.js +5 -4
- package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +1 -0
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -0
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -0
- package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +1 -0
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -0
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -0
- package/packages/datadog-plugin-cucumber/src/index.js +13 -3
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +166 -6
- package/packages/datadog-plugin-cypress/src/index.js +59 -2
- package/packages/datadog-plugin-fs/src/index.js +1 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +2 -7
- package/packages/datadog-plugin-graphql/src/resolve.js +1 -1
- package/packages/datadog-plugin-http/src/client.js +1 -1
- package/packages/datadog-plugin-http/src/server.js +10 -2
- package/packages/datadog-plugin-http2/src/client.js +1 -1
- package/packages/datadog-plugin-http2/src/server.js +10 -2
- package/packages/datadog-plugin-jest/src/index.js +4 -2
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +31 -4
- package/packages/datadog-plugin-mocha/src/index.js +5 -2
- package/packages/datadog-plugin-mongodb-core/src/index.js +3 -3
- package/packages/datadog-plugin-mysql/src/index.js +1 -1
- package/packages/datadog-plugin-next/src/index.js +10 -16
- package/packages/datadog-plugin-openai/src/services.js +1 -0
- package/packages/datadog-plugin-pg/src/index.js +1 -1
- package/packages/datadog-plugin-tedious/src/index.js +1 -1
- package/packages/datadog-plugin-ws/src/close.js +1 -1
- package/packages/datadog-plugin-ws/src/receiver.js +1 -1
- package/packages/datadog-webpack/index.js +3 -3
- package/packages/dd-trace/index.js +12 -10
- package/packages/dd-trace/src/agent/url.js +2 -2
- package/packages/dd-trace/src/aiguard/sdk.js +26 -22
- package/packages/dd-trace/src/appsec/blocked_templates.js +4 -3
- package/packages/dd-trace/src/appsec/blocking.js +64 -33
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
- package/packages/dd-trace/src/appsec/remote_config.js +1 -0
- package/packages/dd-trace/src/appsec/sdk/index.js +4 -0
- package/packages/dd-trace/src/appsec/sdk/set_user.js +1 -1
- package/packages/dd-trace/src/appsec/sdk/track_event.js +5 -5
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +2 -2
- package/packages/dd-trace/src/appsec/sdk/utils.js +4 -2
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +6 -1
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +4 -0
- package/packages/dd-trace/src/config/defaults.js +315 -146
- package/packages/dd-trace/src/config/generated-config-types.d.ts +9 -1
- package/packages/dd-trace/src/config/helper.js +59 -10
- package/packages/dd-trace/src/config/index.js +587 -1496
- package/packages/dd-trace/src/config/parsers.js +256 -0
- package/packages/dd-trace/src/config/remote_config.js +59 -2
- package/packages/dd-trace/src/config/supported-configurations.json +406 -432
- package/packages/dd-trace/src/constants.js +1 -0
- package/packages/dd-trace/src/crashtracking/crashtracker.js +7 -1
- package/packages/dd-trace/src/crashtracking/index.js +1 -7
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +5 -2
- package/packages/dd-trace/src/debugger/index.js +1 -1
- package/packages/dd-trace/src/dogstatsd.js +12 -9
- package/packages/dd-trace/src/encode/0.4.js +8 -7
- package/packages/dd-trace/src/encode/span-stats.js +4 -1
- package/packages/dd-trace/src/exporters/agent/writer.js +7 -1
- package/packages/dd-trace/src/exporters/common/request.js +9 -0
- package/packages/dd-trace/src/exporters/common/writer.js +12 -2
- package/packages/dd-trace/src/heap_snapshots.js +3 -0
- package/packages/dd-trace/src/index.js +5 -2
- package/packages/dd-trace/src/lambda/runtime/ritm.js +6 -6
- package/packages/dd-trace/src/llmobs/index.js +4 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/index.js +5 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +60 -12
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +4 -2
- package/packages/dd-trace/src/llmobs/sdk.js +12 -8
- package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
- package/packages/dd-trace/src/llmobs/tagger.js +9 -6
- package/packages/dd-trace/src/llmobs/writers/base.js +2 -0
- package/packages/dd-trace/src/llmobs/writers/util.js +3 -0
- package/packages/dd-trace/src/log/index.js +20 -59
- package/packages/dd-trace/src/log/writer.js +7 -19
- package/packages/dd-trace/src/noop/proxy.js +8 -0
- package/packages/dd-trace/src/openfeature/remote_config.js +6 -1
- package/packages/dd-trace/src/opentelemetry/context_manager.js +6 -4
- package/packages/dd-trace/src/opentelemetry/logs/index.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +1 -1
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +17 -2
- package/packages/dd-trace/src/opentelemetry/otlp/protobuf_loader.js +14 -2
- package/packages/dd-trace/src/opentelemetry/otlp/trace.proto +358 -0
- package/packages/dd-trace/src/opentelemetry/otlp/trace_service.proto +78 -0
- package/packages/dd-trace/src/opentelemetry/trace/index.js +75 -0
- package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +66 -0
- package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +332 -0
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +9 -4
- package/packages/dd-trace/src/opentracing/tracer.js +9 -4
- package/packages/dd-trace/src/payload-tagging/config/index.js +6 -5
- package/packages/dd-trace/src/plugin_manager.js +8 -6
- package/packages/dd-trace/src/plugins/ci_plugin.js +4 -0
- package/packages/dd-trace/src/plugins/log_plugin.js +3 -0
- package/packages/dd-trace/src/plugins/plugin.js +11 -13
- package/packages/dd-trace/src/plugins/storage.js +2 -2
- package/packages/dd-trace/src/plugins/tracing.js +22 -5
- package/packages/dd-trace/src/plugins/util/test.js +2 -0
- package/packages/dd-trace/src/plugins/util/web.js +6 -88
- package/packages/dd-trace/src/process-tags/index.js +3 -0
- package/packages/dd-trace/src/profiler.js +27 -2
- package/packages/dd-trace/src/profiling/config.js +73 -241
- package/packages/dd-trace/src/profiling/exporter_cli.js +1 -4
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +6 -2
- package/packages/dd-trace/src/profiling/profiler.js +78 -109
- package/packages/dd-trace/src/profiling/profilers/events.js +2 -3
- package/packages/dd-trace/src/profiling/profilers/wall.js +89 -6
- package/packages/dd-trace/src/profiling/ssi-heuristics.js +4 -1
- package/packages/dd-trace/src/propagation-hash/index.js +2 -1
- package/packages/dd-trace/src/proxy.js +40 -6
- package/packages/dd-trace/src/remote_config/index.js +3 -0
- package/packages/dd-trace/src/require-package-json.js +8 -4
- package/packages/dd-trace/src/ritm.js +58 -26
- package/packages/dd-trace/src/runtime_metrics/index.js +3 -0
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +18 -11
- package/packages/dd-trace/src/sampler.js +1 -1
- package/packages/dd-trace/src/service-naming/index.js +1 -1
- package/packages/dd-trace/src/service-naming/schemas/definition.js +4 -1
- package/packages/dd-trace/src/service-naming/schemas/util.js +15 -1
- package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +24 -1
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +60 -0
- package/packages/dd-trace/src/service-naming/schemas/v0/web.js +17 -1
- package/packages/dd-trace/src/service-naming/schemas/v0/websocket.js +5 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +17 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/web.js +11 -1
- package/packages/dd-trace/src/service-naming/schemas/v1/websocket.js +6 -0
- package/packages/dd-trace/src/span_stats.js +5 -1
- package/packages/dd-trace/src/standalone/index.js +3 -0
- package/packages/dd-trace/src/telemetry/index.js +2 -3
- package/packages/dd-trace/src/telemetry/send-data.js +5 -19
- package/packages/dd-trace/src/telemetry/session-propagation.js +19 -44
- package/packages/dd-trace/src/telemetry/telemetry.js +28 -171
- package/packages/dd-trace/src/tracer.js +2 -2
- package/packages/dd-trace/src/util.js +0 -9
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +28 -6
- package/vendor/dist/protobufjs/index.js +1 -1
- package/packages/dd-trace/src/log/utils.js +0 -16
|
@@ -1,17 +1,41 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
+
|
|
2
3
|
const path = require('path')
|
|
4
|
+
|
|
3
5
|
const iitm = require('../../../dd-trace/src/iitm')
|
|
4
6
|
const ritm = require('../../../dd-trace/src/ritm')
|
|
7
|
+
const log = require('../../../dd-trace/src/log')
|
|
8
|
+
const requirePackageJson = require('../../../dd-trace/src/require-package-json')
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {string} moduleBaseDir
|
|
12
|
+
* @returns {string|undefined}
|
|
13
|
+
*/
|
|
14
|
+
function getVersion (moduleBaseDir) {
|
|
15
|
+
if (moduleBaseDir) {
|
|
16
|
+
return requirePackageJson(moduleBaseDir, /** @type {import('module').Module} */ (module)).version
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return process.version
|
|
20
|
+
}
|
|
5
21
|
|
|
6
22
|
/**
|
|
7
23
|
* This is called for every package/internal-module that dd-trace supports instrumentation for
|
|
8
24
|
* In practice, `modules` is always an array with a single entry.
|
|
9
25
|
*
|
|
26
|
+
* @overload
|
|
27
|
+
* @param {string[]} modules list of modules to hook into
|
|
28
|
+
* @param {object} hookOptions hook options
|
|
29
|
+
* @param {Function} onrequire callback to be executed upon encountering module
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* @overload
|
|
10
33
|
* @param {string[]} modules list of modules to hook into
|
|
11
34
|
* @param {object} hookOptions hook options
|
|
12
35
|
* @param {Function} onrequire callback to be executed upon encountering module
|
|
13
36
|
*/
|
|
14
37
|
function Hook (modules, hookOptions, onrequire) {
|
|
38
|
+
// TODO: Rewrite this to use class syntax. The same should be done for ritm.
|
|
15
39
|
if (!(this instanceof Hook)) return new Hook(modules, hookOptions, onrequire)
|
|
16
40
|
|
|
17
41
|
if (typeof hookOptions === 'function') {
|
|
@@ -42,6 +66,13 @@ function Hook (modules, hookOptions, onrequire) {
|
|
|
42
66
|
return result
|
|
43
67
|
}
|
|
44
68
|
|
|
69
|
+
try {
|
|
70
|
+
moduleVersion ||= getVersion(moduleBaseDir)
|
|
71
|
+
} catch (error) {
|
|
72
|
+
log.error('Error getting version for "%s": %s', moduleName, error.message, error)
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
|
|
45
76
|
if (
|
|
46
77
|
isIitm &&
|
|
47
78
|
moduleExports.default &&
|
|
@@ -66,10 +97,4 @@ function Hook (modules, hookOptions, onrequire) {
|
|
|
66
97
|
})
|
|
67
98
|
}
|
|
68
99
|
|
|
69
|
-
Hook.prototype.unhook = function () {
|
|
70
|
-
this._ritmHook.unhook()
|
|
71
|
-
this._iitmHook.unhook()
|
|
72
|
-
this._patched = Object.create(null)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
100
|
module.exports = Hook
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
|
+
// Only list unprefixed node modules. They will automatically be instrumented as prefixed and unprefixed.
|
|
5
|
+
child_process: () => require('../child_process'),
|
|
6
|
+
crypto: () => require('../crypto'),
|
|
7
|
+
dns: () => require('../dns'),
|
|
8
|
+
fs: { serverless: false, fn: () => require('../fs') },
|
|
9
|
+
http: () => require('../http'),
|
|
10
|
+
http2: () => require('../http2'),
|
|
11
|
+
https: () => require('../http'),
|
|
12
|
+
net: () => require('../net'),
|
|
13
|
+
url: () => require('../url'),
|
|
14
|
+
vm: () => require('../vm'),
|
|
15
|
+
// Non Node.js modules
|
|
4
16
|
'@anthropic-ai/sdk': { esmFirst: true, fn: () => require('../anthropic') },
|
|
5
17
|
'@apollo/server': () => require('../apollo-server'),
|
|
6
18
|
'@apollo/gateway': () => require('../apollo'),
|
|
@@ -47,31 +59,24 @@ module.exports = {
|
|
|
47
59
|
bullmq: () => require('../bullmq'),
|
|
48
60
|
bunyan: () => require('../bunyan'),
|
|
49
61
|
'cassandra-driver': () => require('../cassandra-driver'),
|
|
50
|
-
child_process: () => require('../child_process'),
|
|
51
62
|
connect: () => require('../connect'),
|
|
52
63
|
cookie: () => require('../cookie'),
|
|
53
64
|
'cookie-parser': () => require('../cookie-parser'),
|
|
54
65
|
couchbase: () => require('../couchbase'),
|
|
55
|
-
crypto: () => require('../crypto'),
|
|
56
66
|
cypress: () => require('../cypress'),
|
|
57
67
|
'dd-trace-api': () => require('../dd-trace-api'),
|
|
58
|
-
dns: () => require('../dns'),
|
|
59
68
|
elasticsearch: () => require('../elasticsearch'),
|
|
60
69
|
express: () => require('../express'),
|
|
61
70
|
'express-mongo-sanitize': () => require('../express-mongo-sanitize'),
|
|
62
71
|
'express-session': () => require('../express-session'),
|
|
63
72
|
fastify: () => require('../fastify'),
|
|
64
73
|
'find-my-way': () => require('../find-my-way'),
|
|
65
|
-
fs: { serverless: false, fn: () => require('../fs') },
|
|
66
74
|
'generic-pool': () => require('../generic-pool'),
|
|
67
75
|
graphql: () => require('../graphql'),
|
|
68
76
|
grpc: () => require('../grpc'),
|
|
69
77
|
handlebars: () => require('../handlebars'),
|
|
70
78
|
hapi: () => require('../hapi'),
|
|
71
79
|
hono: { esmFirst: true, fn: () => require('../hono') },
|
|
72
|
-
http: () => require('../http'),
|
|
73
|
-
http2: () => require('../http2'),
|
|
74
|
-
https: () => require('../http'),
|
|
75
80
|
ioredis: () => require('../ioredis'),
|
|
76
81
|
iovalkey: () => require('../iovalkey'),
|
|
77
82
|
'jest-circus': () => require('../jest'),
|
|
@@ -103,18 +108,8 @@ module.exports = {
|
|
|
103
108
|
multer: () => require('../multer'),
|
|
104
109
|
mysql: () => require('../mysql'),
|
|
105
110
|
mysql2: () => require('../mysql2'),
|
|
106
|
-
net: () => require('../net'),
|
|
107
111
|
next: () => require('../next'),
|
|
108
112
|
'node-serialize': () => require('../node-serialize'),
|
|
109
|
-
'node:child_process': () => require('../child_process'),
|
|
110
|
-
'node:crypto': () => require('../crypto'),
|
|
111
|
-
'node:dns': () => require('../dns'),
|
|
112
|
-
'node:http': () => require('../http'),
|
|
113
|
-
'node:http2': () => require('../http2'),
|
|
114
|
-
'node:https': () => require('../http'),
|
|
115
|
-
'node:net': () => require('../net'),
|
|
116
|
-
'node:url': () => require('../url'),
|
|
117
|
-
'node:vm': () => require('../vm'),
|
|
118
113
|
nyc: () => require('../nyc'),
|
|
119
114
|
oracledb: () => require('../oracledb'),
|
|
120
115
|
openai: { esmFirst: true, fn: () => require('../openai') },
|
|
@@ -142,9 +137,7 @@ module.exports = {
|
|
|
142
137
|
tedious: () => require('../tedious'),
|
|
143
138
|
tinypool: { esmFirst: true, fn: () => require('../vitest') },
|
|
144
139
|
undici: () => require('../undici'),
|
|
145
|
-
url: () => require('../url'),
|
|
146
140
|
vitest: { esmFirst: true, fn: () => require('../vitest') },
|
|
147
|
-
vm: () => require('../vm'),
|
|
148
141
|
when: () => require('../when'),
|
|
149
142
|
winston: () => require('../winston'),
|
|
150
143
|
workerpool: () => require('../mocha'),
|
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { AsyncResource } = require('async_hooks')
|
|
4
|
-
const dc = require('dc-polyfill')
|
|
4
|
+
const dc = /** @type {typeof import('node:diagnostics_channel')} */ (require('dc-polyfill'))
|
|
5
5
|
const instrumentations = require('./instrumentations')
|
|
6
6
|
const rewriterInstrumentations = require('./rewriter/instrumentations')
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {import('node:diagnostics_channel').Channel} Channel
|
|
10
|
+
* @typedef {import('node:diagnostics_channel').TracingChannel} TracingChannel
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @type {Record<string, Channel>}
|
|
15
|
+
*/
|
|
8
16
|
const channelMap = {}
|
|
17
|
+
/**
|
|
18
|
+
* @param {string} name
|
|
19
|
+
* @returns {Channel}
|
|
20
|
+
*/
|
|
9
21
|
exports.channel = function (name) {
|
|
10
22
|
const maybe = channelMap[name]
|
|
11
23
|
if (maybe) return maybe
|
|
@@ -14,7 +26,14 @@ exports.channel = function (name) {
|
|
|
14
26
|
return ch
|
|
15
27
|
}
|
|
16
28
|
|
|
29
|
+
/**
|
|
30
|
+
* @type {Record<string, TracingChannel>}
|
|
31
|
+
*/
|
|
17
32
|
const tracingChannelMap = {}
|
|
33
|
+
/**
|
|
34
|
+
* @param {string} name
|
|
35
|
+
* @returns {TracingChannel}
|
|
36
|
+
*/
|
|
18
37
|
exports.tracingChannel = function (name) {
|
|
19
38
|
const maybe = tracingChannelMap[name]
|
|
20
39
|
if (maybe) return maybe
|
|
@@ -34,24 +53,19 @@ exports.getHooks = function getHooks (names) {
|
|
|
34
53
|
|
|
35
54
|
/**
|
|
36
55
|
* @param {object} args
|
|
37
|
-
* @param {string
|
|
38
|
-
* @param {string[]} args.versions array of semver range strings
|
|
56
|
+
* @param {string} args.name module name
|
|
57
|
+
* @param {string[]} [args.versions] array of semver range strings
|
|
39
58
|
* @param {string} [args.file='index.js'] path to file within package to instrument
|
|
40
59
|
* @param {string} [args.filePattern] pattern to match files within package to instrument
|
|
41
|
-
* @param {boolean} [args.patchDefault] whether to patch the default export
|
|
42
|
-
* @param {(moduleExports: unknown, version: string) => unknown} hook
|
|
60
|
+
* @param {boolean} [args.patchDefault=true] whether to patch the default export
|
|
61
|
+
* @param {(moduleExports: unknown, version: string, isIitm?: boolean) => unknown} [hook] Patches module exports
|
|
43
62
|
*/
|
|
44
63
|
exports.addHook = function addHook ({ name, versions, file, filePattern, patchDefault }, hook) {
|
|
45
|
-
if (
|
|
46
|
-
name = [
|
|
64
|
+
if (!instrumentations[name]) {
|
|
65
|
+
instrumentations[name] = []
|
|
47
66
|
}
|
|
48
67
|
|
|
49
|
-
|
|
50
|
-
if (!instrumentations[val]) {
|
|
51
|
-
instrumentations[val] = []
|
|
52
|
-
}
|
|
53
|
-
instrumentations[val].push({ name: val, versions, file, filePattern, hook, patchDefault })
|
|
54
|
-
}
|
|
68
|
+
instrumentations[name].push({ versions, file, filePattern, hook, patchDefault })
|
|
55
69
|
}
|
|
56
70
|
|
|
57
71
|
exports.AsyncResource = AsyncResource
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { builtinModules } = require('module')
|
|
3
4
|
const path = require('path')
|
|
4
5
|
const { channel } = require('dc-polyfill')
|
|
5
6
|
const satisfies = require('../../../../vendor/dist/semifies')
|
|
6
|
-
const requirePackageJson = require('../../../dd-trace/src/require-package-json')
|
|
7
7
|
const log = require('../../../dd-trace/src/log')
|
|
8
8
|
const telemetry = require('../../../dd-trace/src/guardrails/telemetry')
|
|
9
9
|
const { IS_SERVERLESS } = require('../../../dd-trace/src/serverless')
|
|
@@ -36,27 +36,47 @@ if (!disabledInstrumentations.has('process')) {
|
|
|
36
36
|
require('../process')
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
const HOOK_SYMBOL = Symbol('hookExportsSet')
|
|
40
|
-
|
|
41
39
|
if (DD_TRACE_DEBUG && DD_TRACE_DEBUG.toLowerCase() !== 'false') {
|
|
42
40
|
checkRequireCache.checkForRequiredModules()
|
|
43
41
|
setImmediate(checkRequireCache.checkForPotentialConflicts)
|
|
44
42
|
}
|
|
45
43
|
|
|
46
|
-
const seenCombo = new Set()
|
|
47
|
-
const allInstrumentations = {}
|
|
48
|
-
|
|
49
44
|
for (const inst of disabledInstrumentations) {
|
|
50
45
|
rewriter.disable(inst)
|
|
51
46
|
}
|
|
52
47
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
48
|
+
/** @type {Map<string, object>} */
|
|
49
|
+
const instrumentedNodeModules = new Map()
|
|
50
|
+
/** @type {Map<string, boolean>} */
|
|
51
|
+
const instrumentedIntegrationsSuccess = new Map()
|
|
52
|
+
/** @type {Set<string>} */
|
|
53
|
+
const alreadyLoggedIncompatibleIntegrations = new Set()
|
|
54
|
+
|
|
55
|
+
// Always disable prefixed and unprefixed node modules if one is disabled.
|
|
56
|
+
if (disabledInstrumentations.size) {
|
|
57
|
+
const builtinsSet = new Set(builtinModules)
|
|
58
|
+
for (const name of disabledInstrumentations) {
|
|
59
|
+
const hasPrefix = name.startsWith('node:')
|
|
60
|
+
if (hasPrefix || builtinsSet.has(name)) {
|
|
61
|
+
if (hasPrefix) {
|
|
62
|
+
const unprefixedName = name.slice(5)
|
|
63
|
+
if (!disabledInstrumentations.has(unprefixedName)) {
|
|
64
|
+
disabledInstrumentations.add(unprefixedName)
|
|
65
|
+
}
|
|
66
|
+
} else if (!disabledInstrumentations.has(`node:${name}`)) {
|
|
67
|
+
disabledInstrumentations.add(`node:${name}`)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
builtinsSet.clear()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
for (const name of names) {
|
|
75
|
+
if (disabledInstrumentations.has(name)) continue
|
|
56
76
|
|
|
57
77
|
const hookOptions = {}
|
|
58
78
|
|
|
59
|
-
let hook = hooks[
|
|
79
|
+
let hook = hooks[name]
|
|
60
80
|
|
|
61
81
|
if (hook !== null && typeof hook === 'object') {
|
|
62
82
|
if (hook.serverless === false && IS_SERVERLESS) continue
|
|
@@ -65,173 +85,114 @@ for (const packageName of names) {
|
|
|
65
85
|
hook = hook.fn
|
|
66
86
|
}
|
|
67
87
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
88
|
+
Hook([name], hookOptions, (moduleExports, moduleName, moduleBaseDir, moduleVersion, isIitm) => {
|
|
89
|
+
// All loaded versions are first expected to fail instrumentation.
|
|
90
|
+
if (!instrumentedIntegrationsSuccess.has(`${name}@${moduleVersion}`)) {
|
|
91
|
+
instrumentedIntegrationsSuccess.set(`${name}@${moduleVersion}`, false)
|
|
92
|
+
}
|
|
73
93
|
|
|
74
94
|
// This executes the integration file thus adding its entries to `instrumentations`
|
|
75
95
|
hook()
|
|
76
96
|
|
|
77
|
-
if (!instrumentations[
|
|
97
|
+
if (!instrumentations[name] || moduleExports === instrumentedNodeModules.get(name)) {
|
|
78
98
|
return moduleExports
|
|
79
99
|
}
|
|
80
100
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
101
|
+
// Used for node: prefixed modules to prevent double instrumentation.
|
|
102
|
+
if (moduleBaseDir) {
|
|
103
|
+
moduleName = moduleName.replace(pathSepExpr, '/')
|
|
104
|
+
} else {
|
|
105
|
+
instrumentedNodeModules.set(name, moduleExports)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
for (const { file, versions, hook, filePattern, patchDefault } of instrumentations[name]) {
|
|
109
|
+
if (isIitm && patchDefault === !!moduleExports.default) {
|
|
110
|
+
if (patchDefault) {
|
|
111
|
+
moduleExports = moduleExports.default
|
|
112
|
+
} else {
|
|
113
|
+
return moduleExports
|
|
114
|
+
}
|
|
87
115
|
}
|
|
88
116
|
|
|
89
|
-
let fullFilePattern = filePattern
|
|
90
117
|
const fullFilename = filename(name, file)
|
|
91
|
-
if (fullFilePattern) {
|
|
92
|
-
fullFilePattern = filename(name, fullFilePattern)
|
|
93
|
-
}
|
|
94
118
|
|
|
95
|
-
// Create a WeakSet associated with the hook function so that patches on the same moduleExport only happens once
|
|
96
|
-
// for example by instrumenting both dns and node:dns double the spans would be created
|
|
97
|
-
// since they both patch the same moduleExport, this WeakSet is used to mitigate that
|
|
98
|
-
// TODO(BridgeAR): Instead of using a WeakSet here, why not just use aliases for the hook in register?
|
|
99
|
-
// That way it would also not be duplicated. The actual name being used has to be identified else wise.
|
|
100
|
-
// Maybe it is also not important to know what name was actually used?
|
|
101
|
-
hook[HOOK_SYMBOL] ??= new WeakSet()
|
|
102
119
|
let matchesFile = moduleName === fullFilename
|
|
103
120
|
|
|
104
121
|
if (!matchesFile && isRelativeRequire(name)) matchesFile = true
|
|
105
122
|
|
|
123
|
+
const fullFilePattern = filePattern && filename(name, filePattern)
|
|
106
124
|
if (fullFilePattern) {
|
|
107
125
|
// Some libraries include a hash in their filenames when installed,
|
|
108
126
|
// so our instrumentation has to include a '.*' to match them for more than a single version.
|
|
109
|
-
matchesFile
|
|
127
|
+
matchesFile ||= new RegExp(fullFilePattern).test(moduleName)
|
|
110
128
|
}
|
|
111
129
|
|
|
112
|
-
if (matchesFile) {
|
|
113
|
-
|
|
130
|
+
if (matchesFile && matchVersion(moduleVersion, versions)) {
|
|
131
|
+
// Do not log in case of an error to prevent duplicate telemetry for the same integration version.
|
|
132
|
+
instrumentedIntegrationsSuccess.set(`${name}@${moduleVersion}`, true)
|
|
114
133
|
try {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
namesAndSuccesses[`${name}@${version}`] = false
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (matchVersion(version, versions)) {
|
|
133
|
-
allInstrumentations[instrumentationFileName] = true
|
|
134
|
-
|
|
135
|
-
// Check if the hook already has a set moduleExport
|
|
136
|
-
if (hook[HOOK_SYMBOL].has(moduleExports)) {
|
|
137
|
-
namesAndSuccesses[`${name}@${version}`] = true
|
|
138
|
-
return moduleExports
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
try {
|
|
142
|
-
loadChannel.publish({ name, version, file })
|
|
143
|
-
// Send the name and version of the module back to the callback because now addHook
|
|
144
|
-
// takes in an array of names so by passing the name the callback will know which module name is being used
|
|
145
|
-
// TODO(BridgeAR): This is only true in case the name is identical
|
|
146
|
-
// in all loads. If they deviate, the deviating name would not be
|
|
147
|
-
// picked up due to the unification. Check what modules actually use the name.
|
|
148
|
-
// TODO(BridgeAR): Only replace moduleExports if the hook returns a new value.
|
|
149
|
-
// This allows to reduce the instrumentation code (no return needed).
|
|
150
|
-
|
|
151
|
-
moduleExports = hook(moduleExports, version, name, isIitm) ?? moduleExports
|
|
152
|
-
// Set the moduleExports in the hooks WeakSet
|
|
153
|
-
hook[HOOK_SYMBOL].add(moduleExports)
|
|
154
|
-
} catch (e) {
|
|
155
|
-
log.info('Error during ddtrace instrumentation of application, aborting.', e)
|
|
156
|
-
telemetry('error', [
|
|
157
|
-
`error_type:${e.constructor.name}`,
|
|
158
|
-
`integration:${name}`,
|
|
159
|
-
`integration_version:${version}`,
|
|
160
|
-
], {
|
|
161
|
-
result: 'error',
|
|
162
|
-
result_class: 'internal_error',
|
|
163
|
-
result_reason: `Error during instrumentation of ${name}@${version}: ${e.message}`,
|
|
164
|
-
})
|
|
165
|
-
}
|
|
166
|
-
namesAndSuccesses[`${name}@${version}`] = true
|
|
134
|
+
loadChannel.publish({ name })
|
|
135
|
+
|
|
136
|
+
moduleExports = hook(moduleExports, moduleVersion, isIitm) ?? moduleExports
|
|
137
|
+
} catch (error) {
|
|
138
|
+
log.info('Error during ddtrace instrumentation of application, aborting.', error)
|
|
139
|
+
telemetry('error', [
|
|
140
|
+
`error_type:${error.constructor.name}`,
|
|
141
|
+
`integration:${name}`,
|
|
142
|
+
`integration_version:${moduleVersion}`,
|
|
143
|
+
], {
|
|
144
|
+
result: 'error',
|
|
145
|
+
result_class: 'internal_error',
|
|
146
|
+
result_reason: `Error during instrumentation of ${name}@${moduleVersion}: ${error.message}`,
|
|
147
|
+
})
|
|
167
148
|
}
|
|
168
149
|
}
|
|
169
150
|
}
|
|
170
|
-
for (const nameVersion of Object.keys(namesAndSuccesses)) {
|
|
171
|
-
const [name, version] = nameVersion.split('@')
|
|
172
|
-
const success = namesAndSuccesses[nameVersion]
|
|
173
|
-
// we check allVersions to see if any version of the integration was successfully instrumented
|
|
174
|
-
if (!success && !seenCombo.has(nameVersion) && !allInstrumentations[instrumentationFileName]) {
|
|
175
|
-
telemetry('abort.integration', [
|
|
176
|
-
`integration:${name}`,
|
|
177
|
-
`integration_version:${version}`,
|
|
178
|
-
], {
|
|
179
|
-
result: 'abort',
|
|
180
|
-
result_class: 'incompatible_library',
|
|
181
|
-
result_reason: `Incompatible integration version: ${name}@${version}`,
|
|
182
|
-
})
|
|
183
|
-
log.info('Found incompatible integration version: %s', nameVersion)
|
|
184
|
-
seenCombo.add(nameVersion)
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
151
|
|
|
188
152
|
return moduleExports
|
|
189
153
|
})
|
|
190
154
|
}
|
|
191
155
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
156
|
+
globalThis[Symbol.for('dd-trace')]?.beforeExitHandlers.add(logAbortedIntegrations)
|
|
157
|
+
// TODO: check if we want to stop using channels for single subscriber tasks
|
|
158
|
+
channel('dd-trace:exporter:first-flush').subscribe(logAbortedIntegrations)
|
|
195
159
|
|
|
196
|
-
function
|
|
197
|
-
|
|
198
|
-
|
|
160
|
+
function logAbortedIntegrations () {
|
|
161
|
+
for (const [nameVersion, success] of instrumentedIntegrationsSuccess) {
|
|
162
|
+
// Only ever log a single version of an integration, even if it is loaded later.
|
|
163
|
+
if (!success && !alreadyLoggedIncompatibleIntegrations.has(nameVersion)) {
|
|
164
|
+
const [name, version] = nameVersion.split('@')
|
|
165
|
+
telemetry('abort.integration', [
|
|
166
|
+
`integration:${name}`,
|
|
167
|
+
`integration_version:${version}`,
|
|
168
|
+
], {
|
|
169
|
+
result: 'abort',
|
|
170
|
+
result_class: 'incompatible_library',
|
|
171
|
+
result_reason: `Incompatible integration version: ${name}@${version}`,
|
|
172
|
+
})
|
|
173
|
+
log.info('Found incompatible integration version: %s', nameVersion)
|
|
174
|
+
alreadyLoggedIncompatibleIntegrations.add(nameVersion)
|
|
175
|
+
}
|
|
199
176
|
}
|
|
177
|
+
// Clear the map to avoid reporting the same integration version again.
|
|
178
|
+
instrumentedIntegrationsSuccess.clear()
|
|
200
179
|
}
|
|
201
180
|
|
|
202
|
-
|
|
203
|
-
|
|
181
|
+
/**
|
|
182
|
+
* @param {string|undefined} version
|
|
183
|
+
* @param {string[]|undefined} ranges
|
|
184
|
+
*/
|
|
185
|
+
function matchVersion (version, ranges) {
|
|
186
|
+
return !version || !ranges || ranges.some(range => satisfies(version, range))
|
|
204
187
|
}
|
|
205
188
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
// @redis/client -> "() => require('../redis')" -> redis
|
|
214
|
-
//
|
|
215
|
-
function parseHookInstrumentationFileName (packageName) {
|
|
216
|
-
let hook = hooks[packageName]
|
|
217
|
-
if (hook.fn) {
|
|
218
|
-
hook = hook.fn
|
|
219
|
-
}
|
|
220
|
-
const hookString = hook.toString()
|
|
221
|
-
const regex = /require\('([^']*)'\)/
|
|
222
|
-
const match = hookString.match(regex)
|
|
223
|
-
|
|
224
|
-
// try to capture the hook require file location.
|
|
225
|
-
if (match && match[1]) {
|
|
226
|
-
let moduleName = match[1]
|
|
227
|
-
// Remove leading '../' if present
|
|
228
|
-
if (moduleName.startsWith('../')) {
|
|
229
|
-
moduleName = moduleName.slice(3)
|
|
230
|
-
}
|
|
231
|
-
return moduleName
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
return null
|
|
189
|
+
/**
|
|
190
|
+
* @param {string} name
|
|
191
|
+
* @param {string} [file]
|
|
192
|
+
* @returns {string}
|
|
193
|
+
*/
|
|
194
|
+
function filename (name, file) {
|
|
195
|
+
return file ? `${name}/${file}` : name
|
|
235
196
|
}
|
|
236
197
|
|
|
237
198
|
module.exports = {
|
|
@@ -16,9 +16,8 @@ const asyncStartChannel = channel('apm:http:client:request:asyncStart')
|
|
|
16
16
|
const errorChannel = channel('apm:http:client:request:error')
|
|
17
17
|
const responseFinishChannel = channel('apm:http:client:response:finish')
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
addHook({ name: names }, hookFn)
|
|
19
|
+
addHook({ name: 'http' }, hookFn)
|
|
20
|
+
addHook({ name: 'https' }, hookFn)
|
|
22
21
|
|
|
23
22
|
function hookFn (http) {
|
|
24
23
|
patch(http, 'request')
|
|
@@ -16,10 +16,7 @@ const startSetHeaderCh = channel('datadog:http:server:response:set-header:start'
|
|
|
16
16
|
|
|
17
17
|
const requestFinishedSet = new WeakSet()
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
const httpsNames = ['https', 'node:https']
|
|
21
|
-
|
|
22
|
-
addHook({ name: httpNames }, http => {
|
|
19
|
+
addHook({ name: 'http' }, http => {
|
|
23
20
|
shimmer.wrap(http.ServerResponse.prototype, 'emit', wrapResponseEmit)
|
|
24
21
|
shimmer.wrap(http.Server.prototype, 'emit', wrapEmit)
|
|
25
22
|
shimmer.wrap(http.ServerResponse.prototype, 'writeHead', wrapWriteHead)
|
|
@@ -34,7 +31,7 @@ addHook({ name: httpNames }, http => {
|
|
|
34
31
|
return http
|
|
35
32
|
})
|
|
36
33
|
|
|
37
|
-
addHook({ name:
|
|
34
|
+
addHook({ name: 'https' }, http => {
|
|
38
35
|
// http.ServerResponse not present on https
|
|
39
36
|
shimmer.wrap(http.Server.prototype, 'emit', wrapEmit)
|
|
40
37
|
return http
|
|
@@ -10,8 +10,6 @@ const asyncStartChannel = channel('apm:http2:client:request:asyncStart')
|
|
|
10
10
|
const asyncEndChannel = channel('apm:http2:client:request:asyncEnd')
|
|
11
11
|
const errorChannel = channel('apm:http2:client:request:error')
|
|
12
12
|
|
|
13
|
-
const names = ['http2', 'node:http2']
|
|
14
|
-
|
|
15
13
|
function createWrapEmit (ctx) {
|
|
16
14
|
return function wrapEmit (emit) {
|
|
17
15
|
return function (event, arg1) {
|
|
@@ -68,7 +66,7 @@ function wrapConnect (connect) {
|
|
|
68
66
|
}
|
|
69
67
|
}
|
|
70
68
|
|
|
71
|
-
addHook({ name:
|
|
69
|
+
addHook({ name: 'http2' }, http2 => {
|
|
72
70
|
shimmer.wrap(http2, 'connect', wrapConnect)
|
|
73
71
|
if (http2.default) http2.default.connect = http2.connect
|
|
74
72
|
|
|
@@ -13,9 +13,7 @@ const startServerCh = channel('apm:http2:server:request:start')
|
|
|
13
13
|
const errorServerCh = channel('apm:http2:server:request:error')
|
|
14
14
|
const emitCh = channel('apm:http2:server:response:emit')
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
addHook({ name: names }, http2 => {
|
|
16
|
+
addHook({ name: 'http2' }, http2 => {
|
|
19
17
|
shimmer.wrap(http2, 'createSecureServer', wrapCreateServer)
|
|
20
18
|
shimmer.wrap(http2, 'createServer', wrapCreateServer)
|
|
21
19
|
})
|