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.
Files changed (151) hide show
  1. package/LICENSE-3rdparty.csv +90 -102
  2. package/index.d.ts +82 -3
  3. package/package.json +15 -15
  4. package/packages/datadog-core/src/storage.js +1 -1
  5. package/packages/datadog-instrumentations/src/aerospike.js +1 -1
  6. package/packages/datadog-instrumentations/src/ai.js +8 -7
  7. package/packages/datadog-instrumentations/src/aws-sdk.js +13 -0
  8. package/packages/datadog-instrumentations/src/azure-cosmos.js +7 -0
  9. package/packages/datadog-instrumentations/src/azure-functions.js +3 -0
  10. package/packages/datadog-instrumentations/src/cucumber.js +78 -5
  11. package/packages/datadog-instrumentations/src/dns.js +54 -18
  12. package/packages/datadog-instrumentations/src/fastify.js +142 -82
  13. package/packages/datadog-instrumentations/src/graphql.js +188 -62
  14. package/packages/datadog-instrumentations/src/helpers/ai-messages.js +322 -14
  15. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
  16. package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -1
  17. package/packages/datadog-instrumentations/src/helpers/openai-ai-guard.js +269 -0
  18. package/packages/datadog-instrumentations/src/helpers/promise-instrumentor.js +42 -0
  19. package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
  20. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -3
  21. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-cosmos.js +50 -0
  22. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
  23. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js +4 -2
  24. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +85 -0
  25. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +37 -236
  26. package/packages/datadog-instrumentations/src/hono.js +54 -3
  27. package/packages/datadog-instrumentations/src/http/server.js +9 -4
  28. package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +163 -0
  29. package/packages/datadog-instrumentations/src/jest.js +360 -150
  30. package/packages/datadog-instrumentations/src/kafkajs.js +120 -16
  31. package/packages/datadog-instrumentations/src/mocha/main.js +128 -17
  32. package/packages/datadog-instrumentations/src/nats.js +182 -0
  33. package/packages/datadog-instrumentations/src/nyc.js +38 -1
  34. package/packages/datadog-instrumentations/src/openai.js +33 -18
  35. package/packages/datadog-instrumentations/src/oracledb.js +6 -1
  36. package/packages/datadog-instrumentations/src/pino.js +17 -5
  37. package/packages/datadog-instrumentations/src/playwright.js +515 -292
  38. package/packages/datadog-instrumentations/src/router.js +76 -32
  39. package/packages/datadog-instrumentations/src/stripe.js +1 -1
  40. package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
  41. package/packages/datadog-plugin-azure-cosmos/src/index.js +144 -0
  42. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -1
  43. package/packages/datadog-plugin-azure-functions/src/index.js +5 -2
  44. package/packages/datadog-plugin-azure-service-bus/src/producer.js +1 -1
  45. package/packages/datadog-plugin-bunyan/src/index.js +28 -0
  46. package/packages/datadog-plugin-cucumber/src/index.js +17 -3
  47. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +199 -28
  48. package/packages/datadog-plugin-cypress/src/support.js +69 -1
  49. package/packages/datadog-plugin-dns/src/lookup.js +8 -6
  50. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +1 -1
  51. package/packages/datadog-plugin-graphql/src/execute.js +2 -0
  52. package/packages/datadog-plugin-graphql/src/resolve.js +64 -67
  53. package/packages/datadog-plugin-http/src/server.js +40 -15
  54. package/packages/datadog-plugin-jest/src/index.js +11 -3
  55. package/packages/datadog-plugin-jest/src/util.js +15 -8
  56. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +1 -1
  57. package/packages/datadog-plugin-kafkajs/src/producer.js +3 -0
  58. package/packages/datadog-plugin-langgraph/src/stream.js +1 -1
  59. package/packages/datadog-plugin-mocha/src/index.js +19 -4
  60. package/packages/datadog-plugin-mongodb-core/src/index.js +281 -40
  61. package/packages/datadog-plugin-nats/src/consumer.js +43 -0
  62. package/packages/datadog-plugin-nats/src/index.js +20 -0
  63. package/packages/datadog-plugin-nats/src/producer.js +62 -0
  64. package/packages/datadog-plugin-nats/src/util.js +33 -0
  65. package/packages/datadog-plugin-next/src/index.js +5 -3
  66. package/packages/datadog-plugin-openai/src/tracing.js +15 -2
  67. package/packages/datadog-plugin-oracledb/src/index.js +13 -2
  68. package/packages/datadog-plugin-pino/src/index.js +42 -0
  69. package/packages/datadog-plugin-playwright/src/index.js +4 -4
  70. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
  71. package/packages/datadog-plugin-rhea/src/producer.js +1 -1
  72. package/packages/datadog-plugin-router/src/index.js +33 -44
  73. package/packages/datadog-plugin-selenium/src/index.js +1 -1
  74. package/packages/datadog-plugin-vitest/src/index.js +5 -13
  75. package/packages/datadog-plugin-winston/src/index.js +30 -0
  76. package/packages/datadog-shimmer/src/shimmer.js +33 -40
  77. package/packages/dd-trace/src/aiguard/index.js +1 -1
  78. package/packages/dd-trace/src/aiguard/sdk.js +1 -1
  79. package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
  80. package/packages/dd-trace/src/appsec/index.js +1 -1
  81. package/packages/dd-trace/src/appsec/reporter.js +5 -6
  82. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
  83. package/packages/dd-trace/src/appsec/sdk/utils.js +1 -1
  84. package/packages/dd-trace/src/appsec/user_tracking.js +5 -4
  85. package/packages/dd-trace/src/baggage.js +7 -1
  86. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +0 -1
  87. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +25 -13
  88. package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +70 -6
  89. package/packages/dd-trace/src/config/generated-config-types.d.ts +6 -2
  90. package/packages/dd-trace/src/config/supported-configurations.json +27 -8
  91. package/packages/dd-trace/src/datastreams/writer.js +2 -4
  92. package/packages/dd-trace/src/debugger/devtools_client/condition.js +5 -8
  93. package/packages/dd-trace/src/encode/0.4.js +124 -108
  94. package/packages/dd-trace/src/encode/0.5.js +114 -26
  95. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +31 -23
  96. package/packages/dd-trace/src/encode/agentless-json.js +4 -2
  97. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +32 -13
  98. package/packages/dd-trace/src/encode/span-stats.js +16 -16
  99. package/packages/dd-trace/src/encode/tags-processors.js +16 -0
  100. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
  101. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
  102. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
  103. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +9 -7
  104. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
  105. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +1 -1
  106. package/packages/dd-trace/src/llmobs/sdk.js +0 -16
  107. package/packages/dd-trace/src/llmobs/span_processor.js +3 -3
  108. package/packages/dd-trace/src/llmobs/tagger.js +9 -1
  109. package/packages/dd-trace/src/llmobs/telemetry.js +1 -1
  110. package/packages/dd-trace/src/llmobs/util.js +66 -3
  111. package/packages/dd-trace/src/log/index.js +1 -1
  112. package/packages/dd-trace/src/msgpack/chunk.js +394 -10
  113. package/packages/dd-trace/src/msgpack/index.js +96 -2
  114. package/packages/dd-trace/src/openfeature/encoding.js +70 -0
  115. package/packages/dd-trace/src/openfeature/flagging_provider.js +20 -0
  116. package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +143 -0
  117. package/packages/dd-trace/src/openfeature/span-enrichment.js +149 -0
  118. package/packages/dd-trace/src/opentelemetry/span-helpers.js +4 -3
  119. package/packages/dd-trace/src/opentelemetry/span.js +1 -1
  120. package/packages/dd-trace/src/opentracing/propagation/log.js +18 -7
  121. package/packages/dd-trace/src/opentracing/propagation/text_map.js +62 -67
  122. package/packages/dd-trace/src/opentracing/span.js +59 -19
  123. package/packages/dd-trace/src/opentracing/span_context.js +49 -0
  124. package/packages/dd-trace/src/plugins/ci_plugin.js +20 -20
  125. package/packages/dd-trace/src/plugins/database.js +7 -6
  126. package/packages/dd-trace/src/plugins/index.js +4 -0
  127. package/packages/dd-trace/src/plugins/log_injection.js +56 -0
  128. package/packages/dd-trace/src/plugins/log_plugin.js +3 -48
  129. package/packages/dd-trace/src/plugins/outbound.js +1 -1
  130. package/packages/dd-trace/src/plugins/plugin.js +15 -17
  131. package/packages/dd-trace/src/plugins/tracing.js +43 -5
  132. package/packages/dd-trace/src/plugins/util/test.js +236 -13
  133. package/packages/dd-trace/src/plugins/util/web.js +79 -65
  134. package/packages/dd-trace/src/priority_sampler.js +2 -2
  135. package/packages/dd-trace/src/profiling/profiler.js +2 -2
  136. package/packages/dd-trace/src/profiling/profilers/wall.js +10 -4
  137. package/packages/dd-trace/src/sampling_rule.js +7 -7
  138. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +10 -0
  139. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +8 -0
  140. package/packages/dd-trace/src/service-naming/source-resolver.js +46 -0
  141. package/packages/dd-trace/src/span_format.js +190 -58
  142. package/packages/dd-trace/src/spanleak.js +1 -1
  143. package/packages/dd-trace/src/standalone/index.js +3 -3
  144. package/packages/dd-trace/src/tagger.js +0 -2
  145. package/vendor/dist/@apm-js-collab/code-transformer/index.js +70 -39
  146. package/vendor/dist/@datadog/sketches-js/LICENSE +10 -36
  147. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  148. package/vendor/dist/protobufjs/index.js +1 -1
  149. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  150. package/packages/dd-trace/src/msgpack/encoder.js +0 -308
  151. package/packages/dd-trace/src/plugins/structured_log_plugin.js +0 -9
