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
|
@@ -7,21 +7,26 @@ const shimmer = require('../../datadog-shimmer')
|
|
|
7
7
|
const log = require('../../dd-trace/src/log')
|
|
8
8
|
const { getEnvironmentVariable } = require('../../dd-trace/src/config/helper')
|
|
9
9
|
const {
|
|
10
|
-
|
|
10
|
+
getCoveredFilesFromCoverage,
|
|
11
|
+
getExecutableFilesFromCoverage,
|
|
11
12
|
resetCoverage,
|
|
12
13
|
mergeCoverage,
|
|
13
14
|
fromCoverageMapToCoverage,
|
|
14
15
|
getTestSuitePath,
|
|
16
|
+
getRelativeCoverageFiles,
|
|
15
17
|
CUCUMBER_WORKER_TRACE_PAYLOAD_CODE,
|
|
16
18
|
getIsFaultyEarlyFlakeDetection,
|
|
17
19
|
getEfdRetryCount,
|
|
18
20
|
getMaxEfdRetryCount,
|
|
21
|
+
applySkippedCoverageToCoverage,
|
|
22
|
+
getTestCoverageLinesPercentage,
|
|
19
23
|
recordAttemptToFixExecution,
|
|
20
24
|
collectAttemptToFixExecutionsFromTraces,
|
|
21
25
|
logAttemptToFixTestExecution,
|
|
22
26
|
logTestOptimizationSummary,
|
|
23
27
|
getTestOptimizationRequestResults,
|
|
24
28
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
29
|
+
const { writeCoverageBackfillToCache } = require('../../dd-trace/src/ci-visibility/test-optimization-cache')
|
|
25
30
|
const satisfies = require('../../../vendor/dist/semifies')
|
|
26
31
|
const { addHook, channel } = require('./helpers/instrument')
|
|
27
32
|
|
|
@@ -86,10 +91,14 @@ let pickleByFile = {}
|
|
|
86
91
|
const pickleResultByFile = {}
|
|
87
92
|
|
|
88
93
|
let skippableSuites = []
|
|
94
|
+
let skippableSuitesCoverage = {}
|
|
95
|
+
let skippedSuitesCoverage = {}
|
|
89
96
|
let itrCorrelationId = ''
|
|
90
97
|
let isForcedToRun = false
|
|
91
98
|
let isUnskippable = false
|
|
99
|
+
let isItrEnabled = false
|
|
92
100
|
let isSuitesSkippingEnabled = false
|
|
101
|
+
let isCoverageReportUploadEnabled = false
|
|
93
102
|
let isEarlyFlakeDetectionEnabled = false
|
|
94
103
|
let earlyFlakeDetectionNumRetries = 0
|
|
95
104
|
let earlyFlakeDetectionSlowTestRetries = {}
|
|
@@ -106,11 +115,55 @@ let numTestRetries = 0
|
|
|
106
115
|
let knownTests = {}
|
|
107
116
|
let skippedSuites = []
|
|
108
117
|
let isSuitesSkipped = false
|
|
118
|
+
let repositoryRoot
|
|
109
119
|
|
|
110
120
|
function isValidKnownTests (receivedKnownTests) {
|
|
111
121
|
return !!receivedKnownTests.cucumber
|
|
112
122
|
}
|
|
113
123
|
|
|
124
|
+
function hasSkippableSuitesCoverage () {
|
|
125
|
+
return skippableSuitesCoverage &&
|
|
126
|
+
typeof skippableSuitesCoverage === 'object' &&
|
|
127
|
+
Object.keys(skippableSuitesCoverage).length > 0
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function isTiaCoverageBackfillEnabled () {
|
|
131
|
+
return isItrEnabled && isCoverageReportUploadEnabled
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function getCoverageRootDir () {
|
|
135
|
+
return repositoryRoot || process.cwd()
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function shouldReportCodeCoverageLinesPct (hasBackfilledCoverage) {
|
|
139
|
+
return !isSuitesSkipped || hasBackfilledCoverage
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function getSkippedSuitesCoverageForRun () {
|
|
143
|
+
return isSuitesSkipped && isTiaCoverageBackfillEnabled() && hasSkippableSuitesCoverage()
|
|
144
|
+
? skippableSuitesCoverage
|
|
145
|
+
: {}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function applySkippedCoverageToCucumberCoverageMap () {
|
|
149
|
+
if (!isTiaCoverageBackfillEnabled()) return false
|
|
150
|
+
return applySkippedCoverageToCoverage(originalCoverageMap, skippedSuitesCoverage, getCoverageRootDir())
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function getCucumberTestSessionCoverageFiles () {
|
|
154
|
+
return getRelativeCoverageFiles(getExecutableFilesFromCoverage(originalCoverageMap), getCoverageRootDir())
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function resetSuiteSkippingRunState () {
|
|
158
|
+
skippableSuites = []
|
|
159
|
+
skippableSuitesCoverage = {}
|
|
160
|
+
skippedSuitesCoverage = {}
|
|
161
|
+
skippedSuites = []
|
|
162
|
+
isSuitesSkipped = false
|
|
163
|
+
repositoryRoot = undefined
|
|
164
|
+
writeCoverageBackfillToCache({})
|
|
165
|
+
}
|
|
166
|
+
|
|
114
167
|
function getSuiteStatusFromTestStatuses (testStatuses) {
|
|
115
168
|
if (testStatuses.includes('fail')) {
|
|
116
169
|
return 'fail'
|
|
@@ -683,6 +736,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
683
736
|
if (!libraryConfigurationCh.hasSubscribers) {
|
|
684
737
|
return start.apply(this, arguments)
|
|
685
738
|
}
|
|
739
|
+
resetSuiteSkippingRunState()
|
|
686
740
|
const options = getCucumberOptions(this)
|
|
687
741
|
|
|
688
742
|
if (!isParallel && this.adapter?.options) {
|
|
@@ -692,11 +746,14 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
692
746
|
|
|
693
747
|
const configurationResponse = await getChannelPromise(libraryConfigurationCh, frameworkVersion)
|
|
694
748
|
|
|
749
|
+
repositoryRoot = configurationResponse.repositoryRoot
|
|
750
|
+
isItrEnabled = configurationResponse.libraryConfig?.isItrEnabled
|
|
695
751
|
isEarlyFlakeDetectionEnabled = configurationResponse.libraryConfig?.isEarlyFlakeDetectionEnabled
|
|
696
752
|
earlyFlakeDetectionNumRetries = configurationResponse.libraryConfig?.earlyFlakeDetectionNumRetries
|
|
697
753
|
earlyFlakeDetectionSlowTestRetries = configurationResponse.libraryConfig?.earlyFlakeDetectionSlowTestRetries ?? {}
|
|
698
754
|
earlyFlakeDetectionFaultyThreshold = configurationResponse.libraryConfig?.earlyFlakeDetectionFaultyThreshold
|
|
699
|
-
isSuitesSkippingEnabled = configurationResponse.libraryConfig?.isSuitesSkippingEnabled
|
|
755
|
+
isSuitesSkippingEnabled = isItrEnabled && configurationResponse.libraryConfig?.isSuitesSkippingEnabled
|
|
756
|
+
isCoverageReportUploadEnabled = configurationResponse.libraryConfig?.isCoverageReportUploadEnabled
|
|
700
757
|
isFlakyTestRetriesEnabled = configurationResponse.libraryConfig?.isFlakyTestRetriesEnabled
|
|
701
758
|
const configRetryCount = configurationResponse.libraryConfig?.flakyTestRetriesCount
|
|
702
759
|
numTestRetries = (typeof configRetryCount === 'number' && configRetryCount > 0) ? configRetryCount : 0
|
|
@@ -733,6 +790,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
733
790
|
|
|
734
791
|
errorSkippableRequest = skippableResponse.err
|
|
735
792
|
skippableSuites = skippableResponse.skippableSuites ?? []
|
|
793
|
+
skippableSuitesCoverage = skippableResponse.skippableSuitesCoverage ?? {}
|
|
736
794
|
|
|
737
795
|
if (!errorSkippableRequest) {
|
|
738
796
|
const filteredPickles = isCoordinator
|
|
@@ -753,6 +811,8 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
753
811
|
}
|
|
754
812
|
|
|
755
813
|
skippedSuites = [...filteredPickles.skippedSuites]
|
|
814
|
+
skippedSuitesCoverage = getSkippedSuitesCoverageForRun()
|
|
815
|
+
writeCoverageBackfillToCache(skippedSuitesCoverage, getCoverageRootDir())
|
|
756
816
|
itrCorrelationId = skippableResponse.itrCorrelationId
|
|
757
817
|
}
|
|
758
818
|
}
|
|
@@ -816,13 +876,25 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
816
876
|
}
|
|
817
877
|
|
|
818
878
|
let testCodeCoverageLinesTotal
|
|
879
|
+
let testSessionCoverageFiles
|
|
819
880
|
|
|
820
|
-
if (global.__coverage__) {
|
|
881
|
+
if (global.__coverage__ || untestedCoverage) {
|
|
821
882
|
try {
|
|
883
|
+
let hasBackfilledCoverage = false
|
|
822
884
|
if (untestedCoverage) {
|
|
823
885
|
originalCoverageMap.merge(fromCoverageMapToCoverage(untestedCoverage))
|
|
824
886
|
}
|
|
825
|
-
|
|
887
|
+
hasBackfilledCoverage = applySkippedCoverageToCucumberCoverageMap()
|
|
888
|
+
if (shouldReportCodeCoverageLinesPct(hasBackfilledCoverage)) {
|
|
889
|
+
testCodeCoverageLinesTotal = getTestCoverageLinesPercentage(
|
|
890
|
+
originalCoverageMap,
|
|
891
|
+
undefined,
|
|
892
|
+
getCoverageRootDir()
|
|
893
|
+
)
|
|
894
|
+
}
|
|
895
|
+
if (isTiaCoverageBackfillEnabled()) {
|
|
896
|
+
testSessionCoverageFiles = getCucumberTestSessionCoverageFiles()
|
|
897
|
+
}
|
|
826
898
|
} catch {
|
|
827
899
|
// ignore errors
|
|
828
900
|
}
|
|
@@ -834,6 +906,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
834
906
|
status: success ? 'pass' : 'fail',
|
|
835
907
|
isSuitesSkipped,
|
|
836
908
|
testCodeCoverageLinesTotal,
|
|
909
|
+
testSessionCoverageFiles,
|
|
837
910
|
numSkippedSuites: skippedSuites.length,
|
|
838
911
|
hasUnskippableSuites: isUnskippable,
|
|
839
912
|
hasForcedToRunSuites: isForcedToRun,
|
|
@@ -1008,7 +1081,7 @@ function getWrappedRunTestCase (runTestCaseFunction, isNewerCucumberVersion = fa
|
|
|
1008
1081
|
// last test in suite
|
|
1009
1082
|
const testSuiteStatus = getSuiteStatusFromTestStatuses(pickleResultByFile[testFileAbsolutePath])
|
|
1010
1083
|
if (global.__coverage__) {
|
|
1011
|
-
const coverageFiles =
|
|
1084
|
+
const coverageFiles = getCoveredFilesFromCoverage(global.__coverage__)
|
|
1012
1085
|
|
|
1013
1086
|
testSuiteCodeCoverageCh.publish({
|
|
1014
1087
|
coverageFiles,
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const shimmer = require('../../datadog-shimmer')
|
|
4
4
|
const { addHook } = require('./helpers/instrument')
|
|
5
5
|
const { createCallbackInstrumentor } = require('./helpers/callback-instrumentor')
|
|
6
|
+
const { createPromiseInstrumentor } = require('./helpers/promise-instrumentor')
|
|
6
7
|
|
|
7
8
|
const rrtypes = {
|
|
8
9
|
resolveAny: 'ANY',
|
|
@@ -18,30 +19,55 @@ const rrtypes = {
|
|
|
18
19
|
resolveSoa: 'SOA',
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
shimmer.wrap(dns, 'lookup', lookup(buildArgsContext()))
|
|
28
|
-
shimmer.wrap(dns, 'lookupService', lookupService(buildArgsContext()))
|
|
29
|
-
shimmer.wrap(dns, 'resolve', resolve(buildArgsContext()))
|
|
30
|
-
shimmer.wrap(dns, 'reverse', reverse(buildArgsContext()))
|
|
31
|
-
|
|
32
|
-
patchResolveShorthands(dns, resolve)
|
|
22
|
+
// `dns.promises` and `require('dns/promises')` resolve to the same exports object. Both
|
|
23
|
+
// access paths register a hook, so without a guard the second hook to fire would stack a
|
|
24
|
+
// second wrap layer on top and publish every `apm:dns:*` event twice per call. The WeakSet
|
|
25
|
+
// collapses the two hooks to one wrap regardless of which one runs first.
|
|
26
|
+
const wrappedPromiseApis = new WeakSet()
|
|
33
27
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
shimmer.wrap(dns.Resolver.prototype, 'reverse', reverse(buildArgsContext()))
|
|
28
|
+
addHook({ name: 'dns' }, dns => {
|
|
29
|
+
patchApi(dns, createCallbackInstrumentor, buildCallbackArgsContext)
|
|
37
30
|
|
|
38
|
-
|
|
31
|
+
if (dns.promises) {
|
|
32
|
+
patchPromiseApi(dns.promises)
|
|
39
33
|
}
|
|
40
34
|
|
|
41
35
|
return dns
|
|
42
36
|
})
|
|
43
37
|
|
|
44
|
-
|
|
38
|
+
addHook({ name: 'dns/promises' }, dnsPromises => {
|
|
39
|
+
patchPromiseApi(dnsPromises)
|
|
40
|
+
return dnsPromises
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
function patchPromiseApi (api) {
|
|
44
|
+
if (wrappedPromiseApis.has(api)) return
|
|
45
|
+
wrappedPromiseApis.add(api)
|
|
46
|
+
patchApi(api, createPromiseInstrumentor, buildPromiseArgsContext)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function patchApi (api, instrumentorFactory, buildArgsContext) {
|
|
50
|
+
const lookup = instrumentorFactory('apm:dns:lookup', { captureResult: true })
|
|
51
|
+
const lookupService = instrumentorFactory('apm:dns:lookup_service', { captureResult: true })
|
|
52
|
+
const resolve = instrumentorFactory('apm:dns:resolve', { captureResult: true })
|
|
53
|
+
const reverse = instrumentorFactory('apm:dns:reverse', { captureResult: true })
|
|
54
|
+
|
|
55
|
+
shimmer.wrap(api, 'lookup', lookup(buildArgsContext()))
|
|
56
|
+
shimmer.wrap(api, 'lookupService', lookupService(buildArgsContext()))
|
|
57
|
+
shimmer.wrap(api, 'resolve', resolve(buildArgsContext()))
|
|
58
|
+
shimmer.wrap(api, 'reverse', reverse(buildArgsContext()))
|
|
59
|
+
|
|
60
|
+
patchResolveShorthands(api, resolve, buildArgsContext)
|
|
61
|
+
|
|
62
|
+
if (api.Resolver) {
|
|
63
|
+
shimmer.wrap(api.Resolver.prototype, 'resolve', resolve(buildArgsContext()))
|
|
64
|
+
shimmer.wrap(api.Resolver.prototype, 'reverse', reverse(buildArgsContext()))
|
|
65
|
+
|
|
66
|
+
patchResolveShorthands(api.Resolver.prototype, resolve, buildArgsContext)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function patchResolveShorthands (prototype, resolve, buildArgsContext) {
|
|
45
71
|
for (const method of Object.keys(rrtypes)) {
|
|
46
72
|
if (prototype[method]) {
|
|
47
73
|
shimmer.wrap(prototype, method, resolve(buildArgsContext(rrtypes[method])))
|
|
@@ -49,7 +75,7 @@ function patchResolveShorthands (prototype, resolve) {
|
|
|
49
75
|
}
|
|
50
76
|
}
|
|
51
77
|
|
|
52
|
-
function
|
|
78
|
+
function buildCallbackArgsContext (rrtype) {
|
|
53
79
|
return function (_, args) {
|
|
54
80
|
if (args.length < 2) return
|
|
55
81
|
const captured = [...args]
|
|
@@ -60,3 +86,13 @@ function buildArgsContext (rrtype) {
|
|
|
60
86
|
return { args: captured }
|
|
61
87
|
}
|
|
62
88
|
}
|
|
89
|
+
|
|
90
|
+
function buildPromiseArgsContext (rrtype) {
|
|
91
|
+
return function (_, args) {
|
|
92
|
+
const captured = [...args]
|
|
93
|
+
if (rrtype) {
|
|
94
|
+
captured.push(rrtype)
|
|
95
|
+
}
|
|
96
|
+
return { args: captured }
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -54,65 +54,119 @@ function wrapAddHook (addHook) {
|
|
|
54
54
|
|
|
55
55
|
if (typeof fn !== 'function') return addHook.apply(this, arguments)
|
|
56
56
|
|
|
57
|
-
arguments[arguments.length - 1] = shimmer.wrapFunction(fn, fn => function (
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (cookieParserReadCh.hasSubscribers && hasCookies && !cookiesPublished.has(req)) {
|
|
73
|
-
ctx.res = getRes(reply)
|
|
74
|
-
ctx.abortController = new AbortController()
|
|
75
|
-
ctx.cookies = request.cookies
|
|
76
|
-
|
|
77
|
-
cookieParserReadCh.publish(ctx)
|
|
78
|
-
cookiesPublished.add(req)
|
|
79
|
-
|
|
80
|
-
if (ctx.abortController.signal.aborted) return
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (name === 'onRequest' || name === 'preParsing') {
|
|
84
|
-
parsingContexts.set(req, ctx)
|
|
85
|
-
|
|
86
|
-
return callbackFinishCh.runStores(ctx, () => {
|
|
87
|
-
return doneCallback.apply(this, arguments)
|
|
88
|
-
})
|
|
89
|
-
}
|
|
90
|
-
return doneCallback.apply(this, arguments)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return fn.apply(this, arguments)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const promise = fn.apply(this, arguments)
|
|
97
|
-
|
|
98
|
-
if (promise && typeof promise.catch === 'function') {
|
|
99
|
-
return promise.catch(err => {
|
|
100
|
-
ctx.error = err
|
|
101
|
-
return publishError(ctx)
|
|
102
|
-
})
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return promise
|
|
106
|
-
} catch (e) {
|
|
107
|
-
ctx.error = e
|
|
108
|
-
throw publishError(ctx)
|
|
57
|
+
arguments[arguments.length - 1] = shimmer.wrapFunction(fn, fn => function wrappedHook () {
|
|
58
|
+
// Fast path: every fastify request invokes each addHook'd handler, so the wrap
|
|
59
|
+
// runs in the user's hot path. The only side effects this wrapper carries are
|
|
60
|
+
// the three channels below; when none of them have a subscriber (the default
|
|
61
|
+
// plugin config, and the steady state once appsec / cookie subscribers detach),
|
|
62
|
+
// the wrap has nothing to do, and a `fn.apply(this, arguments)` forward keeps
|
|
63
|
+
// V8's CallApplyArguments fast path intact.
|
|
64
|
+
//
|
|
65
|
+
// The previous shape mutated `arguments[arguments.length - 1]` to swap `done`.
|
|
66
|
+
// That mutation materialises the magical arguments object and disables V8
|
|
67
|
+
// inlining of the enclosing function. The slow path below builds a fresh args
|
|
68
|
+
// array instead so the hot fast path keeps a clean forward.
|
|
69
|
+
if (errorChannel.hasSubscribers || cookieParserReadCh.hasSubscribers || callbackFinishCh.hasSubscribers) {
|
|
70
|
+
return invokeHookWithContext(name, fn, this, arguments)
|
|
109
71
|
}
|
|
72
|
+
return fn.apply(this, arguments)
|
|
110
73
|
})
|
|
111
74
|
|
|
112
75
|
return addHook.apply(this, arguments)
|
|
113
76
|
})
|
|
114
77
|
}
|
|
115
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Slow path of {@link wrapAddHook}; entered only when at least one wrap-fed
|
|
81
|
+
* channel has a subscriber. Allocates the per-request context, rewraps `done`,
|
|
82
|
+
* and forwards to the user-supplied hook.
|
|
83
|
+
*
|
|
84
|
+
* @param {string} name Lifecycle phase the hook was registered against.
|
|
85
|
+
* @param {Function} fn User-supplied hook.
|
|
86
|
+
* @param {unknown} thisArg `this` Fastify passes to the hook.
|
|
87
|
+
* @param {ArrayLike<unknown>} args Fastify's positional args; the dispatcher always
|
|
88
|
+
* places `done` as the trailing positional (see fastify/lib/hooks.js hookIterator,
|
|
89
|
+
* onSendHookRunner, preParsingHookRunner, onRequestAbortHookRunner).
|
|
90
|
+
*/
|
|
91
|
+
function invokeHookWithContext (name, fn, thisArg, args) {
|
|
92
|
+
const request = args[0]
|
|
93
|
+
const reply = args[1]
|
|
94
|
+
const req = getReq(request)
|
|
95
|
+
const ctx = { req }
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
const lastArg = args[args.length - 1]
|
|
99
|
+
|
|
100
|
+
if (typeof lastArg === 'function') {
|
|
101
|
+
// Copy the args so we can swap the trailing `done` without touching the
|
|
102
|
+
// caller's magical arguments object. Fastify hook arities are 2 to 4
|
|
103
|
+
// across lifecycle phases, but `done` is always last.
|
|
104
|
+
const callArgs = [...args]
|
|
105
|
+
callArgs[callArgs.length - 1] = wrapHookDone(ctx, request, reply, req, name, lastArg)
|
|
106
|
+
return fn.apply(thisArg, callArgs)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const promise = fn.apply(thisArg, args)
|
|
110
|
+
|
|
111
|
+
if (promise && typeof promise.catch === 'function') {
|
|
112
|
+
return promise.catch(error => {
|
|
113
|
+
ctx.error = error
|
|
114
|
+
return publishError(ctx)
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return promise
|
|
119
|
+
} catch (error) {
|
|
120
|
+
ctx.error = error
|
|
121
|
+
throw publishError(ctx)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Per-request closure invoked when fastify resolves the user hook's `done`.
|
|
127
|
+
* Captures `ctx` plus the dispatcher-level fields needed to publish on the
|
|
128
|
+
* cookie / callback channels. The closure cannot be hoisted: fastify invokes
|
|
129
|
+
* `done` with a single `(err)` arg, so request / reply / req / name / doneCallback
|
|
130
|
+
* must close over rather than ride the call signature.
|
|
131
|
+
*
|
|
132
|
+
* @param {{ req: unknown, [key: string]: unknown }} ctx
|
|
133
|
+
* @param {{ cookies?: Record<string, unknown>, [key: string]: unknown }} request
|
|
134
|
+
* @param {object} reply
|
|
135
|
+
* @param {unknown} req
|
|
136
|
+
* @param {string} name
|
|
137
|
+
* @param {Function} doneCallback
|
|
138
|
+
*/
|
|
139
|
+
function wrapHookDone (ctx, request, reply, req, name, doneCallback) {
|
|
140
|
+
return function wrappedDone (error) {
|
|
141
|
+
ctx.error = error
|
|
142
|
+
publishError(ctx)
|
|
143
|
+
|
|
144
|
+
const hasCookies = request.cookies && Object.keys(request.cookies).length > 0
|
|
145
|
+
|
|
146
|
+
if (cookieParserReadCh.hasSubscribers && hasCookies && !cookiesPublished.has(req)) {
|
|
147
|
+
ctx.res = getRes(reply)
|
|
148
|
+
ctx.abortController = new AbortController()
|
|
149
|
+
ctx.cookies = request.cookies
|
|
150
|
+
|
|
151
|
+
cookieParserReadCh.publish(ctx)
|
|
152
|
+
cookiesPublished.add(req)
|
|
153
|
+
|
|
154
|
+
if (ctx.abortController.signal.aborted) return
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (name === 'onRequest' || name === 'preParsing') {
|
|
158
|
+
parsingContexts.set(req, ctx)
|
|
159
|
+
|
|
160
|
+
if (callbackFinishCh.hasSubscribers) {
|
|
161
|
+
const self = this
|
|
162
|
+
const allArgs = arguments
|
|
163
|
+
return callbackFinishCh.runStores(ctx, () => doneCallback.apply(self, allArgs))
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return doneCallback.apply(this, arguments)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
116
170
|
function onRequest (request, reply, done) {
|
|
117
171
|
if (typeof done !== 'function') return
|
|
118
172
|
|
|
@@ -157,45 +211,51 @@ function preValidation (request, reply, done) {
|
|
|
157
211
|
const ctx = parsingContexts.get(req)
|
|
158
212
|
ctx.res = res
|
|
159
213
|
|
|
160
|
-
|
|
161
|
-
let abortController
|
|
214
|
+
if (!ctx) return processInContext(request, ctx, done, req)
|
|
162
215
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
ctx.abortController = abortController
|
|
166
|
-
ctx.query = request.query
|
|
167
|
-
queryParamsReadCh.publish(ctx)
|
|
168
|
-
|
|
169
|
-
if (abortController.signal.aborted) return
|
|
170
|
-
}
|
|
216
|
+
preValidationCh.runStores(ctx, processInContext, undefined, request, ctx, done, req)
|
|
217
|
+
}
|
|
171
218
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
219
|
+
/**
|
|
220
|
+
* @param {{ query?: object, body?: object, params?: object, [key: string]: unknown }} request
|
|
221
|
+
* @param {{ res?: object, abortController?: AbortController, [key: string]: unknown }} ctx
|
|
222
|
+
* @param {Function} done
|
|
223
|
+
* @param {unknown} req
|
|
224
|
+
*/
|
|
225
|
+
function processInContext (request, ctx, done, req) {
|
|
226
|
+
let abortController
|
|
227
|
+
|
|
228
|
+
if (queryParamsReadCh.hasSubscribers && request.query) {
|
|
229
|
+
abortController ??= new AbortController()
|
|
230
|
+
ctx.abortController = abortController
|
|
231
|
+
ctx.query = request.query
|
|
232
|
+
queryParamsReadCh.publish(ctx)
|
|
233
|
+
|
|
234
|
+
if (abortController.signal.aborted) return
|
|
235
|
+
}
|
|
178
236
|
|
|
179
|
-
|
|
237
|
+
// Analyze body before schema validation
|
|
238
|
+
if (bodyParserReadCh.hasSubscribers && request.body && !bodyPublished.has(req)) {
|
|
239
|
+
abortController ??= new AbortController()
|
|
240
|
+
ctx.abortController = abortController
|
|
241
|
+
ctx.body = request.body
|
|
242
|
+
bodyParserReadCh.publish(ctx)
|
|
180
243
|
|
|
181
|
-
|
|
182
|
-
}
|
|
244
|
+
bodyPublished.add(req)
|
|
183
245
|
|
|
184
|
-
if (
|
|
185
|
-
|
|
186
|
-
ctx.abortController = abortController
|
|
187
|
-
ctx.params = request.params
|
|
188
|
-
pathParamsReadCh.publish(ctx)
|
|
246
|
+
if (abortController.signal.aborted) return
|
|
247
|
+
}
|
|
189
248
|
|
|
190
|
-
|
|
191
|
-
|
|
249
|
+
if (pathParamsReadCh.hasSubscribers && request.params) {
|
|
250
|
+
abortController ??= new AbortController()
|
|
251
|
+
ctx.abortController = abortController
|
|
252
|
+
ctx.params = request.params
|
|
253
|
+
pathParamsReadCh.publish(ctx)
|
|
192
254
|
|
|
193
|
-
|
|
255
|
+
if (abortController.signal.aborted) return
|
|
194
256
|
}
|
|
195
257
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
preValidationCh.runStores(ctx, processInContext)
|
|
258
|
+
done()
|
|
199
259
|
}
|
|
200
260
|
|
|
201
261
|
function preParsing (request, reply, payload, done) {
|