dd-trace 3.3.1 → 3.4.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 (44) hide show
  1. package/LICENSE-3rdparty.csv +2 -0
  2. package/index.d.ts +7 -0
  3. package/package.json +5 -3
  4. package/packages/datadog-instrumentations/src/cassandra-driver.js +7 -7
  5. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  6. package/packages/datadog-instrumentations/src/http2/server.js +67 -1
  7. package/packages/datadog-instrumentations/src/jest.js +76 -6
  8. package/packages/datadog-instrumentations/src/mariadb.js +89 -0
  9. package/packages/datadog-instrumentations/src/memcached.js +1 -4
  10. package/packages/datadog-instrumentations/src/next.js +10 -2
  11. package/packages/datadog-instrumentations/src/oracledb.js +8 -8
  12. package/packages/datadog-instrumentations/src/redis.js +12 -3
  13. package/packages/datadog-instrumentations/src/rhea.js +11 -0
  14. package/packages/datadog-plugin-cassandra-driver/src/index.js +22 -60
  15. package/packages/datadog-plugin-elasticsearch/src/index.js +24 -60
  16. package/packages/datadog-plugin-http2/src/server.js +41 -0
  17. package/packages/datadog-plugin-jest/src/index.js +97 -2
  18. package/packages/datadog-plugin-mariadb/src/index.js +10 -0
  19. package/packages/datadog-plugin-memcached/src/index.js +17 -52
  20. package/packages/datadog-plugin-mongodb-core/src/index.js +20 -48
  21. package/packages/datadog-plugin-mysql/src/index.js +23 -52
  22. package/packages/datadog-plugin-mysql2/src/index.js +1 -3
  23. package/packages/datadog-plugin-oracledb/src/index.js +29 -54
  24. package/packages/datadog-plugin-pg/src/index.js +24 -52
  25. package/packages/datadog-plugin-redis/src/index.js +29 -60
  26. package/packages/datadog-plugin-rhea/src/index.js +4 -1
  27. package/packages/datadog-plugin-tedious/src/index.js +20 -41
  28. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +32 -54
  29. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +87 -0
  30. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +79 -0
  31. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
  32. package/packages/dd-trace/src/plugin_manager.js +3 -0
  33. package/packages/dd-trace/src/plugins/cache.js +9 -0
  34. package/packages/dd-trace/src/plugins/client.js +7 -0
  35. package/packages/dd-trace/src/plugins/database.js +9 -0
  36. package/packages/dd-trace/src/plugins/index.js +2 -0
  37. package/packages/dd-trace/src/plugins/outgoing.js +31 -0
  38. package/packages/dd-trace/src/plugins/plugin.js +3 -0
  39. package/packages/dd-trace/src/plugins/storage.js +25 -0
  40. package/packages/dd-trace/src/plugins/tracing.js +91 -0
  41. package/packages/dd-trace/src/plugins/util/git.js +58 -18
  42. package/packages/dd-trace/src/plugins/util/test.js +7 -1
  43. package/packages/dd-trace/src/proxy.js +4 -0
  44. package/packages/dd-trace/src/telemetry/index.js +7 -1
@@ -0,0 +1,31 @@
1
+ 'use strict'
2
+
3
+ const TracingPlugin = require('./tracing')
4
+
5
+ // TODO: Exit span on finish when AsyncResource instances are removed.
6
+ class OutgoingPlugin extends TracingPlugin {
7
+ constructor (...args) {
8
+ super(...args)
9
+
10
+ this.addTraceSub('connect', message => {
11
+ this.connect(message)
12
+ })
13
+ }
14
+
15
+ connect (url) {
16
+ this.addHost(url.hostname, url.port)
17
+ }
18
+
19
+ addHost (hostname, port) {
20
+ const span = this.activeSpan()
21
+
22
+ if (!span) return
23
+
24
+ span.addTags({
25
+ 'out.host': hostname,
26
+ 'out.port': port
27
+ })
28
+ }
29
+ }
30
+
31
+ module.exports = OutgoingPlugin
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ // TODO: move anything related to tracing to TracingPlugin instead
4
+
3
5
  const dc = require('diagnostics_channel')
