dd-trace 5.7.0 → 5.9.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 (116) hide show
  1. package/LICENSE-3rdparty.csv +0 -1
  2. package/ci/init.js +3 -3
  3. package/index.d.ts +35 -0
  4. package/package.json +4 -5
  5. package/packages/datadog-esbuild/index.js +2 -2
  6. package/packages/datadog-instrumentations/src/apollo-server.js +1 -1
  7. package/packages/datadog-instrumentations/src/apollo.js +103 -0
  8. package/packages/datadog-instrumentations/src/aws-sdk.js +4 -1
  9. package/packages/datadog-instrumentations/src/cassandra-driver.js +1 -1
  10. package/packages/datadog-instrumentations/src/cucumber.js +6 -2
  11. package/packages/datadog-instrumentations/src/fs.js +0 -1
  12. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +1 -1
  13. package/packages/datadog-instrumentations/src/helpers/hooks.js +57 -56
  14. package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -2
  15. package/packages/datadog-instrumentations/src/http/client.js +1 -0
  16. package/packages/datadog-instrumentations/src/jest.js +12 -13
  17. package/packages/datadog-instrumentations/src/kafkajs.js +2 -1
  18. package/packages/datadog-instrumentations/src/ldapjs.js +2 -1
  19. package/packages/datadog-instrumentations/src/mocha.js +1 -1
  20. package/packages/datadog-instrumentations/src/mongodb-core.js +4 -6
  21. package/packages/datadog-instrumentations/src/net.js +1 -1
  22. package/packages/datadog-instrumentations/src/passport-utils.js +1 -0
  23. package/packages/datadog-instrumentations/src/playwright.js +158 -7
  24. package/packages/datadog-instrumentations/src/rhea.js +5 -2
  25. package/packages/datadog-instrumentations/src/tedious.js +1 -1
  26. package/packages/datadog-plugin-apollo/src/gateway/execute.js +12 -0
  27. package/packages/datadog-plugin-apollo/src/gateway/fetch.js +36 -0
  28. package/packages/datadog-plugin-apollo/src/gateway/index.js +36 -0
  29. package/packages/datadog-plugin-apollo/src/gateway/plan.js +12 -0
  30. package/packages/datadog-plugin-apollo/src/gateway/postprocessing.js +12 -0
  31. package/packages/datadog-plugin-apollo/src/gateway/request.js +124 -0
  32. package/packages/datadog-plugin-apollo/src/gateway/validate.js +25 -0
  33. package/packages/datadog-plugin-apollo/src/index.js +15 -0
  34. package/packages/datadog-plugin-aws-sdk/src/base.js +3 -3
  35. package/packages/datadog-plugin-aws-sdk/src/services/cloudwatchlogs.js +1 -1
  36. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +2 -2
  37. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -1
  38. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -1
  39. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +1 -1
  40. package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +1 -1
  41. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +1 -1
  42. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -1
  43. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -2
  44. package/packages/datadog-plugin-child_process/src/index.js +1 -1
  45. package/packages/datadog-plugin-couchbase/src/index.js +2 -1
  46. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +1 -0
  47. package/packages/datadog-plugin-fetch/src/index.js +1 -1
  48. package/packages/datadog-plugin-graphql/src/resolve.js +1 -1
  49. package/packages/datadog-plugin-grpc/src/client.js +2 -2
  50. package/packages/datadog-plugin-grpc/src/server.js +2 -2
  51. package/packages/datadog-plugin-http/src/client.js +2 -2
  52. package/packages/datadog-plugin-http2/src/client.js +4 -3
  53. package/packages/datadog-plugin-jest/src/index.js +1 -0
  54. package/packages/datadog-plugin-kafkajs/src/consumer.js +1 -1
  55. package/packages/datadog-plugin-kafkajs/src/producer.js +1 -1
  56. package/packages/datadog-plugin-next/src/index.js +1 -1
  57. package/packages/datadog-plugin-openai/src/index.js +4 -4
  58. package/packages/datadog-plugin-playwright/src/index.js +16 -3
  59. package/packages/datadog-plugin-rhea/src/consumer.js +1 -1
  60. package/packages/datadog-plugin-rhea/src/producer.js +1 -1
  61. package/packages/datadog-plugin-router/src/index.js +1 -1
  62. package/packages/datadog-plugin-tedious/src/index.js +1 -1
  63. package/packages/dd-trace/src/appsec/blocking.js +1 -1
  64. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +17 -17
  65. package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +1 -0
  66. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +132 -132
  67. package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +1 -0
  68. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +1 -1
  69. package/packages/dd-trace/src/appsec/iast/overhead-controller.js +2 -1
  70. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +3 -3
  71. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +4 -4
  72. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -1
  73. package/packages/dd-trace/src/appsec/iast/telemetry/namespaces.js +27 -18
  74. package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +1 -1
  75. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +1 -1
  76. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +7 -4
  77. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +2 -2
  78. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +0 -1
  79. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -1
  80. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +1 -0
  81. package/packages/dd-trace/src/config.js +13 -13
  82. package/packages/dd-trace/src/datastreams/pathway.js +1 -1
  83. package/packages/dd-trace/src/datastreams/processor.js +15 -15
  84. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +2 -2
  85. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +1 -1
  86. package/packages/dd-trace/src/exporters/common/request.js +1 -0
  87. package/packages/dd-trace/src/exporters/span-stats/writer.js +0 -1
  88. package/packages/dd-trace/src/external-logger/src/index.js +5 -5
  89. package/packages/dd-trace/src/opentelemetry/span.js +2 -0
  90. package/packages/dd-trace/src/opentracing/propagation/text_map.js +1 -1
  91. package/packages/dd-trace/src/opentracing/span.js +1 -1
  92. package/packages/dd-trace/src/plugin_manager.js +1 -2
  93. package/packages/dd-trace/src/plugins/apollo.js +52 -0
  94. package/packages/dd-trace/src/plugins/ci_plugin.js +2 -1
  95. package/packages/dd-trace/src/plugins/composite.js +4 -4
  96. package/packages/dd-trace/src/plugins/database.js +1 -0
  97. package/packages/dd-trace/src/plugins/index.js +44 -43
  98. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  99. package/packages/dd-trace/src/plugins/tracing.js +9 -6
  100. package/packages/dd-trace/src/plugins/util/test.js +2 -1
  101. package/packages/dd-trace/src/plugins/util/web.js +4 -4
  102. package/packages/dd-trace/src/profiling/config.js +1 -1
  103. package/packages/dd-trace/src/profiling/loggers/console.js +1 -1
  104. package/packages/dd-trace/src/profiling/profilers/events.js +79 -82
  105. package/packages/dd-trace/src/proxy.js +2 -0
  106. package/packages/dd-trace/src/runtime_metrics.js +8 -5
  107. package/packages/dd-trace/src/serverless.js +3 -2
  108. package/packages/dd-trace/src/service-naming/schemas/v0/web.js +24 -0
  109. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +0 -1
  110. package/packages/dd-trace/src/service-naming/schemas/v1/web.js +24 -0
  111. package/packages/dd-trace/src/span_processor.js +2 -2
  112. package/packages/dd-trace/src/span_stats.js +1 -1
  113. package/packages/dd-trace/src/telemetry/dependencies.js +4 -5
  114. package/packages/dd-trace/src/telemetry/index.js +12 -13
  115. package/packages/dd-trace/src/telemetry/send-data.js +0 -1
  116. package/packages/dd-trace/src/util.js +7 -7
