dd-trace 5.102.0 → 5.104.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 (201) hide show
  1. package/ext/exporters.js +1 -0
  2. package/index.d.ts +25 -3
  3. package/package.json +15 -13
  4. package/packages/datadog-esbuild/src/utils.js +2 -2
  5. package/packages/datadog-instrumentations/src/ai.js +1 -1
  6. package/packages/datadog-instrumentations/src/aws-sdk.js +2 -2
  7. package/packages/datadog-instrumentations/src/cassandra-driver.js +5 -2
  8. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +32 -15
  9. package/packages/datadog-instrumentations/src/couchbase.js +69 -220
  10. package/packages/datadog-instrumentations/src/cucumber.js +104 -31
  11. package/packages/datadog-instrumentations/src/elasticsearch.js +4 -4
  12. package/packages/datadog-instrumentations/src/electron/preload.js +42 -0
  13. package/packages/datadog-instrumentations/src/electron.js +240 -0
  14. package/packages/datadog-instrumentations/src/fetch.js +5 -5
  15. package/packages/datadog-instrumentations/src/graphql.js +13 -17
  16. package/packages/datadog-instrumentations/src/grpc/client.js +48 -32
  17. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +2 -2
  18. package/packages/datadog-instrumentations/src/helpers/hook.js +4 -1
  19. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  20. package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -2
  21. package/packages/datadog-instrumentations/src/helpers/kafka.js +58 -0
  22. package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +3 -2
  23. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +19 -5
  24. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +14 -13
  25. package/packages/datadog-instrumentations/src/http/client.js +2 -2
  26. package/packages/datadog-instrumentations/src/ioredis.js +18 -14
  27. package/packages/datadog-instrumentations/src/jest.js +382 -84
  28. package/packages/datadog-instrumentations/src/kafkajs.js +184 -174
  29. package/packages/datadog-instrumentations/src/mariadb.js +1 -1
  30. package/packages/datadog-instrumentations/src/memcached.js +2 -1
  31. package/packages/datadog-instrumentations/src/mocha/main.js +309 -56
  32. package/packages/datadog-instrumentations/src/mocha/utils.js +48 -8
  33. package/packages/datadog-instrumentations/src/mongodb-core.js +34 -9
  34. package/packages/datadog-instrumentations/src/mongoose.js +10 -12
  35. package/packages/datadog-instrumentations/src/mysql.js +2 -2
  36. package/packages/datadog-instrumentations/src/mysql2.js +1 -1
  37. package/packages/datadog-instrumentations/src/pg.js +25 -11
  38. package/packages/datadog-instrumentations/src/playwright.js +449 -60
  39. package/packages/datadog-instrumentations/src/redis.js +19 -10
  40. package/packages/datadog-instrumentations/src/router.js +4 -2
  41. package/packages/datadog-instrumentations/src/vitest.js +246 -149
  42. package/packages/datadog-plugin-apollo/src/gateway/request.js +1 -21
  43. package/packages/datadog-plugin-aws-sdk/src/base.js +18 -24
  44. package/packages/datadog-plugin-aws-sdk/src/services/cloudwatchlogs.js +1 -1
  45. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -1
  46. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -1
  47. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +1 -1
  48. package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +1 -1
  49. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +1 -1
  50. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +2 -2
  51. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -1
  52. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +1 -1
  53. package/packages/datadog-plugin-couchbase/src/index.js +58 -52
  54. package/packages/datadog-plugin-cucumber/src/index.js +1 -0
  55. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +239 -40
  56. package/packages/datadog-plugin-cypress/src/support.js +13 -1
  57. package/packages/datadog-plugin-elasticsearch/src/index.js +28 -8
  58. package/packages/datadog-plugin-electron/src/index.js +17 -0
  59. package/packages/datadog-plugin-electron/src/ipc.js +143 -0
  60. package/packages/datadog-plugin-electron/src/net.js +82 -0
  61. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +27 -18
  62. package/packages/datadog-plugin-graphql/src/execute.js +6 -28
  63. package/packages/datadog-plugin-graphql/src/resolve.js +30 -35
  64. package/packages/datadog-plugin-graphql/src/tools/signature.js +32 -7
  65. package/packages/datadog-plugin-graphql/src/tools/transforms.js +118 -100
  66. package/packages/datadog-plugin-graphql/src/utils.js +33 -1
  67. package/packages/datadog-plugin-grpc/src/client.js +6 -7
  68. package/packages/datadog-plugin-grpc/src/util.js +57 -22
  69. package/packages/datadog-plugin-http/src/client.js +2 -2
  70. package/packages/datadog-plugin-jest/src/index.js +92 -50
  71. package/packages/datadog-plugin-kafkajs/src/producer.js +32 -0
  72. package/packages/datadog-plugin-mocha/src/index.js +1 -0
  73. package/packages/datadog-plugin-mongodb-core/src/index.js +70 -69
  74. package/packages/datadog-plugin-mysql/src/index.js +1 -1
  75. package/packages/datadog-plugin-openai/src/services.js +2 -1
  76. package/packages/datadog-plugin-pg/src/index.js +3 -3
  77. package/packages/datadog-plugin-playwright/src/index.js +4 -0
  78. package/packages/datadog-plugin-redis/src/index.js +54 -24
  79. package/packages/datadog-plugin-undici/src/index.js +19 -0
  80. package/packages/datadog-plugin-vitest/src/index.js +19 -7
  81. package/packages/datadog-shimmer/src/shimmer.js +35 -0
  82. package/packages/dd-trace/src/aiguard/index.js +3 -1
  83. package/packages/dd-trace/src/aiguard/sdk.js +36 -30
  84. package/packages/dd-trace/src/aiguard/tags.js +20 -11
  85. package/packages/dd-trace/src/appsec/blocking.js +2 -2
  86. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +2 -2
  87. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +1 -1
  88. package/packages/dd-trace/src/appsec/index.js +10 -3
  89. package/packages/dd-trace/src/appsec/reporter.js +19 -5
  90. package/packages/dd-trace/src/azure_metadata.js +17 -6
  91. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +4 -4
  92. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -2
  93. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +6 -4
  94. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +1 -1
  95. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -1
  96. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +5 -3
  97. package/packages/dd-trace/src/config/defaults.js +3 -14
  98. package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -1
  99. package/packages/dd-trace/src/config/helper.js +4 -0
  100. package/packages/dd-trace/src/config/index.js +2 -2
  101. package/packages/dd-trace/src/config/major-overrides.js +98 -0
  102. package/packages/dd-trace/src/config/parsers.js +7 -1
  103. package/packages/dd-trace/src/config/supported-configurations.json +60 -38
  104. package/packages/dd-trace/src/crashtracking/crashtracker.js +15 -3
  105. package/packages/dd-trace/src/datastreams/checkpointer.js +2 -2
  106. package/packages/dd-trace/src/datastreams/context.js +4 -2
  107. package/packages/dd-trace/src/datastreams/manager.js +1 -1
  108. package/packages/dd-trace/src/datastreams/processor.js +2 -2
  109. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +2 -2
  110. package/packages/dd-trace/src/debugger/devtools_client/source-maps.js +1 -1
  111. package/packages/dd-trace/src/debugger/devtools_client/state.js +2 -1
  112. package/packages/dd-trace/src/debugger/index.js +7 -7
  113. package/packages/dd-trace/src/dogstatsd.js +2 -2
  114. package/packages/dd-trace/src/encode/0.4.js +45 -54
  115. package/packages/dd-trace/src/encode/0.5.js +34 -3
  116. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +26 -19
  117. package/packages/dd-trace/src/encode/agentless-json.js +1 -1
  118. package/packages/dd-trace/src/exporter.js +2 -0
  119. package/packages/dd-trace/src/exporters/agent/index.js +2 -1
  120. package/packages/dd-trace/src/exporters/agentless/index.js +3 -2
  121. package/packages/dd-trace/src/exporters/agentless/writer.js +2 -2
  122. package/packages/dd-trace/src/exporters/common/agents.js +3 -1
  123. package/packages/dd-trace/src/exporters/common/buffering-exporter.js +2 -1
  124. package/packages/dd-trace/src/exporters/common/request.js +4 -2
  125. package/packages/dd-trace/src/exporters/electron/index.js +49 -0
  126. package/packages/dd-trace/src/external-logger/src/index.js +2 -1
  127. package/packages/dd-trace/src/git_metadata.js +10 -8
  128. package/packages/dd-trace/src/id.js +17 -4
  129. package/packages/dd-trace/src/lambda/handler-paths.js +52 -0
  130. package/packages/dd-trace/src/lambda/handler.js +2 -4
  131. package/packages/dd-trace/src/lambda/index.js +62 -14
  132. package/packages/dd-trace/src/lambda/runtime/patch.js +21 -46
  133. package/packages/dd-trace/src/llmobs/index.js +13 -2
  134. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +45 -15
  135. package/packages/dd-trace/src/llmobs/sdk.js +10 -0
  136. package/packages/dd-trace/src/llmobs/writers/base.js +2 -1
  137. package/packages/dd-trace/src/log/writer.js +3 -1
  138. package/packages/dd-trace/src/noop/span.js +3 -1
  139. package/packages/dd-trace/src/openfeature/writers/base.js +2 -1
  140. package/packages/dd-trace/src/openfeature/writers/exposures.js +51 -20
  141. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +3 -2
  142. package/packages/dd-trace/src/opentracing/propagation/text_map.js +20 -9
  143. package/packages/dd-trace/src/payload-tagging/config/index.js +2 -2
  144. package/packages/dd-trace/src/plugins/apollo.js +3 -1
  145. package/packages/dd-trace/src/plugins/ci_plugin.js +52 -17
  146. package/packages/dd-trace/src/plugins/database.js +54 -12
  147. package/packages/dd-trace/src/plugins/index.js +1 -0
  148. package/packages/dd-trace/src/plugins/log_plugin.js +3 -1
  149. package/packages/dd-trace/src/plugins/plugin.js +2 -4
  150. package/packages/dd-trace/src/plugins/tracing.js +5 -3
  151. package/packages/dd-trace/src/plugins/util/ci.js +8 -8
  152. package/packages/dd-trace/src/plugins/util/git-cache.js +20 -18
  153. package/packages/dd-trace/src/plugins/util/git.js +3 -1
  154. package/packages/dd-trace/src/plugins/util/stacktrace.js +2 -2
  155. package/packages/dd-trace/src/plugins/util/test.js +119 -5
  156. package/packages/dd-trace/src/plugins/util/user-provided-git.js +17 -15
  157. package/packages/dd-trace/src/plugins/util/web.js +11 -0
  158. package/packages/dd-trace/src/priority_sampler.js +1 -1
  159. package/packages/dd-trace/src/profiling/profiler.js +1 -1
  160. package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
  161. package/packages/dd-trace/src/profiling/ssi-heuristics.js +1 -1
  162. package/packages/dd-trace/src/rate_limiter.js +1 -1
  163. package/packages/dd-trace/src/remote_config/scheduler.js +1 -1
  164. package/packages/dd-trace/src/ritm.js +2 -1
  165. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +5 -8
  166. package/packages/dd-trace/src/scope.js +7 -5
  167. package/packages/dd-trace/src/serverless.js +5 -2
  168. package/packages/dd-trace/src/service-naming/extra-services.js +14 -0
  169. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +20 -0
  170. package/packages/dd-trace/src/service-naming/schemas/v0/web.js +4 -0
  171. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +20 -0
  172. package/packages/dd-trace/src/service-naming/schemas/v1/web.js +4 -0
  173. package/packages/dd-trace/src/span_stats.js +1 -1
  174. package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
  175. package/packages/dd-trace/src/telemetry/endpoints.js +1 -1
  176. package/packages/dd-trace/src/telemetry/telemetry.js +2 -2
  177. package/packages/dd-trace/src/lambda/runtime/ritm.js +0 -133
  178. package/vendor/dist/opentracing/LICENSE +0 -201
  179. package/vendor/dist/opentracing/binary_carrier.d.ts +0 -11
  180. package/vendor/dist/opentracing/constants.d.ts +0 -61
  181. package/vendor/dist/opentracing/examples/demo/demo.d.ts +0 -2
  182. package/vendor/dist/opentracing/ext/tags.d.ts +0 -90
  183. package/vendor/dist/opentracing/functions.d.ts +0 -20
  184. package/vendor/dist/opentracing/global_tracer.d.ts +0 -14
  185. package/vendor/dist/opentracing/index.d.ts +0 -12
  186. package/vendor/dist/opentracing/index.js +0 -1
  187. package/vendor/dist/opentracing/mock_tracer/index.d.ts +0 -5
  188. package/vendor/dist/opentracing/mock_tracer/mock_context.d.ts +0 -13
  189. package/vendor/dist/opentracing/mock_tracer/mock_report.d.ts +0 -16
  190. package/vendor/dist/opentracing/mock_tracer/mock_span.d.ts +0 -50
  191. package/vendor/dist/opentracing/mock_tracer/mock_tracer.d.ts +0 -26
  192. package/vendor/dist/opentracing/noop.d.ts +0 -8
  193. package/vendor/dist/opentracing/reference.d.ts +0 -33
  194. package/vendor/dist/opentracing/span.d.ts +0 -147
  195. package/vendor/dist/opentracing/span_context.d.ts +0 -26
  196. package/vendor/dist/opentracing/test/api_compatibility.d.ts +0 -16
  197. package/vendor/dist/opentracing/test/mocktracer_implemenation.d.ts +0 -3
  198. package/vendor/dist/opentracing/test/noop_implementation.d.ts +0 -4
  199. package/vendor/dist/opentracing/test/opentracing_api.d.ts +0 -3
  200. package/vendor/dist/opentracing/test/unittest.d.ts +0 -2
  201. package/vendor/dist/opentracing/tracer.d.ts +0 -127
