dd-trace 6.12.0 → 6.14.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 +3 -1
- package/ci/init.js +8 -3
- package/ci/test-optimization-validation/ci-package-scripts.js +2 -2
- package/ci/test-optimization-validation/ci-remediation.js +6 -6
- package/ci/test-optimization-validation/command-blocker.js +7 -5
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +1 -1
- package/ci/test-optimization-validation/framework-adapters/cypress.js +9 -11
- package/ci/test-optimization-validation/framework-adapters/vitest.js +3 -3
- package/ci/test-optimization-validation/package-check.js +1 -1
- package/ci/test-optimization-validation/report-writer.js +7 -5
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +5 -4
- package/ci/vitest-no-worker-init-runner-setup.mjs +8 -0
- package/ci/vitest-no-worker-init-setup.mjs +13 -13
- package/ci/vitest-no-worker-init-v5-setup.mjs +4 -0
- package/index.d.ts +127 -26
- package/package.json +22 -19
- package/packages/datadog-esbuild/index.js +3 -1
- package/packages/datadog-instrumentations/src/bunyan.js +4 -2
- package/packages/datadog-instrumentations/src/cypress-config.js +19 -17
- package/packages/datadog-instrumentations/src/fs.js +24 -20
- package/packages/datadog-instrumentations/src/google-cloud-vertexai.js +2 -2
- package/packages/datadog-instrumentations/src/graphql.js +16 -16
- package/packages/datadog-instrumentations/src/helpers/bunyan.js +12 -3
- package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +504 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +266 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +1 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +95 -30
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +0 -25
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql-jit.js +83 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql.js +85 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/mercurius.js +30 -12
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +13 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +279 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +12 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +562 -27
- package/packages/datadog-instrumentations/src/jest.js +165 -38
- package/packages/datadog-instrumentations/src/knex.js +76 -0
- package/packages/datadog-instrumentations/src/mariadb-bundle.js +1597 -0
- package/packages/datadog-instrumentations/src/mariadb.js +13 -0
- package/packages/datadog-instrumentations/src/mocha/common.js +59 -2
- package/packages/datadog-instrumentations/src/mocha/main.js +25 -15
- package/packages/datadog-instrumentations/src/mocha/utils.js +2 -1
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +98 -0
- package/packages/datadog-instrumentations/src/mocha/worker.js +12 -8
- package/packages/datadog-instrumentations/src/net.js +14 -17
- package/packages/datadog-instrumentations/src/next.js +212 -62
- package/packages/datadog-instrumentations/src/openai.js +42 -40
- package/packages/datadog-instrumentations/src/pg.js +15 -0
- package/packages/datadog-instrumentations/src/pino.js +15 -4
- package/packages/datadog-instrumentations/src/playwright.js +137 -27
- package/packages/datadog-instrumentations/src/rum-browser-scripts.js +40 -0
- package/packages/datadog-instrumentations/src/sequelize.js +94 -2
- package/packages/datadog-instrumentations/src/undici.js +53 -4
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +44 -7
- package/packages/datadog-instrumentations/src/vitest-main.js +92 -9
- package/packages/datadog-instrumentations/src/vitest-worker.js +82 -14
- package/packages/datadog-instrumentations/src/webdriverio.js +986 -1
- package/packages/datadog-instrumentations/src/winston.js +6 -3
- package/packages/datadog-plugin-amqp10/src/consumer.js +3 -1
- package/packages/datadog-plugin-amqp10/src/producer.js +3 -1
- package/packages/datadog-plugin-amqp10/src/util.js +2 -1
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +6 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +16 -5
- package/packages/datadog-plugin-cassandra-driver/src/index.js +8 -3
- package/packages/datadog-plugin-cucumber/src/index.js +0 -2
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +262 -48
- package/packages/datadog-plugin-cypress/src/support.js +1 -0
- package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +4 -1
- package/packages/datadog-plugin-graphql/src/execute.js +998 -196
- package/packages/datadog-plugin-graphql/src/index.js +27 -7
- package/packages/datadog-plugin-graphql/src/jit.js +136 -0
- package/packages/datadog-plugin-graphql/src/request.js +18 -27
- package/packages/datadog-plugin-graphql/src/resolve-error.js +108 -0
- package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -2
- package/packages/datadog-plugin-graphql/src/tools/transforms.js +45 -3
- package/packages/datadog-plugin-graphql/src/utils.js +208 -120
- package/packages/datadog-plugin-graphql/src/validate.js +10 -23
- package/packages/datadog-plugin-http/src/client.js +2 -15
- package/packages/datadog-plugin-http2/src/client.js +2 -15
- package/packages/datadog-plugin-jest/src/index.js +0 -6
- package/packages/datadog-plugin-langchain/src/tracing.js +7 -0
- package/packages/datadog-plugin-mocha/src/index.js +403 -75
- package/packages/datadog-plugin-mongodb-core/src/query.js +6 -0
- package/packages/datadog-plugin-mysql/src/index.js +41 -15
- package/packages/datadog-plugin-net/src/tcp.js +3 -1
- package/packages/datadog-plugin-next/src/index.js +63 -29
- package/packages/datadog-plugin-openai-agents/src/integration.js +15 -11
- package/packages/datadog-plugin-playwright/src/index.js +176 -28
- package/packages/datadog-plugin-undici/src/index.js +29 -56
- package/packages/datadog-plugin-vitest/src/index.js +6 -12
- package/packages/dd-trace/src/aiguard/evaluation.js +96 -21
- package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +2 -3
- package/packages/dd-trace/src/aiguard/messages/anthropic.js +29 -10
- package/packages/dd-trace/src/aiguard/messages/openai.js +8 -1
- package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +20 -6
- package/packages/dd-trace/src/aiguard/noop.js +9 -1
- package/packages/dd-trace/src/aiguard/redaction.js +183 -0
- package/packages/dd-trace/src/aiguard/sdk.js +7 -2
- package/packages/dd-trace/src/aiguard/tags.js +2 -0
- package/packages/dd-trace/src/appsec/api_security/index.js +23 -6
- package/packages/dd-trace/src/appsec/api_security/sampler.js +99 -40
- package/packages/dd-trace/src/appsec/graphql.js +6 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +3 -3
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +2 -1
- package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +8 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +11 -36
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +10 -9
- package/packages/dd-trace/src/appsec/lambda.js +44 -26
- package/packages/dd-trace/src/appsec/rule_manager.js +2 -0
- package/packages/dd-trace/src/ci-visibility/encode/json-encoder.js +32 -2
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +8 -8
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +6 -4
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +20 -4
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +7 -150
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +7 -6
- package/packages/dd-trace/src/ci-visibility/exporters/agents.js +54 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/writer.js +1 -2
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +397 -234
- package/packages/dd-trace/src/ci-visibility/exporters/limits.js +9 -0
- package/packages/dd-trace/src/ci-visibility/exporters/request.js +323 -31
- package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +42 -0
- package/packages/dd-trace/src/ci-visibility/final-flush.js +21 -0
- package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +57 -18
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +0 -3
- package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +164 -71
- package/packages/dd-trace/src/ci-visibility/requests/video-request.js +176 -0
- package/packages/dd-trace/src/ci-visibility/telemetry.js +10 -7
- package/packages/dd-trace/src/ci-visibility/test-video.js +61 -0
- package/packages/dd-trace/src/config/generated-config-types.d.ts +10 -0
- package/packages/dd-trace/src/config/index.js +75 -14
- package/packages/dd-trace/src/config/parsers.js +11 -1
- package/packages/dd-trace/src/config/stable.js +3 -3
- package/packages/dd-trace/src/config/supported-configurations.json +47 -2
- package/packages/dd-trace/src/crashtracking/crashtracker.js +82 -18
- package/packages/dd-trace/src/debugger/config.js +12 -1
- package/packages/dd-trace/src/debugger/constants.js +1 -0
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +2 -1
- package/packages/dd-trace/src/debugger/devtools_client/request-options.js +33 -0
- package/packages/dd-trace/src/debugger/devtools_client/send.js +7 -39
- package/packages/dd-trace/src/debugger/devtools_client/status.js +11 -6
- package/packages/dd-trace/src/debugger/devtools_client/tags.js +41 -0
- package/packages/dd-trace/src/debugger/index.js +23 -3
- package/packages/dd-trace/src/dogstatsd.js +532 -71
- package/packages/dd-trace/src/encode/0.4-cross-payload.js +170 -0
- package/packages/dd-trace/src/encode/0.4.js +5 -5
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +9 -8
- package/packages/dd-trace/src/evp_proxy/direct.js +27 -23
- package/packages/dd-trace/src/exporters/agent/index.js +24 -3
- package/packages/dd-trace/src/exporters/agent/writer.js +28 -11
- package/packages/dd-trace/src/exporters/agentless/index.js +7 -9
- package/packages/dd-trace/src/exporters/agentless/writer.js +100 -118
- package/packages/dd-trace/src/exporters/common/agents.js +28 -6
- package/packages/dd-trace/src/exporters/common/buffering-exporter.js +2 -2
- package/packages/dd-trace/src/exporters/common/final-flush-request-tracker.js +191 -0
- package/packages/dd-trace/src/exporters/common/request.js +31 -11
- package/packages/dd-trace/src/exporters/common/url.js +40 -1
- package/packages/dd-trace/src/exporters/common/writer.js +31 -7
- package/packages/dd-trace/src/exporters/span-stats/index.js +23 -4
- package/packages/dd-trace/src/external-logger/src/index.js +4 -3
- package/packages/dd-trace/src/flush.js +105 -0
- package/packages/dd-trace/src/id.js +14 -0
- package/packages/dd-trace/src/index.js +5 -2
- package/packages/dd-trace/src/llmobs/experiments/client.js +4 -0
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +52 -2
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +420 -105
- package/packages/dd-trace/src/llmobs/experiments/index.js +54 -42
- package/packages/dd-trace/src/llmobs/experiments/noop.js +39 -8
- package/packages/dd-trace/src/llmobs/experiments/result.js +1 -0
- package/packages/dd-trace/src/llmobs/experiments/util.js +21 -0
- package/packages/dd-trace/src/llmobs/index.js +111 -48
- package/packages/dd-trace/src/llmobs/noop.js +2 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +22 -71
- package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +23 -13
- package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +8 -4
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +6 -3
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +7 -0
- package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +13 -6
- package/packages/dd-trace/src/llmobs/plugins/openai-agents/utils.js +5 -7
- package/packages/dd-trace/src/llmobs/util.js +0 -33
- package/packages/dd-trace/src/llmobs/writers/base.js +106 -53
- package/packages/dd-trace/src/log/index.js +7 -1
- package/packages/dd-trace/src/log-submission/log-submission-plugin.js +249 -0
- package/packages/dd-trace/src/noop/span.js +5 -0
- package/packages/dd-trace/src/openfeature/writers/base.js +14 -12
- package/packages/dd-trace/src/openfeature/writers/exposures.js +8 -1
- package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
- package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +45 -3
- package/packages/dd-trace/src/opentelemetry/logs/index.js +9 -25
- package/packages/dd-trace/src/opentelemetry/logs/logger_provider.js +7 -4
- package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +14 -4
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +18 -23
- package/packages/dd-trace/src/opentelemetry/metrics/meter_provider.js +8 -0
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +18 -6
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +14 -2
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +25 -5
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +61 -25
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +19 -4
- package/packages/dd-trace/src/opentelemetry/resource-attributes.js +55 -0
- package/packages/dd-trace/src/opentelemetry/trace/index.js +6 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +10 -0
- package/packages/dd-trace/src/opentelemetry/tracer.js +26 -2
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +494 -351
- package/packages/dd-trace/src/opentracing/span.js +28 -0
- package/packages/dd-trace/src/otel-thread-ctx.js +23 -5
- package/packages/dd-trace/src/payload-tagging/index.js +2 -1
- package/packages/dd-trace/src/plugin_manager.js +2 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +1 -6
- package/packages/dd-trace/src/plugins/tracing.js +12 -10
- package/packages/dd-trace/src/plugins/util/ci.js +3 -1
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +16 -15
- package/packages/dd-trace/src/plugins/util/status-validator.js +98 -0
- package/packages/dd-trace/src/plugins/util/test.js +157 -41
- package/packages/dd-trace/src/plugins/util/url.js +2 -2
- package/packages/dd-trace/src/plugins/util/web.js +6 -74
- package/packages/dd-trace/src/profiling/config.js +1 -0
- package/packages/dd-trace/src/profiling/oom.js +11 -5
- package/packages/dd-trace/src/profiling/profiler.js +30 -13
- package/packages/dd-trace/src/profiling/profilers/events.js +3 -3
- package/packages/dd-trace/src/profiling/profilers/space.js +38 -11
- package/packages/dd-trace/src/profiling/profilers/wall.js +14 -14
- package/packages/dd-trace/src/profiling/webspan-utils.js +7 -4
- package/packages/dd-trace/src/proxy.js +108 -10
- package/packages/dd-trace/src/remote_config/index.js +319 -101
- package/packages/dd-trace/src/remote_config/scheduler.js +37 -12
- package/packages/dd-trace/src/runtime_metrics/client.js +37 -8
- package/packages/dd-trace/src/runtime_metrics/index.js +5 -0
- package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +10 -1
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +22 -7
- package/packages/dd-trace/src/sampling_rule.js +36 -9
- package/packages/dd-trace/src/serverless/telemetry-delivery-tracker.js +51 -0
- package/packages/dd-trace/src/serverless/vercel.js +155 -0
- package/packages/dd-trace/src/serverless.js +45 -21
- package/packages/dd-trace/src/service-naming/schemas/util.js +1 -1
- package/packages/dd-trace/src/span_stats.js +64 -31
- package/packages/dd-trace/src/startup-log.js +3 -2
- package/packages/dd-trace/src/telemetry/agentless-url.js +28 -0
- package/packages/dd-trace/src/telemetry/send-data.js +18 -16
- package/packages/dd-trace/src/telemetry/session-propagation.js +3 -2
- package/packages/dd-trace/src/tracer.js +26 -5
- package/packages/dd-trace/src/tracer_metadata.js +11 -3
- package/packages/dd-trace/src/web-tags-cache.js +67 -13
- package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
- 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/datadog-instrumentations/src/playwright-browser-scripts.js +0 -27
- package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +0 -53
- package/packages/dd-trace/src/encode/agentless-json.js +0 -209
|
@@ -5,8 +5,10 @@ const { DD_MAJOR } = require('../../../version')
|
|
|
5
5
|
const CompositePlugin = require('../../dd-trace/src/plugins/composite')
|
|
6
6
|
const log = require('../../dd-trace/src/log')
|
|
7
7
|
const GraphQLExecutePlugin = require('./execute')
|
|
8
|
+
const GraphQLJitExecutePlugin = require('./jit')
|
|
8
9
|
const GraphQLParsePlugin = require('./parse')
|
|
9
10
|
const GraphQLRequestPlugin = require('./request')
|
|
11
|
+
const { GraphQLResolveErrorPlugin, GraphQLToolsResolveErrorPlugin } = require('./resolve-error')
|
|
10
12
|
const GraphQLValidatePlugin = require('./validate')
|
|
11
13
|
|
|
12
14
|
class GraphQLPlugin extends CompositePlugin {
|
|
@@ -14,16 +16,16 @@ class GraphQLPlugin extends CompositePlugin {
|
|
|
14
16
|
static get plugins () {
|
|
15
17
|
return {
|
|
16
18
|
execute: GraphQLExecutePlugin,
|
|
19
|
+
jit: GraphQLJitExecutePlugin,
|
|
17
20
|
parse: GraphQLParsePlugin,
|
|
18
21
|
// Top-level request span for drivers (mercurius) that funnel through a
|
|
19
22
|
// single entry point and parse/execute internally. graphql-js, apollo,
|
|
20
23
|
// and yoga produce no such channel, so the plugin simply never fires for
|
|
21
24
|
// them.
|
|
22
25
|
request: GraphQLRequestPlugin,
|
|
26
|
+
resolveError: GraphQLResolveErrorPlugin,
|
|
27
|
+
toolsResolveError: GraphQLToolsResolveErrorPlugin,
|
|
23
28
|
validate: GraphQLValidatePlugin,
|
|
24
|
-
// resolve plugin is absorbed into execute: per-field data is recorded
|
|
25
|
-
// synchronously in wrapResolve, and all graphql.resolve spans are
|
|
26
|
-
// materialized at execute end.
|
|
27
29
|
}
|
|
28
30
|
}
|
|
29
31
|
|
|
@@ -93,13 +95,31 @@ const noopHooks = { execute: noop, parse: noop, validate: noop, resolve: undefin
|
|
|
93
95
|
function getHooks ({ hooks }) {
|
|
94
96
|
if (!hooks) return noopHooks
|
|
95
97
|
return {
|
|
96
|
-
execute: hooks.execute ?? noop,
|
|
97
|
-
parse: hooks.parse ?? noop,
|
|
98
|
-
validate: hooks.validate ?? noop,
|
|
98
|
+
execute: guardHook('execute', hooks.execute) ?? noop,
|
|
99
|
+
parse: guardHook('parse', hooks.parse) ?? noop,
|
|
100
|
+
validate: guardHook('validate', hooks.validate) ?? noop,
|
|
99
101
|
// No noop fallback: `resolve` runs per-field (hot path); the plugin
|
|
100
102
|
// gates with `if (this.config.hooks.resolve)` so the absent-hook case
|
|
101
103
|
// skips both the call and the payload-object allocation.
|
|
102
|
-
resolve: hooks.resolve,
|
|
104
|
+
resolve: guardHook('resolve', hooks.resolve),
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @param {'execute' | 'parse' | 'resolve' | 'validate'} name
|
|
110
|
+
* @param {((...args: unknown[]) => unknown) | undefined} hook
|
|
111
|
+
* @returns {((...args: unknown[]) => unknown) | undefined}
|
|
112
|
+
*/
|
|
113
|
+
function guardHook (name, hook) {
|
|
114
|
+
if (typeof hook !== 'function') return
|
|
115
|
+
|
|
116
|
+
const errorMessage = `Error in the graphql ${name} hook`
|
|
117
|
+
return function () {
|
|
118
|
+
try {
|
|
119
|
+
return hook.apply(this, arguments)
|
|
120
|
+
} catch (error) {
|
|
121
|
+
log.error(errorMessage, error)
|
|
122
|
+
}
|
|
103
123
|
}
|
|
104
124
|
}
|
|
105
125
|
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { storage } = require('../../datadog-core')
|
|
4
|
+
const createGraphqlJitRuntime = require('../../datadog-instrumentations/src/helpers/graphql-jit-runtime')
|
|
5
|
+
const GraphQLExecutePlugin = require('./execute')
|
|
6
|
+
const { getBaseTypeName } = require('./utils')
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
readJitDefaultInScope,
|
|
10
|
+
recordJitResolverError,
|
|
11
|
+
resolveCompiledJitField,
|
|
12
|
+
resolveJitDefaultInvocation,
|
|
13
|
+
unwrapJitResolve,
|
|
14
|
+
wrapJitResolve,
|
|
15
|
+
} = GraphQLExecutePlugin
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {import('graphql').ExecutionArgs} ExecutionArguments
|
|
19
|
+
* @typedef {import('../../datadog-instrumentations/src/helpers/graphql-jit-runtime').JitPlan} JitPlan
|
|
20
|
+
* @typedef {Record<string, import('graphql').GraphQLFieldResolver<unknown, unknown>>} GraphQLResolverMap
|
|
21
|
+
* @typedef {{
|
|
22
|
+
* arguments: [unknown, unknown, Record<string, unknown> | undefined],
|
|
23
|
+
* currentStore: Record<string, unknown>,
|
|
24
|
+
* ddArgs?: ExecutionArguments,
|
|
25
|
+
* ddDocument: import('graphql').DocumentNode,
|
|
26
|
+
* ddOperationName?: string,
|
|
27
|
+
* ddPlan?: JitPlan,
|
|
28
|
+
* ddResolvers?: GraphQLResolverMap,
|
|
29
|
+
* ddSchema: import('graphql').GraphQLSchema
|
|
30
|
+
* }} JitExecutionContext
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
const graphqlJitCompilePrefix = 'tracing:orchestrion:graphql-jit:compile'
|
|
34
|
+
const legacyStorage = storage('legacy')
|
|
35
|
+
const patchedResolverMaps = new WeakSet()
|
|
36
|
+
|
|
37
|
+
const { configureCompilationContext, runtime: jitRuntime } = createGraphqlJitRuntime({
|
|
38
|
+
createFieldMetadata,
|
|
39
|
+
readDefaultInScope: readJitDefaultInScope,
|
|
40
|
+
recordResolverError: recordJitResolverError,
|
|
41
|
+
resolveDefaultInvocation: resolveJitDefaultInvocation,
|
|
42
|
+
resolveField: resolveCompiledJitField,
|
|
43
|
+
startExecution,
|
|
44
|
+
unwrapResolver: unwrapJitResolve,
|
|
45
|
+
wrapResolver: wrapJitResolve,
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
class GraphQLJitExecutePlugin extends GraphQLExecutePlugin {
|
|
49
|
+
static prefix = 'tracing:orchestrion:graphql-jit:apm:graphql:execute'
|
|
50
|
+
static extraPrefixes = []
|
|
51
|
+
|
|
52
|
+
addTraceSubs () {
|
|
53
|
+
super.addTraceSubs()
|
|
54
|
+
this.addSub(`${graphqlJitCompilePrefix}:end`, configureCompilationContext)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @param {JitExecutionContext} ctx
|
|
59
|
+
* @returns {ExecutionArguments}
|
|
60
|
+
*/
|
|
61
|
+
readExecutionArgs (ctx) {
|
|
62
|
+
const [rootValue, contextValue, variableValues] = ctx.arguments
|
|
63
|
+
return {
|
|
64
|
+
schema: ctx.ddSchema,
|
|
65
|
+
document: ctx.ddDocument,
|
|
66
|
+
rootValue,
|
|
67
|
+
contextValue,
|
|
68
|
+
variableValues,
|
|
69
|
+
operationName: ctx.ddOperationName,
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @param {JitExecutionContext} ctx
|
|
75
|
+
* @param {ExecutionArguments} args
|
|
76
|
+
*/
|
|
77
|
+
wrapExecutionResolvers (ctx, args) {
|
|
78
|
+
const { ddResolvers: resolvers } = ctx
|
|
79
|
+
if (ctx.ddPlan === undefined && resolvers && !patchedResolverMaps.has(resolvers)) {
|
|
80
|
+
patchedResolverMaps.add(resolvers)
|
|
81
|
+
for (const name of Object.keys(resolvers)) {
|
|
82
|
+
resolvers[name] = wrapJitResolve(resolvers[name])
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
ctx.ddArgs = args
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @param {JitExecutionContext} ctx
|
|
90
|
+
* @param {unknown} _contextValue
|
|
91
|
+
* @param {object} rootCtx
|
|
92
|
+
*/
|
|
93
|
+
storeRootContext (ctx, _contextValue, rootCtx) {
|
|
94
|
+
ctx.currentStore.graphqlRootCtx = rootCtx
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @param {Record<string, unknown> | undefined} variableValues
|
|
100
|
+
* @returns {object | undefined}
|
|
101
|
+
*/
|
|
102
|
+
function startExecution (variableValues) {
|
|
103
|
+
const rootCtx = legacyStorage.getStore()?.graphqlRootCtx
|
|
104
|
+
if (!rootCtx) return
|
|
105
|
+
|
|
106
|
+
rootCtx.variableValues = variableValues
|
|
107
|
+
rootCtx.jitRuntime = jitRuntime
|
|
108
|
+
return rootCtx
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @param {string} parentTypeName
|
|
113
|
+
* @param {string} fieldName
|
|
114
|
+
* @param {import('graphql').GraphQLOutputType} returnType
|
|
115
|
+
* @param {string} collapsedPath
|
|
116
|
+
* @returns {{
|
|
117
|
+
* baseTypeName: string,
|
|
118
|
+
* resource: string,
|
|
119
|
+
* tags: Record<string, string>
|
|
120
|
+
* }}
|
|
121
|
+
*/
|
|
122
|
+
function createFieldMetadata (parentTypeName, fieldName, returnType, collapsedPath) {
|
|
123
|
+
const baseTypeName = getBaseTypeName(returnType)
|
|
124
|
+
return {
|
|
125
|
+
baseTypeName,
|
|
126
|
+
resource: `${fieldName}:${returnType}`,
|
|
127
|
+
tags: {
|
|
128
|
+
'graphql.field.coordinates': `${parentTypeName}.${fieldName}`,
|
|
129
|
+
'graphql.field.name': fieldName,
|
|
130
|
+
'graphql.field.path': collapsedPath,
|
|
131
|
+
'graphql.field.type': baseTypeName,
|
|
132
|
+
},
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
module.exports = GraphQLJitExecutePlugin
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
|
|
4
|
-
const {
|
|
4
|
+
const {
|
|
5
|
+
extractErrorIntoSpanEvent,
|
|
6
|
+
getCachedRequestOperation,
|
|
7
|
+
getRequestCache,
|
|
8
|
+
isApolloHealthCheckSource,
|
|
9
|
+
} = require('./utils')
|
|
10
|
+
|
|
11
|
+
/** @typedef {ReturnType<typeof getRequestCache>} RequestCache */
|
|
5
12
|
|
|
6
13
|
/**
|
|
7
14
|
* @typedef {object} GraphQLRequestStore
|
|
8
15
|
* @property {import('../../dd-trace/src/opentracing/span')} [span]
|
|
9
16
|
* @property {import('../../dd-trace/src/opentracing/span')} [graphqlRequestSpan]
|
|
17
|
+
* @property {RequestCache} [graphqlRequestCache]
|
|
10
18
|
* @property {string} [graphqlRequestOperationName]
|
|
11
19
|
* @property {unknown} [graphqlRequestSource]
|
|
12
20
|
*/
|
|
@@ -17,24 +25,25 @@ const { extractErrorIntoSpanEvent, getCachedRequestOperation, isApolloHealthChec
|
|
|
17
25
|
* @property {GraphQLRequestStore} [currentStore]
|
|
18
26
|
* @property {GraphQLRequestStore} [parentStore]
|
|
19
27
|
* @property {boolean} [ddSkipped]
|
|
28
|
+
* @property {boolean | number} [ddCacheLimit]
|
|
20
29
|
* @property {{ errors?: import('graphql').GraphQLError[] }} [result]
|
|
30
|
+
* @property {object} [self]
|
|
21
31
|
*/
|
|
22
32
|
|
|
23
33
|
// Top-level GraphQL request span for drivers that funnel every operation
|
|
24
34
|
// through a single entry point but parse/validate/execute internally (mercurius
|
|
25
35
|
// today). It parents the `graphql.parse`/`graphql.validate`/`graphql.execute`
|
|
26
36
|
// (or JIT) sub-spans and carries the request text + operation name/type, which
|
|
27
|
-
// otherwise have no home
|
|
28
|
-
// never fires.
|
|
37
|
+
// otherwise have no home if GraphQL-JIT instrumentation is unavailable.
|
|
29
38
|
//
|
|
30
39
|
// The entry boundary only hands us the raw `source` (string or pre-parsed AST)
|
|
31
40
|
// and `operationName`; the parsed document — and therefore the precise
|
|
32
41
|
// operation signature — is only known once mercurius parses internally. On the
|
|
33
42
|
// cold path the `validate` sub-plugin refines the resource/operation tags onto
|
|
34
43
|
// this span via `ctx.currentStore.graphqlRequestSpan` once the document is
|
|
35
|
-
// available
|
|
36
|
-
//
|
|
37
|
-
//
|
|
44
|
+
// available. The normal and JIT execute plugins use the same refinement path
|
|
45
|
+
// when present. A bounded cache preserves the metadata when a warm JIT query
|
|
46
|
+
// skips validation and GraphQL-JIT instrumentation is unavailable or disabled.
|
|
38
47
|
class GraphQLRequestPlugin extends TracingPlugin {
|
|
39
48
|
static id = 'graphql'
|
|
40
49
|
static operation = 'request'
|
|
@@ -55,25 +64,13 @@ class GraphQLRequestPlugin extends TracingPlugin {
|
|
|
55
64
|
}
|
|
56
65
|
|
|
57
66
|
const operationName = ctx.arguments?.[3]
|
|
67
|
+
const requestCache = getRequestCache(ctx.self, ctx.ddCacheLimit)
|
|
58
68
|
|
|
59
|
-
// `source` is the request text on the common path, but mercurius also
|
|
60
|
-
// accepts a pre-parsed document AST; only a string is the query text, and
|
|
61
|
-
// `graphql.source` carries only the text form.
|
|
62
69
|
const docSource = typeof source === 'string' ? source : undefined
|
|
63
|
-
|
|
64
|
-
// Warm (JIT-compiled) path: execute never fires, so recover the operation
|
|
65
|
-
// signature/type the cold path cached, keyed by source + operationName —
|
|
66
|
-
// by query text for a string, by document identity for a pre-parsed AST.
|
|
67
|
-
// Empty on the cold path — validate hasn't refined yet — where the request
|
|
68
|
-
// span is refined from the parsed document instead.
|
|
69
|
-
const cached = getCachedRequestOperation(source, operationName)
|
|
70
|
+
const cached = getCachedRequestOperation(source, operationName, this.config.signature, requestCache)
|
|
70
71
|
|
|
71
72
|
const span = this.startSpan(this.operationName({ id: 'request' }), {
|
|
72
73
|
service: this.config.service || this.serviceName(),
|
|
73
|
-
// The cached signature is the precise resource; otherwise provisional and
|
|
74
|
-
// refined by the validate sub-plugin once the document is parsed.
|
|
75
|
-
// `operationName` is the best name at the boundary; falls back to the
|
|
76
|
-
// operation signature once validate sees the document.
|
|
77
74
|
resource: cached?.signature || operationName || undefined,
|
|
78
75
|
kind: this.constructor.kind,
|
|
79
76
|
type: this.constructor.type,
|
|
@@ -84,14 +81,8 @@ class GraphQLRequestPlugin extends TracingPlugin {
|
|
|
84
81
|
},
|
|
85
82
|
}, ctx)
|
|
86
83
|
|
|
87
|
-
// Hand the span, the requested operation name, and the raw source to the
|
|
88
|
-
// validate sub-plugin running inside this store so it can refine the
|
|
89
|
-
// resource + operation tags from the parsed document (validate is the first
|
|
90
|
-
// boundary that has it) and cache them keyed by the source the request
|
|
91
|
-
// boundary saw. The raw source is the cache key — validate sees mercurius's
|
|
92
|
-
// internally parsed document, not the caller's source, and for a pre-parsed
|
|
93
|
-
// AST the two are different objects.
|
|
94
84
|
ctx.currentStore.graphqlRequestSpan = span
|
|
85
|
+
ctx.currentStore.graphqlRequestCache = requestCache
|
|
95
86
|
ctx.currentStore.graphqlRequestOperationName = operationName
|
|
96
87
|
ctx.currentStore.graphqlRequestSource = source
|
|
97
88
|
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { storage } = require('../../datadog-core')
|
|
4
|
+
const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
|
|
5
|
+
|
|
6
|
+
const legacyStorage = storage('legacy')
|
|
7
|
+
const normalizedFalsyErrors = new WeakSet()
|
|
8
|
+
|
|
9
|
+
class GraphQLResolveErrorPlugin extends TracingPlugin {
|
|
10
|
+
static id = 'graphql'
|
|
11
|
+
static prefix = 'tracing:orchestrion:graphql:apm:graphql:resolve:error'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {{ arguments?: unknown[], result?: unknown }} ctx
|
|
15
|
+
*/
|
|
16
|
+
start (ctx) {
|
|
17
|
+
const args = ctx.arguments
|
|
18
|
+
if (args?.length === 1) return
|
|
19
|
+
|
|
20
|
+
const error = args?.[0]
|
|
21
|
+
const errorPath = error?.path
|
|
22
|
+
const path = Array.isArray(errorPath) ? errorPath : args?.[2]
|
|
23
|
+
if (path) {
|
|
24
|
+
recordResolveErrorForPath(normalizedFalsyErrors.delete(error) ? undefined : error, path, args?.[1])
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {{ arguments?: unknown[], result?: unknown }} ctx
|
|
30
|
+
*/
|
|
31
|
+
end (ctx) {
|
|
32
|
+
const args = ctx.arguments
|
|
33
|
+
if (args?.length !== 1 || args[0]) return
|
|
34
|
+
|
|
35
|
+
const error = ctx.result
|
|
36
|
+
if (error !== null && typeof error === 'object') normalizedFalsyErrors.add(error)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
class GraphQLToolsResolveErrorPlugin extends TracingPlugin {
|
|
41
|
+
static id = 'graphql'
|
|
42
|
+
static prefix = 'tracing:orchestrion:@graphql-tools/executor:apm:graphql:resolve:error'
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @param {{ arguments?: unknown[] }} ctx
|
|
46
|
+
*/
|
|
47
|
+
start (ctx) {
|
|
48
|
+
const error = ctx.arguments?.[0]
|
|
49
|
+
if (error?.path) {
|
|
50
|
+
recordResolveErrorForPath(error, error.path)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// `start` owns attribution while the normalized error path is available.
|
|
55
|
+
error () {}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @param {unknown} error
|
|
60
|
+
* @param {(string | number)[]} path
|
|
61
|
+
* @param {readonly object[]} [fieldNodes]
|
|
62
|
+
*/
|
|
63
|
+
function recordResolveErrorForPath (error, path, fieldNodes) {
|
|
64
|
+
const fieldNode = fieldNodes?.[0]
|
|
65
|
+
const rootCtx = legacyStorage.getStore()?.graphqlRootCtx
|
|
66
|
+
for (let field = rootCtx?.resolveFields; field; field = field.nextResolveField) {
|
|
67
|
+
if ((!fieldNode || field.fieldNode === fieldNode) && matchesPath(field.pathString, path)) {
|
|
68
|
+
recordResolveError(field, error)
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @param {string} fieldPath
|
|
76
|
+
* @param {(string | number)[]} path
|
|
77
|
+
* @returns {boolean}
|
|
78
|
+
*/
|
|
79
|
+
function matchesPath (fieldPath, path) {
|
|
80
|
+
let pathString = ''
|
|
81
|
+
for (let index = 0; index < path.length; index++) {
|
|
82
|
+
if (index !== 0) pathString += '.'
|
|
83
|
+
pathString += typeof path[index] === 'number' ? '*' : path[index]
|
|
84
|
+
}
|
|
85
|
+
return pathString === fieldPath
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @param {object} field
|
|
90
|
+
* @param {unknown} error
|
|
91
|
+
*/
|
|
92
|
+
function recordResolveError (field, error) {
|
|
93
|
+
if (field.error !== undefined) return
|
|
94
|
+
|
|
95
|
+
const recordedError = error || new Error('GraphQL resolver rejected without an error')
|
|
96
|
+
field.error = recordedError
|
|
97
|
+
field.span.setTag('error', recordedError)
|
|
98
|
+
if (field.resolveHookContext) {
|
|
99
|
+
field.resolveHookContext.error = recordedError
|
|
100
|
+
field.resolveHookContext.result = undefined
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = {
|
|
105
|
+
GraphQLResolveErrorPlugin,
|
|
106
|
+
GraphQLToolsResolveErrorPlugin,
|
|
107
|
+
recordResolveError,
|
|
108
|
+
}
|
|
@@ -6,8 +6,7 @@ const transforms = require('./transforms')
|
|
|
6
6
|
// Apollo Server / Yoga / Mercurius hand back the same parsed `DocumentNode`
|
|
7
7
|
// from their own document caches per execute, so memoizing the signature on
|
|
8
8
|
// the document keeps the visit/print pipeline off the hot path. The inner
|
|
9
|
-
// Map keys on operationName since
|
|
10
|
-
// sub-document for each operation.
|
|
9
|
+
// Map keys on operationName since each operation has a different sub-document.
|
|
11
10
|
const cache = new WeakMap()
|
|
12
11
|
|
|
13
12
|
function defaultEngineReportingSignature (ast, operationName) {
|
|
@@ -8,11 +8,53 @@ const printer = ddGlobal.graphql_printer
|
|
|
8
8
|
const utilities = ddGlobal.graphql_utilities
|
|
9
9
|
|
|
10
10
|
function dropUnusedDefinitions (ast, operationName) {
|
|
11
|
-
const
|
|
12
|
-
if (!
|
|
11
|
+
const operation = utilities.getOperationAST(ast, operationName)
|
|
12
|
+
if (!operation) {
|
|
13
13
|
return ast
|
|
14
14
|
}
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
const fragments = new Map()
|
|
17
|
+
for (const definition of ast.definitions) {
|
|
18
|
+
if (definition.kind === 'FragmentDefinition') {
|
|
19
|
+
fragments.set(definition.name.value, definition)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const dependencies = new Set()
|
|
24
|
+
collectFragmentDependencies(operation.selectionSet, fragments, dependencies)
|
|
25
|
+
|
|
26
|
+
const definitions = []
|
|
27
|
+
for (const definition of ast.definitions) {
|
|
28
|
+
if (definition === operation ||
|
|
29
|
+
(definition.kind === 'FragmentDefinition' && dependencies.has(definition.name.value))) {
|
|
30
|
+
definitions.push(definition)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return { kind: ast.kind, definitions }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {import('graphql').SelectionSetNode} selectionSet
|
|
39
|
+
* @param {Map<string, import('graphql').FragmentDefinitionNode>} fragments
|
|
40
|
+
* @param {Set<string>} dependencies
|
|
41
|
+
*/
|
|
42
|
+
function collectFragmentDependencies (selectionSet, fragments, dependencies) {
|
|
43
|
+
visitor.visit(selectionSet, {
|
|
44
|
+
/**
|
|
45
|
+
* @param {import('graphql').FragmentSpreadNode} node
|
|
46
|
+
*/
|
|
47
|
+
FragmentSpread (node) {
|
|
48
|
+
const name = node.name.value
|
|
49
|
+
if (dependencies.has(name)) return
|
|
50
|
+
|
|
51
|
+
dependencies.add(name)
|
|
52
|
+
const fragment = fragments.get(name)
|
|
53
|
+
if (fragment) {
|
|
54
|
+
collectFragmentDependencies(fragment.selectionSet, fragments, dependencies)
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
})
|
|
16
58
|
}
|
|
17
59
|
|
|
18
60
|
// One walk replaces Apollo's `hideLiterals` + `removeAliases` + `sortAST` +
|