dd-trace 6.9.0 → 6.10.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 (59) hide show
  1. package/ci/vitest-no-worker-init-setup.mjs +112 -10
  2. package/index.d.ts +42 -0
  3. package/package.json +4 -3
  4. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +111 -6
  5. package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +629 -0
  6. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -1
  7. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +81 -0
  8. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +1 -0
  9. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +83 -1
  10. package/packages/datadog-instrumentations/src/jest.js +1 -1
  11. package/packages/datadog-instrumentations/src/mocha/main.js +1 -1
  12. package/packages/datadog-instrumentations/src/mocha/utils.js +2 -8
  13. package/packages/datadog-instrumentations/src/mysql.js +45 -15
  14. package/packages/datadog-instrumentations/src/mysql2.js +119 -18
  15. package/packages/datadog-instrumentations/src/path-to-regexp.js +67 -1
  16. package/packages/datadog-instrumentations/src/pg.js +116 -92
  17. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +43 -4
  18. package/packages/datadog-instrumentations/src/vitest-main.js +169 -17
  19. package/packages/datadog-instrumentations/src/vitest-util.js +64 -5
  20. package/packages/datadog-instrumentations/src/vitest-worker.js +150 -25
  21. package/packages/datadog-instrumentations/src/webdriverio.js +31 -17
  22. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +12 -6
  23. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -5
  24. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -5
  25. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +1 -1
  26. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +31 -17
  27. package/packages/datadog-plugin-jest/src/index.js +5 -4
  28. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +2 -3
  29. package/packages/datadog-plugin-kafkajs/src/consumer.js +2 -3
  30. package/packages/datadog-plugin-kafkajs/src/producer.js +3 -2
  31. package/packages/datadog-plugin-kafkajs/src/utils.js +65 -7
  32. package/packages/datadog-plugin-mocha/src/index.js +550 -39
  33. package/packages/datadog-plugin-mysql/src/index.js +37 -0
  34. package/packages/datadog-plugin-next/src/index.js +1 -19
  35. package/packages/datadog-plugin-openai-agents/src/integration.js +278 -69
  36. package/packages/datadog-plugin-openai-agents/src/processor.js +16 -4
  37. package/packages/datadog-plugin-pg/src/index.js +1 -0
  38. package/packages/datadog-plugin-vitest/src/index.js +8 -20
  39. package/packages/datadog-plugin-ws/src/util.js +2 -1
  40. package/packages/dd-trace/src/appsec/api_security/normalized-route.js +453 -0
  41. package/packages/dd-trace/src/appsec/handlers/http-request.js +13 -0
  42. package/packages/dd-trace/src/carrier.js +356 -0
  43. package/packages/dd-trace/src/config/generated-config-types.d.ts +3 -0
  44. package/packages/dd-trace/src/config/supported-configurations.json +10 -0
  45. package/packages/dd-trace/src/datastreams/context.js +6 -1
  46. package/packages/dd-trace/src/datastreams/manager.js +5 -1
  47. package/packages/dd-trace/src/datastreams/pathway.js +23 -22
  48. package/packages/dd-trace/src/datastreams/processor.js +3 -2
  49. package/packages/dd-trace/src/llmobs/constants/tags.js +5 -0
  50. package/packages/dd-trace/src/llmobs/index.js +34 -2
  51. package/packages/dd-trace/src/llmobs/span_processor.js +16 -0
  52. package/packages/dd-trace/src/llmobs/tagger.js +96 -0
  53. package/packages/dd-trace/src/llmobs/util.js +78 -0
  54. package/packages/dd-trace/src/opentracing/propagation/text_map.js +126 -120
  55. package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +4 -8
  56. package/packages/dd-trace/src/plugin_manager.js +2 -0
  57. package/packages/{datadog-plugin-jest/src/util.js → dd-trace/src/plugins/util/jest.js} +1 -62
  58. package/packages/dd-trace/src/plugins/util/test.js +84 -5
  59. package/packages/dd-trace/src/plugins/util/web.js +53 -2
