dd-trace 5.109.0 → 5.110.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 (128) hide show
  1. package/ci/init.js +4 -3
  2. package/index.d.ts +66 -24
  3. package/loader-hook.mjs +88 -2
  4. package/package.json +18 -14
  5. package/packages/datadog-esbuild/index.js +26 -0
  6. package/packages/datadog-esbuild/src/utils.js +46 -3
  7. package/packages/datadog-instrumentations/src/connect.js +4 -3
  8. package/packages/datadog-instrumentations/src/fastify.js +4 -12
  9. package/packages/datadog-instrumentations/src/graphql.js +17 -6
  10. package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +81 -8
  11. package/packages/datadog-instrumentations/src/helpers/instrument.js +27 -2
  12. package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +65 -0
  13. package/packages/datadog-instrumentations/src/helpers/register.js +6 -4
  14. package/packages/datadog-instrumentations/src/helpers/require-optional-peer.js +17 -0
  15. package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +18 -2
  16. package/packages/datadog-instrumentations/src/koa.js +3 -2
  17. package/packages/datadog-instrumentations/src/mariadb.js +4 -2
  18. package/packages/datadog-instrumentations/src/mocha/main.js +3 -3
  19. package/packages/datadog-instrumentations/src/next.js +10 -10
  20. package/packages/datadog-instrumentations/src/otel-sdk-trace.js +7 -6
  21. package/packages/datadog-instrumentations/src/playwright.js +1 -1
  22. package/packages/datadog-instrumentations/src/restify.js +4 -3
  23. package/packages/datadog-instrumentations/src/router.js +18 -5
  24. package/packages/datadog-instrumentations/src/selenium.js +1 -2
  25. package/packages/datadog-instrumentations/src/tedious.js +28 -0
  26. package/packages/datadog-instrumentations/src/vitest.js +264 -7
  27. package/packages/datadog-plugin-avsc/src/schema_iterator.js +2 -2
  28. package/packages/datadog-plugin-aws-sdk/src/base.js +13 -9
  29. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +43 -6
  30. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +83 -91
  31. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +9 -1
  32. package/packages/datadog-plugin-http/src/client.js +8 -3
  33. package/packages/datadog-plugin-http2/src/client.js +5 -2
  34. package/packages/datadog-plugin-mysql/src/index.js +7 -2
  35. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +2 -2
  36. package/packages/datadog-plugin-undici/src/index.js +5 -2
  37. package/packages/datadog-plugin-vitest/src/index.js +7 -1
  38. package/packages/datadog-webpack/index.js +17 -1
  39. package/packages/datadog-webpack/src/optional-peer-loader.js +17 -0
  40. package/packages/dd-trace/src/aiguard/sdk.js +13 -1
  41. package/packages/dd-trace/src/appsec/api_security/index.js +55 -0
  42. package/packages/dd-trace/src/appsec/api_security/sampler.js +147 -0
  43. package/packages/dd-trace/src/appsec/index.js +10 -6
  44. package/packages/dd-trace/src/appsec/reporter.js +1 -0
  45. package/packages/dd-trace/src/appsec/telemetry/api_security.js +34 -0
  46. package/packages/dd-trace/src/appsec/telemetry/index.js +26 -0
  47. package/packages/dd-trace/src/ci-visibility/requests/request.js +1 -17
  48. package/packages/dd-trace/src/config/defaults.js +22 -3
  49. package/packages/dd-trace/src/config/generated-config-types.d.ts +535 -1
  50. package/packages/dd-trace/src/config/helper.js +133 -33
  51. package/packages/dd-trace/src/config/index.js +4 -1
  52. package/packages/dd-trace/src/config/parsers.js +19 -1
  53. package/packages/dd-trace/src/config/supported-configurations.json +21 -3
  54. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +47 -35
  55. package/packages/dd-trace/src/debugger/devtools_client/index.js +31 -66
  56. package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +83 -0
  57. package/packages/dd-trace/src/debugger/devtools_client/state.js +1 -0
  58. package/packages/dd-trace/src/debugger/index.js +5 -0
  59. package/packages/dd-trace/src/debugger/probe_sampler.js +112 -0
  60. package/packages/dd-trace/src/debugger/probe_sampler_constants.js +19 -0
  61. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +77 -26
  62. package/packages/dd-trace/src/exporters/common/request.js +1 -20
  63. package/packages/dd-trace/src/exporters/common/url.js +34 -0
  64. package/packages/dd-trace/src/exporters/span-stats/writer.js +1 -3
  65. package/packages/dd-trace/src/guardrails/index.js +8 -5
  66. package/packages/dd-trace/src/index.js +6 -4
  67. package/packages/dd-trace/src/llmobs/constants/tags.js +6 -0
  68. package/packages/dd-trace/src/llmobs/index.js +16 -5
  69. package/packages/dd-trace/src/llmobs/plugins/genai/util.js +3 -3
  70. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +5 -1
  71. package/packages/dd-trace/src/llmobs/sdk.js +5 -3
  72. package/packages/dd-trace/src/llmobs/span_processor.js +4 -0
  73. package/packages/dd-trace/src/llmobs/tagger.js +55 -0
  74. package/packages/dd-trace/src/llmobs/telemetry.js +1 -0
  75. package/packages/dd-trace/src/log/index.js +18 -20
  76. package/packages/dd-trace/src/openfeature/flagging_provider.js +2 -7
  77. package/packages/dd-trace/src/opentelemetry/bridge-span-base.js +5 -4
  78. package/packages/dd-trace/src/opentelemetry/metrics/instruments.js +2 -1
  79. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +4 -3
  80. package/packages/dd-trace/src/opentelemetry/metrics/time.js +19 -0
  81. package/packages/dd-trace/src/opentelemetry/otlp/common.proto +2 -2
  82. package/packages/dd-trace/src/opentelemetry/otlp/logs.proto +1 -1
  83. package/packages/dd-trace/src/opentelemetry/otlp/logs_service.proto +1 -1
  84. package/packages/dd-trace/src/opentelemetry/otlp/metrics.proto +1 -1
  85. package/packages/dd-trace/src/opentelemetry/otlp/metrics_service.proto +1 -1
  86. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +11 -4
  87. package/packages/dd-trace/src/opentelemetry/span-helpers.js +29 -13
  88. package/packages/dd-trace/src/opentelemetry/span.js +14 -3
  89. package/packages/dd-trace/src/opentelemetry/span_context.js +1 -0
  90. package/packages/dd-trace/src/opentelemetry/trace/index.js +2 -1
  91. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +3 -2
  92. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +26 -13
  93. package/packages/dd-trace/src/opentracing/propagation/text_map.js +3 -3
  94. package/packages/dd-trace/src/opentracing/span_context.js +17 -0
  95. package/packages/dd-trace/src/plugin_manager.js +7 -1
  96. package/packages/dd-trace/src/plugins/ci_plugin.js +9 -1
  97. package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +276 -0
  98. package/packages/dd-trace/src/plugins/util/test.js +80 -0
  99. package/packages/dd-trace/src/plugins/util/url.js +68 -1
  100. package/packages/dd-trace/src/plugins/util/web.js +19 -36
  101. package/packages/dd-trace/src/priority_sampler.js +1 -13
  102. package/packages/dd-trace/src/profiling/config.js +129 -198
  103. package/packages/dd-trace/src/profiling/constants.js +4 -7
  104. package/packages/dd-trace/src/profiling/exporter_cli.js +10 -10
  105. package/packages/dd-trace/src/profiling/exporters/agent.js +23 -16
  106. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +45 -14
  107. package/packages/dd-trace/src/profiling/exporters/file.js +16 -5
  108. package/packages/dd-trace/src/profiling/oom.js +71 -0
  109. package/packages/dd-trace/src/profiling/profiler.js +35 -23
  110. package/packages/dd-trace/src/profiling/profilers/events.js +14 -7
  111. package/packages/dd-trace/src/profiling/profilers/space.js +27 -18
  112. package/packages/dd-trace/src/profiling/profilers/wall.js +35 -25
  113. package/packages/dd-trace/src/ritm.js +4 -2
  114. package/packages/dd-trace/src/serverless.js +1 -2
  115. package/packages/dd-trace/src/service-naming/schemas/util.js +36 -5
  116. package/packages/dd-trace/src/service-naming/schemas/v1/web.js +5 -3
  117. package/packages/dd-trace/src/span_format.js +2 -1
  118. package/packages/dd-trace/src/span_processor.js +6 -0
  119. package/packages/dd-trace/src/telemetry/send-data.js +12 -10
  120. package/packages/dd-trace/src/tracer.js +15 -1
  121. package/packages/dd-trace/src/util.js +14 -0
  122. package/register.js +58 -1
  123. package/vendor/dist/@apm-js-collab/code-transformer/index.js +1 -1
  124. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  125. package/vendor/dist/pprof-format/index.js +1 -1
  126. package/vendor/dist/protobufjs/index.js +1 -1
  127. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  128. package/packages/dd-trace/src/appsec/api_security_sampler.js +0 -117
