dd-trace 5.110.0 → 5.112.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.
Files changed (164) hide show
  1. package/LICENSE-3rdparty.csv +1 -2
  2. package/README.md +13 -8
  3. package/ci/init.js +21 -2
  4. package/ci/vitest-no-worker-init-setup.mjs +430 -0
  5. package/ext/tags.js +2 -0
  6. package/index.d.ts +34 -1
  7. package/initialize.mjs +5 -6
  8. package/loader-hook.mjs +76 -55
  9. package/package.json +37 -34
  10. package/packages/datadog-instrumentations/src/ai.js +45 -0
  11. package/packages/datadog-instrumentations/src/apollo-server.js +5 -13
  12. package/packages/datadog-instrumentations/src/child_process.js +3 -3
  13. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +587 -0
  14. package/packages/datadog-instrumentations/src/cucumber.js +102 -43
  15. package/packages/datadog-instrumentations/src/cypress-config.js +11 -3
  16. package/packages/datadog-instrumentations/src/fastify.js +27 -8
  17. package/packages/datadog-instrumentations/src/fs.js +8 -6
  18. package/packages/datadog-instrumentations/src/graphql.js +26 -495
  19. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  20. package/packages/datadog-instrumentations/src/helpers/instrument.js +7 -0
  21. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +6 -6
  22. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/claude-agent-sdk.js +17 -0
  23. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql.js +201 -0
  24. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
  25. package/packages/datadog-instrumentations/src/jest.js +713 -63
  26. package/packages/datadog-instrumentations/src/mocha/main.js +24 -3
  27. package/packages/datadog-instrumentations/src/mocha/utils.js +128 -22
  28. package/packages/datadog-instrumentations/src/mocha/worker.js +13 -0
  29. package/packages/datadog-instrumentations/src/mongodb.js +74 -0
  30. package/packages/datadog-instrumentations/src/mongoose.js +13 -2
  31. package/packages/datadog-instrumentations/src/playwright.js +13 -9
  32. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +1297 -0
  33. package/packages/datadog-instrumentations/src/vitest-main.js +1594 -0
  34. package/packages/datadog-instrumentations/src/vitest-util.js +254 -0
  35. package/packages/datadog-instrumentations/src/vitest-worker.js +823 -0
  36. package/packages/datadog-instrumentations/src/vitest.js +11 -1855
  37. package/packages/datadog-plugin-ai/src/index.js +1 -1
  38. package/packages/datadog-plugin-ai/src/tracing.js +66 -3
  39. package/packages/datadog-plugin-ai/src/utils.js +17 -4
  40. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/client.js +2 -2
  41. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js +19 -10
  42. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/handler.js +1 -0
  43. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +47 -11
  44. package/packages/datadog-plugin-child_process/src/index.js +13 -2
  45. package/packages/datadog-plugin-claude-agent-sdk/src/index.js +31 -0
  46. package/packages/datadog-plugin-claude-agent-sdk/src/tracing.js +107 -0
  47. package/packages/datadog-plugin-claude-agent-sdk/src/util.js +15 -0
  48. package/packages/datadog-plugin-cucumber/src/index.js +15 -24
  49. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +360 -14
  50. package/packages/datadog-plugin-cypress/src/index.js +47 -2
  51. package/packages/datadog-plugin-cypress/src/plugin.js +1 -0
  52. package/packages/datadog-plugin-cypress/src/support.js +45 -1
  53. package/packages/datadog-plugin-express/src/code_origin.js +1 -1
  54. package/packages/datadog-plugin-fastify/src/code_origin.js +1 -1
  55. package/packages/datadog-plugin-graphql/src/execute.js +639 -12
  56. package/packages/datadog-plugin-graphql/src/index.js +37 -9
  57. package/packages/datadog-plugin-graphql/src/parse.js +24 -4
  58. package/packages/datadog-plugin-graphql/src/utils.js +9 -2
  59. package/packages/datadog-plugin-graphql/src/validate.js +17 -6
  60. package/packages/datadog-plugin-http/src/index.js +6 -8
  61. package/packages/datadog-plugin-jest/src/index.js +31 -15
  62. package/packages/datadog-plugin-mocha/src/index.js +40 -15
  63. package/packages/datadog-plugin-mongodb-core/src/bulk-write.js +43 -0
  64. package/packages/datadog-plugin-mongodb-core/src/index.js +8 -443
  65. package/packages/datadog-plugin-mongodb-core/src/query.js +452 -0
  66. package/packages/datadog-plugin-openai/src/services.js +2 -2
  67. package/packages/datadog-plugin-playwright/src/index.js +4 -3
  68. package/packages/datadog-plugin-vitest/src/index.js +120 -72
  69. package/packages/datadog-shimmer/src/shimmer.js +37 -16
  70. package/packages/dd-trace/src/aiguard/index.js +9 -14
  71. package/packages/dd-trace/src/aiguard/integrations/index.js +34 -0
  72. package/packages/dd-trace/src/aiguard/integrations/openai.js +47 -33
  73. package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +42 -28
  74. package/packages/dd-trace/src/aiguard/sdk.js +2 -2
  75. package/packages/dd-trace/src/appsec/api_security/sampler.js +3 -3
  76. package/packages/dd-trace/src/appsec/channels.js +3 -1
  77. package/packages/dd-trace/src/appsec/downstream_requests.js +4 -4
  78. package/packages/dd-trace/src/appsec/graphql.js +14 -11
  79. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +23 -23
  80. package/packages/dd-trace/src/appsec/iast/security-controls/index.js +2 -2
  81. package/packages/dd-trace/src/appsec/iast/telemetry/index.js +2 -1
  82. package/packages/dd-trace/src/appsec/index.js +10 -1
  83. package/packages/dd-trace/src/appsec/lambda.js +135 -0
  84. package/packages/dd-trace/src/appsec/reporter.js +49 -10
  85. package/packages/dd-trace/src/appsec/telemetry/index.js +1 -1
  86. package/packages/dd-trace/src/appsec/waf/index.js +16 -4
  87. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +4 -4
  88. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +26 -1
  89. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +115 -24
  90. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +21 -6
  91. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +5 -2
  92. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
  93. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +1 -1
  94. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +6 -2
  95. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +1 -1
  96. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +130 -20
  97. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +2 -2
  98. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +17 -0
  99. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +47 -26
  100. package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +2 -2
  101. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +64 -53
  102. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +3 -3
  103. package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +156 -0
  104. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +23 -5
  105. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +128 -0
  106. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +287 -0
  107. package/packages/dd-trace/src/config/defaults.js +3 -2
  108. package/packages/dd-trace/src/config/generated-config-types.d.ts +71 -57
  109. package/packages/dd-trace/src/config/helper.js +1 -0
  110. package/packages/dd-trace/src/config/index.js +35 -22
  111. package/packages/dd-trace/src/config/major-overrides.js +4 -2
  112. package/packages/dd-trace/src/config/remote_config.js +1 -1
  113. package/packages/dd-trace/src/config/supported-configurations.json +127 -56
  114. package/packages/dd-trace/src/constants.js +7 -0
  115. package/packages/dd-trace/src/crashtracking/crashtracker.js +2 -2
  116. package/packages/dd-trace/src/datastreams/processor.js +11 -3
  117. package/packages/dd-trace/src/exporters/agent/index.js +1 -1
  118. package/packages/dd-trace/src/exporters/agentless/writer.js +4 -4
  119. package/packages/dd-trace/src/llmobs/index.js +1 -1
  120. package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +403 -0
  121. package/packages/dd-trace/src/llmobs/plugins/ai/index.js +8 -395
  122. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +27 -0
  123. package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +363 -0
  124. package/packages/dd-trace/src/llmobs/plugins/base.js +4 -4
  125. package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +270 -0
  126. package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/utils.js +10 -0
  127. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
  128. package/packages/dd-trace/src/llmobs/sdk.js +3 -3
  129. package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
  130. package/packages/dd-trace/src/llmobs/tagger.js +3 -3
  131. package/packages/dd-trace/src/llmobs/writers/base.js +1 -1
  132. package/packages/dd-trace/src/opentelemetry/metrics/index.js +54 -5
  133. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +40 -0
  134. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +169 -0
  135. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +38 -39
  136. package/packages/dd-trace/src/opentelemetry/span.js +5 -0
  137. package/packages/dd-trace/src/opentelemetry/trace/index.js +4 -0
  138. package/packages/dd-trace/src/opentelemetry/tracer_provider.js +1 -1
  139. package/packages/dd-trace/src/opentracing/tracer.js +6 -1
  140. package/packages/dd-trace/src/plugin_manager.js +23 -7
  141. package/packages/dd-trace/src/plugins/ci_plugin.js +159 -10
  142. package/packages/dd-trace/src/plugins/index.js +2 -0
  143. package/packages/dd-trace/src/plugins/util/llm.js +6 -1
  144. package/packages/dd-trace/src/plugins/util/test.js +15 -9
  145. package/packages/dd-trace/src/profiling/exporter_cli.js +2 -2
  146. package/packages/dd-trace/src/profiling/exporters/agent.js +28 -3
  147. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +3 -3
  148. package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
  149. package/packages/dd-trace/src/proxy.js +8 -8
  150. package/packages/dd-trace/src/span_processor.js +5 -6
  151. package/packages/dd-trace/src/span_stats.js +96 -78
  152. package/packages/dd-trace/src/startup-log.js +2 -1
  153. package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
  154. package/packages/dd-trace/src/telemetry/endpoints.js +6 -4
  155. package/packages/dd-trace/src/telemetry/index.js +2 -2
  156. package/packages/dd-trace/src/telemetry/logs/index.js +1 -1
  157. package/packages/dd-trace/src/telemetry/send-data.js +8 -8
  158. package/packages/dd-trace/src/telemetry/session-propagation.js +1 -1
  159. package/packages/dd-trace/src/telemetry/telemetry.js +9 -9
  160. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  161. package/vendor/dist/protobufjs/index.js +1 -1
  162. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  163. package/vendor/dist/shell-quote/index.js +1 -1
  164. package/packages/datadog-plugin-graphql/src/resolve.js +0 -170