@@ -15,7 +15,7 @@ const startTCPCh = channel('apm:net:tcp:start')
15
15
  const finishTCPCh = channel('apm:net:tcp:finish')
16
16
  const errorTCPCh = channel('apm:net:tcp:error')
17
17
 
18
- const connectionCh = channel(`apm:net:tcp:connection`)
18
+ const connectionCh = channel('apm:net:tcp:connection')
19
19
 
20
20
  const names = ['net', 'node:net']
21
21
 
@@ -10,6 +10,7 @@ function wrapVerifiedAndPublish (username, password, verified, type) {
10
10
  return verified
11
11
  }
12
12
 
13
+ // eslint-disable-next-line n/handle-callback-err
13
14
  return shimmer.wrap(verified, function (err, user, info) {
14
15
  const credentials = { type, username }
15
16
  passportVerifyChannel.publish({ credentials, user })
@@ -1,6 +1,9 @@
1
+ const semver = require('semver')
2
+
1
3
  const { addHook, channel, AsyncResource } = require('./helpers/instrument')
2
4
  const shimmer = require('../../datadog-shimmer')
3
- const { parseAnnotations } = require('../../dd-trace/src/plugins/util/test')
5
+ const { parseAnnotations, getTestSuitePath } = require('../../dd-trace/src/plugins/util/test')
6
+ const log = require('../../dd-trace/src/log')
4
7
 
5
8
  const testStartCh = channel('ci:playwright:test:start')
6
9
  const testFinishCh = channel('ci:playwright:test:finish')
@@ -8,6 +11,9 @@ const testFinishCh = channel('ci:playwright:test:finish')
8
11
  const testSessionStartCh = channel('ci:playwright:session:start')
9
12
  const testSessionFinishCh = channel('ci:playwright:session:finish')
10
13
 
14
+ const libraryConfigurationCh = channel('ci:playwright:library-configuration')
15
+ const knownTestsCh = channel('ci:playwright:known-tests')
16
+
11
17
  const testSuiteStartCh = channel('ci:playwright:test-suite:start')
12
18
  const testSuiteFinishCh = channel('ci:playwright:test-suite:finish')
13
19
 
@@ -16,6 +22,8 @@ const testSuiteToAr = new Map()
16
22
  const testSuiteToTestStatuses = new Map()
17
23
  const testSuiteToErrors = new Map()
18
24
 
25
+ let applyRepeatEachIndex = null
26
+
19
27
  let startedSuites = []
20
28
 
21
29
  const STATUS_TO_TEST_STATUS = {
@@ -26,6 +34,44 @@ const STATUS_TO_TEST_STATUS = {
26
34
  }
27
35
 
28
36
  let remainingTestsByFile = {}
37
+ let isEarlyFlakeDetectionEnabled = false
38
+ let earlyFlakeDetectionNumRetries = 0
39
+ let knownTests = {}
40
+ let rootDir = ''
41
+ const MINIMUM_SUPPORTED_VERSION_EFD = '1.38.0'
42
+
43
+ function isNewTest (test) {
44
+ const testSuite = getTestSuitePath(test._requireFile, rootDir)
45
+ const testsForSuite = knownTests?.playwright?.[testSuite] || []
46
+
47
+ return !testsForSuite.includes(test.title)
48
+ }
49
+
50
+ function getSuiteType (test, type) {
51
+ let suite = test.parent
52
+ while (suite && suite._type !== type) {
53
+ suite = suite.parent
54
+ }
55
+ return suite
56
+ }
57
+
58
+ // Copy of Suite#_deepClone but with a function to filter tests
59
+ function deepCloneSuite (suite, filterTest) {
60
+ const copy = suite._clone()
61
+ for (const entry of suite._entries) {
62
+ if (entry.constructor.name === 'Suite') {
63
+ copy._addSuite(deepCloneSuite(entry, filterTest))
64
+ } else {
65
+ if (filterTest(entry)) {
66
+ const copiedTest = entry._clone()
67
+ copiedTest._ddIsNew = true
68
+ copiedTest._ddIsEfdRetry = true
69
+ copy._addTest(copiedTest)
70
+ }
71
+ }
72
+ }
73
+ return copy
74
+ }
29
75
 
30
76
  function getTestsBySuiteFromTestGroups (testGroups) {
31
77
  return testGroups.reduce((acc, { requireFile, tests }) => {
@@ -153,8 +199,11 @@ function getTestSuiteError (testSuiteAbsolutePath) {
153
199
  function testBeginHandler (test, browserName) {
154
200
  const {
155
201
  _requireFile: testSuiteAbsolutePath,
156
- title: testName, _type,
157
- location: { line: testSourceLine }
202
+ title: testName,
203
+ _type,
204
+ location: {
205
+ line: testSourceLine
206
+ }
158
207
  } = test
159
208
 
160
209
  if (_type === 'beforeAll' || _type === 'afterAll') {
@@ -198,7 +247,14 @@ function testEndHandler (test, annotations, testStatus, error, isTimeout) {
198
247
  const testResult = results[results.length - 1]
199
248
  const testAsyncResource = testToAr.get(test)
200
249
  testAsyncResource.runInAsyncScope(() => {
201
- testFinishCh.publish({ testStatus, steps: testResult.steps, error, extraTags: annotationTags })
250
+ testFinishCh.publish({
251
+ testStatus,
252
+ steps: testResult.steps,
253
+ error,
254
+ extraTags: annotationTags,
255
+ isNew: test._ddIsNew,
256
+ isEfdRetry: test._ddIsEfdRetry
257
+ })
202
258
  })
203
259
 
204
260
  if (testSuiteToTestStatuses.has(testSuiteAbsolutePath)) {
@@ -309,14 +365,56 @@ function dispatcherHookNew (dispatcherExport, runWrapper) {
309
365
 
310
366
  function runnerHook (runnerExport, playwrightVersion) {
311
367
  shimmer.wrap(runnerExport.Runner.prototype, 'runAllTests', runAllTests => async function () {
368
+ let onDone
369
+
312
370
  const testSessionAsyncResource = new AsyncResource('bound-anonymous-fn')
313
- const rootDir = getRootDir(this)
371
+
372
+ rootDir = getRootDir(this)
314
373
 
315
374
  const processArgv = process.argv.slice(2).join(' ')
316
375
  const command = `playwright ${processArgv}`
317
376
  testSessionAsyncResource.runInAsyncScope(() => {
318
377
  testSessionStartCh.publish({ command, frameworkVersion: playwrightVersion, rootDir })
319
378
  })
379
+
380
+ const configurationPromise = new Promise((resolve) => {
381
+ onDone = resolve
382
+ })
383
+
384
+ testSessionAsyncResource.runInAsyncScope(() => {
385
+ libraryConfigurationCh.publish({ onDone })
386
+ })
387
+
388
+ try {
389
+ const { err, libraryConfig } = await configurationPromise
390
+ if (!err) {
391
+ isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
392
+ earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
393
+ }
394
+ } catch (e) {
395
+ log.error(e)
396
+ }
397
+
398
+ if (isEarlyFlakeDetectionEnabled && semver.gte(playwrightVersion, MINIMUM_SUPPORTED_VERSION_EFD)) {
399
+ const knownTestsPromise = new Promise((resolve) => {
400
+ onDone = resolve
401
+ })
402
+ testSessionAsyncResource.runInAsyncScope(() => {
403
+ knownTestsCh.publish({ onDone })
404
+ })
405
+
406
+ try {
407
+ const { err, knownTests: receivedKnownTests } = await knownTestsPromise
408
+ if (!err) {
409
+ knownTests = receivedKnownTests
410
+ } else {
411
+ isEarlyFlakeDetectionEnabled = false
412
+ }
413
+ } catch (err) {
414
+ log.error(err)
415
+ }
416
+ }
417
+
320
418
  const projects = getProjectsFromRunner(this)
321
419
 
322
420
  const runAllTestsReturn = await runAllTests.apply(this, arguments)
@@ -334,12 +432,15 @@ function runnerHook (runnerExport, playwrightVersion) {
334
432
 
335
433
  const sessionStatus = runAllTestsReturn.status || runAllTestsReturn
336
434
 
337
- let onDone
338
435
  const flushWait = new Promise(resolve => {
339
436
  onDone = resolve
340
437
  })
341
438
  testSessionAsyncResource.runInAsyncScope(() => {
342
- testSessionFinishCh.publish({ status: STATUS_TO_TEST_STATUS[sessionStatus], onDone })
439
+ testSessionFinishCh.publish({
440
+ status: STATUS_TO_TEST_STATUS[sessionStatus],
441
+ isEarlyFlakeDetectionEnabled,
442
+ onDone
443
+ })
343
444
  })
344
445
  await flushWait
345
446
 
@@ -394,3 +495,53 @@ addHook({
394
495
  file: 'lib/runner/dispatcher.js',
395
496
  versions: ['>=1.38.0']
396
497
  }, (dispatcher) => dispatcherHookNew(dispatcher, dispatcherRunWrapperNew))
498
+
499
+ // Hook used for early flake detection. EFD only works from >=1.38.0
500
+ addHook({
501
+ name: 'playwright',
502
+ file: 'lib/common/suiteUtils.js',
503
+ versions: [`>=${MINIMUM_SUPPORTED_VERSION_EFD}`]
504
+ }, suiteUtilsPackage => {
505
+ // We grab `applyRepeatEachIndex` to use it later
506
+ // `applyRepeatEachIndex` needs to be applied to a cloned suite
507
+ applyRepeatEachIndex = suiteUtilsPackage.applyRepeatEachIndex
508
+ return suiteUtilsPackage
509
+ })
510
+
511
+ // Hook used for early flake detection. EFD only works from >=1.38.0
512
+ addHook({
513
+ name: 'playwright',
514
+ file: 'lib/runner/loadUtils.js',
515
+ versions: [`>=${MINIMUM_SUPPORTED_VERSION_EFD}`]
516
+ }, (loadUtilsPackage) => {
517
+ const oldCreateRootSuite = loadUtilsPackage.createRootSuite
518
+
519
+ async function newCreateRootSuite () {
520
+ const rootSuite = await oldCreateRootSuite.apply(this, arguments)
521
+ if (!isEarlyFlakeDetectionEnabled) {
522
+ return rootSuite
523
+ }
524
+ const newTests = rootSuite
525
+ .allTests()
526
+ .filter(isNewTest)
527
+
528
+ newTests.forEach(newTest => {
529
+ newTest._ddIsNew = true
530
+ if (newTest.expectedStatus !== 'skipped') {
531
+ const fileSuite = getSuiteType(newTest, 'file')
532
+ const projectSuite = getSuiteType(newTest, 'project')
533
+ for (let repeatEachIndex = 0; repeatEachIndex < earlyFlakeDetectionNumRetries; repeatEachIndex++) {
534
+ const copyFileSuite = deepCloneSuite(fileSuite, isNewTest)
535
+ applyRepeatEachIndex(projectSuite._fullProject, copyFileSuite, repeatEachIndex + 1)
536
+ projectSuite._addSuite(copyFileSuite)
537
+ }
538
+ }
539
+ })
540
+
541
+ return rootSuite
542
+ }
543
+
544
+ loadUtilsPackage.createRootSuite = newCreateRootSuite
545
+
546
+ return loadUtilsPackage
547
+ })
@@ -45,7 +45,9 @@ addHook({ name: 'rhea', versions: ['>=1'], file: 'lib/link.js' }, obj => {
45
45
  const { host, port } = getHostAndPort(this.connection)
46
46
 
47
47
  const targetAddress = this.options && this.options.target &&
48
- this.options.target.address ? this.options.target.address : undefined
48
+ this.options.target.address
49
+ ? this.options.target.address
50
+ : undefined
49
51
 
50
52
  const asyncResource = new AsyncResource('bound-anonymous-fn')
51
53
  return asyncResource.runInAsyncScope(() => {
@@ -187,7 +189,8 @@ function patchCircularBuffer (proto, Session) {
187
189
  if (shouldPop) {
188
190
  const remoteState = entry.remote_state
189
191
  const state = remoteState && remoteState.constructor
190
- ? entry.remote_state.constructor.composite_type : undefined
192
+ ? entry.remote_state.constructor.composite_type
193
+ : undefined
191
194
  asyncResource.runInAsyncScope(() => {
192
195
  exports.beforeFinish(entry, state)
193
196
  finishSendCh.publish()
@@ -7,7 +7,7 @@ const {
7
7
  } = require('./helpers/instrument')
8
8
  const shimmer = require('../../datadog-shimmer')
9
9
 
10
- addHook({ name: 'tedious', versions: [ '>=1.0.0' ] }, tedious => {
10
+ addHook({ name: 'tedious', versions: ['>=1.0.0'] }, tedious => {
11
11
  const startCh = channel('apm:tedious:request:start')
12
12
  const finishCh = channel('apm:tedious:request:finish')
13
13
  const errorCh = channel('apm:tedious:request:error')
@@ -0,0 +1,12 @@
1
+ 'use strict'
2
+
3
+ const ApolloBasePlugin = require('../../../dd-trace/src/plugins/apollo')
4
+
5
+ class ApolloGatewayExecutePlugin extends ApolloBasePlugin {
6
+ static get operation () { return 'execute' }
7
+ static get prefix () {
8
+ return 'tracing:apm:apollo:gateway:execute'
9
+ }
10
+ }
11
+
12
+ module.exports = ApolloGatewayExecutePlugin
@@ -0,0 +1,36 @@
1
+ 'use strict'
2
+
3
+ const { storage } = require('../../../datadog-core')
4
+ const ApolloBasePlugin = require('../../../dd-trace/src/plugins/apollo')
5
+
6
+ class ApolloGatewayFetchPlugin extends ApolloBasePlugin {
7
+ static get operation () { return 'fetch' }
8
+ static get prefix () {
9
+ return 'tracing:apm:apollo:gateway:fetch'
10
+ }
11
+
12
+ bindStart (ctx) {
13
+ const store = storage.getStore()
14
+ const childOf = store ? store.span : null
15
+
16
+ const spanData = {
17
+ childOf,
18
+ service: this.getServiceName(),
19
+ type: this.constructor.type,
20
+ meta: {}
21
+ }
22
+
23
+ const serviceName = ctx?.attributes?.service
24
+
25
+ if (serviceName) { spanData.meta.serviceName = serviceName }
26
+
27
+ const span = this.startSpan(this.getOperationName(), spanData, false)
28
+
29
+ ctx.parentStore = store
30
+ ctx.currentStore = { ...store, span }
31
+
32
+ return ctx.currentStore
33
+ }
34
+ }
35
+
36
+ module.exports = ApolloGatewayFetchPlugin
@@ -0,0 +1,36 @@
1
+ 'use strict'
2
+
3
+ const { storage } = require('../../../datadog-core')
4
+ const CompositePlugin = require('../../../dd-trace/src/plugins/composite')
5
+ const ApolloGatewayExecutePlugin = require('./execute')
6
+ const ApolloGatewayPostProcessingPlugin = require('./postprocessing')
7
+ const ApolloGatewayRequestPlugin = require('./request')
8
+ const ApolloGatewayPlanPlugin = require('./plan')
9
+ const ApolloGatewayValidatePlugin = require('./validate')
10
+ const ApolloGatewayFetchPlugin = require('./fetch')
11
+
12
+ class ApolloGatewayPlugin extends CompositePlugin {
13
+ static get id () { return 'gateway' }
14
+ static get plugins () {
15
+ return {
16
+ execute: ApolloGatewayExecutePlugin,
17
+ postprocessing: ApolloGatewayPostProcessingPlugin,
18
+ request: ApolloGatewayRequestPlugin,
19
+ plan: ApolloGatewayPlanPlugin,
20
+ fetch: ApolloGatewayFetchPlugin,
21
+ validate: ApolloGatewayValidatePlugin
22
+ }
23
+ }
24
+
25
+ constructor (...args) {
26
+ super(...args)
27
+ this.addSub('apm:apollo:gateway:general:error', (ctx) => {
28
+ const store = storage.getStore()
29
+ const span = store?.span
30
+ if (!span) return
31
+ span.setTag('error', ctx.error)
32
+ })
33
+ }
34
+ }
35
+
36
+ module.exports = ApolloGatewayPlugin
@@ -0,0 +1,12 @@
1
+ 'use strict'
2
+
3
+ const ApolloBasePlugin = require('../../../dd-trace/src/plugins/apollo')
4
+
5
+ class ApolloGatewayPlanPlugin extends ApolloBasePlugin {
6
+ static get operation () { return 'plan' }
7
+ static get prefix () {
8
+ return 'tracing:apm:apollo:gateway:plan'
9
+ }
10
+ }
11
+
12
+ module.exports = ApolloGatewayPlanPlugin
@@ -0,0 +1,12 @@
1
+ 'use strict'
2
+
3
+ const ApolloBasePlugin = require('../../../dd-trace/src/plugins/apollo')
4
+
5
+ class ApolloGatewayPostProcessingPlugin extends ApolloBasePlugin {
6
+ static get operation () { return 'postprocessing' }
7
+ static get prefix () {
8
+ return 'tracing:apm:apollo:gateway:postprocessing'
9
+ }
10
+ }
11
+
12
+ module.exports = ApolloGatewayPostProcessingPlugin
@@ -0,0 +1,124 @@
1
+ 'use strict'
2
+
3
+ const { storage } = require('../../../datadog-core')
4
+ const ApolloBasePlugin = require('../../../dd-trace/src/plugins/apollo')
5
+
6
+ let tools
7
+
8
+ const OPERATION_DEFINITION = 'OperationDefinition'
9
+ const FRAGMENT_DEFINITION = 'FragmentDefinition'
10
+
11
+ class ApolloGatewayRequestPlugin extends ApolloBasePlugin {
12
+ static get operation () { return 'request' }
13
+ static get prefix () {
14
+ return 'tracing:apm:apollo:gateway:request'
15
+ }
16
+
17
+ bindStart (ctx) {
18
+ const store = storage.getStore()
19
+ const childOf = store ? store.span : null
20
+ const spanData = {
21
+ childOf,
22
+ service: this.serviceName(
23
+ { id: `${this.constructor.id}.${this.constructor.operation}`, pluginConfig: this.config }),
24
+ type: this.constructor.type,
25
+ kind: this.constructor.kind,
26
+ meta: {}
27
+ }
28
+
29
+ const { requestContext, gateway } = ctx
30
+
31
+ if (requestContext?.operationName) {
32
+ spanData.meta['graphql.operation.name'] = requestContext.operationName
33
+ }
34
+ if ((this.config.source || gateway?.config?.telemetry?.includeDocument) && requestContext?.source) {
35
+ spanData.meta['graphql.source'] = requestContext.source
36
+ }
37
+
38
+ const operationContext =
39
+ buildOperationContext(gateway.schema, requestContext.document, requestContext.request.operationName)
40
+
41
+ if (operationContext?.operation?.operation) {
42
+ const document = requestContext?.document
43
+ const type = operationContext?.operation?.operation
44
+ const name = operationContext?.operation?.name && operationContext?.operation?.name?.value
45
+
46
+ spanData.resource = getSignature(document, name, type, this?.config?.signature)
47
+ spanData.meta['graphql.operation.type'] = type
48
+ }
49
+ const span = this.startSpan(this.operationName({ id: `${this.constructor.id}.${this.constructor.operation}` }),
50
+ spanData, false)
51
+
52
+ ctx.parentStore = store
53
+ ctx.currentStore = { ...store, span }
54
+ return ctx.currentStore
55
+ }
56
+
57
+ asyncStart (ctx) {
58
+ const errors = ctx?.result?.errors
59
+ // apollo gateway catches certain errors and returns them in the result object
60
+ // we want to capture these errors as spans
61
+ if (errors instanceof Array &&
62
+ errors[errors.length - 1] && errors[errors.length - 1].stack && errors[errors.length - 1].message) {
63
+ ctx.currentStore.span.setTag('error', errors[errors.length - 1])
64
+ }
65
+ ctx.currentStore.span.finish()
66
+ return ctx.parentStore
67
+ }
68
+ }
69
+
70
+ function buildOperationContext (schema, operationDocument, operationName) {
71
+ let operation
72
+ let operationCount = 0
73
+ const fragments = Object.create(null)
74
+ try {
75
+ operationDocument.definitions.forEach(definition => {
76
+ switch (definition.kind) {
77
+ case OPERATION_DEFINITION:
78
+ operationCount++
79
+ if (!operationName && operationCount > 1) {
80
+ return
81
+ }
82
+ if (
83
+ !operationName ||
84
+ (definition.name && definition.name.value === operationName)
85
+ ) {
86
+ operation = definition
87
+ }
88
+ break
89
+ case FRAGMENT_DEFINITION:
90
+ fragments[definition.name.value] = definition
91
+ break
92
+ }
93
+ })
94
+ } catch (e) {
95
+ // safety net
96
+ }
97
+
98
+ return {
99
+ schema,
100
+ operation,
101
+ fragments
102
+ }
103
+ }
104
+
105
+ function getSignature (document, operationName, operationType, calculate) {
106
+ if (calculate !== false && tools !== false) {
107
+ try {
108
+ try {
109
+ tools = tools || require('../../../datadog-plugin-graphql/src/tools')
110
+ } catch (e) {
111
+ tools = false
112
+ throw e
113
+ }
114
+
115
+ return tools.defaultEngineReportingSignature(document, operationName)
116
+ } catch (e) {
117
+ // safety net
118
+ }
119
+ }
120
+
121
+ return [operationType, operationName].filter(val => val).join(' ')
122
+ }
123
+
124
+ module.exports = ApolloGatewayRequestPlugin
@@ -0,0 +1,25 @@
1
+ 'use strict'
2
+
3
+ const ApolloBasePlugin = require('../../../dd-trace/src/plugins/apollo')
4
+
5
+ class ApolloGatewayValidatePlugin extends ApolloBasePlugin {
6
+ static get operation () { return 'validate' }
7
+ static get prefix () {
8
+ return 'tracing:apm:apollo:gateway:validate'
9
+ }
10
+
11
+ end (ctx) {
12
+ const result = ctx.result
13
+ const span = ctx.currentStore?.span
14
+
15
+ if (!span) return
16
+
17
+ if (result instanceof Array &&
18
+ result[result.length - 1] && result[result.length - 1].stack && result[result.length - 1].message) {
19
+ span.setTag('error', result[result.length - 1])
20
+ }
21
+ span.finish()
22
+ }
23
+ }
24
+
25
+ module.exports = ApolloGatewayValidatePlugin
@@ -0,0 +1,15 @@
1
+ 'use strict'
2
+
3
+ const CompositePlugin = require('../../dd-trace/src/plugins/composite')
4
+ const ApolloGatewayPlugin = require('./gateway')
5
+
6
+ class ApolloPlugin extends CompositePlugin {
7
+ static get id () { return 'apollo' }
8
+ static get plugins () {
9
+ return {
10
+ gateway: ApolloGatewayPlugin
11
+ }
12
+ }
13
+ }
14
+
15
+ module.exports = ApolloPlugin
@@ -37,10 +37,10 @@ class BaseAwsSdkPlugin extends ClientPlugin {
37
37
  'service.name': this.serviceName(),
38
38
  'aws.operation': operation,
39
39
  'aws.region': awsRegion,
40
- 'region': awsRegion,
41
- 'aws_service': awsService,
40
+ region: awsRegion,
41
+ aws_service: awsService,
42
42
  'aws.service': awsService,
43
- 'component': 'aws-sdk'
43
+ component: 'aws-sdk'
44
44
  }
45
45
  if (this.requestTags) this.requestTags.set(request, tags)
46
46
 
@@ -13,7 +13,7 @@ class CloudwatchLogs extends BaseAwsSdkPlugin {
13
13
  return Object.assign(tags, {
14
14
  'resource.name': `${operation} ${params.logGroupName}`,
15
15
  'aws.cloudwatch.logs.log_group_name': params.logGroupName,
16
- 'loggroupname': params.logGroupName
16
+ loggroupname: params.logGroupName
17
17
  })
18
18
  }
19
19
  }
@@ -14,7 +14,7 @@ class DynamoDb extends BaseAwsSdkPlugin {
14
14
  Object.assign(tags, {
15
15
  'resource.name': `${operation} ${params.TableName}`,
16
16
  'aws.dynamodb.table_name': params.TableName,
17
- 'tablename': params.TableName
17
+ tablename: params.TableName
18
18
  })
19
19
  }
20
20
 
@@ -30,7 +30,7 @@ class DynamoDb extends BaseAwsSdkPlugin {
30
30
  Object.assign(tags, {
31
31
  'resource.name': `${operation} ${tableName}`,
32
32
  'aws.dynamodb.table_name': tableName,
33
- 'tablename': tableName
33
+ tablename: tableName
34
34
  })
35
35
  }
36
36
  }
@@ -11,7 +11,7 @@ class EventBridge extends BaseAwsSdkPlugin {
11
11
  return {
12
12
  'resource.name': operation ? `${operation} ${params.source}` : params.source,
13
13
  'aws.eventbridge.source': `${params.source}`,
14
- 'rulename': `${rulename}`
14
+ rulename: `${rulename}`
15
15
  }
16
16
  }
17
17
 
@@ -69,7 +69,7 @@ class Kinesis extends BaseAwsSdkPlugin {
69
69
  return {
70
70
  'resource.name': `${operation} ${params.StreamName}`,
71
71
  'aws.kinesis.stream_name': params.StreamName,
72
- 'streamname': params.StreamName
72
+ streamname: params.StreamName
73
73
  }
74
74
  }
75
75
 
@@ -13,7 +13,7 @@ class Lambda extends BaseAwsSdkPlugin {
13
13
 
14
14
  return Object.assign(tags, {
15
15
  'resource.name': `${operation} ${params.FunctionName}`,
16
- 'functionname': params.FunctionName,
16
+ functionname: params.FunctionName,
17
17
  'aws.lambda': params.FunctionName
18
18
  })
19
19
  }
@@ -13,7 +13,7 @@ class Redshift extends BaseAwsSdkPlugin {
13
13
  return Object.assign(tags, {
14
14
  'resource.name': `${operation} ${params.ClusterIdentifier}`,
15
15
  'aws.redshift.cluster_identifier': params.ClusterIdentifier,
16
- 'clusteridentifier': params.ClusterIdentifier
16
+ clusteridentifier: params.ClusterIdentifier
17
17
  })
18
18
  }
19
19
  }
@@ -14,7 +14,7 @@ class S3 extends BaseAwsSdkPlugin {
14
14
  return Object.assign(tags, {
15
15
  'resource.name': `${operation} ${params.Bucket}`,
16
16
  'aws.s3.bucket_name': params.Bucket,
17
- 'bucketname': params.Bucket
17
+ bucketname: params.Bucket
18
18
  })
19
19
  }
20
20
  }
@@ -23,7 +23,7 @@ class Sns extends BaseAwsSdkPlugin {
23
23
  return {
24
24
  'resource.name': `${operation} ${params.TopicArn || response.data.TopicArn}`,
25
25
  'aws.sns.topic_arn': TopicArn,
26
- 'topicname': topicName
26
+ topicname: topicName
27
27
  }
28
28
 
29
29
  // TODO: should arn be sanitized or quantized in some way here,