@@ -8,17 +8,18 @@ const { getLageTestSessionName } = require('../../ci-visibility/lage')
8
8
  const log = require('../../log')
9
9
  const { getEnvironmentVariable, getValueFromEnvSources } = require('../../config/helper')
10
10
  const { getSegment } = require('../../util')
11
+ const { parse } = require('../../../../../vendor/dist/jest-docblock')
11
12
  const satisfies = require('../../../../../vendor/dist/semifies')
12
13
 
13
14
  const istanbul = require('../../../../../vendor/dist/istanbul-lib-coverage')
14
15
 
16
+ const { writeDatadogParentId, writeDatadogTraceId } = require('../../carrier')
15
17
  const id = require('../../id')
16
18
  const {
17
19
  incrementCountMetric,
18
20
  TELEMETRY_GIT_COMMIT_SHA_DISCREPANCY,
19
21
  TELEMETRY_GIT_SHA_MATCH,
20
22
  } = require('../../ci-visibility/telemetry')
21
-
22
23
  const { SPAN_TYPE, RESOURCE_NAME, SAMPLING_PRIORITY } = require('../../../../../ext/tags')
23
24
  const { SAMPLING_RULE_DECISION } = require('../../constants')
24
25
  const { AUTO_KEEP } = require('../../../../../ext/priority')
@@ -195,6 +196,8 @@ const VITEST_WORKER_TRACE_PAYLOAD_CODE = 100
195
196
  const VITEST_WORKER_COVERAGE_PAYLOAD_CODE = 101
196
197
  const VITEST_WORKER_LOGS_PAYLOAD_CODE = 102
197
198
  const VITEST_WORKER_TELEMETRY_PAYLOAD_CODE = 103
199
+ const VITEST_WORKER_EFD_SUITE_ADMISSION_REQUEST_CODE = 104
200
+ const VITEST_WORKER_EFD_SUITE_ADMISSION_RESPONSE_CODE = 105
198
201
 
199
202
  const TEST_IS_TEST_FRAMEWORK_WORKER = 'test.is_test_framework_worker'
200
203
 