@@ -1,12 +1,12 @@
1
1
  'use strict'
2
2
 
3
3
  const pick = require('../../datadog-core/src/utils/src/pick')
4
+ const { DD_MAJOR } = require('../../../version')
4
5
  const CompositePlugin = require('../../dd-trace/src/plugins/composite')
5
6
  const log = require('../../dd-trace/src/log')
6
7
  const GraphQLExecutePlugin = require('./execute')
7
8
  const GraphQLParsePlugin = require('./parse')
8
9
  const GraphQLValidatePlugin = require('./validate')
9
- const GraphQLResolvePlugin = require('./resolve')
10
10
 
11
11
  class GraphQLPlugin extends CompositePlugin {
12
12
  static id = 'graphql'
@@ -15,7 +15,9 @@ class GraphQLPlugin extends CompositePlugin {
15
15
  execute: GraphQLExecutePlugin,
16
16
  parse: GraphQLParsePlugin,
17
17
  validate: GraphQLValidatePlugin,
18
- resolve: GraphQLResolvePlugin,
18
+ // resolve plugin is absorbed into execute: per-field data is recorded
19
+ // synchronously in wrapResolve, and all graphql.resolve spans are
20
+ // materialized at execute end.
19
21
  }
20
22
  }
21
23
 
@@ -28,13 +30,25 @@ class GraphQLPlugin extends CompositePlugin {
28
30
  }