4
6
  const { storage } = require('../../../datadog-core')
5
7
 
@@ -39,6 +41,7 @@ module.exports = class Plugin {
39
41
  storage.enterWith({ ...store, span })
40
42
  }
41
43
 
44
+ // TODO: Implement filters on resource name for all plugins.
42
45
  /** Prevents creation of spans here and for all async descendants. */
43
46
  skip () {
44
47
  storage.enterWith({ noop: true })
@@ -0,0 +1,25 @@
1
+ 'use strict'
2
+
3
+ const ClientPlugin = require('./client')
4
+
5
+ class StoragePlugin extends ClientPlugin {
6
+ constructor (...args) {
7
+ super(...args)
8
+
9
+ this.system = this.constructor.system || this.component
10
+
11
+ this.addTraceSub('connect', message => {
12
+ this.connect(message)
13
+ })
14
+ }
15
+
16
+ startSpan (name, options) {
17
+ if (!options.service && this.system) {
18
+ options.service = `${this.tracer._service}-${this.system}`
19
+ }
20
+
21
+ return super.startSpan(name, options)
22
+ }
23
+ }
24
+
25
+ module.exports = StoragePlugin
@@ -0,0 +1,91 @@
1
+ 'use strict'
2
+
3
+ const Plugin = require('./plugin')
4
+ const { storage } = require('../../../datadog-core')
5
+ const analyticsSampler = require('../analytics_sampler')
6
+
7
+ class TracingPlugin extends Plugin {
8
+ constructor (...args) {
9
+ super(...args)
10
+
11
+ this.component = this.constructor.component || this.constructor.name
12
+ this.operation = this.constructor.operation
13
+
14
+ this.addTraceSub('start', message => {
15
+ this.start(message)
16
+ })
17
+
18
+ this.addTraceSub('error', err => {
19
+ this.error(err)
20
+ })
21
+
22
+ this.addTraceSub('finish', message => {
23
+ this.finish(message)
24
+ })
25
+ }
26
+
27
+ configure (config) {
28
+ return super.configure({
29
+ ...config,
30
+ hooks: {
31
+ [this.operation]: () => {},
32
+ ...config.hooks
33
+ }
34
+ })
35
+ }
36
+
37
+ start () {} // implemented by individual plugins
38
+
39
+ finish () {
40
+ this.activeSpan().finish()
41
+ }
42
+
43
+ error (error) {
44
+ this.addError(error)
45
+ }
46
+
47
+ addTraceSub (eventName, handler) {
48
+ this.addSub(`apm:${this.component}:${this.operation}:${eventName}`, handler)
49
+ }
50
+
51
+ addError (error) {
52
+ const span = this.activeSpan()
53
+
54
+ if (!span._spanContext._tags['error']) {
55
+ span.setTag('error', error || 1)
56
+ }
57
+ }
58
+
59
+ startSpan (name, { childOf, kind, meta, metrics, service, resource, type } = {}) {
60
+ const store = storage.getStore()
61
+
62
+ if (store && childOf === undefined) {
63
+ childOf = store.span
64
+ }
65
+
66
+ const span = this.tracer.startSpan(name, {
67
+ tags: {
68
+ 'service.name': service,
69
+ 'resource.name': resource,
70
+ 'span.kind': kind,
71
+ 'span.type': type,
72
+ ...meta,
73
+ ...metrics
74
+ }
75
+ })
76
+
77
+ analyticsSampler.sample(span, this.config.measured)
78
+
79
+ storage.enterWith({ ...store, span })
80
+
81
+ return span
82
+ }
83
+
84
+ activeSpan () {
85
+ const store = storage.getStore()
86
+
87
+ return store && store.span
88
+ }
89
+ }
90
+
91
+ module.exports = TracingPlugin
@@ -1,6 +1,8 @@
1
1
  const { execSync } = require('child_process')
2
2
  const os = require('os')
3
+ const path = require('path')
3
4
 
5
+ const log = require('../../log')
4
6
  const { sanitizedExec } = require('./exec')
5
7
  const {
6
8
  GIT_COMMIT_SHA,
@@ -17,15 +19,22 @@ const {
17
19
  CI_WORKSPACE_PATH
18
20
  } = require('./tags')
19
21
 
22
+ const GIT_REV_LIST_MAX_BUFFER = 8 * 1024 * 1024 // 8MB
23
+
20
24
  function getRepositoryUrl () {
21
25
  return sanitizedExec('git config --get remote.origin.url', { stdio: 'pipe' })
22
26
  }
23
27
 
24
28
  function getLatestCommits () {
25
- return execSync('git log --format=%H -n 1000 --since="1 month ago"', { stdio: 'pipe' })
26
- .toString()
27
- .split('\n')
28
- .filter(commit => !!commit)
29
+ try {
30
+ return execSync('git log --format=%H -n 1000 --since="1 month ago"', { stdio: 'pipe' })
31
+ .toString()
32
+ .split('\n')
33
+ .filter(commit => commit)
34
+ } catch (err) {
35
+ log.error(err)
36
+ return []
37
+ }
29
38
  }
30
39
 
31
40
  function getCommitsToUpload (commitsToExclude) {
@@ -36,27 +45,57 @@ function getCommitsToUpload (commitsToExclude) {
36
45
  gitCommandToGetCommitsToUpload = `${gitCommandToGetCommitsToUpload} ^${commit}`
37
46
  })
38
47
 
39
- return execSync(gitCommandToGetCommitsToUpload, { stdio: 'pipe' })
40
- .toString()
41
- .split('\n')
42
- .filter(commit => !!commit)
48
+ try {
49
+ return execSync(gitCommandToGetCommitsToUpload, { stdio: 'pipe', maxBuffer: GIT_REV_LIST_MAX_BUFFER })
50
+ .toString()
51
+ .split('\n')
52
+ .filter(commit => commit)
53
+ } catch (err) {
54
+ log.error(err)
55
+ return []
56
+ }
43
57
  }
44
58
 
45
- // Generates pack files to upload and
46
- // returns the ordered list of packfiles' paths
47
59
  function generatePackFilesForCommits (commitsToUpload) {
48
60
  const tmpFolder = os.tmpdir()
49
61
 
50
- const prefix = Math.floor(Math.random() * 10000)
51
- const path = `${tmpFolder}/${prefix}`
62
+ const randomPrefix = String(Math.floor(Math.random() * 10000))
63
+ const temporaryPath = path.join(tmpFolder, randomPrefix)
64
+ const cwdPath = path.join(process.cwd(), randomPrefix)
52
65
 
53
- const orderedCommits =
54
- execSync(
55
- `git pack-objects --compression=9 --max-pack-size=3m ${path}`,
66
+ // Generates pack files to upload and
67
+ // returns the ordered list of packfiles' paths
68
+ function execGitPackObjects (targetPath) {
69
+ return execSync(
70
+ `git pack-objects --compression=9 --max-pack-size=3m ${targetPath}`,
56
71
  { input: commitsToUpload.join('\n') }
57
- ).toString().split('\n').filter(commit => !!commit)
72
+ ).toString().split('\n').filter(commit => commit).map(commit => `${targetPath}-${commit}.pack`)
73
+ }
74
+
75
+ try {
76
+ return execGitPackObjects(temporaryPath, commitsToUpload)
77
+ } catch (err) {
78
+ log.error(err)
79
+ /**
80
+ * The generation of pack files in the temporary folder (from `os.tmpdir()`)
81
+ * sometimes fails in certain CI setups with the error message
82
+ * `unable to rename temporary pack file: Invalid cross-device link`.
83
+ * The reason why is unclear.
84
+ *
85
+ * A workaround is to attempt to generate the pack files in `process.cwd()`.
86
+ * While this works most of the times, it's not ideal since it affects the git status.
87
+ * This workaround is intended to be temporary.
88
+ *
89
+ * TODO: fix issue and remove workaround.
90
+ */
91
+ try {
92
+ return execGitPackObjects(cwdPath, commitsToUpload)
93
+ } catch (err) {
94
+ log.error(err)
95
+ }
58
96
 
59
- return orderedCommits.map(commit => `${path}-${commit}.pack`)
97
+ return []
98
+ }
60
99
  }
61
100
 
62
101
  // If there is ciMetadata, it takes precedence.
@@ -106,5 +145,6 @@ module.exports = {
106
145
  getLatestCommits,
107
146
  getRepositoryUrl,
108
147
  generatePackFilesForCommits,
109
- getCommitsToUpload
148
+ getCommitsToUpload,
149
+ GIT_REV_LIST_MAX_BUFFER
110
150
  }
@@ -48,6 +48,10 @@ const CI_APP_ORIGIN = 'ciapp-test'
48
48
 
49
49
  const JEST_TEST_RUNNER = 'test.jest.test_runner'
50
50
 
51
+ const TEST_ITR_TESTS_SKIPPED = '_dd.ci.itr.tests_skipped'
52
+
53
+ const TEST_CODE_COVERAGE_LINES_TOTAL = 'test.codecov_lines_total'
54
+
51
55
  module.exports = {
52
56
  TEST_CODE_OWNERS,
53
57
  TEST_FRAMEWORK,
@@ -78,7 +82,9 @@ module.exports = {
78
82
  getTestSuiteCommonTags,
79
83
  TEST_COMMAND,
80
84
  TEST_SESSION_ID,
81
- TEST_SUITE_ID
85
+ TEST_SUITE_ID,
86
+ TEST_ITR_TESTS_SKIPPED,
87
+ TEST_CODE_COVERAGE_LINES_TOTAL
82
88
  }
83
89
 
84
90
  function getTestEnvironmentMetadata (testFramework, config) {
@@ -1,4 +1,5 @@
1
1
  'use strict'
2
+ const { channel } = require('diagnostics_channel')
2
3
 
3
4
  const NoopProxy = require('./noop/proxy')
4
5
  const DatadogTracer = require('./tracer')
@@ -10,6 +11,8 @@ const telemetry = require('./telemetry')
10
11
  const PluginManager = require('./plugin_manager')
11
12
  const { sendGitMetadata } = require('./ci-visibility/exporters/git/git_metadata')
12
13
 
14
+ const gitMetadataUploadFinishCh = channel('ci:git-metadata-upload:finish')
15
+
13
16
  class Tracer extends NoopProxy {
14
17
  constructor () {
15
18
  super()
@@ -65,6 +68,7 @@ class Tracer extends NoopProxy {
65
68
  } else {
66
69
  log.debug('Successfully uploaded git metadata')
67
70
  }
71
+ gitMetadataUploadFinishCh.publish(err)
68
72
  })
69
73
  }
70
74
  } catch (e) {
@@ -6,6 +6,10 @@ const os = require('os')
6
6
  const dependencies = require('./dependencies')
7
7
  const { sendData } = require('./send-data')
8
8
 
9
+ const HEARTBEAT_INTERVAL = process.env.DD_TELEMETRY_HEARTBEAT_INTERVAL
10
+ ? Number(process.env.DD_TELEMETRY_HEARTBEAT_INTERVAL) * 1000
11
+ : 60000
12
+
9
13
  let config
10
14
  let pluginManager
11
15
 
@@ -88,7 +92,9 @@ function start (aConfig, thePluginManager) {
88
92
  host = createHostObject()
89
93
  dependencies.start(config, application, host)
90
94
  sendData(config, application, host, 'app-started', appStarted())
91
- interval = setInterval(() => sendData(config, application, host, 'app-heartbeat'), 60000)
95
+ interval = setInterval(() => {
96
+ sendData(config, application, host, 'app-heartbeat')
97
+ }, HEARTBEAT_INTERVAL)
92
98
  interval.unref()
93
99
  process.on('beforeExit', onBeforeExit)
94
100
  }