dd-trace 5.103.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 +107 -6
- package/package.json +18 -17
- 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 +15 -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/cassandra-driver.js +5 -2
- package/packages/datadog-instrumentations/src/cucumber.js +181 -35
- package/packages/datadog-instrumentations/src/dns.js +54 -18
- package/packages/datadog-instrumentations/src/elasticsearch.js +4 -4
- package/packages/datadog-instrumentations/src/fastify.js +142 -82
- package/packages/datadog-instrumentations/src/graphql.js +188 -67
- package/packages/datadog-instrumentations/src/grpc/client.js +48 -32
- package/packages/datadog-instrumentations/src/helpers/ai-messages.js +322 -14
- package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +1 -1
- 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/kafka.js +17 -0
- 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/compiler.js +3 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +19 -6
- 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 +31 -229
- package/packages/datadog-instrumentations/src/hono.js +54 -3
- package/packages/datadog-instrumentations/src/http/client.js +2 -2
- package/packages/datadog-instrumentations/src/http/server.js +9 -4
- package/packages/datadog-instrumentations/src/ioredis.js +3 -3
- package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +163 -0
- package/packages/datadog-instrumentations/src/jest.js +390 -183
- package/packages/datadog-instrumentations/src/kafkajs.js +140 -17
- package/packages/datadog-instrumentations/src/mariadb.js +1 -1
- package/packages/datadog-instrumentations/src/memcached.js +2 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +399 -107
- package/packages/datadog-instrumentations/src/mocha/utils.js +48 -8
- package/packages/datadog-instrumentations/src/mongodb-core.js +1 -1
- package/packages/datadog-instrumentations/src/mongoose.js +10 -12
- package/packages/datadog-instrumentations/src/mysql.js +2 -2
- package/packages/datadog-instrumentations/src/mysql2.js +1 -1
- package/packages/datadog-instrumentations/src/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/pg.js +1 -1
- package/packages/datadog-instrumentations/src/pino.js +17 -5
- package/packages/datadog-instrumentations/src/playwright.js +537 -297
- package/packages/datadog-instrumentations/src/router.js +80 -34
- package/packages/datadog-instrumentations/src/stripe.js +1 -1
- package/packages/datadog-instrumentations/src/vitest.js +246 -149
- 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 +223 -45
- package/packages/datadog-plugin-cypress/src/support.js +69 -1
- package/packages/datadog-plugin-dns/src/lookup.js +8 -6
- package/packages/datadog-plugin-elasticsearch/src/index.js +28 -8
- 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-graphql/src/utils.js +4 -1
- 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 +35 -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 +311 -35
- 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-redis/src/index.js +37 -2
- 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-undici/src/index.js +19 -0
- package/packages/datadog-plugin-vitest/src/index.js +24 -20
- package/packages/datadog-plugin-winston/src/index.js +30 -0
- package/packages/datadog-shimmer/src/shimmer.js +49 -21
- 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/blocking.js +2 -2
- package/packages/dd-trace/src/appsec/index.js +11 -4
- package/packages/dd-trace/src/appsec/reporter.js +24 -11
- 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/requests/request.js +3 -1
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +5 -3
- package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +70 -6
- package/packages/dd-trace/src/config/generated-config-types.d.ts +7 -2
- package/packages/dd-trace/src/config/supported-configurations.json +36 -8
- package/packages/dd-trace/src/crashtracking/crashtracker.js +15 -3
- package/packages/dd-trace/src/datastreams/context.js +4 -2
- package/packages/dd-trace/src/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 +57 -42
- 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/exporters/common/agents.js +3 -1
- package/packages/dd-trace/src/exporters/common/request.js +3 -1
- package/packages/dd-trace/src/id.js +17 -4
- package/packages/dd-trace/src/lambda/handler.js +2 -4
- package/packages/dd-trace/src/llmobs/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 +10 -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/log/writer.js +3 -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/noop/span.js +3 -1
- 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/openfeature/writers/exposures.js +51 -20
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -1
- 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/apollo.js +3 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +23 -33
- 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 -46
- 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 +48 -8
- package/packages/dd-trace/src/plugins/util/git.js +3 -1
- package/packages/dd-trace/src/plugins/util/test.js +318 -13
- package/packages/dd-trace/src/plugins/util/web.js +89 -64
- 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/scope.js +7 -5
- package/packages/dd-trace/src/service-naming/extra-services.js +14 -0
- 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
- package/vendor/dist/opentracing/LICENSE +0 -201
- package/vendor/dist/opentracing/binary_carrier.d.ts +0 -11
- package/vendor/dist/opentracing/constants.d.ts +0 -61
- package/vendor/dist/opentracing/examples/demo/demo.d.ts +0 -2
- package/vendor/dist/opentracing/ext/tags.d.ts +0 -90
- package/vendor/dist/opentracing/functions.d.ts +0 -20
- package/vendor/dist/opentracing/global_tracer.d.ts +0 -14
- package/vendor/dist/opentracing/index.d.ts +0 -12
- package/vendor/dist/opentracing/index.js +0 -1
- package/vendor/dist/opentracing/mock_tracer/index.d.ts +0 -5
- package/vendor/dist/opentracing/mock_tracer/mock_context.d.ts +0 -13
- package/vendor/dist/opentracing/mock_tracer/mock_report.d.ts +0 -16
- package/vendor/dist/opentracing/mock_tracer/mock_span.d.ts +0 -50
- package/vendor/dist/opentracing/mock_tracer/mock_tracer.d.ts +0 -26
- package/vendor/dist/opentracing/noop.d.ts +0 -8
- package/vendor/dist/opentracing/reference.d.ts +0 -33
- package/vendor/dist/opentracing/span.d.ts +0 -147
- package/vendor/dist/opentracing/span_context.d.ts +0 -26
- package/vendor/dist/opentracing/test/api_compatibility.d.ts +0 -16
- package/vendor/dist/opentracing/test/mocktracer_implemenation.d.ts +0 -3
- package/vendor/dist/opentracing/test/noop_implementation.d.ts +0 -4
- package/vendor/dist/opentracing/test/opentracing_api.d.ts +0 -3
- package/vendor/dist/opentracing/test/unittest.d.ts +0 -2
- package/vendor/dist/opentracing/tracer.d.ts +0 -127
|
@@ -1,245 +1,47 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
//
|
|
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.
|
|
4
10
|
|
|
5
|
-
const { parse, query
|
|
11
|
+
const { parse, query } = require('./compiler')
|
|
6
12
|
|
|
7
|
-
|
|
8
|
-
node.specifiers?.[0]?.local?.name === 'tr_ch_apm_tracingChannel' ||
|
|
9
|
-
node.declarations?.[0]?.id?.properties?.[0]?.value?.name === 'tr_ch_apm_tracingChannel'
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
const transforms = module.exports = {
|
|
13
|
-
tracingChannelImport ({ dcModule, sourceType }, node) {
|
|
14
|
-
if (node.body.some(tracingChannelPredicate)) return
|
|
15
|
-
|
|
16
|
-
const index = node.body.findIndex(child => child.directive === 'use strict')
|
|
17
|
-
const code = isModuleSourceType(sourceType)
|
|
18
|
-
? `import { tracingChannel as tr_ch_apm_tracingChannel } from "${dcModule}"`
|
|
19
|
-
: `const {tracingChannel: tr_ch_apm_tracingChannel} = require("${dcModule}")`
|
|
20
|
-
|
|
21
|
-
node.body.splice(index + 1, 0, parse(code, {
|
|
22
|
-
isModule: isModuleSourceType(sourceType),
|
|
23
|
-
}).body[0])
|
|
24
|
-
},
|
|
25
|
-
|
|
26
|
-
tracingChannelDeclaration (state, node) {
|
|
27
|
-
const { channelName, module: { name } } = state
|
|
28
|
-
const channelVariable = 'tr_ch_apm$' + channelName.replaceAll(':', '_')
|
|
29
|
-
|
|
30
|
-
if (node.body.some(child => child.declarations?.[0]?.id?.name === channelVariable)) return
|
|
31
|
-
|
|
32
|
-
transforms.tracingChannelImport(state, node)
|
|
33
|
-
|
|
34
|
-
const index = node.body.findIndex(tracingChannelPredicate)
|
|
35
|
-
const code = `
|
|
36
|
-
const ${channelVariable} = tr_ch_apm_tracingChannel("orchestrion:${name}:${channelName}")
|
|
37
|
-
`
|
|
38
|
-
|
|
39
|
-
node.body.splice(index + 1, 0, parse(code).body[0])
|
|
40
|
-
},
|
|
41
|
-
|
|
42
|
-
traceAsyncIterator: traceAny,
|
|
43
|
-
traceIterator: traceAny,
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function traceAny (state, node, _parent, ancestry) {
|
|
47
|
-
const program = ancestry[ancestry.length - 1]
|
|
48
|
-
|
|
49
|
-
if (node.type === 'ClassDeclaration' || node.type === 'ClassExpression') {
|
|
50
|
-
traceInstanceMethod(state, node, program)
|
|
51
|
-
} else {
|
|
52
|
-
traceFunction(state, node, program)
|
|
53
|
-
}
|
|
54
|
-
}
|
|
13
|
+
module.exports = { waitForAsyncEnd }
|
|
55
14
|
|
|
56
15
|
/**
|
|
57
|
-
*
|
|
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}
|
|
58
22
|
*/
|
|
59
|
-
function
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
function traceFunction (state, node, program) {
|
|
64
|
-
transforms.tracingChannelDeclaration(state, program)
|
|
23
|
+
function waitForAsyncEnd (_state, node) {
|
|
24
|
+
const onFulfilled = node.arguments[0]
|
|
25
|
+
const statements = onFulfilled?.body?.body
|
|
65
26
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
params: node.params,
|
|
69
|
-
body: node.body,
|
|
70
|
-
async: node.async,
|
|
71
|
-
expression: false,
|
|
72
|
-
generator: node.generator,
|
|
73
|
-
}, program)
|
|
74
|
-
|
|
75
|
-
// The original function no longer contains any calls to `await` or `yield` as
|
|
76
|
-
// the function body is copied to the internal wrapped function, so we set
|
|
77
|
-
// these to false to avoid altering the return value of the wrapper. The old
|
|
78
|
-
// values are instead copied to the new AST node above.
|
|
79
|
-
node.generator = false
|
|
80
|
-
node.async = false
|
|
81
|
-
|
|
82
|
-
wrapSuper(state, node)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function traceInstanceMethod (state, node, program) {
|
|
86
|
-
const { functionQuery, operator } = state
|
|
87
|
-
const { methodName } = functionQuery
|
|
88
|
-
|
|
89
|
-
const classBody = node.body
|
|
90
|
-
|
|
91
|
-
// If the method exists on the class, we return as it will be patched later
|
|
92
|
-
// while traversing child nodes later on.
|
|
93
|
-
if (classBody.body.some(({ key }) => key.name === methodName)) return
|
|
94
|
-
|
|
95
|
-
// Method doesn't exist on the class so we assume an instance method and
|
|
96
|
-
// wrap it in the constructor instead.
|
|
97
|
-
let ctor = classBody.body.find(({ kind }) => kind === 'constructor')
|
|
98
|
-
|
|
99
|
-
transforms.tracingChannelDeclaration(state, program)
|
|
100
|
-
|
|
101
|
-
if (!ctor) {
|
|
102
|
-
ctor = parse(
|
|
103
|
-
node.superClass
|
|
104
|
-
? 'class A { constructor (...args) { super(...args) } }'
|
|
105
|
-
: 'class A { constructor () {} }'
|
|
106
|
-
).body[0].body.body[0] // Extract constructor from dummy class body.
|
|
107
|
-
|
|
108
|
-
classBody.body.unshift(ctor)
|
|
27
|
+
if (!statements || query(onFulfilled.body, '[id.name=__apm$asyncEndPromise]').length > 0) {
|
|
28
|
+
return
|
|
109
29
|
}
|
|
110
30
|
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
`).body
|
|
115
|
-
|
|
116
|
-
// Extract only right-hand side function of line 2.
|
|
117
|
-
const fn = ctorBody[1].expression.right
|
|
118
|
-
|
|
119
|
-
fn.async = operator === 'tracePromise'
|
|
120
|
-
fn.body = wrap(state, { type: 'Identifier', name: `__apm$${methodName}` }, program)
|
|
31
|
+
const returnIndex = statements.findIndex(statement => (
|
|
32
|
+
statement.type === 'ReturnStatement' && statement.argument?.name === 'result'
|
|
33
|
+
))
|
|
121
34
|
|
|
122
|
-
|
|
35
|
+
if (returnIndex === -1) return
|
|
123
36
|
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function wrap (state, node, program) {
|
|
128
|
-
const { operator } = state
|
|
129
|
-
|
|
130
|
-
if (operator === 'traceAsyncIterator') return wrapIterator(state, node, program)
|
|
131
|
-
if (operator === 'traceIterator') return wrapIterator(state, node, program)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function wrapSuper (_state, node) {
|
|
135
|
-
const members = new Set()
|
|
136
|
-
|
|
137
|
-
traverse(
|
|
138
|
-
node.body,
|
|
139
|
-
'[object.type=Super]',
|
|
140
|
-
(node, parent) => {
|
|
141
|
-
const { name } = node.property
|
|
142
|
-
|
|
143
|
-
let child
|
|
144
|
-
|
|
145
|
-
if (parent.callee) {
|
|
146
|
-
// This is needed because for generator functions we have to move the
|
|
147
|
-
// original function to a nested wrapped function, but we can't use an
|
|
148
|
-
// arrow function because arrow function cannot be generator functions,
|
|
149
|
-
// and `super` cannot be called from a nested function, so we have to
|
|
150
|
-
// rewrite any `super` call to not use the keyword.
|
|
151
|
-
const { expression } = parse(`__apm$super['${name}'].call(this)`).body[0]
|
|
152
|
-
|
|
153
|
-
parent.callee = child = expression.callee
|
|
154
|
-
parent.arguments.unshift(...expression.arguments)
|
|
155
|
-
} else {
|
|
156
|
-
parent.expression = child = parse(`__apm$super['${name}']`).body[0]
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
child.computed = parent.callee.computed
|
|
160
|
-
child.optional = parent.callee.optional
|
|
161
|
-
|
|
162
|
-
members.add(name)
|
|
163
|
-
}
|
|
164
|
-
)
|
|
165
|
-
|
|
166
|
-
for (const name of members) {
|
|
167
|
-
const member = parse(`
|
|
168
|
-
class Wrapper {
|
|
169
|
-
wrapper () {
|
|
170
|
-
__apm$super['${name}'] = super['${name}']
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
`).body[0].body.body[0].value.body.body[0]
|
|
174
|
-
|
|
175
|
-
node.body.body.unshift(member)
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (members.size > 0) {
|
|
179
|
-
node.body.body.unshift(parse('const __apm$super = {}').body[0])
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function wrapIterator (state, node, program) {
|
|
184
|
-
const { channelName, operator } = state
|
|
185
|
-
const baseChannel = channelName.replaceAll(':', '_')
|
|
186
|
-
const channelVariable = 'tr_ch_apm$' + baseChannel
|
|
187
|
-
const nextChannel = baseChannel + '_next'
|
|
188
|
-
const traceMethod = operator === 'traceAsyncIterator' ? 'tracePromise' : 'traceSync'
|
|
189
|
-
const traceNext = `tr_ch_apm$${nextChannel}.${traceMethod}`
|
|
190
|
-
|
|
191
|
-
transforms.tracingChannelDeclaration({ ...state, channelName: nextChannel }, program)
|
|
192
|
-
|
|
193
|
-
const wrapper = parse(`
|
|
37
|
+
const waitStatements = parse(`
|
|
194
38
|
function wrapper () {
|
|
195
|
-
const __apm$
|
|
196
|
-
|
|
197
|
-
return __apm$
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (!${channelVariable}.start.hasSubscribers) return __apm$traced();
|
|
201
|
-
|
|
202
|
-
{
|
|
203
|
-
const wrap = iter => {
|
|
204
|
-
const { next: iterNext, return: iterReturn, throw: iterThrow } = iter;
|
|
205
|
-
|
|
206
|
-
iter.next = (...args) => ${traceNext}(iterNext, ctx, iter, ...args);
|
|
207
|
-
iter.return = (...args) => ${traceNext}(iterReturn, ctx, iter, ...args);
|
|
208
|
-
iter.throw = (...args) => ${traceNext}(iterThrow, ctx, iter, ...args);
|
|
209
|
-
|
|
210
|
-
return iter;
|
|
211
|
-
};
|
|
212
|
-
const ctx = {
|
|
213
|
-
arguments,
|
|
214
|
-
self: this,
|
|
215
|
-
moduleVersion: "1.0.0"
|
|
216
|
-
};
|
|
217
|
-
const iter = ${channelVariable}.traceSync(__apm$traced, ctx);
|
|
218
|
-
|
|
219
|
-
if (typeof iter.then !== 'function') return wrap(iter);
|
|
220
|
-
|
|
221
|
-
return iter.then(result => {
|
|
222
|
-
ctx.result = result;
|
|
223
|
-
|
|
224
|
-
${channelVariable}.asyncStart.publish(ctx);
|
|
225
|
-
${channelVariable}.asyncEnd.publish(ctx);
|
|
226
|
-
|
|
227
|
-
return wrap(result);
|
|
228
|
-
}, err => {
|
|
229
|
-
ctx.error = err;
|
|
230
|
-
|
|
231
|
-
${channelVariable}.error.publish(ctx);
|
|
232
|
-
${channelVariable}.asyncStart.publish(ctx);
|
|
233
|
-
${channelVariable}.asyncEnd.publish(ctx);
|
|
234
|
-
|
|
235
|
-
return Promise.reject(err);
|
|
236
|
-
});
|
|
237
|
-
};
|
|
39
|
+
const __apm$asyncEndPromise = __apm$ctx.asyncEndPromise;
|
|
40
|
+
if (__apm$asyncEndPromise && typeof __apm$asyncEndPromise.then === 'function') {
|
|
41
|
+
return __apm$asyncEndPromise.then(() => result, () => result);
|
|
42
|
+
}
|
|
238
43
|
}
|
|
239
|
-
`).body[0].body
|
|
240
|
-
|
|
241
|
-
// Replace the right-hand side assignment of `const __apm$wrapped = () => {}`.
|
|
242
|
-
query(wrapper, '[id.name=__apm$wrapped]')[0].init = node
|
|
44
|
+
`).body[0].body.body
|
|
243
45
|
|
|
244
|
-
|
|
46
|
+
statements.splice(returnIndex, 0, ...waitStatements)
|
|
245
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
|
|
|
@@ -188,8 +188,8 @@ function patch (http, methodName) {
|
|
|
188
188
|
let finished = false
|
|
189
189
|
let callback = args.callback
|
|
190
190
|
|
|
191
|
-
if (callback) {
|
|
192
|
-
callback = shimmer.
|
|
191
|
+
if (typeof callback === 'function') {
|
|
192
|
+
callback = shimmer.wrapCallback(args.callback, cb => function (...args) {
|
|
193
193
|
return asyncStartChannel.runStores(ctx, () => {
|
|
194
194
|
return cb.apply(this, args)
|
|
195
195
|
})
|
|
@@ -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,
|
|
@@ -14,9 +14,9 @@ const connectionOptionsCache = new WeakMap()
|
|
|
14
14
|
|
|
15
15
|
function wrapRedis (Redis) {
|
|
16
16
|
shimmer.wrap(Redis.prototype, 'sendCommand', sendCommand => function (command, stream) {
|
|
17
|
-
if (!startCh.hasSubscribers) return sendCommand.
|
|
17
|
+
if (!startCh.hasSubscribers) return sendCommand.call(this, command, stream)
|
|
18
18
|
|
|
19
|
-
if (!command
|
|
19
|
+
if (!command?.promise) return sendCommand.call(this, command, stream)
|
|
20
20
|
|
|
21
21
|
const options = this.options || {}
|
|
22
22
|
let connectionOptions = connectionOptionsCache.get(this)
|
|
@@ -35,7 +35,7 @@ function wrapRedis (Redis) {
|
|
|
35
35
|
return startCh.runStores(ctx, () => {
|
|
36
36
|
command.promise.then(() => finish(finishCh, errorCh, ctx), err => finish(finishCh, errorCh, ctx, err))
|
|
37
37
|
|
|
38
|
-
return sendCommand.
|
|
38
|
+
return sendCommand.call(this, command, stream)
|
|
39
39
|
})
|
|
40
40
|
})
|
|
41
41
|
return Redis
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { readFileSync } = require('node:fs')
|
|
4
|
+
const path = require('node:path')
|
|
5
|
+
|
|
6
|
+
const COVERAGE_BACKFILL_CACHE_DIRECTORY = 'dd-trace-coverage-backfill'
|
|
7
|
+
const TRANSFORM_OPTIONS = {
|
|
8
|
+
instrument: true,
|
|
9
|
+
supportsDynamicImport: true,
|
|
10
|
+
supportsExportNamespaceFrom: true,
|
|
11
|
+
supportsStaticESM: true,
|
|
12
|
+
supportsTopLevelAwait: true,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function getCoverageBackfillFiles (skippableSuitesCoverage, rootDir, getTestSuitePath) {
|
|
16
|
+
const files = []
|
|
17
|
+
for (const filename of Object.keys(skippableSuitesCoverage || {})) {
|
|
18
|
+
const relativeFilename = path.isAbsolute(filename)
|
|
19
|
+
? getTestSuitePath(filename, rootDir)
|
|
20
|
+
: filename
|
|
21
|
+
files.push(relativeFilename)
|
|
22
|
+
}
|
|
23
|
+
return files
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Use a separate Jest cache namespace for synthetic backfill transforms so they cannot reuse or overwrite normal
|
|
27
|
+
// Jest transform cache entries produced during the user's test run.
|
|
28
|
+
function getCoverageBackfillConfig (config) {
|
|
29
|
+
if (!config?.cacheDirectory) return config
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
...config,
|
|
33
|
+
cacheDirectory: path.join(config.cacheDirectory, COVERAGE_BACKFILL_CACHE_DIRECTORY),
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function getCoverageBackfillDependencies (CoverageReporter, getCoverageBackfillRequire) {
|
|
38
|
+
const coverageWorkerRequire = getCoverageBackfillRequire(CoverageReporter)
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
createFileCoverage: coverageWorkerRequire('istanbul-lib-coverage').createFileCoverage,
|
|
42
|
+
createScriptTransformer: coverageWorkerRequire('@jest/transform').createScriptTransformer,
|
|
43
|
+
readInitialCoverage: coverageWorkerRequire('istanbul-lib-instrument').readInitialCoverage,
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Some transformers expose Istanbul coverage as a literal that readInitialCoverage does not parse.
|
|
48
|
+
function extractCoverageDataObject (code) {
|
|
49
|
+
const marker = 'var coverageData = '
|
|
50
|
+
const start = code.indexOf(marker)
|
|
51
|
+
if (start === -1) return
|
|
52
|
+
|
|
53
|
+
let depth = 0
|
|
54
|
+
let quote
|
|
55
|
+
let escaped = false
|
|
56
|
+
let index = start + marker.length
|
|
57
|
+
for (; index < code.length; index++) {
|
|
58
|
+
const char = code[index]
|
|
59
|
+
if (quote) {
|
|
60
|
+
if (escaped) {
|
|
61
|
+
escaped = false
|
|
62
|
+
} else if (char === '\\') {
|
|
63
|
+
escaped = true
|
|
64
|
+
} else if (char === quote) {
|
|
65
|
+
quote = undefined
|
|
66
|
+
}
|
|
67
|
+
continue
|
|
68
|
+
}
|
|
69
|
+
if (char === '"' || char === "'" || char === '`') {
|
|
70
|
+
quote = char
|
|
71
|
+
} else if (char === '{') {
|
|
72
|
+
depth++
|
|
73
|
+
} else if (char === '}') {
|
|
74
|
+
depth--
|
|
75
|
+
if (depth === 0) {
|
|
76
|
+
index++
|
|
77
|
+
break
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (depth !== 0) return
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
// eslint-disable-next-line no-new-func
|
|
85
|
+
return new Function(`return (${code.slice(start + marker.length, index)})`)()
|
|
86
|
+
} catch {
|
|
87
|
+
// Ignore transformer output that does not contain parseable Istanbul metadata.
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Read the Istanbul file metadata emitted by Jest's transformer.
|
|
92
|
+
function getCoverageDataFromCode (code, readInitialCoverage) {
|
|
93
|
+
return readInitialCoverage(code)?.coverageData || extractCoverageDataObject(code)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function transformFileWithTransformers (absoluteFile, sourceText, transformers, readInitialCoverage) {
|
|
97
|
+
return Promise.all(transformers.map(transformer => {
|
|
98
|
+
return transformer.transformSourceAsync(absoluteFile, sourceText, TRANSFORM_OPTIONS)
|
|
99
|
+
.then(({ code }) => getCoverageDataFromCode(code, readInitialCoverage))
|
|
100
|
+
.catch(() => {})
|
|
101
|
+
})).then(coverageDataByContext => coverageDataByContext.find(Boolean))
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function getBackfillCoverageDataForFile (file, rootDir, transformers, coverageMap, readInitialCoverage) {
|
|
105
|
+
const absoluteFile = path.isAbsolute(file) ? file : path.join(rootDir, file)
|
|
106
|
+
if (coverageMap.data[absoluteFile]) return Promise.resolve()
|
|
107
|
+
|
|
108
|
+
let sourceText
|
|
109
|
+
try {
|
|
110
|
+
sourceText = readFileSync(absoluteFile, 'utf8')
|
|
111
|
+
} catch {
|
|
112
|
+
return Promise.resolve()
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return transformFileWithTransformers(absoluteFile, sourceText, transformers, readInitialCoverage)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Seed Jest's coverage map with files that did not run locally but are covered by backend meta.coverage.
|
|
119
|
+
function addCoverageBackfillUntestedFiles ({
|
|
120
|
+
coverageMap,
|
|
121
|
+
testContexts,
|
|
122
|
+
rootDir,
|
|
123
|
+
CoverageReporter,
|
|
124
|
+
coverageBackfillFiles,
|
|
125
|
+
getCoverageBackfillRequire,
|
|
126
|
+
}) {
|
|
127
|
+
if (!coverageBackfillFiles?.length || !coverageMap || !rootDir) return Promise.resolve()
|
|
128
|
+
|
|
129
|
+
let createFileCoverage, createScriptTransformer, readInitialCoverage
|
|
130
|
+
try {
|
|
131
|
+
({
|
|
132
|
+
createFileCoverage,
|
|
133
|
+
createScriptTransformer,
|
|
134
|
+
readInitialCoverage,
|
|
135
|
+
} = getCoverageBackfillDependencies(CoverageReporter, getCoverageBackfillRequire))
|
|
136
|
+
} catch {
|
|
137
|
+
return Promise.resolve()
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const contexts = [...(testContexts || [])]
|
|
141
|
+
return Promise.all(contexts.map(context => {
|
|
142
|
+
return createScriptTransformer(getCoverageBackfillConfig(context.config)).catch(() => {})
|
|
143
|
+
}))
|
|
144
|
+
.then(transformers => transformers.filter(Boolean))
|
|
145
|
+
.then(transformers => {
|
|
146
|
+
if (!transformers.length) return []
|
|
147
|
+
return Promise.all(coverageBackfillFiles.map(file => {
|
|
148
|
+
return getBackfillCoverageDataForFile(file, rootDir, transformers, coverageMap, readInitialCoverage)
|
|
149
|
+
}))
|
|
150
|
+
})
|
|
151
|
+
.then(coverageDataByFile => {
|
|
152
|
+
for (const coverageData of coverageDataByFile) {
|
|
153
|
+
if (coverageData && !coverageMap.data[coverageData.path]) {
|
|
154
|
+
coverageMap.addFileCoverage(createFileCoverage(coverageData))
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
module.exports = {
|
|
161
|
+
addCoverageBackfillUntestedFiles,
|
|
162
|
+
getCoverageBackfillFiles,
|
|
163
|
+
}
|