29
31
 
30
32
  // config validator helpers
33
+ //
34
+ // `collapse`, `depth`, `variables`, and `errorExtensions` arrive pre-merged on
35
+ // `config`: plugin_manager seeds the `DD_TRACE_GRAPHQL_*` env values (already
36
+ // parsed to their declared type) as the base and a programmatic
37
+ // `tracer.use('graphql', …)` value overrides them. So these helpers only shape
38
+ // the merged value — coerce, validate, and turn `variables` into a filter — and
39
+ // never read the environment themselves.
31
40
 
32
41
  function validateConfig (config) {
42
+ const collapse = config.collapse === undefined || !!config.collapse
33
43
  return {
34
44
  ...config,
35
45
  depth: getDepth(config),
36
46
  variables: getVariablesFilter(config),
37
- collapse: config.collapse === undefined || !!config.collapse,
47
+ collapse,
48
+ // v5 counted collapsed list indices toward `depth`, so the same query reached a
49
+ // different depth depending on `collapse`. v6 counts selection-set depth only.
50
+ countListIndices: DD_MAJOR < 6 && collapse,
51
+ errorExtensions: getErrorExtensions(config),
38
52
  hooks: getHooks(config),
39
53
  }
40
54
  }
@@ -52,21 +66,35 @@ function getVariablesFilter (config) {
52
66
  if (typeof config.variables === 'function') {
53
67
  return config.variables
54
68
  } else if (Array.isArray(config.variables)) {
55
- return variables => pick(variables, config.variables)
69
+ return config.variables.length > 0 ? variables => pick(variables, config.variables) : null
56
70
  } else if (config.hasOwnProperty('variables')) {
57
71
  log.error('Expected `variables` to be an array or function.')
58
72
  }
59
73
  return null
60
74
  }