@@ -1,17 +1,65 @@
1
1
  'use strict'
2
2
 
3
- const { getValueFromEnvSources } = require('../config/helper')
4
- const { registerLambdaHook } = require('./runtime/ritm')
5
-
6
- /**
7
- * It is safe to do it this way, since customers will never be expected to disable
8
- * this specific instrumentation through the init config object.
9
- */
10
- const _DD_TRACE_DISABLED_INSTRUMENTATIONS = getValueFromEnvSources('DD_TRACE_DISABLED_INSTRUMENTATIONS') || ''
11
- const _disabledInstrumentations = new Set(
12
- _DD_TRACE_DISABLED_INSTRUMENTATIONS ? _DD_TRACE_DISABLED_INSTRUMENTATIONS.split(',') : []
13
- )
14
-
15
- if (!_disabledInstrumentations.has('lambda')) {
16
- registerLambdaHook()
3
+ const path = require('path')
4
+
5
+ const log = require('../log')
6
+ const { getEnvironmentVariable, getValueFromEnvSources } = require('../config/helper')
7
+ const Hook = require('../../../datadog-instrumentations/src/helpers/hook')
8
+ const instrumentations = require('../../../datadog-instrumentations/src/helpers/instrumentations')
9
+ const {
10
+ filename,
11
+ pathSepExpr,
12
+ } = require('../../../datadog-instrumentations/src/helpers/register')
13
+ const {
14
+ extractModuleNameAndHandlerPath,
15
+ extractModuleRootAndHandler,
16
+ getLambdaFilePaths,
17
+ } = require('./handler-paths')
18
+
19
+ if (!getValueFromEnvSources('DD_TRACE_DISABLED_INSTRUMENTATIONS')?.split(',').includes('lambda')) {
20
+ const lambdaTaskRoot = getEnvironmentVariable('LAMBDA_TASK_ROOT')
21
+ const originalLambdaHandler = getValueFromEnvSources('DD_LAMBDA_HANDLER')
22
+
23
+ if (originalLambdaHandler !== undefined && lambdaTaskRoot !== undefined) {
24
+ const [moduleRoot, moduleAndHandler] = extractModuleRootAndHandler(originalLambdaHandler)
25
+ const [moduleName] = extractModuleNameAndHandlerPath(moduleAndHandler)
26
+
27
+ const lambdaStylePath = path.resolve(lambdaTaskRoot, moduleRoot, moduleName)
28
+ const lambdaFilePaths = getLambdaFilePaths(lambdaStylePath)
29
+
30
+ // TODO: Redo this like any other instrumentation.
31
+ Hook(lambdaFilePaths, (moduleExports, name, _, moduleVersion) => {
32
+ require('./runtime/patch')
33
+
34
+ for (const { hook } of instrumentations[name]) {
35
+ try {
36
+ moduleExports = hook(moduleExports, moduleVersion) ?? moduleExports
37
+ } catch (error) {
38
+ log.error('Error executing lambda hook', error)
39
+ }
40
+ }
41
+
42
+ return moduleExports
43
+ })
44
+ return
45
+ }
46
+
47
+ const moduleToPatch = 'datadog-lambda-js'
48
+ Hook([moduleToPatch], (moduleExports, moduleName, _, moduleVersion) => {
49
+ moduleName = moduleName.replace(pathSepExpr, '/')
50
+ require('./runtime/patch')
51
+
52
+ for (const { file, hook } of instrumentations[moduleToPatch]) {
53
+ const fullFilename = filename(moduleToPatch, file)
54
+ if (moduleName === fullFilename) {
55
+ try {
56
+ moduleExports = hook(moduleExports, moduleVersion) ?? moduleExports
57
+ } catch (error) {
58
+ log.error('Error executing lambda hook for datadog-lambda-js', error)
59
+ }
60
+ }
61
+ }
62
+
63
+ return moduleExports
64
+ })
17
65
  }
@@ -6,54 +6,32 @@ const { datadog } = require('../handler')
6
6
  const { addHook } = require('../../../../datadog-instrumentations/src/helpers/instrument')
7
7
  const shimmer = require('../../../../datadog-shimmer')
8
8
  const { getEnvironmentVariable, getValueFromEnvSources } = require('../../config/helper')
9
- const { _extractModuleNameAndHandlerPath, _extractModuleRootAndHandler, _getLambdaFilePaths } = require('./ritm')
10
-
11
- /**
12
- * Patches a Datadog Lambda module by calling `patchDatadogLambdaHandler`
13
- * with the handler name `datadog`.
14
- *
15
- * @param {object} datadogLambdaModule node module to be patched.
16
- * @returns a Datadog Lambda module with the `datadog` function from
17
- * `datadog-lambda-js` patched.
18
- */
19
- const patchDatadogLambdaModule = (datadogLambdaModule) => {
9
+ const {
10
+ extractModuleNameAndHandlerPath,
11
+ extractModuleRootAndHandler,
12
+ getLambdaFilePaths,
13
+ } = require('../handler-paths')
14
+
15
+ /** @param {object} datadogLambdaModule */
16
+ function patchDatadogLambdaModule (datadogLambdaModule) {
20
17
  shimmer.wrap(datadogLambdaModule, 'datadog', patchDatadogLambdaHandler)
21
-
22
18
  return datadogLambdaModule
23
19
  }
24
20
 
25
- /**
26
- * Patches a Datadog Lambda handler in order to do
27
- * Datadog instrumentation by getting the Lambda handler from its
28
- * arguments.
29
- *
30
- * @param {Function} datadogHandler the Datadog Lambda handler to destructure.
31
- * @returns the datadogHandler with its arguments patched.
32
- */
21
+ /** @param {Function} datadogHandler */
33
22
  function patchDatadogLambdaHandler (datadogHandler) {
34
- return (userHandler) => {
35
- return datadogHandler(datadog(userHandler))
36
- }
23
+ return userHandler => datadogHandler(datadog(userHandler))
37
24
  }
38
25
 
39
- /**
40
- * Patches a Lambda module on the given handler path.
41
- *
42
- * @param {string} handlerPath path of the handler to be patched.
43
- * @returns a module with the given handler path patched.
44
- */
45
- const patchLambdaModule = (handlerPath) => (lambdaModule) => {
46
- shimmer.wrap(lambdaModule, handlerPath, patchLambdaHandler)
47
-
48
- return lambdaModule
26
+ /** @param {string} handlerPath */
27
+ function patchLambdaModule (handlerPath) {
28
+ return lambdaModule => {
29
+ shimmer.wrap(lambdaModule, handlerPath, patchLambdaHandler)
30
+ return lambdaModule
31
+ }
49
32
  }
50
33
 
51
- /**
52
- * Patches a Lambda handler in order to do Datadog instrumentation.
53
- *
54
- * @param {Function} lambdaHandler the Lambda handler to be patched.
55
- * @returns a function which patches the given Lambda handler.
56
- */
34
+ /** @param {Function} lambdaHandler */
57
35
  function patchLambdaHandler (lambdaHandler) {
58
36
  return datadog(lambdaHandler)
59
37
  }
@@ -62,16 +40,13 @@ const lambdaTaskRoot = getEnvironmentVariable('LAMBDA_TASK_ROOT')
62
40
  const originalLambdaHandler = getValueFromEnvSources('DD_LAMBDA_HANDLER')
63
41
 
64
42
  if (originalLambdaHandler === undefined) {
65
- // Instrumentation is done manually.
66
43
  addHook({ name: 'datadog-lambda-js' }, patchDatadogLambdaModule)
67
44
  } else {
68
- const [moduleRoot, moduleAndHandler] = _extractModuleRootAndHandler(originalLambdaHandler)
69
- const [_module, handlerPath] = _extractModuleNameAndHandlerPath(moduleAndHandler)
70
-
71
- const lambdaStylePath = path.resolve(lambdaTaskRoot, moduleRoot, _module)
72
- const lambdaFilePaths = _getLambdaFilePaths(lambdaStylePath)
45
+ const [moduleRoot, moduleAndHandler] = extractModuleRootAndHandler(originalLambdaHandler)
46
+ const [moduleName, handlerPath] = extractModuleNameAndHandlerPath(moduleAndHandler)
73
47
 
74
- for (const lambdaFilePath of lambdaFilePaths) {
48
+ const lambdaStylePath = path.resolve(lambdaTaskRoot, moduleRoot, moduleName)
49
+ for (const lambdaFilePath of getLambdaFilePaths(lambdaStylePath)) {
75
50
  addHook({ name: lambdaFilePath }, patchLambdaModule(handlerPath))
76
51
  }
77
52
  }
@@ -108,6 +108,10 @@ function disable () {
108
108
  // since LLMObs traces can extend between services and be the same trace,
109
109
  // we need to propagate the parent id and mlApp.
110
110
  function handleLLMObsParentIdInjection ({ carrier }) {
111
+ // Respect the standard propagator's gate: when trace tag propagation is
112
+ // disabled, don't write `x-datadog-tags` for LLMObs either.
113
+ if (globalTracerConfig.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH === 0) return
114
+
111
115
  const parent = storage.getStore()?.span
112
116
  const mlObsSpanTags = LLMObsTagger.tagMap.get(parent)
113
117
 
@@ -118,8 +122,15 @@ function handleLLMObsParentIdInjection ({ carrier }) {
118
122
  parentContext?._trace?.tags?.[PROPAGATED_ML_APP_KEY] ||
119
123
  globalTracerConfig.llmobs.mlApp
120
124
 
121
- if (parentId) carrier['x-datadog-tags'] += `,${PROPAGATED_PARENT_ID_KEY}=${parentId}`
122
- if (mlApp) carrier['x-datadog-tags'] += `,${PROPAGATED_ML_APP_KEY}=${mlApp}`
125
+ if (!parentId && !mlApp) return
126
+
127
+ // `_injectTags` only writes `x-datadog-tags` when the trace has `_dd.p.*`
128
+ // tags, so it may be undefined here — coalesce before appending.
129
+ const existing = carrier['x-datadog-tags']
130
+ let tags = existing || ''
131
+ if (parentId) tags += `${tags ? ',' : ''}${PROPAGATED_PARENT_ID_KEY}=${parentId}`
132
+ if (mlApp) tags += `${tags ? ',' : ''}${PROPAGATED_ML_APP_KEY}=${mlApp}`
133
+ if (tags !== existing) carrier['x-datadog-tags'] = tags
123
134
  }
124
135
 
125
136
  function handleFlush () {
@@ -14,7 +14,17 @@ const llmobsStore = storage('llmobs')
14
14
 
15
15
  const ENABLED_OPERATIONS = new Set(['invokeModel', 'invokeModelWithResponseStream'])
16
16
 
17
- const requestIdsToTokens = {}
17
+ /**
18
+ * @typedef {{
19
+ * inputTokensFromHeaders?: number,
20
+ * outputTokensFromHeaders?: number,
21
+ * cacheReadTokensFromHeaders?: number,
22
+ * cacheWriteTokensFromHeaders?: number,
23
+ * }} HeaderTokens
24
+ */
25
+
26
+ /** @type {Map<string, HeaderTokens>} */
27
+ const pendingTokenHeaders = new Map()
18
28
 
19
29
  class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
20
30
  constructor () {
@@ -24,33 +34,39 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
24
34
  const { response } = ctx
25
35
  const request = response.request
26
36
  const operation = request.operation
37
+
38
+ // Release the cached headers even for operations the plugin does not tag,
39
+ // so non-LLM Bedrock calls do not leak entries into pendingTokenHeaders.
40
+ const tokensFromHeaders = consumeTokenHeaders(response.$metadata?.requestId)
41
+
27
42
  // avoids instrumenting other non supported runtime operations
28
- if (!ENABLED_OPERATIONS.has(operation)) {
29
- return
30
- }
43
+ if (!ENABLED_OPERATIONS.has(operation)) return
44
+
31
45
  const { modelProvider, modelName } = parseModelId(request.params.modelId)
32
46
 
33
47
  // avoids instrumenting non llm type
34
- if (modelName.includes('embed')) {
35
- return
36
- }
48
+ if (modelName.includes('embed')) return
49
+
37
50
  const span = ctx.currentStore?.span
38
- this.setLLMObsTags({ ctx, request, span, response, modelProvider, modelName })
51
+ this.setLLMObsTags({ ctx, request, span, response, modelProvider, modelName, tokensFromHeaders })
39
52
  })
40
53
 
41
54
  this.addSub('apm:aws:response:deserialize:bedrockruntime', ({ headers }) => {
42
55
  const requestId = headers['x-amzn-requestid']
56
+ // No request id means no way to correlate with the :complete: event.
57
+ if (!requestId) return
58
+
43
59
  const inputTokenCount = headers['x-amzn-bedrock-input-token-count']
44
60
  const outputTokenCount = headers['x-amzn-bedrock-output-token-count']
45
61
  const cacheReadTokenCount = headers['x-amzn-bedrock-cache-read-input-token-count']
46
62
  const cacheWriteTokenCount = headers['x-amzn-bedrock-cache-write-input-token-count']
47
63
 
48
- requestIdsToTokens[requestId] = {
64
+ pendingTokenHeaders.set(requestId, {
49
65
  inputTokensFromHeaders: inputTokenCount && Number.parseInt(inputTokenCount),
50
66
  outputTokensFromHeaders: outputTokenCount && Number.parseInt(outputTokenCount),
51
67
  cacheReadTokensFromHeaders: cacheReadTokenCount && Number.parseInt(cacheReadTokenCount),
52
68
  cacheWriteTokensFromHeaders: cacheWriteTokenCount && Number.parseInt(cacheWriteTokenCount),
53
- }
69
+ })
54
70
  })
55
71
 
56
72
  this.addSub('apm:aws:response:streamed-chunk:bedrockruntime', ({ ctx, chunk }) => {
@@ -60,7 +76,7 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
60
76
  })
61
77
  }
62
78
 
63
- setLLMObsTags ({ ctx, request, span, response, modelProvider, modelName }) {
79
+ setLLMObsTags ({ ctx, request, span, response, modelProvider, modelName, tokensFromHeaders }) {
64
80
  const isStream = request?.operation?.toLowerCase().includes('stream')
65
81
  telemetry.incrementLLMObsSpanStartCount({ autoinstrumented: true, integration: 'bedrock' })
66
82
 
@@ -97,7 +113,7 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
97
113
 
98
114
  // add token metrics
99
115
  const { inputTokens, outputTokens, totalTokens, cacheReadTokens, cacheWriteTokens } = extractTokens({
100
- requestId: response.$metadata.requestId,
116
+ tokensFromHeaders,
101
117
  usage: textAndResponseReason.usage,
102
118
  })
103
119
  this._tagger.tagMetrics(span, {
@@ -110,14 +126,28 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
110
126
  }
111
127
  }
112
128
 
113
- function extractTokens ({ requestId, usage }) {
129
+ /**
130
+ * @param {string | undefined} requestId
131
+ * @returns {HeaderTokens | undefined}
132
+ */
133
+ function consumeTokenHeaders (requestId) {
134
+ const tokens = pendingTokenHeaders.get(requestId)
135
+ pendingTokenHeaders.delete(requestId)
136
+ return tokens
137
+ }
138
+
139
+ /**
140
+ * Combine response-body usage with header-derived counts, preferring the body.
141
+ *
142
+ * @param {{ tokensFromHeaders: HeaderTokens | undefined, usage: Record<string, number | undefined> }} options
143
+ */
144
+ function extractTokens ({ tokensFromHeaders, usage }) {
114
145
  const {
115
146
  inputTokensFromHeaders,
116
147
  outputTokensFromHeaders,
117
148
  cacheReadTokensFromHeaders,
118
149
  cacheWriteTokensFromHeaders,
119
- } = requestIdsToTokens[requestId] || {}
120
- delete requestIdsToTokens[requestId]
150
+ } = tokensFromHeaders ?? {}
121
151
 
122
152
  const inputTokens = usage.inputTokens || inputTokensFromHeaders || 0
123
153
  const outputTokens = usage.outputTokens || outputTokensFromHeaders || 0
@@ -55,6 +55,11 @@ class LLMObs extends NoopLLMObs {
55
55
  }
56
56
 
57
57
  enable (options = {}) {
58
+ logger.warn(
59
+ 'Enabling LLM Observability via `llmobs.enable()` is deprecated and will be removed in dd-trace@7.0.0. ' +
60
+ 'Please instantiate LLM Observability via DD_LLMOBS_ENABLED or `tracer.init({ llmobs: ...options })`.'
61
+ )
62
+
58
63
  if (this.enabled) {
59
64
  logger.debug('LLMObs is already enabled.')
60
65
  return
@@ -79,6 +84,11 @@ class LLMObs extends NoopLLMObs {
79
84
  }
80
85
 
81
86
  disable () {
87
+ logger.warn(
88
+ 'Disabling LLM Observability via `llmobs.disable()` is deprecated and will be removed in dd-trace@7.0.0. ' +
89
+ 'Set DD_LLMOBS_ENABLED=false to disable LLM Observability.'
90
+ )
91
+
82
92
  if (!this.enabled) {
83
93
  logger.debug('LLMObs is already disabled.')
84
94
  return
@@ -54,7 +54,8 @@ class BaseLLMObsWriter {
54
54
 
55
55
  this._periodic = setInterval(() => {
56
56
  this.flush()
57
- }, this._interval).unref()
57
+ }, this._interval)
58
+ this._periodic.unref?.()
58
59
 
59
60
  const destroyer = this.destroy.bind(this)
60
61
  globalThis[Symbol.for('dd-trace')].beforeExitHandlers.add(destroyer)
@@ -3,6 +3,8 @@
3
3
  const { storage } = require('../../../datadog-core')
4
4
  const { LogChannel } = require('./channels')
5
5
 
6
+ const legacyStorage = storage('legacy')
7
+
6
8
  const defaultLogger = {
7
9
  debug: msg => console.debug(msg), /* eslint-disable-line no-console */
8
10
  info: msg => console.info(msg), /* eslint-disable-line no-console */
@@ -15,7 +17,7 @@ let logger = defaultLogger
15
17
  let logChannel = new LogChannel()
16
18
 
17
19
  function withNoop (fn) {
18
- storage('legacy').run({ noop: true }, fn)
20
+ legacyStorage.run({ noop: true }, fn)
19
21
  }
20
22
 
21
23
  function toggleSubscription (enable, level) {
@@ -4,9 +4,11 @@ const id = require('../id')
4
4
  const { storage } = require('../../../datadog-core') // TODO: noop storage?
5
5
  const NoopSpanContext = require('./span_context')
6
6
 
7
+ const legacyStorage = storage('legacy')
8
+
7
9
  class NoopSpan {
8
10
  constructor (tracer, parent) {
9
- this._store = storage('legacy').getHandle()
11
+ this._store = legacyStorage.getHandle()
10
12
  this._noopTracer = tracer
11
13
  this._noopContext = this._createContext(parent)
12
14
  }
@@ -55,7 +55,8 @@ class BaseFFEWriter {
55
55
 
56
56
  this._periodic = setInterval(() => {
57
57
  this.flush()
58
- }, this._interval).unref()
58
+ }, this._interval)
59
+ this._periodic.unref?.()
59
60
 
60
61
  const destroyer = this.destroy.bind(this)
61
62
  globalThis[Symbol.for('dd-trace')].beforeExitHandlers.add(destroyer)
@@ -8,8 +8,14 @@ const {
8
8
  EVP_PAYLOAD_SIZE_LIMIT,
9
9
  EVP_EVENT_SIZE_LIMIT,
10
10
  } = require('../constants/constants')
11
+ const log = require('../../log')
11
12
  const BaseFFEWriter = require('./base')
12
13
 
14
+ // Disabled-state cap. Drops invalidate experiment results because the provider's
15
+ // exposure dedupe cache keeps masking dropped events after recovery. The first
16
+ // drop emits a warning and `droppedEventCount` accumulates the cumulative loss.
17
+ const PENDING_MAX_EVENTS = 1000
18
+
13
19
  /**
14
20
  * @typedef {object} ExposureEvent
15
21
  * @property {number} timestamp - Unix timestamp in milliseconds
@@ -42,11 +48,21 @@ const BaseFFEWriter = require('./base')
42
48
  * ExposuresWriter is responsible for sending exposure events to the Datadog Agent.
43
49
  */
44
50
  class ExposuresWriter extends BaseFFEWriter {
51
+ // Disabled until the agent strategy probe resolves.
52
+ #enabled = false
53
+
54
+ /** @type {ExposureEvent[]} */
55
+ #pendingEvents = []
56
+
57
+ /** @type {ExposureContext} */
58
+ #context
59
+
60
+ #dropWarned = false
61
+
45
62
  /**
46
63
  * @param {import('../../config/config-base')} config - Tracer configuration object
47
64
  */
48
65
  constructor (config) {
49
- // Build full EVP endpoint path
50
66
  const basePath = EVP_PROXY_AGENT_BASE_PATH.replace(/\/+$/, '')
51
67
  const endpoint = EXPOSURES_ENDPOINT.replace(/^\/+/, '')
52
68
  const fullEndpoint = `${basePath}/${endpoint}`
@@ -60,33 +76,33 @@ class ExposuresWriter extends BaseFFEWriter {
60
76
  [EVP_SUBDOMAIN_HEADER_NAME]: EVP_SUBDOMAIN_VALUE,
61
77
  },
62
78
  })
63
- this._enabled = false // Start disabled until agent strategy is set
64
- this._pendingEvents = [] // Buffer events until enabled
65
79
 
80
+ /** @type {ExposureContext} */
66
81
  const context = {
67
82
  service: config.service,
68
83
  }
69
- // Only include version and env if they are defined
84
+
70
85
  if (config.version !== undefined) {
71
86
  context.version = config.version
72
87
  }
88
+
73
89
  if (config.env !== undefined) {
74
90
  context.env = config.env
75
91
  }
76
92
 
77
- this._context = context
93
+ this.#context = context
78
94
  }
79
95
 
80
96
  /**
81
97
  * @param {boolean} enabled - Whether to enable the writer
82
98
  */
83
99
  setEnabled (enabled) {
84
- this._enabled = enabled
100
+ this.#enabled = enabled
85
101
 
86
- if (enabled && this._pendingEvents.length > 0) {
102
+ if (enabled && this.#pendingEvents.length > 0) {
87
103
  // Flush all pending events as a batch
88
- super.append(this._pendingEvents)
89
- this._pendingEvents = []
104
+ super.append(this.#pendingEvents)
105
+ this.#pendingEvents = []
90
106
  }
91
107
  }
92
108
 
@@ -95,24 +111,38 @@ class ExposuresWriter extends BaseFFEWriter {
95
111
  * @param {ExposureEvent|ExposureEvent[]} events - Exposure event(s) to append
96
112
  */
97
113
  append (events) {
98
- if (!this._enabled) {
99
- // Buffer events until writer is ready
100
- if (Array.isArray(events)) {
101
- this._pendingEvents.push(...events)
102
- } else {
103
- this._pendingEvents.push(events)
104
- }
114
+ if (this.#enabled) {
115
+ super.append(events)
105
116
  return
106
117
  }
107
- super.append(events)
118
+
119
+ const eventArray = Array.isArray(events) ? events : [events]
120
+ this.#pendingEvents.push(...eventArray)
121
+ if (this.#pendingEvents.length > PENDING_MAX_EVENTS) {
122
+ const dropped = this.#pendingEvents.length - PENDING_MAX_EVENTS
123
+ this.#pendingEvents.splice(0, dropped)
124
+ this._droppedEvents += dropped
125
+ if (!this.#dropWarned) {
126
+ this.#dropWarned = true
127
+ log.warn(
128
+ '%s dropped exposure event(s) at cap %d. This may invalidate experiment results.',
129
+ this.constructor.name, PENDING_MAX_EVENTS)
130
+ }
131
+ }
132
+ }
133
+
134
+ /**
135
+ * @returns {number} Cumulative number of exposure events dropped due to buffer overflow.
136
+ */
137
+ get droppedEventCount () {
138
+ return this._droppedEvents
108
139
  }
109
140
 
110
141
  /**
111
142
  * Flushes buffered exposure events to the agent
112
143
  */
113
144
  flush () {
114
- if (!this._enabled) {
115
- // Don't flush when disabled
145
+ if (!this.#enabled) {
116
146
  return
117
147
  }
118
148
  super.flush()
@@ -125,6 +155,7 @@ class ExposuresWriter extends BaseFFEWriter {
125
155
  */
126
156
  makePayload (events) {
127
157
  const formattedEvents = events.map(event => {
158
+ /** @type {ExposureEvent} */
128
159
  return {
129
160
  timestamp: event.timestamp || Date.now(),
130
161
  allocation: {
@@ -145,7 +176,7 @@ class ExposuresWriter extends BaseFFEWriter {
145
176
  })
146
177
 
147
178
  return {
148
- context: this._context,
179
+ context: this.#context,
149
180
  exposures: formattedEvents,
150
181
  }
151
182
  }
@@ -167,7 +167,8 @@ class PeriodicMetricReader {
167
167
 
168
168
  this.#timer = setInterval(() => {
169
169
  this.#collectAndExport()
170
- }, this.#exportInterval).unref()
170
+ }, this.#exportInterval)
171
+ this.#timer.unref?.()
171
172
  }
172
173
 
173
174
  /**
@@ -335,7 +336,7 @@ class MetricAggregator {
335
336
  }
336
337
  }
337
338
 
338
- this.#applyDeltaTemporality(metricsMap, lastExportedState)
339
+ this.#applyDeltaTemporality(metricsMap.values(), lastExportedState)
339
340
  return metricsMap
340
341
  }
341
342
 
@@ -9,6 +9,7 @@ const tags = require('../../../../../ext/tags')
9
9
  const { getConfiguredEnvName } = require('../../config/helper')
10
10
  const { setAllBaggageItems, getAllBaggageItems, removeAllBaggageItems } = require('../../baggage')
11
11
  const telemetryMetrics = require('../../telemetry/metrics')
12
+ const { DD_MAJOR } = require('../../../../../version')
12
13
 
13
14
  const { AUTO_KEEP, AUTO_REJECT, USER_KEEP } = require('../../../../../ext/priority')
14
15
  const TraceState = require('./tracestate')
@@ -78,10 +79,17 @@ class TextMapPropagator {
78
79
  constructor (config) {
79
80
  this._config = config
80
81
 
81
- // TODO: should match "b3 single header" in next major
82
- const envName = getConfiguredEnvName('DD_TRACE_PROPAGATION_STYLE')
83
- // eslint-disable-next-line eslint-rules/eslint-env-aliases
84
- this.#extractB3Context = envName === 'OTEL_PROPAGATORS' ? this._extractB3SingleContext : this._extractB3MultiContext
82
+ // v6: `'b3'` is always single-header. v5: env-name decides — OTEL_PROPAGATORS callers expect
83
+ // single, the legacy `DD_TRACE_PROPAGATION_STYLE` callers expect multi.
84
+ if (DD_MAJOR >= 6) {
85
+ this.#extractB3Context = this._extractB3SingleContext
86
+ } else {
87
+ const envName = getConfiguredEnvName('DD_TRACE_PROPAGATION_STYLE')
88
+ // eslint-disable-next-line eslint-rules/eslint-env-aliases
89
+ this.#extractB3Context = envName === 'OTEL_PROPAGATORS'
90
+ ? this._extractB3SingleContext
91
+ : this._extractB3MultiContext
92
+ }
85
93
  }
86
94
 
87
95
  /**
@@ -262,9 +270,10 @@ class TextMapPropagator {
262
270
  }
263
271
 
264
272
  _injectB3MultipleHeaders (spanContext, carrier) {
265
- const hasB3 = this._hasPropagationStyle('inject', 'b3')
266
- const hasB3multi = this._hasPropagationStyle('inject', 'b3multi')
267
- if (!(hasB3 || hasB3multi)) return
273
+ // v5 also accepts the legacy `'b3'` spelling for multi; v6 routes `'b3'` to single-header.
274
+ const hasB3multi = this._hasPropagationStyle('inject', 'b3multi') ||
275
+ (DD_MAJOR < 6 && this._hasPropagationStyle('inject', 'b3'))
276
+ if (!hasB3multi) return
268
277
 
269
278
  carrier[b3TraceKey] = this._getB3TraceId(spanContext)
270
279
  carrier[b3SpanKey] = spanContext._spanId.toString(16)
@@ -280,7 +289,9 @@ class TextMapPropagator {
280
289
  }
281
290
 
282
291
  _injectB3SingleHeader (spanContext, carrier) {
283
- const hasB3SingleHeader = this._hasPropagationStyle('inject', 'b3 single header')
292
+ // v6 keeps `'b3 single header'` as a back-compat alias for callers that bypass parser normalisation.
293
+ const hasB3SingleHeader = this._hasPropagationStyle('inject', 'b3 single header') ||
294
+ (DD_MAJOR >= 6 && this._hasPropagationStyle('inject', 'b3'))
284
295
  if (!hasB3SingleHeader) return null
285
296
 
286
297
  const traceId = this._getB3TraceId(spanContext)
@@ -394,7 +405,7 @@ class TextMapPropagator {
394
405
  case 'tracecontext':
395
406
  extractedContext = this._extractTraceparentContext(carrier)
396
407
  break
397
- case 'b3 single header': // TODO: delete in major after singular "b3"
408
+ case 'b3 single header':
398
409
  extractedContext = this._extractB3SingleContext(carrier)
399
410
  break
400
411
  case 'b3':
@@ -30,8 +30,8 @@ function getSDKRules (sdk, requestInput, responseInput) {
30
30
  * Appends input rules to all supported SDKs and returns a structure mapping SDK
31
31
  * names to per-service rules.
32
32
  *
33
- * @param {string[]} [requestInput=[]]
34
- * @param {string[]} [responseInput=[]]
33
+ * @param {string[]} [requestInput]
34
+ * @param {string[]} [responseInput]
35
35
  * @returns {Record<string, SDKRules>}
36
36
  */
37
37
  function appendRules (requestInput = [], responseInput = []) {
@@ -3,13 +3,15 @@
3
3
  const { storage } = require('../../../datadog-core')
4
4
  const TracingPlugin = require('./tracing')
5
5
 
6
+ const legacyStorage = storage('legacy')
7
+
6
8
  class ApolloBasePlugin extends TracingPlugin {
7
9
  static id = 'apollo.gateway'
8
10
  static type = 'web'
9
11
  static kind = 'server'
10
12
 
11
13
  bindStart (ctx) {
12
- const store = storage('legacy').getStore()
14
+ const store = legacyStorage.getStore()
13
15
  const childOf = store ? /** @type {import('../opentracing/span') | undefined} */ (store.span) : null
14
16
 
15
17
  const span = this.startSpan(this.getOperationName(), {