dd-trace 5.104.0 → 5.105.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-3rdparty.csv +90 -102
- package/index.d.ts +82 -3
- package/package.json +15 -15
- package/packages/datadog-core/src/storage.js +1 -1
- package/packages/datadog-instrumentations/src/aerospike.js +1 -1
- package/packages/datadog-instrumentations/src/ai.js +8 -7
- package/packages/datadog-instrumentations/src/aws-sdk.js +13 -0
- package/packages/datadog-instrumentations/src/azure-cosmos.js +7 -0
- package/packages/datadog-instrumentations/src/azure-functions.js +3 -0
- package/packages/datadog-instrumentations/src/cucumber.js +78 -5
- package/packages/datadog-instrumentations/src/dns.js +54 -18
- package/packages/datadog-instrumentations/src/fastify.js +142 -82
- package/packages/datadog-instrumentations/src/graphql.js +188 -62
- package/packages/datadog-instrumentations/src/helpers/ai-messages.js +322 -14
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/openai-ai-guard.js +269 -0
- package/packages/datadog-instrumentations/src/helpers/promise-instrumentor.js +42 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-cosmos.js +50 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js +4 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +85 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +37 -236
- package/packages/datadog-instrumentations/src/hono.js +54 -3
- package/packages/datadog-instrumentations/src/http/server.js +9 -4
- package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +163 -0
- package/packages/datadog-instrumentations/src/jest.js +360 -150
- package/packages/datadog-instrumentations/src/kafkajs.js +120 -16
- package/packages/datadog-instrumentations/src/mocha/main.js +128 -17
- package/packages/datadog-instrumentations/src/nats.js +182 -0
- package/packages/datadog-instrumentations/src/nyc.js +38 -1
- package/packages/datadog-instrumentations/src/openai.js +33 -18
- package/packages/datadog-instrumentations/src/oracledb.js +6 -1
- package/packages/datadog-instrumentations/src/pino.js +17 -5
- package/packages/datadog-instrumentations/src/playwright.js +515 -292
- package/packages/datadog-instrumentations/src/router.js +76 -32
- package/packages/datadog-instrumentations/src/stripe.js +1 -1
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-azure-cosmos/src/index.js +144 -0
- package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -1
- package/packages/datadog-plugin-azure-functions/src/index.js +5 -2
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +1 -1
- package/packages/datadog-plugin-bunyan/src/index.js +28 -0
- package/packages/datadog-plugin-cucumber/src/index.js +17 -3
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +199 -28
- package/packages/datadog-plugin-cypress/src/support.js +69 -1
- package/packages/datadog-plugin-dns/src/lookup.js +8 -6
- package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +1 -1
- package/packages/datadog-plugin-graphql/src/execute.js +2 -0
- package/packages/datadog-plugin-graphql/src/resolve.js +64 -67
- package/packages/datadog-plugin-http/src/server.js +40 -15
- package/packages/datadog-plugin-jest/src/index.js +11 -3
- package/packages/datadog-plugin-jest/src/util.js +15 -8
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +1 -1
- package/packages/datadog-plugin-kafkajs/src/producer.js +3 -0
- package/packages/datadog-plugin-langgraph/src/stream.js +1 -1
- package/packages/datadog-plugin-mocha/src/index.js +19 -4
- package/packages/datadog-plugin-mongodb-core/src/index.js +281 -40
- package/packages/datadog-plugin-nats/src/consumer.js +43 -0
- package/packages/datadog-plugin-nats/src/index.js +20 -0
- package/packages/datadog-plugin-nats/src/producer.js +62 -0
- package/packages/datadog-plugin-nats/src/util.js +33 -0
- package/packages/datadog-plugin-next/src/index.js +5 -3
- package/packages/datadog-plugin-openai/src/tracing.js +15 -2
- package/packages/datadog-plugin-oracledb/src/index.js +13 -2
- package/packages/datadog-plugin-pino/src/index.js +42 -0
- package/packages/datadog-plugin-playwright/src/index.js +4 -4
- package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-rhea/src/producer.js +1 -1
- package/packages/datadog-plugin-router/src/index.js +33 -44
- package/packages/datadog-plugin-selenium/src/index.js +1 -1
- package/packages/datadog-plugin-vitest/src/index.js +5 -13
- package/packages/datadog-plugin-winston/src/index.js +30 -0
- package/packages/datadog-shimmer/src/shimmer.js +33 -40
- package/packages/dd-trace/src/aiguard/index.js +1 -1
- package/packages/dd-trace/src/aiguard/sdk.js +1 -1
- package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
- package/packages/dd-trace/src/appsec/index.js +1 -1
- package/packages/dd-trace/src/appsec/reporter.js +5 -6
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
- package/packages/dd-trace/src/appsec/sdk/utils.js +1 -1
- package/packages/dd-trace/src/appsec/user_tracking.js +5 -4
- package/packages/dd-trace/src/baggage.js +7 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +0 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +25 -13
- package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +70 -6
- package/packages/dd-trace/src/config/generated-config-types.d.ts +6 -2
- package/packages/dd-trace/src/config/supported-configurations.json +27 -8
- package/packages/dd-trace/src/datastreams/writer.js +2 -4
- package/packages/dd-trace/src/debugger/devtools_client/condition.js +5 -8
- package/packages/dd-trace/src/encode/0.4.js +124 -108
- package/packages/dd-trace/src/encode/0.5.js +114 -26
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +31 -23
- package/packages/dd-trace/src/encode/agentless-json.js +4 -2
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +32 -13
- package/packages/dd-trace/src/encode/span-stats.js +16 -16
- package/packages/dd-trace/src/encode/tags-processors.js +16 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +9 -7
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +0 -16
- package/packages/dd-trace/src/llmobs/span_processor.js +3 -3
- package/packages/dd-trace/src/llmobs/tagger.js +9 -1
- package/packages/dd-trace/src/llmobs/telemetry.js +1 -1
- package/packages/dd-trace/src/llmobs/util.js +66 -3
- package/packages/dd-trace/src/log/index.js +1 -1
- package/packages/dd-trace/src/msgpack/chunk.js +394 -10
- package/packages/dd-trace/src/msgpack/index.js +96 -2
- package/packages/dd-trace/src/openfeature/encoding.js +70 -0
- package/packages/dd-trace/src/openfeature/flagging_provider.js +20 -0
- package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +143 -0
- package/packages/dd-trace/src/openfeature/span-enrichment.js +149 -0
- package/packages/dd-trace/src/opentelemetry/span-helpers.js +4 -3
- package/packages/dd-trace/src/opentelemetry/span.js +1 -1
- package/packages/dd-trace/src/opentracing/propagation/log.js +18 -7
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +62 -67
- package/packages/dd-trace/src/opentracing/span.js +59 -19
- package/packages/dd-trace/src/opentracing/span_context.js +49 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +20 -20
- package/packages/dd-trace/src/plugins/database.js +7 -6
- package/packages/dd-trace/src/plugins/index.js +4 -0
- package/packages/dd-trace/src/plugins/log_injection.js +56 -0
- package/packages/dd-trace/src/plugins/log_plugin.js +3 -48
- package/packages/dd-trace/src/plugins/outbound.js +1 -1
- package/packages/dd-trace/src/plugins/plugin.js +15 -17
- package/packages/dd-trace/src/plugins/tracing.js +43 -5
- package/packages/dd-trace/src/plugins/util/test.js +236 -13
- package/packages/dd-trace/src/plugins/util/web.js +79 -65
- package/packages/dd-trace/src/priority_sampler.js +2 -2
- package/packages/dd-trace/src/profiling/profiler.js +2 -2
- package/packages/dd-trace/src/profiling/profilers/wall.js +10 -4
- package/packages/dd-trace/src/sampling_rule.js +7 -7
- package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +10 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +8 -0
- package/packages/dd-trace/src/service-naming/source-resolver.js +46 -0
- package/packages/dd-trace/src/span_format.js +190 -58
- package/packages/dd-trace/src/spanleak.js +1 -1
- package/packages/dd-trace/src/standalone/index.js +3 -3
- package/packages/dd-trace/src/tagger.js +0 -2
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +70 -39
- package/vendor/dist/@datadog/sketches-js/LICENSE +10 -36
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/packages/dd-trace/src/msgpack/encoder.js +0 -308
- package/packages/dd-trace/src/plugins/structured_log_plugin.js +0 -9
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const dc = require('dc-polyfill')
|
|
4
|
+
|
|
5
|
+
const { channel } = require('./instrument')
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Shimmer-compatible instrumentor for promise-returning APIs (e.g. `dns.promises.lookup`).
|
|
9
|
+
* Mirrors `createCallbackInstrumentor`'s channel triplet (`<prefix>:start`, `:finish`, `:error`)
|
|
10
|
+
* so a plugin subscribing to those channels for the callback variant works for the promise
|
|
11
|
+
* variant unchanged. `:finish` is the `tracingChannel` `asyncEnd` slot, so it fires after the
|
|
12
|
+
* promise settles with `ctx.result` set to the resolved value.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} prefix
|
|
15
|
+
* @returns {(buildContext: (thisArg: unknown, args: unknown[]) => object | undefined) =>
|
|
16
|
+
* (fn: Function) => Function}
|
|
17
|
+
*/
|
|
18
|
+
function createPromiseInstrumentor (prefix) {
|
|
19
|
+
const start = channel(prefix + ':start')
|
|
20
|
+
const finish = channel(prefix + ':finish')
|
|
21
|
+
const error = channel(prefix + ':error')
|
|
22
|
+
const tracing = dc.tracingChannel({
|
|
23
|
+
start,
|
|
24
|
+
end: channel(prefix + ':end'),
|
|
25
|
+
asyncStart: channel(prefix + ':asyncStart'),
|
|
26
|
+
asyncEnd: finish,
|
|
27
|
+
error,
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
return function instrument (buildContext) {
|
|
31
|
+
return function wrap (fn) {
|
|
32
|
+
return function (...args) {
|
|
33
|
+
if (!start.hasSubscribers) return fn.apply(this, args)
|
|
34
|
+
const ctx = buildContext(this, args)
|
|
35
|
+
if (ctx === undefined) return fn.apply(this, args)
|
|
36
|
+
return tracing.tracePromise(fn, ctx, this, ...args)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = { createPromiseInstrumentor }
|
|
@@ -133,7 +133,7 @@ for (const name of names) {
|
|
|
133
133
|
try {
|
|
134
134
|
loadChannel.publish({ name })
|
|
135
135
|
|
|
136
|
-
moduleExports = hook(moduleExports, moduleVersion, isIitm) ?? moduleExports
|
|
136
|
+
moduleExports = hook(moduleExports, moduleVersion, isIitm, { moduleBaseDir, moduleName }) ?? moduleExports
|
|
137
137
|
} catch (error) {
|
|
138
138
|
log.info('Error during ddtrace instrumentation of application, aborting.', error)
|
|
139
139
|
telemetry('error', [
|
|
@@ -5,7 +5,7 @@ const { join } = require('path')
|
|
|
5
5
|
const { pathToFileURL } = require('url')
|
|
6
6
|
const log = require('../../../../dd-trace/src/log')
|
|
7
7
|
const { create } = require('../../../../../vendor/dist/@apm-js-collab/code-transformer')
|
|
8
|
-
const {
|
|
8
|
+
const { waitForAsyncEnd } = require('./transforms')
|
|
9
9
|
const instrumentations = require('./instrumentations')
|
|
10
10
|
|
|
11
11
|
// `dc-polyfill` is referenced from injected `require()` (CJS) and `import`
|
|
@@ -34,8 +34,7 @@ const matcherCjs = create(instrumentations, dcPolyfillCjs)
|
|
|
34
34
|
const matcherEsm = create(instrumentations, dcPolyfillEsm)
|
|
35
35
|
|
|
36
36
|
for (const matcher of [matcherCjs, matcherEsm]) {
|
|
37
|
-
matcher.addTransform('
|
|
38
|
-
matcher.addTransform('traceAsyncIterator', traceAsyncIterator)
|
|
37
|
+
matcher.addTransform('waitForAsyncEnd', waitForAsyncEnd)
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
function rewrite (content, filename, format) {
|
package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-cosmos.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
module.exports = [{
|
|
4
|
+
module: {
|
|
5
|
+
name: '@azure/cosmos',
|
|
6
|
+
versionRange: '>=4.4.1',
|
|
7
|
+
filePath: 'dist/browser/plugins/Plugin.js',
|
|
8
|
+
},
|
|
9
|
+
functionQuery: {
|
|
10
|
+
functionName: 'executePlugins',
|
|
11
|
+
kind: 'Async',
|
|
12
|
+
},
|
|
13
|
+
channelName: 'executePlugins',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
module: {
|
|
17
|
+
name: '@azure/cosmos',
|
|
18
|
+
versionRange: '>=4.4.1',
|
|
19
|
+
filePath: 'dist/commonjs/plugins/Plugin.js',
|
|
20
|
+
},
|
|
21
|
+
functionQuery: {
|
|
22
|
+
functionName: 'executePlugins',
|
|
23
|
+
kind: 'Async',
|
|
24
|
+
},
|
|
25
|
+
channelName: 'executePlugins',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
module: {
|
|
29
|
+
name: '@azure/cosmos',
|
|
30
|
+
versionRange: '>=4.4.1',
|
|
31
|
+
filePath: 'dist/esm/plugins/Plugin.js',
|
|
32
|
+
},
|
|
33
|
+
functionQuery: {
|
|
34
|
+
functionName: 'executePlugins',
|
|
35
|
+
kind: 'Async',
|
|
36
|
+
},
|
|
37
|
+
channelName: 'executePlugins',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
module: {
|
|
41
|
+
name: '@azure/cosmos',
|
|
42
|
+
versionRange: '>=4.4.1',
|
|
43
|
+
filePath: 'dist/react-native/plugins/Plugin.js',
|
|
44
|
+
},
|
|
45
|
+
functionQuery: {
|
|
46
|
+
functionName: 'executePlugins',
|
|
47
|
+
kind: 'Async',
|
|
48
|
+
},
|
|
49
|
+
channelName: 'executePlugins',
|
|
50
|
+
}]
|
package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js
CHANGED
|
@@ -10,9 +10,10 @@ module.exports = [
|
|
|
10
10
|
functionQuery: {
|
|
11
11
|
methodName: 'stream',
|
|
12
12
|
className: 'Pregel',
|
|
13
|
+
kind: 'Async',
|
|
14
|
+
returnKind: 'AsyncIterator',
|
|
13
15
|
},
|
|
14
16
|
channelName: 'Pregel_stream',
|
|
15
|
-
transform: 'traceAsyncIterator',
|
|
16
17
|
},
|
|
17
18
|
{
|
|
18
19
|
module: {
|
|
@@ -23,8 +24,9 @@ module.exports = [
|
|
|
23
24
|
functionQuery: {
|
|
24
25
|
methodName: 'stream',
|
|
25
26
|
className: 'Pregel',
|
|
27
|
+
kind: 'Async',
|
|
28
|
+
returnKind: 'AsyncIterator',
|
|
26
29
|
},
|
|
27
30
|
channelName: 'Pregel_stream',
|
|
28
|
-
transform: 'traceAsyncIterator',
|
|
29
31
|
},
|
|
30
32
|
]
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// Playwright 1.60 bundles several former hook targets into local classes/functions.
|
|
4
|
+
// Keep these rewrites limited to private bundled internals that addHook cannot wrap.
|
|
5
|
+
module.exports = [
|
|
6
|
+
{
|
|
7
|
+
module: {
|
|
8
|
+
name: 'playwright',
|
|
9
|
+
versionRange: '>=1.60.0',
|
|
10
|
+
filePath: 'lib/runner/index.js',
|
|
11
|
+
},
|
|
12
|
+
functionQuery: {
|
|
13
|
+
className: 'Dispatcher',
|
|
14
|
+
methodName: 'run',
|
|
15
|
+
kind: 'Async',
|
|
16
|
+
},
|
|
17
|
+
channelName: 'Dispatcher_run',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
module: {
|
|
21
|
+
name: 'playwright',
|
|
22
|
+
versionRange: '>=1.60.0',
|
|
23
|
+
filePath: 'lib/runner/index.js',
|
|
24
|
+
},
|
|
25
|
+
functionQuery: {
|
|
26
|
+
className: 'Dispatcher',
|
|
27
|
+
methodName: '_createWorker',
|
|
28
|
+
kind: 'Sync',
|
|
29
|
+
},
|
|
30
|
+
channelName: 'Dispatcher_createWorker',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
module: {
|
|
34
|
+
name: 'playwright',
|
|
35
|
+
versionRange: '>=1.60.0',
|
|
36
|
+
filePath: 'lib/runner/index.js',
|
|
37
|
+
},
|
|
38
|
+
functionQuery: {
|
|
39
|
+
className: 'ProcessHost',
|
|
40
|
+
methodName: 'startRunner',
|
|
41
|
+
kind: 'Async',
|
|
42
|
+
},
|
|
43
|
+
channelName: 'ProcessHost_startRunner',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
module: {
|
|
47
|
+
name: 'playwright',
|
|
48
|
+
versionRange: '>=1.60.0',
|
|
49
|
+
filePath: 'lib/runner/index.js',
|
|
50
|
+
},
|
|
51
|
+
functionQuery: {
|
|
52
|
+
functionName: 'createRootSuite',
|
|
53
|
+
kind: 'Async',
|
|
54
|
+
},
|
|
55
|
+
channelName: 'createRootSuite',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
module: {
|
|
59
|
+
name: 'playwright-core',
|
|
60
|
+
versionRange: '>=1.60.0',
|
|
61
|
+
filePath: 'lib/coreBundle.js',
|
|
62
|
+
},
|
|
63
|
+
astQuery: 'AssignmentExpression[left.name="Page2"] > ClassExpression > ClassBody > ' +
|
|
64
|
+
'MethodDefinition[kind="method"][key.name="goto"] > FunctionExpression[async], ' +
|
|
65
|
+
'VariableDeclarator[id.name="Page2"] > ClassExpression > ClassBody > ' +
|
|
66
|
+
'MethodDefinition[kind="method"][key.name="goto"] > FunctionExpression[async], ' +
|
|
67
|
+
'ClassDeclaration[id.name="Page2"] > ClassBody > ' +
|
|
68
|
+
'MethodDefinition[kind="method"][key.name="goto"] > FunctionExpression[async]',
|
|
69
|
+
functionQuery: {
|
|
70
|
+
methodName: 'goto',
|
|
71
|
+
kind: 'Async',
|
|
72
|
+
},
|
|
73
|
+
channelName: 'Page_goto',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
module: {
|
|
77
|
+
name: 'playwright-core',
|
|
78
|
+
versionRange: '>=1.60.0',
|
|
79
|
+
filePath: 'lib/coreBundle.js',
|
|
80
|
+
},
|
|
81
|
+
astQuery: 'ReturnStatement > CallExpression[callee.object.name="promise"][callee.property.name="then"]',
|
|
82
|
+
channelName: 'Page_goto',
|
|
83
|
+
transform: 'waitForAsyncEnd',
|
|
84
|
+
},
|
|
85
|
+
]
|
|
@@ -1,246 +1,47 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
: `const {tracingChannel: tr_ch_apm_tracingChannel} = require("${dcModule}")`
|
|
30
|
-
|
|
31
|
-
node.body.splice(index + 1, 0, ...parse(code, { isModule }).body)
|
|
32
|
-
},
|
|
33
|
-
|
|
34
|
-
tracingChannelDeclaration (state, node) {
|
|
35
|
-
const { channelName, module: { name } } = state
|
|
36
|
-
const channelVariable = 'tr_ch_apm$' + channelName.replaceAll(':', '_')
|
|
37
|
-
|
|
38
|
-
if (node.body.some(child => child.declarations?.[0]?.id?.name === channelVariable)) return
|
|
39
|
-
|
|
40
|
-
transforms.tracingChannelImport(state, node)
|
|
41
|
-
|
|
42
|
-
const index = node.body.findIndex(tracingChannelPredicate)
|
|
43
|
-
const code = `
|
|
44
|
-
const ${channelVariable} = tr_ch_apm_tracingChannel("orchestrion:${name}:${channelName}")
|
|
45
|
-
`
|
|
46
|
-
|
|
47
|
-
node.body.splice(index + 1, 0, parse(code).body[0])
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
traceAsyncIterator: traceAny,
|
|
51
|
-
traceIterator: traceAny,
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function traceAny (state, node, _parent, ancestry) {
|
|
55
|
-
const program = ancestry[ancestry.length - 1]
|
|
56
|
-
|
|
57
|
-
if (node.type === 'ClassDeclaration' || node.type === 'ClassExpression') {
|
|
58
|
-
traceInstanceMethod(state, node, program)
|
|
59
|
-
} else {
|
|
60
|
-
traceFunction(state, node, program)
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function traceFunction (state, node, program) {
|
|
65
|
-
transforms.tracingChannelDeclaration(state, program)
|
|
66
|
-
|
|
67
|
-
node.body = wrap(state, {
|
|
68
|
-
type: 'FunctionExpression',
|
|
69
|
-
params: node.params,
|
|
70
|
-
body: node.body,
|
|
71
|
-
async: node.async,
|
|
72
|
-
expression: false,
|
|
73
|
-
generator: node.generator,
|
|
74
|
-
}, program)
|
|
75
|
-
|
|
76
|
-
// The original function no longer contains any calls to `await` or `yield` as
|
|
77
|
-
// the function body is copied to the internal wrapped function, so we set
|
|
78
|
-
// these to false to avoid altering the return value of the wrapper. The old
|
|
79
|
-
// values are instead copied to the new AST node above.
|
|
80
|
-
node.generator = false
|
|
81
|
-
node.async = false
|
|
82
|
-
|
|
83
|
-
wrapSuper(state, node)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function traceInstanceMethod (state, node, program) {
|
|
87
|
-
const { functionQuery, operator } = state
|
|
88
|
-
const { methodName } = functionQuery
|
|
89
|
-
|
|
90
|
-
const classBody = node.body
|
|
91
|
-
|
|
92
|
-
// If the method exists on the class, we return as it will be patched later
|
|
93
|
-
// while traversing child nodes later on.
|
|
94
|
-
if (classBody.body.some(({ key }) => key.name === methodName)) return
|
|
95
|
-
|
|
96
|
-
// Method doesn't exist on the class so we assume an instance method and
|
|
97
|
-
// wrap it in the constructor instead.
|
|
98
|
-
let ctor = classBody.body.find(({ kind }) => kind === 'constructor')
|
|
99
|
-
|
|
100
|
-
transforms.tracingChannelDeclaration(state, program)
|
|
101
|
-
|
|
102
|
-
if (!ctor) {
|
|
103
|
-
ctor = parse(
|
|
104
|
-
node.superClass
|
|
105
|
-
? 'class A { constructor (...args) { super(...args) } }'
|
|
106
|
-
: 'class A { constructor () {} }'
|
|
107
|
-
).body[0].body.body[0] // Extract constructor from dummy class body.
|
|
108
|
-
|
|
109
|
-
classBody.body.unshift(ctor)
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const ctorBody = parse(`
|
|
113
|
-
const __apm$${methodName} = this["${methodName}"]
|
|
114
|
-
this["${methodName}"] = function () {}
|
|
115
|
-
`).body
|
|
116
|
-
|
|
117
|
-
// Extract only right-hand side function of line 2.
|
|
118
|
-
const fn = ctorBody[1].expression.right
|
|
119
|
-
|
|
120
|
-
fn.async = operator === 'tracePromise'
|
|
121
|
-
fn.body = wrap(state, { type: 'Identifier', name: `__apm$${methodName}` }, program)
|
|
122
|
-
|
|
123
|
-
wrapSuper(state, fn)
|
|
124
|
-
|
|
125
|
-
ctor.value.body.body.push(...ctorBody)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function wrap (state, node, program) {
|
|
129
|
-
const { operator } = state
|
|
130
|
-
|
|
131
|
-
if (operator === 'traceAsyncIterator') return wrapIterator(state, node, program)
|
|
132
|
-
if (operator === 'traceIterator') return wrapIterator(state, node, program)
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function wrapSuper (_state, node) {
|
|
136
|
-
const members = new Set()
|
|
137
|
-
|
|
138
|
-
traverse(
|
|
139
|
-
node.body,
|
|
140
|
-
'[object.type=Super]',
|
|
141
|
-
(node, parent) => {
|
|
142
|
-
const { name } = node.property
|
|
143
|
-
|
|
144
|
-
let child
|
|
145
|
-
|
|
146
|
-
if (parent.callee) {
|
|
147
|
-
// This is needed because for generator functions we have to move the
|
|
148
|
-
// original function to a nested wrapped function, but we can't use an
|
|
149
|
-
// arrow function because arrow function cannot be generator functions,
|
|
150
|
-
// and `super` cannot be called from a nested function, so we have to
|
|
151
|
-
// rewrite any `super` call to not use the keyword.
|
|
152
|
-
const { expression } = parse(`__apm$super['${name}'].call(this)`).body[0]
|
|
153
|
-
|
|
154
|
-
parent.callee = child = expression.callee
|
|
155
|
-
parent.arguments.unshift(...expression.arguments)
|
|
156
|
-
} else {
|
|
157
|
-
parent.expression = child = parse(`__apm$super['${name}']`).body[0]
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
child.computed = parent.callee.computed
|
|
161
|
-
child.optional = parent.callee.optional
|
|
162
|
-
|
|
163
|
-
members.add(name)
|
|
164
|
-
}
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
for (const name of members) {
|
|
168
|
-
const member = parse(`
|
|
169
|
-
class Wrapper {
|
|
170
|
-
wrapper () {
|
|
171
|
-
__apm$super['${name}'] = super['${name}']
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
`).body[0].body.body[0].value.body.body[0]
|
|
175
|
-
|
|
176
|
-
node.body.body.unshift(member)
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
if (members.size > 0) {
|
|
180
|
-
node.body.body.unshift(parse('const __apm$super = {}').body[0])
|
|
3
|
+
// Custom transforms registered via InstrumentationMatcher.addTransform().
|
|
4
|
+
//
|
|
5
|
+
// Use this file for transforms that are not yet supported upstream in
|
|
6
|
+
// @apm-js-collab/code-transformer (Orchestrion) or that cannot land there
|
|
7
|
+
// for dd-trace-specific reasons. Once a transform is available natively in
|
|
8
|
+
// the library, replace the custom registration with the built-in option and
|
|
9
|
+
// remove the entry here.
|
|
10
|
+
|
|
11
|
+
const { parse, query } = require('./compiler')
|
|
12
|
+
|
|
13
|
+
module.exports = { waitForAsyncEnd }
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Injects a wait for `ctx.asyncEndPromise` into a generated `tracePromise`
|
|
17
|
+
* wrapper's native-Promise fulfillment handler.
|
|
18
|
+
*
|
|
19
|
+
* @param {object} _state
|
|
20
|
+
* @param {import('estree').CallExpression} node
|
|
21
|
+
* @returns {void}
|
|
22
|
+
*/
|
|
23
|
+
function waitForAsyncEnd (_state, node) {
|
|
24
|
+
const onFulfilled = node.arguments[0]
|
|
25
|
+
const statements = onFulfilled?.body?.body
|
|
26
|
+
|
|
27
|
+
if (!statements || query(onFulfilled.body, '[id.name=__apm$asyncEndPromise]').length > 0) {
|
|
28
|
+
return
|
|
181
29
|
}
|
|
182
|
-
}
|
|
183
30
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const channelVariable = 'tr_ch_apm$' + baseChannel
|
|
188
|
-
const nextChannel = baseChannel + '_next'
|
|
189
|
-
const traceMethod = operator === 'traceAsyncIterator' ? 'tracePromise' : 'traceSync'
|
|
190
|
-
const traceNext = `tr_ch_apm$${nextChannel}.${traceMethod}`
|
|
31
|
+
const returnIndex = statements.findIndex(statement => (
|
|
32
|
+
statement.type === 'ReturnStatement' && statement.argument?.name === 'result'
|
|
33
|
+
))
|
|
191
34
|
|
|
192
|
-
|
|
35
|
+
if (returnIndex === -1) return
|
|
193
36
|
|
|
194
|
-
const
|
|
37
|
+
const waitStatements = parse(`
|
|
195
38
|
function wrapper () {
|
|
196
|
-
const __apm$
|
|
197
|
-
|
|
198
|
-
return __apm$
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
if (!${channelVariable}.start.hasSubscribers) return __apm$traced();
|
|
202
|
-
|
|
203
|
-
{
|
|
204
|
-
const wrap = iter => {
|
|
205
|
-
const { next: iterNext, return: iterReturn, throw: iterThrow } = iter;
|
|
206
|
-
|
|
207
|
-
iter.next = (...args) => ${traceNext}(iterNext, ctx, iter, ...args);
|
|
208
|
-
iter.return = (...args) => ${traceNext}(iterReturn, ctx, iter, ...args);
|
|
209
|
-
iter.throw = (...args) => ${traceNext}(iterThrow, ctx, iter, ...args);
|
|
210
|
-
|
|
211
|
-
return iter;
|
|
212
|
-
};
|
|
213
|
-
const ctx = {
|
|
214
|
-
arguments,
|
|
215
|
-
self: this,
|
|
216
|
-
moduleVersion: "1.0.0"
|
|
217
|
-
};
|
|
218
|
-
const iter = ${channelVariable}.traceSync(__apm$traced, ctx);
|
|
219
|
-
|
|
220
|
-
if (typeof iter.then !== 'function') return wrap(iter);
|
|
221
|
-
|
|
222
|
-
return iter.then(result => {
|
|
223
|
-
ctx.result = result;
|
|
224
|
-
|
|
225
|
-
${channelVariable}.asyncStart.publish(ctx);
|
|
226
|
-
${channelVariable}.asyncEnd.publish(ctx);
|
|
227
|
-
|
|
228
|
-
return wrap(result);
|
|
229
|
-
}, err => {
|
|
230
|
-
ctx.error = err;
|
|
231
|
-
|
|
232
|
-
${channelVariable}.error.publish(ctx);
|
|
233
|
-
${channelVariable}.asyncStart.publish(ctx);
|
|
234
|
-
${channelVariable}.asyncEnd.publish(ctx);
|
|
235
|
-
|
|
236
|
-
return Promise.reject(err);
|
|
237
|
-
});
|
|
238
|
-
};
|
|
39
|
+
const __apm$asyncEndPromise = __apm$ctx.asyncEndPromise;
|
|
40
|
+
if (__apm$asyncEndPromise && typeof __apm$asyncEndPromise.then === 'function') {
|
|
41
|
+
return __apm$asyncEndPromise.then(() => result, () => result);
|
|
42
|
+
}
|
|
239
43
|
}
|
|
240
|
-
`).body[0].body
|
|
241
|
-
|
|
242
|
-
// Replace the right-hand side assignment of `const __apm$wrapped = () => {}`.
|
|
243
|
-
query(wrapper, '[id.name=__apm$wrapped]')[0].init = node
|
|
44
|
+
`).body[0].body.body
|
|
244
45
|
|
|
245
|
-
|
|
46
|
+
statements.splice(returnIndex, 0, ...waitStatements)
|
|
246
47
|
}
|
|
@@ -14,6 +14,11 @@ const enterChannel = channel('apm:hono:middleware:enter')
|
|
|
14
14
|
const exitChannel = channel('apm:hono:middleware:exit')
|
|
15
15
|
const finishChannel = channel('apm:hono:middleware:finish')
|
|
16
16
|
|
|
17
|
+
// Tracks handlers registered via `app.use()` so route-publishing wrappers
|
|
18
|
+
// installed by `wrapRouterAdd` can skip middleware-only matches (a request
|
|
19
|
+
// matching only middleware should keep the bare HTTP-method resource name).
|
|
20
|
+
const middlewareHandlers = new WeakSet()
|
|
21
|
+
|
|
17
22
|
// `app.request()` and non-node adapters call `app.fetch` without an `incoming`
|
|
18
23
|
// IncomingMessage; the APM `web` helpers depend on one, so the wrappers below
|
|
19
24
|
// skip publishing whenever it is missing.
|
|
@@ -27,6 +32,53 @@ function wrapFetch (fetch) {
|
|
|
27
32
|
}
|
|
28
33
|
}
|
|
29
34
|
|
|
35
|
+
function wrapUse (originalUse) {
|
|
36
|
+
return function (arg1, ...handlers) {
|
|
37
|
+
if (typeof arg1 === 'function') middlewareHandlers.add(arg1)
|
|
38
|
+
for (const h of handlers) middlewareHandlers.add(h)
|
|
39
|
+
return originalUse.call(this, arg1, ...handlers)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// `app.basePath()` returns a clone Hono instance built via the library's
|
|
44
|
+
// internal class binding, so it never hits our instrumented constructor. The
|
|
45
|
+
// clone shares the parent router (so `router.add` stays wrapped), but its
|
|
46
|
+
// `use` is a fresh per-instance method that must be wrapped too, otherwise
|
|
47
|
+
// middleware registered on the sub-app never lands in `middlewareHandlers`.
|
|
48
|
+
function wrapBasePath (originalBasePath) {
|
|
49
|
+
return function (path) {
|
|
50
|
+
const clone = originalBasePath.apply(this, arguments)
|
|
51
|
+
shimmer.wrap(clone, 'use', wrapUse)
|
|
52
|
+
shimmer.wrap(clone, 'basePath', wrapBasePath)
|
|
53
|
+
return clone
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function wrapRouterAdd (originalAdd) {
|
|
58
|
+
return function (method, path, handlerData) {
|
|
59
|
+
const handler = handlerData?.[0]
|
|
60
|
+
if (typeof handler === 'function' && !middlewareHandlers.has(handler)) {
|
|
61
|
+
const meta = handlerData[1]
|
|
62
|
+
const wrappedHandler = function (context, next) {
|
|
63
|
+
const req = context.env?.incoming
|
|
64
|
+
if (req && routeChannel.hasSubscribers) {
|
|
65
|
+
routeChannel.publish({ req, route: meta?.path })
|
|
66
|
+
}
|
|
67
|
+
return handler.apply(this, arguments)
|
|
68
|
+
}
|
|
69
|
+
handlerData = [wrappedHandler, meta]
|
|
70
|
+
}
|
|
71
|
+
return originalAdd.call(this, method, path, handlerData)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function instrumentHonoInstance (instance) {
|
|
76
|
+
shimmer.wrap(instance, 'fetch', wrapFetch)
|
|
77
|
+
shimmer.wrap(instance, 'use', wrapUse)
|
|
78
|
+
shimmer.wrap(instance, 'basePath', wrapBasePath)
|
|
79
|
+
shimmer.wrap(instance.router, 'add', wrapRouterAdd)
|
|
80
|
+
}
|
|
81
|
+
|
|
30
82
|
function onErrorFn (error, _context_) {
|
|
31
83
|
throw error
|
|
32
84
|
}
|
|
@@ -74,7 +126,6 @@ function wrapMiddleware (middleware, route) {
|
|
|
74
126
|
if (!req) {
|
|
75
127
|
return middleware.apply(this, arguments)
|
|
76
128
|
}
|
|
77
|
-
routeChannel.publish({ req, route })
|
|
78
129
|
enterChannel.publish({ req, name, route })
|
|
79
130
|
if (typeof next === 'function') {
|
|
80
131
|
arguments[1] = wrapNext(req, route, next)
|
|
@@ -113,7 +164,7 @@ addHook({
|
|
|
113
164
|
class Hono extends hono.Hono {
|
|
114
165
|
constructor (...args) {
|
|
115
166
|
super(...args)
|
|
116
|
-
|
|
167
|
+
instrumentHonoInstance(this)
|
|
117
168
|
}
|
|
118
169
|
}
|
|
119
170
|
|
|
@@ -130,7 +181,7 @@ addHook({
|
|
|
130
181
|
class Hono extends hono.Hono {
|
|
131
182
|
constructor (...args) {
|
|
132
183
|
super(...args)
|
|
133
|
-
|
|
184
|
+
instrumentHonoInstance(this)
|
|
134
185
|
}
|
|
135
186
|
}
|
|
136
187
|
|
|
@@ -43,7 +43,7 @@ function wrapResponseEmit (emit) {
|
|
|
43
43
|
return emit.apply(this, arguments)
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
if (
|
|
46
|
+
if ((eventName === 'finish' || eventName === 'close') && !requestFinishedSet.has(this)) {
|
|
47
47
|
finishServerCh.publish({ req: this.req })
|
|
48
48
|
requestFinishedSet.add(this)
|
|
49
49
|
}
|
|
@@ -51,6 +51,7 @@ function wrapResponseEmit (emit) {
|
|
|
51
51
|
return emit.apply(this, arguments)
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
+
|
|
54
55
|
function wrapEmit (emit) {
|
|
55
56
|
return function (eventName, req, res) {
|
|
56
57
|
if (!startServerCh.hasSubscribers) {
|
|
@@ -61,8 +62,12 @@ function wrapEmit (emit) {
|
|
|
61
62
|
res.req = req
|
|
62
63
|
|
|
63
64
|
const abortController = new AbortController()
|
|
65
|
+
// Single ctx shared with `exitServerCh` below and forwarded by the
|
|
66
|
+
// server plugin to `incomingHttpRequestStart`; existing subscribers
|
|
67
|
+
// only read the message, so the reuse is safe.
|
|
68
|
+
const ctx = { req, res, abortController }
|
|
64
69
|
|
|
65
|
-
startServerCh.publish(
|
|
70
|
+
startServerCh.publish(ctx)
|
|
66
71
|
|
|
67
72
|
try {
|
|
68
73
|
if (abortController.signal.aborted) {
|
|
@@ -76,7 +81,7 @@ function wrapEmit (emit) {
|
|
|
76
81
|
|
|
77
82
|
throw err
|
|
78
83
|
} finally {
|
|
79
|
-
exitServerCh.publish(
|
|
84
|
+
exitServerCh.publish(ctx)
|
|
80
85
|
}
|
|
81
86
|
}
|
|
82
87
|
return emit.apply(this, arguments)
|
|
@@ -107,7 +112,7 @@ function wrapWriteHead (writeHead) {
|
|
|
107
112
|
}
|
|
108
113
|
|
|
109
114
|
// this doesn't support explicit duplicate headers, but it's an edge case
|
|
110
|
-
const responseHeaders = Object.assign(this.getHeaders(), obj)
|
|
115
|
+
const responseHeaders = obj === undefined ? this.getHeaders() : Object.assign(this.getHeaders(), obj)
|
|
111
116
|
|
|
112
117
|
startWriteHeadCh.publish({
|
|
113
118
|
req: this.req,
|