61
75
 
76
+ function getErrorExtensions (config) {
77
+ if (Array.isArray(config.errorExtensions)) {
78
+ return config.errorExtensions.length > 0 ? config.errorExtensions : undefined
79
+ } else if (config.hasOwnProperty('errorExtensions')) {
80
+ log.error('Expected `errorExtensions` to be an array.')
81
+ }
82
+ }
83
+
62
84
  const noop = () => {}
85
+ const noopHooks = { execute: noop, parse: noop, validate: noop, resolve: undefined }
63
86
 
64
87
  function getHooks ({ hooks }) {
65
- const execute = hooks?.execute ?? noop
66
- const parse = hooks?.parse ?? noop
67
- const validate = hooks?.validate ?? noop
68
-
69
- return { execute, parse, validate }
88
+ if (!hooks) return noopHooks
89
+ return {
90
+ execute: hooks.execute ?? noop,
91
+ parse: hooks.parse ?? noop,
92
+ validate: hooks.validate ?? noop,
93
+ // No noop fallback: `resolve` runs per-field (hot path); the plugin
94
+ // gates with `if (this.config.hooks.resolve)` so the absent-hook case
95
+ // skips both the call and the payload-object allocation.
96
+ resolve: hooks.resolve,
97
+ }
70
98
  }
71
99
 
72
100
  module.exports = GraphQLPlugin
@@ -2,34 +2,54 @@
2
2
 
3
3
  const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
4
4
 
