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
@@ -8,7 +8,6 @@ const { getCompileToRegexp } = require('./path-to-regexp')
8
8
  const {
9
9
  getRouterMountPaths,
10
10
  joinPath,
11
- getLayerMatchers,
12
11
  setLayerMatchers,
13
12
  isAppMounted,
14
13
  setRouterMountPath,
@@ -42,34 +41,47 @@ function createWrapRouterMethod (name, compile) {
42
41
  const nextChannel = channel(`apm:${name}:middleware:next`)
43
42
  const routeAddedChannel = channel(`apm:${name}:route:added`)
44
43
 
45
- function wrapLayerHandle (layer, original) {
46
- original._name = original._name || layer.name
44
+ function wrapLayerHandle (layer, original, matchers) {
45
+ // Resolve `name` once at wrap time: cached on the original for any code
46
+ // that reads `_name`, captured in the closure so the per-call body avoids
47
+ // the property-lookup / `||` fallback.
48
+ const name = original._name || layer.name || original.name
49
+ original._name = name
50
+
51
+ // Wrap-time matcher analysis. The single-pattern case yields a constant
52
+ // route; only multi-pattern stacks need a per-request layer.path match.
53
+ let captureRoute
54
+ let needMultiMatch = false
55
+ if (matchers.length !== 0 && !isFastStar(layer, matchers) && !isFastSlash(layer, matchers)) {
56
+ if (matchers.length === 1) {
57
+ captureRoute = matchers[0].path
58
+ } else {
59
+ needMultiMatch = true
60
+ }
61
+ }
47
62
 
48
- return shimmer.wrapFunction(original, original => function (...args) {
49
- if (!enterChannel.hasSubscribers) return original.apply(this, args)
63
+ // Split by arity: router only ever dispatches 3-arg request handlers
64
+ // through `Layer.handleRequest` and 4-arg error handlers through
65
+ // `Layer.handleError`. Specialising lets the per-call body use named
66
+ // parameters and `.call`, avoiding the rest-spread Array allocation that
67
+ // the unified shape forced on every middleware invocation.
68
+ return original.length === 4
69
+ ? shimmer.wrapFunction(original, errorHandlerLayerWrap(layer, name, captureRoute, needMultiMatch, matchers))
70
+ : shimmer.wrapFunction(original, requestHandlerLayerWrap(layer, name, captureRoute, needMultiMatch, matchers))
71
+ }
50
72
 
51
- const matchers = getLayerMatchers(layer)
52
- const lastIndex = args.length - 1
53
- const name = original._name || original.name
54
- const req = args[args.length > 3 ? 1 : 0]
55
- const next = args[lastIndex]
73
+ function requestHandlerLayerWrap (layer, name, captureRoute, needMultiMatch, matchers) {
74
+ return original => function (req, res, next) {
75
+ if (!enterChannel.hasSubscribers) return original.call(this, req, res, next)
56
76
 
57
- if (typeof next === 'function') {
58
- args[lastIndex] = wrapNext(req, next)
59
- }
77
+ const wrappedNext = typeof next === 'function' ? wrapNext(req, next) : next
60
78
 
61
- let route
62
-
63
- if (matchers?.length && !isFastStar(layer, matchers) && !isFastSlash(layer, matchers)) {
64
- if (matchers.length === 1) {
65
- // The host already matched this layer; the lone pattern is the route.
66
- route = matchers[0].path
67
- } else {
68
- for (const matcher of matchers) {
69
- if (matcher.regex?.test(layer.path)) {
70
- route = matcher.path
71
- break
72
- }
79
+ let route = captureRoute
80
+ if (needMultiMatch) {
81
+ for (const matcher of matchers) {
82
+ if (matcher.regex?.test(layer.path)) {
83
+ route = matcher.path
84
+ break
73
85
  }
74
86
  }
75
87
  }
@@ -77,7 +89,7 @@ function createWrapRouterMethod (name, compile) {
77
89
  enterChannel.publish({ name, req, route, layer })
78
90
 
79
91
  try {
80
- return original.apply(this, args)
92
+ return original.call(this, req, res, wrappedNext)
81
93
  } catch (error) {
82
94
  errorChannel.publish({ req, error })
83
95
  nextChannel.publish({ req })
@@ -87,15 +99,47 @@ function createWrapRouterMethod (name, compile) {
87
99
  } finally {
88
100
  exitChannel.publish({ req })
89
101
  }
90
- })
102
+ }
103
+ }
104
+
105
+ function errorHandlerLayerWrap (layer, name, captureRoute, needMultiMatch, matchers) {
106
+ return original => function (error, req, res, next) {
107
+ if (!enterChannel.hasSubscribers) return original.call(this, error, req, res, next)
108
+
109
+ const wrappedNext = typeof next === 'function' ? wrapNext(req, next) : next
110
+
111
+ let route = captureRoute
112
+ if (needMultiMatch) {
113
+ for (const matcher of matchers) {
114
+ if (matcher.regex?.test(layer.path)) {
115
+ route = matcher.path
116
+ break
117
+ }
118
+ }
119
+ }
120
+
121
+ enterChannel.publish({ name, req, route, layer })
122
+
123
+ try {
124
+ return original.call(this, error, req, res, wrappedNext)
125
+ } catch (caught) {
126
+ errorChannel.publish({ req, error: caught })
127
+ nextChannel.publish({ req })
128
+ finishChannel.publish({ req })
129
+
130
+ throw caught
131
+ } finally {
132
+ exitChannel.publish({ req })
133
+ }
134
+ }
91
135
  }
92
136
 
93
137
  function wrapStack (layers, matchers) {
94
138
  for (const layer of layers) {
95
139
  if (layer.__handle) { // express-async-errors
96
- layer.__handle = wrapLayerHandle(layer, layer.__handle)
140
+ layer.__handle = wrapLayerHandle(layer, layer.__handle, matchers)
97
141
  } else {
98
- layer.handle = wrapLayerHandle(layer, layer.handle)
142
+ layer.handle = wrapLayerHandle(layer, layer.handle, matchers)
99
143
  }
100
144
 
101
145
  setLayerMatchers(layer, matchers)
@@ -258,15 +302,15 @@ addHook({ name: 'router', versions: ['>=2'] }, Router => {
258
302
 
259
303
  shimmer.wrap(router, 'handle', function wrapHandle (originalHandle) {
260
304
  return function wrappedHandle (req, res, next) {
261
- const abortController = new AbortController()
262
-
263
305
  if (queryParserReadCh.hasSubscribers && req) {
306
+ const abortController = new AbortController()
307
+
264
308
  queryParserReadCh.publish({ req, res, query: req.query, abortController })
265
309
 
266
310
  if (abortController.signal.aborted) return
267
311
  }
268
312
 
269
- return originalHandle.apply(this, arguments)
313
+ return originalHandle.call(this, req, res, next)
270
314
  }
271
315
  })
272
316
 
@@ -97,7 +97,7 @@ function wrapStripe (Stripe) {
97
97
 
98
98
  addHook({
99
99
  name: 'stripe',
100
- versions: ['9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '>=20.0.0 <22'],
100
+ versions: ['>=9 <22'],
101
101
  }, Stripe => shimmer.wrapFunction(Stripe, wrapLegacyStripe))
102
102
 
103
103
  addHook({
@@ -140,7 +140,7 @@ class SchemaExtractor {
140
140
  return
141
141
  }
142
142
 
143
- if (span.context()._tags[SCHEMA_TYPE] && operation === 'serialization') {
143
+ if (span.context().getTag(SCHEMA_TYPE) && operation === 'serialization') {
144
144
  // we have already added a schema to this span, this call is an encode of nested schema types
145
145
  return
146
146
  }
@@ -0,0 +1,144 @@
1
+ 'use strict'
2
+
3
+ const { storage } = require('../../datadog-core')
4
+
5
+ const DatabasePlugin = require('../../dd-trace/src/plugins/database')
6
+
7
+ class AzureCosmosPlugin extends DatabasePlugin {
8
+ static id = 'azure-cosmos'
9
+ // Channel prefix determines how the plugin subscribes to instrumentation events.
10
+ // Three patterns exist — set `static prefix` explicitly based on instrumentation type:
11
+ //
12
+ // Orchestrion: static prefix = 'tracing:orchestrion:<npm-package>:<channelName>'
13
+ // Shimmer + tracingChannel: static prefix = 'tracing:apm:<name>:<operation>'
14
+ // Shimmer + manual channels: omit prefix — defaults to `apm:${id}:${operation}`
15
+ static prefix = 'tracing:orchestrion:@azure/cosmos:executePlugins'
16
+ static peerServicePrecursors = ['db.name']
17
+
18
+ operationName () {
19
+ return 'cosmosdb.query'
20
+ }
21
+
22
+ asyncEnd (ctx) {
23
+ if (!ctx.span) return
24
+ const span = ctx.currentStore?.span
25
+ if (span) {
26
+ const result = ctx.result
27
+ if (result?.code) span.setTag('db.response.status_code', (result.code).toString())
28
+ if (result?.substatus) span.setTag('cosmosdb.response.sub_status_code', result.substatus)
29
+ span.finish()
30
+ }
31
+ }
32
+
33
+ error (ctx) {
34
+ if (!ctx.span) return
35
+ const span = ctx.currentStore?.span
36
+ if (span) {
37
+ const error = ctx.error
38
+ this.addError(error, span)
39
+ if (error?.code) span.setTag('db.response.status_code', (error.code).toString())
40
+ if (error?.substatus) span.setTag('cosmosdb.response.sub_status_code', error.substatus)
41
+ }
42
+ }
43
+
44
+ bindStart (ctx) {
45
+ const requestContext = ctx.arguments[1]
46
+ const resource = this.getResource(requestContext)
47
+ const { dbName, containerName } = this.getDbInfo(requestContext)
48
+ const connectionMode = this.getConnectionMode(requestContext)
49
+ const { outHost, userAgent } = this.getHttpInfo(requestContext)
50
+ const pluginOn = ctx.arguments[3]
51
+
52
+ if (pluginOn != null && requestContext.operationType != null && requestContext.resourceType != null) {
53
+ const operationType = requestContext.operationType
54
+ const resourceType = requestContext.resourceType
55
+ // only trace operations not requests (pluginOn)
56
+ // trace requests only if they are read or query operations not on docs
57
+ // prevents doubled read spans for createIfNotExists calls
58
+ if (pluginOn === 'request' && ((operationType !== 'read' && operationType !== 'query') ||
59
+ (operationType === 'read' && resourceType !== 'docs'))) {
60
+ return storage('legacy').getStore()
61
+ }
62
+
63
+ // separately, skip tracing read requests without a path, these don't
64
+ // represent CRUD operations on a resource we care about
65
+ // not returning current store because we don't want the child http.request spans
66
+ // to be created
67
+ if (operationType === 'read' && requestContext.path === '') {
68
+ return { noop: true }
69
+ }
70
+ }
71
+
72
+ const span = this.startSpan(this.operationName(), {
73
+ resource,
74
+ type: 'cosmosdb',
75
+ kind: 'client',
76
+ meta: {
77
+ component: 'azure_cosmos',
78
+ 'db.system': 'cosmosdb',
79
+ 'db.name': dbName,
80
+ 'cosmosdb.container': containerName,
81
+ 'cosmosdb.connection.mode': connectionMode,
82
+ 'http.useragent': userAgent,
83
+ 'out.host': outHost,
84
+ },
85
+ }, ctx)
86
+
87
+ ctx.span = span
88
+ return ctx.currentStore
89
+ }
90
+
91
+ getResource (requestContext) {
92
+ const path = requestContext.path
93
+ const parts = path.split('/')
94
+ let modified = false
95
+ for (let i = 2; i < parts.length; i += 2) {
96
+ if (parts[i].length > 0 && parts[i - 1] !== 'dbs' && parts[i - 1] !== 'colls') {
97
+ parts[i] = '?'
98
+ modified = true
99
+ }
100
+ }
101
+
102
+ return `${requestContext.operationType} ${modified ? parts.join('/') : path}`
103
+ }
104
+
105
+ getDbInfo (requestContext) {
106
+ let dbName = null
107
+ let containerName = null
108
+
109
+ if (requestContext.operationType === 'create' && requestContext.resourceType === 'dbs' &&
110
+ requestContext.body != null && requestContext.body.id != null) {
111
+ dbName = requestContext.body.id
112
+ }
113
+
114
+ let resourceLink = requestContext.path
115
+ if (resourceLink?.length > 1 && resourceLink.startsWith('/')) {
116
+ resourceLink = resourceLink.slice(1)
117
+ const parts = resourceLink.split('/')
118
+ if (parts.length > 0 && parts[0].toLowerCase() === 'dbs' && parts.length >= 2) {
119
+ dbName = parts[1]
120
+ if (parts.length >= 4 && parts[2].toLowerCase() === 'colls' && parts[3] !== '') {
121
+ containerName = parts[3]
122
+ }
123
+ }
124
+ }
125
+
126
+ return { dbName, containerName }
127
+ }
128
+
129
+ getConnectionMode (requestContext) {
130
+ const mode = requestContext.client?.connectionPolicy?.connectionMode
131
+ if (mode === 0) {
132
+ return 'gateway'
133
+ }
134
+ return 'direct'
135
+ }
136
+
137
+ getHttpInfo (requestContext) {
138
+ const outHost = requestContext.client?.cosmosClientOptions?.endpoint
139
+ const userAgent = requestContext.headers?.['User-Agent']
140
+ return { outHost, userAgent }
141
+ }
142
+ }
143
+
144
+ module.exports = AzureCosmosPlugin
@@ -62,7 +62,7 @@ class AzureEventHubsProducerPlugin extends ProducerPlugin {
62
62
  const contexts = spanContexts.get(eventData)
63
63
  if (contexts) {
64
64
  for (const spanContext of contexts) {
65
- span.addLink(spanContext)
65
+ span.addLink({ context: spanContext })
66
66
  }
67
67
  }
68
68
  }
@@ -13,6 +13,7 @@ const triggerMap = {
13
13
  serviceBusQueue: 'ServiceBus',
14
14
  serviceBusTopic: 'ServiceBus',
15
15
  eventHub: 'EventHubs',
16
+ cosmosDB: 'CosmosDB',
16
17
  }
17
18
 
18
19
  class AzureFunctionsPlugin extends TracingPlugin {
@@ -53,7 +54,7 @@ class AzureFunctionsPlugin extends TracingPlugin {
53
54
  )
54
55
 
55
56
  span._integrationName = 'azure-functions'
56
- span.context()._tags.component = 'azure-functions'
57
+ span.context().setTag('component', 'azure-functions')
57
58
  span.addTags(meta)
58
59
  webContext.span = span
59
60
  webContext.azureFunctionCtx = ctx
@@ -127,6 +128,8 @@ function getMetaForTrigger ({ functionName, methodName, invocationContext }) {
127
128
  'resource.name': `EventHubs ${functionName}`,
128
129
  'span.kind': 'consumer',
129
130
  }
131
+ } else if (triggerMap[methodName] === 'CosmosDB') {
132
+ meta['resource.name'] = `CosmosDB ${functionName}`
130
133
  }
131
134
 
132
135
  return meta
@@ -155,7 +158,7 @@ function setSpanLinks (triggerType, tracer, span, ctx) {
155
158
  if (!props || Object.keys(props).length === 0) return
156
159
  const spanContext = tracer.extract('text_map', props)
157
160
  if (spanContext) {
158
- span.addLink(spanContext)
161
+ span.addLink({ context: spanContext })
159
162
  }
160
163
  }
161
164
 
@@ -56,7 +56,7 @@ class AzureServiceBusProducerPlugin extends ProducerPlugin {
56
56
  const contexts = spanContexts.get(messages)
57
57
  if (contexts) {
58
58
  for (const spanContext of contexts) {
59
- span.addLink(spanContext)
59
+ span.addLink({ context: spanContext })
60
60
  }
61
61
  }
62
62
  }
@@ -1,8 +1,36 @@
1
1
  'use strict'
2
2
 
3
+ const { buildLogHolder } = require('../../dd-trace/src/plugins/log_injection')
3
4
  const LogPlugin = require('../../dd-trace/src/plugins/log_plugin')
4
5
 
5
6
  class BunyanPlugin extends LogPlugin {
6
7
  static id = 'bunyan'
8
+
9
+ constructor (...args) {
10
+ super(...args)
11
+ this.addSub('apm:bunyan:log', (arg) => this.handleLog(arg))
12
+ }
13
+
14
+ /**
15
+ * Inject `dd` directly on the record bunyan hands us. bunyan builds the
16
+ * record inside `mkRecord` via `objCopy(log.fields)` and then copies the
17
+ * caller's fields onto the result, so the `rec` object that flows
18
+ * through `_emit` is always bunyan-owned, has `Object.prototype` for its
19
+ * prototype, and is never the caller's input directly. Mutating it adds
20
+ * `dd` for every consumer (JSON streams via `JSON.stringify(rec)`, raw
21
+ * streams via the record reference) without paying for a Proxy view.
22
+ *
23
+ * @param {{ message: object }} arg
24
+ */
25
+ handleLog (arg) {
26
+ const rec = arg.message
27
+ if (rec === null || typeof rec !== 'object' || Object.hasOwn(rec, 'dd')) return
28
+
29
+ const logHolder = buildLogHolder(this.tracer)
30
+ if (!logHolder) return
31
+
32
+ rec.dd = logHolder.dd
33
+ }
7
34
  }
35
+
8
36
  module.exports = BunyanPlugin
@@ -11,6 +11,7 @@ const { getEnvironmentVariable } = require('../../dd-trace/src/config/helper')
11
11
  const {
12
12
  addIntelligentTestRunnerSpanTags,
13
13
  finishAllTraceSpans,
14
+ getRelativeCoverageFiles,
14
15
  getTestEndLine,
15
16
  getTestSuiteCommonTags,
16
17
  getTestSuitePath,
@@ -71,6 +72,7 @@ class CucumberPlugin extends CiPlugin {
71
72
  isSuitesSkipped,
72
73
  numSkippedSuites,
73
74
  testCodeCoverageLinesTotal,
75
+ testSessionCoverageFiles,
74
76
  hasUnskippableSuites,
75
77
  hasForcedToRunSuites,
76
78
  isEarlyFlakeDetectionEnabled,
@@ -78,7 +80,11 @@ class CucumberPlugin extends CiPlugin {
78
80
  isTestManagementTestsEnabled,
79
81
  isParallel,
80
82
  }) => {
81
- const { isSuitesSkippingEnabled, isCodeCoverageEnabled } = this.libraryConfig || {}
83
+ const {
84
+ isSuitesSkippingEnabled,
85
+ isCodeCoverageEnabled,
86
+ isCoverageReportUploadEnabled,
87
+ } = this.libraryConfig || {}
82
88
  addIntelligentTestRunnerSpanTags(
83
89
  this.testSessionSpan,
84
90
  this.testModuleSpan,
@@ -93,6 +99,12 @@ class CucumberPlugin extends CiPlugin {
93
99
  hasForcedToRunSuites,
94
100
  }
95
101
  )
102
+ if (testSessionCoverageFiles?.length && isCoverageReportUploadEnabled) {
103
+ this.tracer._exporter.exportCoverage({
104
+ sessionId: this.testSessionSpan.context()._traceId,
105
+ files: testSessionCoverageFiles,
106
+ })
107
+ }
96
108
  if (isEarlyFlakeDetectionEnabled) {
97
109
  this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ENABLED, 'true')
98
110
  }
@@ -197,8 +209,10 @@ class CucumberPlugin extends CiPlugin {
197
209
  }
198
210
  const testSuiteSpan = this._testSuiteSpansByTestSuite.get(testSuitePath)
199
211
 
200
- const relativeCoverageFiles = [...coverageFiles, suiteFile]
201
- .map(filename => getTestSuitePath(filename, this.repositoryRoot))
212
+ const relativeCoverageFiles = [
213
+ ...getRelativeCoverageFiles(coverageFiles, this.repositoryRoot),
214
+ getTestSuitePath(suiteFile, this.repositoryRoot),
215
+ ]
202
216
 
203
217
  this.telemetry.distribution(TELEMETRY_CODE_COVERAGE_NUM_FILES, {}, relativeCoverageFiles.length)
204
218