@@ -138,6 +138,8 @@ function getProvidedContext () {
138
138
  _ddTestManagementTests: testManagementTests,
139
139
  _ddIsFlakyTestRetriesEnabled: isFlakyTestRetriesEnabled,
140
140
  _ddFlakyTestRetriesCount: flakyTestRetriesCount,
141
+ _ddFlakyTestRetriesIncludesUnnamedProject: flakyTestRetriesIncludesUnnamedProject,
142
+ _ddFlakyTestRetriesProjectNames: flakyTestRetriesProjectNames,
141
143
  _ddIsImpactedTestsEnabled: isImpactedTestsEnabled,
142
144
  _ddModifiedFiles: modifiedFiles,
143
145
  _ddTestSessionId: testSessionId,
@@ -159,6 +161,8 @@ function getProvidedContext () {
159
161
  testManagementTests,
160
162
  isFlakyTestRetriesEnabled,
161
163
  flakyTestRetriesCount: flakyTestRetriesCount ?? 0,
164
+ flakyTestRetriesIncludesUnnamedProject,
165
+ flakyTestRetriesProjectNames,
162
166
  isImpactedTestsEnabled,
163
167
  modifiedFiles,
164
168
  testSessionId,
@@ -181,6 +185,8 @@ function getProvidedContext () {
181
185
  testManagementTests: {},
182
186
  isFlakyTestRetriesEnabled: false,
183
187
  flakyTestRetriesCount: 0,
188
+ flakyTestRetriesIncludesUnnamedProject: false,
189
+ flakyTestRetriesProjectNames: undefined,
184
190
  isImpactedTestsEnabled: false,
185
191
  modifiedFiles: {},
186
192
  testSessionId: undefined,
@@ -501,11 +507,13 @@ async function runMainProcessSetup (ctx, frameworkVersion, testSpecifications) {
501
507
  getTestManagementTests: () => getChannelPromise(testManagementTestsCh),
502
508
  })
503
509
 
504
- if (isFlakyTestRetriesEnabled && !ctx.config.retry && flakyTestRetriesCount > 0) {
505
- ctx.config.retry = flakyTestRetriesCount
510
+ const flakyTestRetriesConfiguration = configureFlakyTestRetries(ctx, testSpecifications)
511
+ if (flakyTestRetriesConfiguration) {
506
512
  setProvidedContext(ctx, {
507
513
  _ddIsFlakyTestRetriesEnabled: isFlakyTestRetriesEnabled,
508
514
  _ddFlakyTestRetriesCount: flakyTestRetriesCount,
515
+ _ddFlakyTestRetriesIncludesUnnamedProject: flakyTestRetriesConfiguration.includesUnnamedProject,
516
+ _ddFlakyTestRetriesProjectNames: flakyTestRetriesConfiguration.projectNames,
509
517
  }, 'Could not send library configuration to workers.')
510
518
  }
511
519
 
@@ -591,6 +599,242 @@ function ensureMainProcessSetup (ctx, frameworkVersion, testSpecifications) {
591
599
  return setupPromise
592
600
  }
593
601
 
602
+ /**
603
+ * Configure Vitest retries for the root project and resolved workspace projects.
604
+ *
605
+ * @param {object} ctx
606
+ * @param {unknown[]|undefined} testSpecifications
607
+ * @returns {{ projectNames: string[], includesUnnamedProject: boolean }|undefined}
608
+ */
609
+ function configureFlakyTestRetries (ctx, testSpecifications) {
610
+ if (!isFlakyTestRetriesEnabled || flakyTestRetriesCount <= 0) return
611
+
612
+ let configured = false
613
+ let includesUnnamedProject = false
614
+ const projectNames = []
615
+ for (const { config, projectName } of getVitestProjectConfigs(ctx, testSpecifications)) {
616
+ if (!config.retry) {
617
+ config.retry = flakyTestRetriesCount
618
+ configured = true
619
+ if (projectName) {
620
+ projectNames.push(projectName)
621
+ } else {
622
+ includesUnnamedProject = true
623
+ }
624
+ }
625
+ }
626
+
627
+ if (!configured) return
628
+
629
+ return {
630
+ includesUnnamedProject,
631
+ projectNames,
632
+ }
633
+ }
634
+
635
+ /**
636
+ * Return unique Vitest configs that can be used to run tests.
637
+ *
638
+ * @param {object} ctx
639
+ * @param {unknown[]|undefined} testSpecifications
640
+ * @returns {{ config: object, projectName?: string }[]}
641
+ */
642
+ function getVitestProjectConfigs (ctx, testSpecifications) {
643
+ const entries = []
644
+
645
+ addTestSpecificationConfigs(entries, testSpecifications)
646
+ if (entries.length > 0) {
647
+ return entries
648
+ }
649
+
650
+ const selectedProjectNames = getSelectedProjectNames()
651
+ addSelectedInlineProjectConfigs(entries, safeConfig(ctx), selectedProjectNames)
652
+ addSelectedRuntimeProjectConfigs(entries, ctx?.projects, selectedProjectNames)
653
+ if (entries.length > 0) {
654
+ return entries
655
+ }
656
+
657
+ if (Array.isArray(ctx?.projects)) {
658
+ for (const project of ctx.projects) {
659
+ addConfig(entries, safeConfig(project), getProjectName(project))
660
+ }
661
+ if (entries.length > 0) {
662
+ return entries
663
+ }
664
+ }
665
+
666
+ addConfig(entries, safeConfig(ctx))
667
+ addConfig(entries, safeConfig(safeWorkspaceProject(ctx)))
668
+
669
+ return entries
670
+ }
671
+
672
+ /**
673
+ * Add configs from runnable test specifications once.
674
+ *
675
+ * @param {{ config: object, projectName?: string }[]} entries
676
+ * @param {unknown[]|undefined} testSpecifications
677
+ */
678
+ function addTestSpecificationConfigs (entries, testSpecifications) {
679
+ if (!Array.isArray(testSpecifications)) return
680
+
681
+ for (const testSpecification of testSpecifications) {
682
+ const project = getTestSpecificationProject(testSpecification)
683
+ addConfig(entries, safeConfig(project), getProjectName(project))
684
+ }
685
+ }
686
+
687
+ /**
688
+ * Add selected inline project configs from the root Vitest config once.
689
+ *
690
+ * @param {{ config: object, projectName?: string }[]} entries
691
+ * @param {object|undefined} rootConfig
692
+ * @param {string[]} selectedProjectNames
693
+ */
694
+ function addSelectedInlineProjectConfigs (entries, rootConfig, selectedProjectNames) {
695
+ if (selectedProjectNames.length === 0 || !Array.isArray(rootConfig?.projects)) return
696
+
697
+ for (const project of rootConfig.projects) {
698
+ const config = getInlineProjectConfig(project)
699
+ const projectName = getProjectName(project)
700
+ if (selectedProjectNames.includes(projectName)) {
701
+ addConfig(entries, config, projectName)
702
+ }
703
+ }
704
+ }
705
+
706
+ /**
707
+ * Add selected resolved project configs once.
708
+ *
709
+ * @param {{ config: object, projectName?: string }[]} entries
710
+ * @param {unknown[]|undefined} projects
711
+ * @param {string[]} selectedProjectNames
712
+ */
713
+ function addSelectedRuntimeProjectConfigs (entries, projects, selectedProjectNames) {
714
+ if (selectedProjectNames.length === 0 || !Array.isArray(projects)) return
715
+
716
+ for (const project of projects) {
717
+ const projectName = getProjectName(project)
718
+ if (selectedProjectNames.includes(projectName)) {
719
+ addConfig(entries, safeConfig(project), projectName)
720
+ }
721
+ }
722
+ }
723
+
724
+ /**
725
+ * Return selected project names from the Vitest CLI arguments.
726
+ *
727
+ * @returns {string[]}
728
+ */
729
+ function getSelectedProjectNames () {
730
+ const names = []
731
+ for (let index = 0; index < process.argv.length; index++) {
732
+ const argument = process.argv[index]
733
+ if (argument === '--project' && process.argv[index + 1]) {
734
+ names.push(process.argv[index + 1])
735
+ index++
736
+ } else if (argument.startsWith('--project=')) {
737
+ names.push(argument.slice('--project='.length))
738
+ }
739
+ }
740
+ return names
741
+ }
742
+
743
+ /**
744
+ * Return the test config from an inline Vitest project entry.
745
+ *
746
+ * @param {unknown} project
747
+ * @returns {object|undefined}
748
+ */
749
+ function getInlineProjectConfig (project) {
750
+ return project?.test || project
751
+ }
752
+
753
+ /**
754
+ * Return a Vitest project name from runtime or inline project objects.
755
+ *
756
+ * @param {unknown} project
757
+ * @returns {string|undefined}
758
+ */
759
+ function getProjectName (project) {
760
+ return normalizeProjectName(project?.name || project?.config?.name || project?.test?.name)
761
+ }
762
+
763
+ /**
764
+ * Return a normalized Vitest project name.
765
+ *
766
+ * @param {unknown} name
767
+ * @returns {string|undefined}
768
+ */
769
+ function normalizeProjectName (name) {
770
+ if (typeof name === 'string') return name
771
+
772
+ const label = name?.label
773
+ return typeof label === 'string' ? label : undefined
774
+ }
775
+
776
+ /**
777
+ * Add a config object once.
778
+ *
779
+ * @param {{ config: object, projectName?: string }[]} entries
780
+ * @param {object|undefined} config
781
+ * @param {string|undefined} projectName
782
+ */
783
+ function addConfig (entries, config, projectName) {
784
+ if (config && !entries.some(entry => entry.config === config || (projectName && entry.projectName === projectName))) {
785
+ entries.push({ config, projectName })
786
+ }
787
+ }
788
+
789
+ /**
790
+ * Read a Vitest config object without assuming the project is initialized.
791
+ *
792
+ * @param {object|undefined} project
793
+ * @returns {object|undefined}
794
+ */
795
+ function safeConfig (project) {
796
+ let config
797
+ try {
798
+ config = project?.config
799
+ } catch {}
800
+ return config
801
+ }
802
+
803
+ /**
804
+ * Read the workspace project without assuming the root server is initialized.
805
+ *
806
+ * @param {object} ctx
807
+ * @returns {object|undefined}
808
+ */
809
+ function safeWorkspaceProject (ctx) {
810
+ let project
811
+ try {
812
+ project = getWorkspaceProject(ctx)
813
+ } catch {}
814
+ return project
815
+ }
816
+
817
+ /**
818
+ * Return whether Datadog configured ATR retries for a task.
819
+ *
820
+ * @param {object} providedContext
821
+ * @param {object} task
822
+ * @returns {boolean}
823
+ */
824
+ function isFlakyTestRetriesEnabledForTask (providedContext, task) {
825
+ if (!providedContext.isFlakyTestRetriesEnabled) return false
826
+
827
+ const { flakyTestRetriesProjectNames } = providedContext
828
+ if (!Array.isArray(flakyTestRetriesProjectNames)) return true
829
+
830
+ const projectName = task.file?.projectName
831
+ if (!projectName) {
832
+ return providedContext.flakyTestRetriesIncludesUnnamedProject === true
833
+ }
834
+
835
+ return flakyTestRetriesProjectNames.includes(projectName)
836
+ }
837
+
594
838
  function getSortWrapper (sort, frameworkVersion) {
595
839
  return async function () {
596
840
  await ensureMainProcessSetup(this.ctx, frameworkVersion, arguments[0])
@@ -669,8 +913,21 @@ function isThreadPool (pool) {
669
913
  return pool === 'threads' || pool === 'vmThreads'
670
914
  }
671
915
 
916
+ /**
917
+ * Return the project object attached to a Vitest test specification.
918
+ *
919
+ * @param {unknown} testSpecification
920
+ * @returns {object|undefined}
921
+ */
922
+ function getTestSpecificationProject (testSpecification) {
923
+ if (Array.isArray(testSpecification)) {
924
+ return testSpecification[0]
925
+ }
926
+ return testSpecification?.project
927
+ }
928
+
672
929
  function getTestSpecificationPool (testSpecification) {
673
- const project = Array.isArray(testSpecification) ? testSpecification[0] : testSpecification?.project
930
+ const project = getTestSpecificationProject(testSpecification)
674
931
  return project?.config?.pool || project?.serializedConfig?.pool || project?.pool || testSpecification?.pool
675
932
  }
676
933
 
@@ -995,15 +1252,15 @@ function wrapVitestTestRunner (VitestTestRunner) {
995
1252
  let isNew = false
996
1253
  let isQuarantined = false
997
1254
 
1255
+ const providedContext = getProvidedContext()
998
1256
  const {
999
1257
  isKnownTestsEnabled,
1000
1258
  isEarlyFlakeDetectionEnabled,
1001
1259
  isDiEnabled,
1002
1260
  isTestManagementTestsEnabled,
1003
1261
  testManagementTests,
1004
- isFlakyTestRetriesEnabled,
1005
1262
  slowTestRetries,
1006
- } = getProvidedContext()
1263
+ } = providedContext
1007
1264
 
1008
1265
  if (isKnownTestsEnabled) {
1009
1266
  isNew = newTasks.has(task)
@@ -1133,7 +1390,7 @@ function wrapVitestTestRunner (VitestTestRunner) {
1133
1390
  }
1134
1391
 
1135
1392
  const isRetryReasonAtr = numAttempt > 0 &&
1136
- isFlakyTestRetriesEnabled &&
1393
+ isFlakyTestRetriesEnabledForTask(providedContext, task) &&
1137
1394
  !isRetryReasonAttemptToFix &&
1138
1395
  !isRetryReasonEfd
1139
1396
 
@@ -1524,7 +1781,7 @@ addHook({
1524
1781
  }
1525
1782
 
1526
1783
  // ATR: set hasFailedAllRetries when all auto test retries were exhausted and every attempt failed
1527
- const isAtrRetry = providedContext.isFlakyTestRetriesEnabled && !attemptToFixTasks.has(task) &&
1784
+ const isAtrRetry = isFlakyTestRetriesEnabledForTask(providedContext, task) && !attemptToFixTasks.has(task) &&
1528
1785
  !newTasks.has(task) && !modifiedTasks.has(task)
1529
1786
  if (isAtrRetry) {
1530
1787
  const maxRetries = providedContext.flakyTestRetriesCount ?? 0
@@ -43,9 +43,9 @@ class SchemaExtractor {
43
43
  let type
44
44
  let format
45
45
  let enumValues
46
- let description
47
46
  let ref
48
47
 
48
+ const description = field.doc
49
49
  const fieldType = field.type?.types ?? field.type?.typeName ?? field.type
50
50
 
51
51
  if (Array.isArray(fieldType)) {
@@ -129,7 +129,7 @@ class SchemaExtractor {
129
129
  }
130
130
 
131
131
  iterateOverSchema (builder) {
132
- this.constructor.extractSchema(this.schema, builder, 0)
132
+ SchemaExtractor.extractSchema(this.schema, builder, 0)
133
133
  }
134
134
 
135
135
  static attachSchemaOnSpan (args, span, operation, tracer) {
@@ -108,7 +108,7 @@ class BaseAwsSdkPlugin extends ClientPlugin {
108
108
  const span = this.startSpan(this.operationFromRequest(request), {
109
109
  childOf,
110
110
  meta,
111
- service: this.serviceName(),
111
+ service: this.serviceName(request),
112
112
  integrationName: 'aws-sdk',
113
113
  }, ctx)
114
114
 
@@ -216,14 +216,18 @@ class BaseAwsSdkPlugin extends ClientPlugin {
216
216
  })
217
217
  }
218
218
 
219
- serviceName () {
220
- return this.config.service ||
221
- super.serviceName({
222
- id: 'aws',
223
- type: 'web',
224
- kind: 'client',
225
- awsService: this.serviceIdentifier,
226
- })
219
+ /**
220
+ * @param {{ params?: object }} request
221
+ */
222
+ serviceName (request) {
223
+ return super.serviceName({
224
+ id: 'aws',
225
+ type: 'web',
226
+ kind: 'client',
227
+ awsService: this.serviceIdentifier,
228
+ pluginConfig: this.config,
229
+ params: request.params,
230
+ })
227
231
  }
228
232
 
229
233
  isEnabled (request) {
@@ -2,6 +2,34 @@
2
2
  const log = require('../../../dd-trace/src/log')
3
3
  const BaseAwsSdkPlugin = require('../base')
4
4
 
5
+ // EventBridge enforces this limit over the whole PutEvents request (the sum of
6
+ // every entry), not over a single entry. 1 MiB == 1,048,576 bytes.
7
+ const MAX_PUT_EVENTS_BYTES = 1024 * 1024
8
+
9
+ /**
10
+ * Size a single `PutEventsRequestEntry` the way EventBridge does server-side:
11
+ * the UTF-8 byte length of `Source`, `DetailType`, `Detail`, and each
12
+ * `Resources` ARN, plus a flat 14 bytes when `Time` is set.
13
+ *
14
+ * @param {object} entry a single PutEvents request entry
15
+ * @param {string} [detail] overrides `entry.Detail`, used to size the entry as
16
+ * it would be sent with the injected `_datadog` context
17
+ * @returns {number}
18
+ * @see https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-putevents.html
19
+ */
20
+ function putEventEntrySize (entry, detail = entry.Detail) {
21
+ let size = entry.Time == null ? 0 : 14
22
+ if (entry.Source != null) size += Buffer.byteLength(entry.Source)
23
+ if (entry.DetailType != null) size += Buffer.byteLength(entry.DetailType)
24
+ if (detail != null) size += Buffer.byteLength(detail)
25
+ if (entry.Resources != null) {
26
+ for (const resource of entry.Resources) {
27
+ if (resource != null) size += Buffer.byteLength(resource)
28
+ }
29
+ }
30
+ return size
31
+ }
32
+
5
33
  class EventBridge extends BaseAwsSdkPlugin {
6
34
  static id = 'eventbridge'
7
35
  static isPayloadReporter = true
@@ -25,7 +53,8 @@ class EventBridge extends BaseAwsSdkPlugin {
25
53
  * Docs: https://docs.aws.amazon.com/eventbridge/latest/APIReference/API_PutEventsRequestEntry.html
26
54
  * We cannot use the traceHeader field as that's reserved for X-Ray.
27
55
  * Detail must be a valid JSON string
28
- * Max size per event is 256kb (https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-putevent-size.html)
56
+ * Max PutEvents request size is 1mb, summed over all entries
57
+ * (https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-putevent-size.html)
29
58
  */
30
59
  requestInject (span, request) {
31
60
  const operation = request.operation
@@ -34,6 +63,7 @@ class EventBridge extends BaseAwsSdkPlugin {
34
63
  request.params.Entries &&
35
64
  request.params.Entries.length > 0 &&
36
65
  request.params.Entries[0].Detail) {
66
+ const entries = request.params.Entries
37
67
  const injected = {}
38
68
  this.tracer.inject(span, 'text_map', injected)
39
69
 
@@ -42,19 +72,26 @@ class EventBridge extends BaseAwsSdkPlugin {
42
72
  // it so the rest of the body stays in V8's optimisable surface.
43
73
  let finalData
44
74
  try {
45
- finalData = BaseAwsSdkPlugin.injectFieldIntoJsonObject(
46
- request.params.Entries[0].Detail, '_datadog', injected
47
- )
75
+ finalData = BaseAwsSdkPlugin.injectFieldIntoJsonObject(entries[0].Detail, '_datadog', injected)
48
76
  } catch (error) {
49
77
  log.error('EventBridge error injecting request', error)
50
78
  return
51
79
  }
52
80
 
53
- if (Buffer.byteLength(finalData) >= 1024 * 256) {
81
+ // EventBridge applies the 1 MiB cap to the whole request, so size every
82
+ // entry as it would be sent (the first with `_datadog` injected) and skip
83
+ // rather than tip a request AWS would otherwise accept over the limit. The
84
+ // running total only needs to clear the cap, so stop summing the moment it
85
+ // does instead of byte-counting the rest of a batch we already know is over.
86
+ let requestSize = putEventEntrySize(entries[0], finalData)
87
+ for (let i = 1; requestSize < MAX_PUT_EVENTS_BYTES && i < entries.length; i++) {
88
+ requestSize += putEventEntrySize(entries[i])
89
+ }
90
+ if (requestSize >= MAX_PUT_EVENTS_BYTES) {
54
91
  log.info('Payload size too large to pass context')
55
92
  return
56
93
  }
57
- request.params.Entries[0].Detail = finalData
94
+ entries[0].Detail = finalData
58
95
  }
59
96
  }
60
97
  }