5
+ const documentSources = new WeakMap()
6
+
5
7
  class GraphQLParsePlugin extends TracingPlugin {
6
8
  static id = 'graphql'
7
9
  static operation = 'parser'
10
+ static prefix = 'tracing:orchestrion:graphql:apm:graphql:parser'
8
11
 
9
12
  bindStart (ctx) {
13
+ const source = ctx.arguments?.[0]
14
+
10
15
  this.startSpan('graphql.parse', {
11
16
  service: this.config.service,
12
17
  type: 'graphql',
13
18
  meta: {},
14
19
  }, ctx)
15
20
 
21
+ ctx.ddSource = source
22
+
16
23
  return ctx.currentStore
17
24
  }
18
25
 
19
- finish (ctx) {
20
- const { source, document, docSource } = ctx
26
+ end (ctx) {
27
+ const source = ctx.ddSource
28
+ const document = ctx.result
21
29
  const span = ctx?.currentStore?.span || this.activeSpan
22
30
 
23
- if (this.config.source && document) {
31
+ let docSource
32
+ if (document) {
33
+ if (source) {
34
+ docSource = source.body || source
35
+ documentSources.set(document, docSource)
36
+ } else {
37
+ docSource = documentSources.get(document)
38
+ }
39
+ }
40
+
41
+ if (this.config.source && docSource) {
24
42
  span.setTag('graphql.source', docSource)
25
43
  }
26
44
 
27
45
  this.config.hooks.parse(span, source, document)
28
46
 
29
- super.finish(ctx)
47
+ span.finish()
30
48
 
31
49
  return ctx.parentStore
32
50
  }
33
51
  }
34
52
 
53
+ GraphQLParsePlugin.documentSources = documentSources
54
+
35
55
  module.exports = GraphQLParsePlugin
@@ -1,5 +1,12 @@
1
1
  'use strict'
2
2
 
3
+ /**
4
+ * @param {{ errorExtensions?: string[] }} config Resolved plugin config; `errorExtensions` lists the
5
+ * GraphQL error `extensions` keys to copy onto the span event.
6
+ * @param {import('../../dd-trace/src/opentracing/span')} span
7
+ * @param {{ name?: string, message?: string, stack?: string, locations?: Array<{ line: number, column: number }>,
8
+ * path?: Array<string|number>, extensions?: Record<string, unknown> }} exc
9
+ */
3
10
  function extractErrorIntoSpanEvent (config, span, exc) {
4
11
  const attributes = {}
5
12
 
@@ -29,8 +36,8 @@ function extractErrorIntoSpanEvent (config, span, exc) {
29
36
  attributes.message = exc.message
30
37
  }
31
38
 
32
- if (config.DD_TRACE_GRAPHQL_ERROR_EXTENSIONS) {
33
- for (const ext of config.DD_TRACE_GRAPHQL_ERROR_EXTENSIONS) {
39
+ if (config.errorExtensions) {
40
+ for (const ext of config.errorExtensions) {
34
41
  if (exc.extensions?.[ext]) {
35
42
  const value = exc.extensions[ext]
36
43
 
@@ -1,14 +1,18 @@
1
1
  'use strict'
2
2
 
3
3
  const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
4
+ const GraphQLParsePlugin = require('./parse')
4
5
  const { extractErrorIntoSpanEvent } = require('./utils')
5
6
 
6
7
  class GraphQLValidatePlugin extends TracingPlugin {
7
8
  static id = 'graphql'
8
9
  static operation = 'validate'
10
+ static prefix = 'tracing:orchestrion:graphql:apm:graphql:validate'
9
11
 
10
12
  bindStart (ctx) {
11
- const { docSource, document } = ctx
13
+ // validate(schema, documentAST, rules, options, typeInfo)
14
+ const document = ctx.arguments?.[1]
15
+ const docSource = document ? GraphQLParsePlugin.documentSources.get(document) : undefined
12
16
  const source = this.config.source && document && docSource
13
17
 
14
18
  this.startSpan('graphql.validate', {
@@ -19,19 +23,26 @@ class GraphQLValidatePlugin extends TracingPlugin {
19
23
  },
20
24
  }, ctx)
21
25
 
26
+ ctx.ddDocument = document
27
+
22
28
  return ctx.currentStore
23
29
  }
24
30
 
25
- finish (ctx) {
26
- const { document, errors } = ctx
31
+ end (ctx) {
32
+ const document = ctx.ddDocument
33
+ const errors = ctx.result
27
34
  const span = ctx?.currentStore?.span || this.activeSpan
35
+
28
36
  this.config.hooks.validate(span, document, errors)
29
- if (errors) {
37
+
38
+ if (errors?.length) {
39
+ span.setTag('error', errors[0])
30
40
  for (const err of errors) {
31
- extractErrorIntoSpanEvent(this._tracerConfig, span, err)
41
+ extractErrorIntoSpanEvent(this.config, span, err)
32
42
  }
33
43
  }
34
- super.finish(ctx)
44
+
45
+ span.finish()
35
46
 
36
47
  return ctx.parentStore
37
48
  }
@@ -1,6 +1,5 @@
1
1
  'use strict'
2
2
 
3
- const PushSubscriptionPlugin = require('../../datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription')
4
3
  const CompositePlugin = require('../../dd-trace/src/plugins/composite')
5
4
  const { enableGCPPubSubPushSubscription } = require('../../dd-trace/src/serverless')
6
5
  const log = require('../../dd-trace/src/log')
@@ -17,14 +16,13 @@ class HttpPlugin extends CompositePlugin {
17
16
  static get plugins () {
18
17
  const plugins = {}
19
18
 
20
- // Load push subscription plugin first (if enabled) for GCP Cloud Run
19
+ // Load the push subscription plugin first (if enabled) for GCP Cloud Run.
20
+ // The require stays inside the gate so the pubsub plugin graph is not pulled
21
+ // into every process that instruments http — only GCP Cloud Run reaches it.
21
22
  if (enableGCPPubSubPushSubscription()) {
22
- try {
23
- plugins['pubsub-push-subscription'] = PushSubscriptionPlugin
24
- log.debug('Loaded GCP Pub/Sub Push Subscription plugin for HTTP requests')
25
- } catch (e) {
26
- log.debug('Failed to load GCP Pub/Sub Push Subscription plugin:', e)
27
- }
23
+ plugins['pubsub-push-subscription'] =
24
+ require('../../datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription')
25
+ log.debug('Loaded GCP Pub/Sub Push Subscription plugin for HTTP requests')
28
26
  }
29
27
 
30
28
  plugins.server = HttpServerPlugin
@@ -61,15 +61,6 @@ const isJestWorker = !!getEnvironmentVariable('JEST_WORKER_ID')
61
61
  // https://github.com/facebook/jest/blob/d6ad15b0f88a05816c2fe034dd6900d28315d570/packages/jest-worker/src/types.ts#L38
62
62
  const CHILD_MESSAGE_END = 2
63
63
 
64
- function withTimeout (promise, timeoutMs) {
65
- return new Promise(resolve => {
66
- realSetTimeout(resolve, timeoutMs)
67
-
68
- // Also resolve if the original promise resolves
69
- promise.then(resolve)
70
- })
71
- }
72
-
73
64
  class JestPlugin extends CiPlugin {
74
65
  static id = 'jest'
75
66
 
@@ -177,7 +168,7 @@ class JestPlugin extends CiPlugin {
177
168
 
178
169
  this.telemetry.count(TELEMETRY_TEST_SESSION, {
179
170
  provider: this.ciProviderName,
180
- autoInjected: !!this._tracerConfig.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
171
+ autoInjected: !!this._tracerConfig.testOptimization.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
181
172
  })
182
173
 
183
174
  appClosingTelemetry()
@@ -451,6 +442,7 @@ class JestPlugin extends CiPlugin {
451
442
  isAtrRetry,
452
443
  finalStatus,
453
444
  earlyFlakeAbortReason,
445
+ promises,
454
446
  }) => {
455
447
  span.setTag(TEST_STATUS, status)
456
448
  if (finalStatus) {
@@ -481,12 +473,33 @@ class JestPlugin extends CiPlugin {
481
473
  this.getTestTelemetryTags(span)
482
474
  )
483
475
 
484
- span.finish()
485
- finishAllTraceSpans(span)
486
- this.activeTestSpan = null
476
+ const finish = () => {
477
+ span.finish()
478
+ finishAllTraceSpans(span)
479
+ this.activeTestSpan = null
480
+ }
481
+
482
+ if (finalStatus) {
483
+ if (promises?.hitBreakpointPromise) {
484
+ finish()
485
+ this.cancelDiBreakpointHitWait()
486
+ return
487
+ }
488
+ if (promises && this.diBreakpointHitPromise) {
489
+ promises.hitBreakpointPromise = this.waitForPreparedDiBreakpointHit().then(finish)
490
+ return
491
+ }
492
+ finish()
493
+ this.cancelDiBreakpointHitWait()
494
+ return
495
+ }
496
+ finish()
497
+ if (status === 'fail' && promises?.hitBreakpointPromise) {
498
+ this.prepareDiBreakpointHitWait()
499
+ }
487
500
  })
488
501
 
489
- this.addSub('ci:jest:test:err', ({ span, error, shouldSetProbe, promises }) => {
502
+ this.addSub('ci:jest:test:err', ({ span, error, shouldSetProbe, shouldWaitForHitProbe, promises }) => {
490
503
  if (error && span) {
491
504
  span.setTag(TEST_STATUS, 'fail')
492
505
  span.setTag('error', getFormattedError(error, this.repositoryRoot))
@@ -494,8 +507,11 @@ class JestPlugin extends CiPlugin {
494
507
  const probeInformation = this.addDiProbe(error)
495
508
  if (probeInformation) {
496
509
  const { setProbePromise } = probeInformation
497
- promises.isProbeReady = withTimeout(setProbePromise, 2000)
510
+ this.prepareDiBreakpointHitWait()
511
+ promises.isProbeReady = this.waitForDiOperation(setProbePromise)
498
512
  }
513
+ } else if (shouldWaitForHitProbe && this.di) {
514
+ promises.hitBreakpointPromise = this.waitForDiBreakpointHits()
499
515
  }
500
516
  }
501
517
  })
@@ -1,8 +1,5 @@
1
1
  'use strict'
2
2
 
3
- // Capture real Date.now at module load time, before any test can install fake timers.
4
- const realDateNow = Date.now.bind(Date)
5
-
6
3
  const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin')
7
4
  const { storage } = require('../../datadog-core')
8
5
 
@@ -52,8 +49,6 @@ const {
52
49
  TELEMETRY_TEST_SESSION,
53
50
  } = require('../../dd-trace/src/ci-visibility/telemetry')
54
51
 
55
- const BREAKPOINT_SET_GRACE_PERIOD_MS = 200
56
-
57
52
  class MochaPlugin extends CiPlugin {
58
53
  static id = 'mocha'
59
54
 
@@ -263,6 +258,7 @@ class MochaPlugin extends CiPlugin {
263
258
  span.finish()
264
259
  finishAllTraceSpans(span)
265
260
  this.activeTestSpan = null
261
+ this.cancelDiBreakpointHitWait()
266
262
  if (this.di && this.libraryConfig?.isDiEnabled && this.runningTestProbe && isLastRetry) {
267
263
  this.removeDiProbe(this.runningTestProbe)
268
264
  this.runningTestProbe = null
@@ -307,8 +303,24 @@ class MochaPlugin extends CiPlugin {
307
303
  return ctx.currentStore
308
304
  })
309
305
 
310
- this.addSub('ci:mocha:test:retry', ({ span, isFirstAttempt, willBeRetried, err, test, isAtrRetry }) => {
306
+ this.addSub('ci:mocha:test:retry', ({
307
+ span,
308
+ isFirstAttempt,
309
+ willBeRetried,
310
+ err,
311
+ test,
312
+ isAtrRetry,
313
+ promises,
314
+ }) => {
311
315
  if (span) {
316
+ const finishSpan = () => {
317
+ span.finish()
318
+ finishAllTraceSpans(span)
319
+ if (this.activeTestSpan === span) {
320
+ this.activeTestSpan = null
321
+ }
322
+ }
323
+
312
324
  span.setTag(TEST_STATUS, 'fail')
313
325
  if (!isFirstAttempt) {
314
326
  span.setTag(TEST_IS_RETRY, 'true')
@@ -330,21 +342,34 @@ class MochaPlugin extends CiPlugin {
330
342
  if (isFirstAttempt && willBeRetried && this.di && this.libraryConfig?.isDiEnabled) {
331
343
  const probeInformation = this.addDiProbe(err)
332
344
  if (probeInformation) {
333
- const { file, line, stackIndex } = probeInformation
345
+ const { file, line, stackIndex, setProbePromise } = probeInformation
334
346
  this.runningTestProbe = { file, line }
335
347
  this.testErrorStackIndex = stackIndex
336
348
  test._ddShouldWaitForHitProbe = true
337
- const waitUntil = realDateNow() + BREAKPOINT_SET_GRACE_PERIOD_MS
338
- while (realDateNow() < waitUntil) {
339
- // TODO: To avoid a race condition, we should wait until `probeInformation.setProbePromise` has resolved.
340
- // However, Mocha doesn't have a mechanism for waiting asyncrounously here, so for now, we'll have to
341
- // fall back to a fixed syncronous delay.
349
+ this.prepareDiBreakpointHitWait()
350
+ if (promises) {
351
+ promises.setProbePromise = this.waitForDiOperation(setProbePromise)
342
352
  }
343
353
  }
344
354
  }
345
355
 
346
- span.finish()
347
- finishAllTraceSpans(span)
356
+ if (!isFirstAttempt &&
357
+ willBeRetried &&
358
+ this.di &&
359
+ this.libraryConfig?.isDiEnabled &&
360
+ this.runningTestProbe &&
361
+ promises) {
362
+ promises.finishTestPromise = this.waitForInFlightDiBreakpointHits().then(finishSpan, finishSpan)
363
+ return
364
+ }
365
+
366
+ finishSpan()
367
+ }
368
+ })
369
+
370
+ this.addSub('ci:mocha:test:di:wait', ({ promises }) => {
371
+ if (this.di) {
372
+ promises.hitBreakpointPromise = this.waitForDiBreakpointHits()
348
373
  }
349
374
  })
350
375
 
@@ -427,7 +452,7 @@ class MochaPlugin extends CiPlugin {
427
452
  finishAllTraceSpans(this.testSessionSpan)
428
453
  this.telemetry.count(TELEMETRY_TEST_SESSION, {
429
454
  provider: this.ciProviderName,
430
- autoInjected: !!this._tracerConfig.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
455
+ autoInjected: !!this._tracerConfig.testOptimization.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
431
456
  })
432
457
  }
433
458
  this.libraryConfig = null
@@ -0,0 +1,43 @@
1
+ 'use strict'
2
+
3
+ const MongodbCoreQueryPlugin = require('./query')
4
+
5
+ const MAX_RESOURCE_LENGTH = 10_000
6
+
7
+ class MongodbCoreBulkWritePlugin extends MongodbCoreQueryPlugin {
8
+ // bulkWrite is higher-level than the wire commands `query` traces, so it has its own operation
9
+ // and thus its own `apm:mongodb:bulkwrite:*` channels. It reuses the query plugin's `id`,
10
+ // `component`, and collection-stripping `getPeerService`, and inherits `finish`, `error`, and the
11
+ // finish-time parent-store restore from the tracing/outbound base classes.
12
+ static operation = 'bulkwrite'
13
+
14
+ /**
15
+ * Open the parent span for a `Collection#bulkWrite`. The per-type wire commands nest as
16
+ * children and carry the statements, host, and DBM comment, so this span only records
17
+ * the namespace and resource.
18
+ *
19
+ * @param {{ ns: string }} ctx
20
+ */
21
+ bindStart (ctx) {
22
+ const { ns } = ctx
23
+ const serviceResult = this.serviceName({ pluginConfig: this.config })
24
+
25
+ this.startSpan(this.operationName(), {
26
+ service: serviceResult,
27
+ resource: truncate(`bulkWrite ${ns}`),
28
+ type: 'mongodb',
29
+ kind: 'client',
30
+ meta: {
31
+ 'db.name': ns,
32
+ },
33
+ }, ctx)
34
+
35
+ return ctx.currentStore
36
+ }
37
+ }
38
+
39
+ function truncate (input) {
40
+ return input.length > MAX_RESOURCE_LENGTH ? input.slice(0, MAX_RESOURCE_LENGTH) : input
41
+ }
42
+
43
+ module.exports = MongodbCoreBulkWritePlugin