@@ -489,6 +492,8 @@ module.exports = {
489
492
  VITEST_WORKER_COVERAGE_PAYLOAD_CODE,
490
493
  VITEST_WORKER_LOGS_PAYLOAD_CODE,
491
494
  VITEST_WORKER_TELEMETRY_PAYLOAD_CODE,
495
+ VITEST_WORKER_EFD_SUITE_ADMISSION_REQUEST_CODE,
496
+ VITEST_WORKER_EFD_SUITE_ADMISSION_RESPONSE_CODE,
492
497
  TEST_IS_TEST_FRAMEWORK_WORKER,
493
498
  TEST_SOURCE_START,
494
499
  TEST_SKIPPED_BY_ITR,
@@ -504,6 +509,7 @@ module.exports = {
504
509
  getTestParametersString,
505
510
  finishAllTraceSpans,
506
511
  getTestParentSpan,
512
+ isMarkedAsUnskippable,
507
513
  getTestSuitePath,
508
514
  getCodeOwnersFileEntries,
509
515
  getCodeOwnersForFilename,
@@ -544,6 +550,7 @@ module.exports = {
544
550
  removeInvalidMetadata,
545
551
  parseAnnotations,
546
552
  getIsFaultyEarlyFlakeDetection,
553
+ getFailedTestReplayPromise,
547
554
  TEST_BROWSER_DRIVER,
548
555
  TEST_BROWSER_DRIVER_VERSION,
549
556
  TEST_BROWSER_NAME,
@@ -901,10 +908,10 @@ function setRumTestCorrelation (context, activeSpan) {
901
908
  * @returns {import('../../opentracing/span_context')}
902
909
  */
903
910
  function getTestParentSpan (tracer, testExecutionId) {
904
- return tracer.extract('text_map', {
905
- 'x-datadog-trace-id': testExecutionId || id().toString(10),
906
- 'x-datadog-parent-id': '0000000000000000',
907
- })
911
+ const carrier = /** @type {Record<string, unknown>} */ ({})
912
+ writeDatadogTraceId(carrier, testExecutionId || id().toString(10))
913
+ writeDatadogParentId(carrier, '0000000000000000')
914
+ return tracer.extract('text_map', carrier)
908
915
  }
909
916
 
910
917
  function getTestCommonTags (name, suite, version, testFramework) {
@@ -941,6 +948,62 @@ function getTestSuitePath (testSuiteAbsolutePath, sourceRoot) {
941
948
  return testSuitePath.replaceAll(path.sep, '/')
942
949
  }
943
950
 
951
+ const globalDocblockRegExp = /^\s*(\/\*\*?(.|\r?\n)*?\*\/)/
952
+ const MAX_COMMENTS_CHECKED = 10
953
+
954
+ function isMarkedAsUnskippable (test) {
955
+ let testSource
956
+
957
+ try {
958
+ testSource = fs.readFileSync(test.path, 'utf8')
959
+ } catch {
960
+ return false
961
+ }
962
+
963
+ const re = globalDocblockRegExp
964
+ re.lastIndex = 0
965
+ let commentsChecked = 0
966
+
967
+ while (testSource.length) {
968
+ const match = re.exec(testSource)
969
+ if (!match) break
970
+ const comment = match[1]
971
+
972
+ let docblocks
973
+ try {
974
+ docblocks = parse(comment)
975
+ } catch {
976
+ // Skip unparsable comment and continue scanning
977
+ if (commentsChecked++ >= MAX_COMMENTS_CHECKED) {
978
+ return false
979
+ }
980
+ continue
981
+ }
982
+
983
+ if (docblocks?.datadog) {
984
+ try {
985
+ // @ts-expect-error The datadog type is defined by us and may only be a string.
986
+ return JSON.parse(docblocks.datadog).unskippable
987
+ } catch {
988
+ // If the @datadog block comment is present but malformed, we'll run the suite
989
+ log.warn('@datadog block comment is malformed.')
990
+ return true
991
+ }
992
+ }
993
+
994
+ if (commentsChecked++ >= MAX_COMMENTS_CHECKED) {
995
+ return false
996
+ }
997
+
998
+ // To stop as soon as no doc blocks are found, slice the source. That way the
999
+ // regexp works by using the `^` anchor. Without it, it would continue
1000
+ // scanning the rest of the file.
1001
+ testSource = testSource.slice(match[0].length)
1002
+ }
1003
+
1004
+ return false
1005
+ }
1006
+
944
1007
  const POSSIBLE_CODEOWNERS_LOCATIONS = [
945
1008
  'CODEOWNERS',
946
1009
  '.github/CODEOWNERS',
@@ -1542,6 +1605,22 @@ function parseAnnotations (annotations) {
1542
1605
  }, {})
1543
1606
  }
1544
1607
 
1608
+ /**
1609
+ * Combines the optional Failed Test Replay operations that must settle before a retry.
1610
+ *
1611
+ * @param {{setProbePromise?: Promise<void>, finishTestPromise?: Promise<void>}} promises
1612
+ * @returns {Promise<void>|undefined}
1613
+ */
1614
+ function getFailedTestReplayPromise (promises) {
1615
+ if (promises.setProbePromise && promises.finishTestPromise) {
1616
+ return Promise.all([
1617
+ promises.setProbePromise,
1618
+ promises.finishTestPromise,
1619
+ ]).then(() => {})
1620
+ }
1621
+ return promises.setProbePromise || promises.finishTestPromise
1622
+ }
1623
+
1545
1624
  function getIsFaultyEarlyFlakeDetection (projectSuites, testsBySuiteName, faultyThresholdPercentage) {
1546
1625
  let newSuites = 0
1547
1626
  for (const suite of projectSuites) {
@@ -35,6 +35,11 @@ const MANUAL_DROP = tags.MANUAL_DROP
35
35
 
36
36
  const contexts = new WeakMap()
37
37
  const requests = new WeakMap()
38
+ const statusCodeRangesPattern = /^[1-5]\d{2}(?:-[1-5]\d{2})?(?:,[1-5]\d{2}(?:-[1-5]\d{2})?)*$/
39
+ const whitespacePattern = /\s/g
40
+ const MAX_HTTP_STATUS_CODE = 599
41
+
42
+ /** @typedef {(code: number) => boolean} StatusValidator */
38
43
 
39
44
  // TODO: change this to no longer rely on creating a dummy plugin to be able to access startSpan
40
45
  function createWebPlugin (tracer, config = {}) {
@@ -559,13 +564,59 @@ function isNot500ErrorCode (code) {
559
564
  return code < 500
560
565
  }
561
566
 
567
+ /**
568
+ * @param {{ validateStatus?: unknown, DD_TRACE_HTTP_SERVER_ERROR_STATUSES?: unknown }} config
569
+ * @returns {StatusValidator}
570
+ */
562
571
  function getStatusValidator (config) {
563
572
  if (typeof config.validateStatus === 'function') {
564
- return config.validateStatus
573
+ return /** @type {StatusValidator} */ (config.validateStatus)
565
574
  } else if (config.hasOwnProperty('validateStatus')) {
566
575
  log.error('Expected `validateStatus` to be a function.')
567
576
  }
568
- return isNot500ErrorCode
577
+
578
+ const { DD_TRACE_HTTP_SERVER_ERROR_STATUSES } = config
579
+ if (DD_TRACE_HTTP_SERVER_ERROR_STATUSES === undefined) return isNot500ErrorCode
580
+ if (typeof DD_TRACE_HTTP_SERVER_ERROR_STATUSES !== 'string') {
581
+ log.error('Expected `DD_TRACE_HTTP_SERVER_ERROR_STATUSES` to be a string.')
582
+ return isNot500ErrorCode
583
+ }
584
+ if (DD_TRACE_HTTP_SERVER_ERROR_STATUSES === '500-599') return isNot500ErrorCode
585
+
586
+ const normalized = DD_TRACE_HTTP_SERVER_ERROR_STATUSES.replaceAll(whitespacePattern, '')
587
+ if (normalized === '500-599') return isNot500ErrorCode
588
+ if (!statusCodeRangesPattern.test(normalized)) {
589
+ log.error(
590
+ '`DD_TRACE_HTTP_SERVER_ERROR_STATUSES` must contain comma-separated status codes or ranges from 100 to 599.'
591
+ )
592
+ return isNot500ErrorCode
593
+ }
594
+
595
+ const errorStatusCodes = new Uint8Array(MAX_HTTP_STATUS_CODE + 1)
596
+ const ranges = normalized.split(',')
597
+ for (const range of ranges) {
598
+ const separator = range.indexOf('-')
599
+ if (separator === -1) {
600
+ errorStatusCodes[Number(range)] = 1
601
+ continue
602
+ }
603
+
604
+ const first = Number(range.slice(0, separator))
605
+ const second = Number(range.slice(separator + 1))
606
+ const start = Math.min(first, second)
607
+ const end = Math.max(first, second)
608
+ errorStatusCodes.fill(1, start, end + 1)
609
+ }
610
+
611
+ /**
612
+ * @param {number} code
613
+ * @returns {boolean}
614
+ */
615
+ function isValidStatusCode (code) {
616
+ return errorStatusCodes[code] !== 1
617
+ }
618
+
619
+ return isValidStatusCode
569
620
  }
570
621
 
571
622
  const noop = () => {}