@@ -3,59 +3,61 @@
3
3
  const dc = require('dc-polyfill')
4
4
  const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
5
5
 
6
- const collapsedPathSym = Symbol('collapsedPaths')
7
-
8
6
  class GraphQLResolvePlugin extends TracingPlugin {
9
7
  static id = 'graphql'
10
8
  static operation = 'resolve'
11
9
 
10
+ /**
11
+ * @param {{
12
+ * rootCtx: {
13
+ * source?: string,
14
+ * collapse: boolean,
15
+ * collapsedFields?: Map<string, { ctx: object }>,
16
+ * },
17
+ * args: Record<string, unknown>,
18
+ * path: { prev: object | undefined, key: string | number },
19
+ * pathString: string,
20
+ * fieldName: string,
21
+ * returnType: { name: string },
22
+ * fieldNode: { loc?: { start: number, end: number }, arguments?: object[], directives?: object[] } | undefined,
23
+ * variableValues: Record<string, unknown> | undefined,
24
+ * }} fieldCtx
25
+ */
12
26
  start (fieldCtx) {
13
- const { info, rootCtx, args, path: pathAsArray, pathString } = fieldCtx
14
-
15
- // we need to get the parent span to the field if it exists for correct span parenting
16
- // of nested fields
17
- const parentField = getParentField(rootCtx, pathString)
18
- const childOf = parentField?.ctx?.currentStore?.span
27
+ if (!shouldInstrument(this.config, fieldCtx.path)) return
19
28
 
20
- fieldCtx.parent = parentField
29
+ const { rootCtx, args, path, pathString, fieldName, returnType, fieldNode, variableValues } = fieldCtx
21
30
 
22
- if (!shouldInstrument(this.config, pathAsArray)) return
23
- const computedPathString = this.config.collapse
24
- ? buildCollapsedPathString(pathAsArray)
25
- : pathString
31
+ // Siblings 2..N of a collapsed list share the first sibling's span, so
32
+ // skip span creation here. updateField still fires on the shared ctx and
33
+ // advances the shared span's finishTime.
34
+ if (rootCtx.collapse && rootCtx.collapsedFields?.has(pathString)) return
26
35
 
27
- if (this.config.collapse) {
28
- if (rootCtx.fields[computedPathString]) return
29
-
30
- if (!rootCtx[collapsedPathSym]) {
31
- rootCtx[collapsedPathSym] = Object.create(null)
32
- } else if (rootCtx[collapsedPathSym][computedPathString]) {
33
- return
34
- }
35
-
36
- rootCtx[collapsedPathSym][computedPathString] = true
37
- }
36
+ const parentField = getParentField(rootCtx, path)
37
+ const childOf = parentField?.ctx?.currentStore?.span
38
38
 
39
39
  const document = rootCtx.source
40
- const fieldNode = info.fieldNodes[0]
41
40
  const loc = this.config.source && document && fieldNode && fieldNode.loc
42
41
  const source = loc && document.slice(loc.start, loc.end)
43
42
 
43
+ let namedReturnType = returnType
44
+ while (namedReturnType.ofType) namedReturnType = namedReturnType.ofType
45
+
44
46
  const span = this.startSpan('graphql.resolve', {
45
47
  service: this.config.service,
46
- resource: `${info.fieldName}:${info.returnType}`,
48
+ resource: `${fieldName}:${returnType}`,
47
49
  childOf,
48
50
  type: 'graphql',
49
51
  meta: {
50
- 'graphql.field.name': info.fieldName,
51
- 'graphql.field.path': computedPathString,
52
- 'graphql.field.type': info.returnType.name,
52
+ 'graphql.field.name': fieldName,
53
+ 'graphql.field.path': pathString,
54
+ 'graphql.field.type': namedReturnType.name,
53
55
  'graphql.source': source,
54
56
  },
55
57
  }, fieldCtx)
56
58
 
57
59
  if (fieldNode && this.config.variables && fieldNode.arguments) {
58
- const variables = this.config.variables(info.variableValues)
60
+ const variables = this.config.variables(variableValues)
59
61
 
60
62
  for (const arg of fieldNode.arguments) {
61
63
  if (arg.value?.name && arg.value.kind === 'Variable' && variables[arg.value.name.value]) {
@@ -66,7 +68,7 @@ class GraphQLResolvePlugin extends TracingPlugin {
66
68
  }
67
69
 
68
70
  if (this.resolverStartCh.hasSubscribers) {
69
- this.resolverStartCh.publish({ ctx: rootCtx, resolverInfo: getResolverInfo(info, args) })
71
+ this.resolverStartCh.publish({ ctx: rootCtx, resolverInfo: getResolverInfo(fieldNode, fieldName, args) })
70
72
  }
71
73
 
72
74
  return fieldCtx.currentStore
@@ -76,11 +78,11 @@ class GraphQLResolvePlugin extends TracingPlugin {
76
78
  super(...args)
77
79
 
78
80
  this.addTraceSub('updateField', (ctx) => {
79
- const { field, error, path: pathAsArray } = ctx
81
+ // start short-circuited on the depth gate, so there is no span to advance.
82
+ if (ctx.currentStore === undefined) return
80
83
 
81
- if (!shouldInstrument(this.config, pathAsArray)) return
82
-
83
- const span = ctx?.currentStore?.span || this.activeSpan
84
+ const { field, error } = ctx
85
+ const span = ctx.currentStore.span
84
86
  field.finishTime = span._getTime ? span._getTime() : 0
85
87
  field.error = field.error || error
86
88
  })
@@ -105,38 +107,38 @@ class GraphQLResolvePlugin extends TracingPlugin {
105
107
 
106
108
  // helpers
107
109
 
108
- function shouldInstrument (config, pathAsArray) {
109
- if (config.depth < 0) return true
110
+ /**
111
+ * @param {{ depth: number, collapse: boolean }} config
112
+ * @param {{ prev: object | undefined, key: string | number }} path
113
+ */
114
+ function shouldInstrument (config, path) {
115
+ const depth = config.depth
116
+ if (depth < 0) return true
110
117
 
111
- let depth = 0
118
+ let count = 0
112
119
  if (config.collapse) {
113
- depth = pathAsArray.length
120
+ for (let curr = path; curr; curr = curr.prev) count += 1
114
121
  } else {
115
- for (const segment of pathAsArray) {
116
- if (typeof segment === 'string') depth += 1
122
+ for (let curr = path; curr; curr = curr.prev) {
123
+ if (typeof curr.key === 'string') count += 1
117
124
  }
118
125
  }
119
-
120
- return config.depth >= depth
121
- }
122
-
123
- function buildCollapsedPathString (pathAsArray) {
124
- let result = ''
125
- for (const segment of pathAsArray) {
126
- if (result.length > 0) result += '.'
127
- result += typeof segment === 'number' ? '*' : segment
128
- }
129
- return result
126
+ return depth >= count
130
127
  }
131
128
 
132
- function getResolverInfo (info, args) {
129
+ /**
130
+ * @param {object | undefined} fieldNode
131
+ * @param {string} fieldName
132
+ * @param {Record<string, unknown> | undefined} args
133
+ */
134
+ function getResolverInfo (fieldNode, fieldName, args) {
133
135
  let resolverVars
134
136
 
135
137
  if (args && Object.keys(args).length > 0) {
136
138
  resolverVars = { ...args }
137
139
  }
138
140
 
139
- const directives = info.fieldNodes?.[0]?.directives
141
+ const directives = fieldNode?.directives
140
142
  if (Array.isArray(directives)) {
141
143
  for (const directive of directives) {
142
144
  if (directive.arguments.length === 0) continue
@@ -151,23 +153,18 @@ function getResolverInfo (info, args) {
151
153
  }
152
154
  }
153
155
 
154
- return resolverVars === undefined ? null : { [info.fieldName]: resolverVars }
156
+ return resolverVars === undefined ? null : { [fieldName]: resolverVars }
155
157
  }
156
158
 
157
- function getParentField (parentCtx, pathToString) {
158
- let current = pathToString
159
-
160
- while (current) {
161
- const lastJoin = current.lastIndexOf('.')
162
- if (lastJoin === -1) break
163
-
164
- current = current.slice(0, lastJoin)
165
- const field = parentCtx.fields[current]
166
-
159
+ /**
160
+ * @param {{ fields: Map<object, { error: unknown, ctx: object }> }} rootCtx
161
+ * @param {{ prev: object | undefined }} path
162
+ */
163
+ function getParentField (rootCtx, path) {
164
+ for (let curr = path.prev; curr; curr = curr.prev) {
165
+ const field = rootCtx.fields.get(curr)
167
166
  if (field) return field
168
167
  }
169
-
170
- return null
171
168
  }
172
169
 
173
170
  module.exports = GraphQLResolvePlugin
@@ -14,30 +14,35 @@ class HttpServerPlugin extends ServerPlugin {
14
14
 
15
15
  static prefix = 'apm:http:server:request'
16
16
 
17
+ /** @type {string | undefined} */
18
+ #operationName
19
+
20
+ /** @type {object | undefined} */
21
+ #startConfig
22
+
23
+ /** @type {string | undefined} */
24
+ #serviceSource
25
+
17
26
  constructor (...args) {
18
27
  super(...args)
19
28
  this.addTraceSub('exit', message => this.exit(message))
20
29
  }
21
30
 
22
- start ({ req, res, abortController }) {
31
+ start (ctx) {
32
+ const { req, res } = ctx
23
33
  let store = legacyStorage.getStore()
24
- const { name: schemaServiceName, source: schemaServiceSource } = this.serviceName()
25
- const service = this.config.service || schemaServiceName
26
- const serviceSource = (this.config.service && service !== this.tracer._service)
27
- ? 'opt.plugin'
28
- : (service === this.tracer._service ? undefined : schemaServiceSource)
34
+ if (this.#startConfig === undefined) {
35
+ this.#refreshStartCache()
36
+ }
29
37
  const span = web.startSpan(
30
38
  this.tracer,
31
- {
32
- ...this.config,
33
- service,
34
- },
39
+ this.#startConfig,
35
40
  req,
36
41
  res,
37
- this.operationName()
42
+ this.#operationName
38
43
  )
39
- if (serviceSource !== undefined) {
40
- span.setTag(SVC_SRC_KEY, serviceSource)
44
+ if (this.#serviceSource !== undefined) {
45
+ span.setTag(SVC_SRC_KEY, this.#serviceSource)
41
46
  }
42
47
  span.setTag(COMPONENT, this.constructor.id)
43
48
  span._integrationName = this.constructor.id
@@ -60,7 +65,10 @@ class HttpServerPlugin extends ServerPlugin {
60
65
  }
61
66
 
62
67
  if (appsecActive) {
63
- incomingHttpRequestStart.publish({ req, res, abortController }) // TODO: no need to make a new object here
68
+ // Reuse the ctx allocated by the HTTP server instrumentation rather
69
+ // than a fresh `{ req, res, abortController }` per request; the AppSec
70
+ // subscriber only reads from the message.
71
+ incomingHttpRequestStart.publish(ctx)
64
72
  }
65
73
  }
66
74
 
@@ -93,7 +101,24 @@ class HttpServerPlugin extends ServerPlugin {
93
101
  }
94
102
 
95
103
  configure (config) {
96
- return super.configure(web.normalizeConfig(config))
104
+ const result = super.configure(web.normalizeConfig(config))
105
+ // Invalidate the start-cache; the next `start` refills it. Resolving
106
+ // service / operation eagerly here would pin nomenclature lookups to
107
+ // the order plugins and tracer initialise.
108
+ this.#startConfig = undefined
109
+ return result
110
+ }
111
+
112
+ #refreshStartCache () {
113
+ const { name: schemaServiceName, source: schemaServiceSource } = this.serviceName()
114
+ const tracerService = this.tracer._service
115
+ const configService = this.config.service
116
+ const service = configService || schemaServiceName
117
+ this.#serviceSource = (configService && service !== tracerService)
118
+ ? 'opt.plugin'
119
+ : (service === tracerService ? undefined : schemaServiceSource)
120
+ this.#operationName = this.operationName()
121
+ this.#startConfig = { ...this.config, service }
97
122
  }
98
123
  }
99
124
 
@@ -16,7 +16,6 @@ const {
16
16
  getTestSuiteCommonTags,
17
17
  addIntelligentTestRunnerSpanTags,
18
18
  TEST_PARAMETERS,
19
- TEST_COMMAND,
20
19
  TEST_FRAMEWORK_VERSION,
21
20
  TEST_SOURCE_START,
22
21
  TEST_ITR_UNSKIPPABLE,
@@ -115,7 +114,9 @@ class JestPlugin extends CiPlugin {
115
114
  isSuitesSkipped,
116
115
  isSuitesSkippingEnabled,
117
116
  isCodeCoverageEnabled,
117
+ isCoverageReportUploadEnabled,
118
118
  testCodeCoverageLinesTotal,
119
+ testSessionCoverageFiles,
119
120
  numSkippedSuites,
120
121
  hasUnskippableSuites,
121
122
  hasForcedToRunSuites,
@@ -149,6 +150,13 @@ class JestPlugin extends CiPlugin {
149
150
  }
150
151
  )
151
152
 
153
+ if (testSessionCoverageFiles?.length && isCoverageReportUploadEnabled) {
154
+ this.tracer._exporter.exportCoverage({
155
+ sessionId: this.testSessionSpan.context()._traceId,
156
+ files: testSessionCoverageFiles,
157
+ })
158
+ }
159
+
152
160
  if (isEarlyFlakeDetectionEnabled) {
153
161
  this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ENABLED, 'true')
154
162
  }
@@ -194,7 +202,7 @@ class JestPlugin extends CiPlugin {
194
202
  for (const config of configs) {
195
203
  config._ddTestSessionId = this.testSessionSpan.context().toTraceId()
196
204
  config._ddTestModuleId = this.testModuleSpan.context().toSpanId()
197
- config._ddTestCommand = this.testSessionSpan.context()._tags[TEST_COMMAND]
205
+ config._ddTestCommand = this.command
198
206
  config._ddRequestErrorTags = this.getSessionRequestErrorTags()
199
207
  config._ddItrCorrelationId = this.itrCorrelationId
200
208
  config._ddIsEarlyFlakeDetectionEnabled = !!this.libraryConfig?.isEarlyFlakeDetectionEnabled
@@ -596,7 +604,7 @@ class JestPlugin extends CiPlugin {
596
604
  extraTags[TEST_HAS_DYNAMIC_NAME] = 'true'
597
605
  }
598
606
  const testSuiteSpan = this.testSuiteSpanPerTestSuiteAbsolutePath.get(testSuiteAbsolutePath) || this.testSuiteSpan
599
- const skippingEnabled = testSuiteSpan?.context()._tags?.[TEST_ITR_SKIPPING_ENABLED]
607
+ const skippingEnabled = testSuiteSpan?.context()?.getTag?.(TEST_ITR_SKIPPING_ENABLED)
600
608
  if (skippingEnabled !== undefined) {
601
609
  extraTags[TEST_ITR_SKIPPING_ENABLED] = skippingEnabled
602
610
  }
@@ -41,11 +41,16 @@ function getFormattedJestTestParameters (testParameters) {
41
41
  return formattedParameters
42
42
  }
43
43
 
44
- // Support for `@fast-check/jest`: this library modifies the test name to include the seed
45
- // A test name that keeps changing breaks some Test Optimization's features.
44
+ // @fast-check/jest appends a random seed to the reported test name. A test name that keeps changing
45
+ // breaks some Test Optimization features, so normalize this narrow suffix regardless of import style.
46
46
  const SEED_SUFFIX_RE = /\s*\(with seed=-?\d+\)\s*$/i
47
+
48
+ function removeSeedSuffixFromTestName (testName) {
49
+ return testName.replace(SEED_SUFFIX_RE, '')
50
+ }
51
+
47
52
  // https://github.com/facebook/jest/blob/3e38157ad5f23fb7d24669d24fae8ded06a7ab75/packages/jest-circus/src/utils.ts#L396
48
- function getJestTestName (test, shouldStripSeed = false) {
53
+ function getRawJestTestName (test) {
49
54
  const titles = []
50
55
  let parent = test
51
56
  do {
@@ -54,11 +59,11 @@ function getJestTestName (test, shouldStripSeed = false) {
54
59
 
55
60
  titles.shift() // remove TOP_DESCRIBE_BLOCK_NAME
56
61
 
57
- const testName = titles.join(' ')
58
- if (shouldStripSeed) {
59
- return testName.replace(SEED_SUFFIX_RE, '')
60
- }
61
- return testName
62
+ return titles.join(' ')
63
+ }
64
+
65
+ function getJestTestName (test) {
66
+ return removeSeedSuffixFromTestName(getRawJestTestName(test))
62
67
  }
63
68
 
64
69
  const globalDocblockRegExp = /^\s*(\/\*\*?(.|\r?\n)*?\*\/)/
@@ -170,6 +175,8 @@ module.exports = {
170
175
  SEED_SUFFIX_RE,
171
176
  getFormattedJestTestParameters,
172
177
  getJestTestName,
178
+ getRawJestTestName,
173
179
  getJestSuitesToRun,
174
180
  isMarkedAsUnskippable,
181
+ removeSeedSuffixFromTestName,
175
182
  }
@@ -34,7 +34,7 @@ class KafkajsBatchConsumerPlugin extends ConsumerPlugin {
34
34
  if (headers) {
35
35
  const childOf = this.tracer.extract('text_map', headers)
36
36
  if (childOf) {
37
- span.addLink(childOf)
37
+ span.addLink({ context: childOf })
38
38
  }
39
39
  }
40
40
 
@@ -101,6 +101,9 @@ class KafkajsProducerPlugin extends ProducerPlugin {
101
101
  // response, only the starting offset.
102
102
  const offsets = []
103
103
  for (const entry of result) {
104
+ // sendBatch hands the same multi-topic response to every per-topic
105
+ // ctx; the span only owns its own topic's entries.
106
+ if (entry.topicName !== ctx.topic) continue
104
107
  const offsetAsLong = entry.offset ?? entry.baseOffset
105
108
  if (entry.partition === undefined || offsetAsLong === undefined) continue
106
109
  // Kafka offsets are 64-bit; coercing to Number loses precision past
@@ -20,7 +20,7 @@ class PregelStreamPlugin extends TracingPlugin {
20
20
  }
21
21
  class NextStreamPlugin extends TracingPlugin {
22
22
  static id = 'langgraph_stream_next'
23
- static prefix = 'tracing:orchestrion:@langchain/langgraph:Pregel_stream_next'
23
+ static prefix = 'tracing:orchestrion:@langchain/langgraph:Pregel_stream:next'
24
24
 
25
25
  bindStart (ctx) {
26
26
  return ctx.currentStore
@@ -11,6 +11,7 @@ const {
11
11
  TEST_PARAMETERS,
12
12
  finishAllTraceSpans,
13
13
  getTestSuitePath,
14
+ getRelativeCoverageFiles,
14
15
  getTestParametersString,
15
16
  getTestSuiteCommonTags,
16
17
  addIntelligentTestRunnerSpanTags,
@@ -73,8 +74,10 @@ class MochaPlugin extends CiPlugin {
73
74
  this.telemetry.count(TELEMETRY_CODE_COVERAGE_EMPTY)
74
75
  }
75
76
 
76
- const relativeCoverageFiles = [...coverageFiles, suiteFile]
77
- .map(filename => getTestSuitePath(filename, this.repositoryRoot || this.sourceRoot))
77
+ const relativeCoverageFiles = [
78
+ ...getRelativeCoverageFiles(coverageFiles, this.repositoryRoot || this.sourceRoot),
79
+ getTestSuitePath(suiteFile, this.repositoryRoot || this.sourceRoot),
80
+ ]
78
81
 
79
82
  const { _traceId, _spanId } = testSuiteSpan.context()
80
83
 
@@ -152,7 +155,7 @@ class MochaPlugin extends CiPlugin {
152
155
  this.addSub('ci:mocha:test-suite:finish', ({ testSuiteSpan, status }) => {
153
156
  if (testSuiteSpan) {
154
157
  // the test status of the suite may have been set in ci:mocha:test-suite:error already
155
- if (!testSuiteSpan.context()._tags[TEST_STATUS]) {
158
+ if (!testSuiteSpan.context().getTag(TEST_STATUS)) {
156
159
  testSuiteSpan.setTag(TEST_STATUS, status)
157
160
  }
158
161
  testSuiteSpan.finish()
@@ -352,6 +355,7 @@ class MochaPlugin extends CiPlugin {
352
355
  status,
353
356
  isSuitesSkipped,
354
357
  testCodeCoverageLinesTotal,
358
+ testSessionCoverageFiles,
355
359
  numSkippedSuites,
356
360
  hasForcedToRunSuites,
357
361
  hasUnskippableSuites,
@@ -362,7 +366,11 @@ class MochaPlugin extends CiPlugin {
362
366
  isParallel,
363
367
  }) => {
364
368
  if (this.testSessionSpan) {
365
- const { isSuitesSkippingEnabled, isCodeCoverageEnabled } = this.libraryConfig || {}
369
+ const {
370
+ isSuitesSkippingEnabled,
371
+ isCodeCoverageEnabled,
372
+ isCoverageReportUploadEnabled,
373
+ } = this.libraryConfig || {}
366
374
  this.testSessionSpan.setTag(TEST_STATUS, status)
367
375
  this.testModuleSpan.setTag(TEST_STATUS, status)
368
376
 
@@ -394,6 +402,13 @@ class MochaPlugin extends CiPlugin {
394
402
  }
395
403
  )
396
404
 
405
+ if (testSessionCoverageFiles?.length && isCoverageReportUploadEnabled) {
406
+ this.tracer._exporter.exportCoverage({
407
+ sessionId: this.testSessionSpan.context()._traceId,
408
+ files: testSessionCoverageFiles,
409
+ })
410
+ }
411
+
397
412
  if (isEarlyFlakeDetectionEnabled) {
398
413
  this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ENABLED, 'true')
399
414
  }