dd-trace 2.4.2 → 2.7.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 (96) hide show
  1. package/LICENSE-3rdparty.csv +1 -2
  2. package/ci/init.js +6 -0
  3. package/ci/jest/env.js +16 -3
  4. package/ext/exporters.d.ts +2 -1
  5. package/ext/exporters.js +2 -1
  6. package/index.d.ts +17 -8
  7. package/package.json +20 -23
  8. package/packages/datadog-instrumentations/index.js +14 -0
  9. package/packages/datadog-instrumentations/src/connect.js +111 -0
  10. package/packages/datadog-instrumentations/src/cypress.js +8 -0
  11. package/packages/datadog-instrumentations/src/express.js +27 -0
  12. package/packages/datadog-instrumentations/src/fastify.js +187 -0
  13. package/packages/datadog-instrumentations/src/find-my-way.js +30 -0
  14. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +100 -0
  15. package/packages/datadog-instrumentations/src/http/server.js +1 -1
  16. package/packages/datadog-instrumentations/src/jest.js +175 -0
  17. package/packages/datadog-instrumentations/src/kafkajs.js +112 -0
  18. package/packages/datadog-instrumentations/src/knex.js +20 -0
  19. package/packages/datadog-instrumentations/src/koa.js +159 -0
  20. package/packages/datadog-instrumentations/src/limitd-client.js +21 -0
  21. package/packages/datadog-instrumentations/src/oracledb.js +128 -0
  22. package/packages/datadog-instrumentations/src/paperplane.js +77 -0
  23. package/packages/datadog-instrumentations/src/pg.js +2 -2
  24. package/packages/datadog-instrumentations/src/restify.js +58 -0
  25. package/packages/datadog-instrumentations/src/rhea.js +1 -1
  26. package/packages/datadog-instrumentations/src/router.js +177 -0
  27. package/packages/datadog-plugin-aws-sdk/src/helpers.js +4 -4
  28. package/packages/datadog-plugin-aws-sdk/src/index.js +1 -1
  29. package/packages/datadog-plugin-connect/src/index.js +10 -114
  30. package/packages/datadog-plugin-cucumber/src/index.js +16 -16
  31. package/packages/datadog-plugin-cypress/src/index.js +10 -5
  32. package/packages/datadog-plugin-cypress/src/plugin.js +18 -17
  33. package/packages/datadog-plugin-dns/src/index.js +12 -1
  34. package/packages/datadog-plugin-express/src/index.js +11 -25
  35. package/packages/datadog-plugin-fastify/src/index.js +17 -4
  36. package/packages/datadog-plugin-find-my-way/src/index.js +20 -0
  37. package/packages/datadog-plugin-fs/src/index.js +2 -0
  38. package/packages/datadog-plugin-google-cloud-pubsub/src/index.js +56 -111
  39. package/packages/datadog-plugin-http/src/server.js +2 -10
  40. package/packages/datadog-plugin-jest/src/index.js +101 -3
  41. package/packages/datadog-plugin-jest/src/util.js +1 -29
  42. package/packages/datadog-plugin-kafkajs/src/index.js +64 -90
  43. package/packages/datadog-plugin-koa/src/index.js +12 -164
  44. package/packages/datadog-plugin-mocha/src/index.js +14 -15
  45. package/packages/datadog-plugin-oracledb/src/index.js +34 -100
  46. package/packages/datadog-plugin-paperplane/src/index.js +14 -100
  47. package/packages/datadog-plugin-paperplane/src/logger.js +11 -0
  48. package/packages/datadog-plugin-paperplane/src/server.js +24 -0
  49. package/packages/datadog-plugin-restify/src/index.js +13 -75
  50. package/packages/datadog-plugin-router/src/index.js +67 -164
  51. package/packages/datadog-plugin-web/src/index.js +20 -0
  52. package/packages/dd-trace/lib/version.js +1 -1
  53. package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +34 -12
  54. package/packages/dd-trace/src/appsec/index.js +7 -3
  55. package/packages/dd-trace/src/appsec/recommended.json +15 -5
  56. package/packages/dd-trace/src/appsec/reporter.js +33 -3
  57. package/packages/dd-trace/src/appsec/rule_manager.js +2 -2
  58. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +32 -0
  59. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +51 -0
  60. package/packages/dd-trace/src/config.js +33 -4
  61. package/packages/dd-trace/src/encode/0.4.js +0 -1
  62. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +193 -0
  63. package/packages/dd-trace/src/encode/tags-processors.js +116 -0
  64. package/packages/dd-trace/src/exporter.js +3 -0
  65. package/packages/dd-trace/src/exporters/agent/index.js +1 -1
  66. package/packages/dd-trace/src/exporters/agent/writer.js +7 -32
  67. package/packages/dd-trace/src/exporters/{agent → common}/docker.js +0 -0
  68. package/packages/dd-trace/src/exporters/common/request.js +83 -0
  69. package/packages/dd-trace/src/exporters/common/writer.js +36 -0
  70. package/packages/dd-trace/src/exporters/{agent/scheduler.js → scheduler.js} +0 -0
  71. package/packages/dd-trace/src/format.js +9 -5
  72. package/packages/dd-trace/src/instrumenter.js +3 -0
  73. package/packages/dd-trace/src/pkg.js +11 -6
  74. package/packages/dd-trace/src/plugin_manager.js +13 -7
  75. package/packages/dd-trace/src/plugins/index.js +1 -2
  76. package/packages/dd-trace/src/plugins/log_plugin.js +8 -4
  77. package/packages/dd-trace/src/plugins/plugin.js +8 -0
  78. package/packages/dd-trace/src/plugins/util/test.js +79 -1
  79. package/packages/dd-trace/src/plugins/util/web.js +41 -12
  80. package/packages/dd-trace/src/profiling/config.js +8 -8
  81. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -1
  82. package/packages/dd-trace/src/profiling/index.js +4 -4
  83. package/packages/dd-trace/src/profiling/profilers/{heap.js → space.js} +2 -2
  84. package/packages/dd-trace/src/profiling/profilers/{cpu.js → wall.js} +3 -3
  85. package/packages/dd-trace/src/proxy.js +2 -0
  86. package/packages/dd-trace/src/span_processor.js +4 -1
  87. package/packages/dd-trace/src/telemetry.js +187 -0
  88. package/scripts/install_plugin_modules.js +1 -0
  89. package/packages/datadog-plugin-fastify/src/fastify.js +0 -198
  90. package/packages/datadog-plugin-fastify/src/find-my-way.js +0 -37
  91. package/packages/datadog-plugin-jest/src/jest-environment.js +0 -272
  92. package/packages/datadog-plugin-jest/src/jest-jasmine2.js +0 -185
  93. package/packages/datadog-plugin-knex/src/index.js +0 -23
  94. package/packages/datadog-plugin-limitd-client/src/index.js +0 -30
  95. package/packages/dd-trace/src/exporters/agent/request.js +0 -86
  96. package/scripts/postpublish.js +0 -24
@@ -1,28 +1,23 @@
1
1
  'use strict'
2
2
 
3
- const request = require('./request')
3
+ const request = require('../common/request')
4
4
  const { startupLog } = require('../../startup-log')
5
5
  const metrics = require('../../metrics')
6
6
  const log = require('../../log')
7
7
  const tracerVersion = require('../../../lib/version')
8
+ const BaseWriter = require('../common/writer')
8
9
 
9
10
  const METRIC_PREFIX = 'datadog.tracer.node.exporter.agent'
10
11
 
11
- class Writer {
12
- constructor ({ url, prioritySampler, lookup, protocolVersion }) {
12
+ class Writer extends BaseWriter {
13
+ constructor ({ prioritySampler, lookup, protocolVersion }) {
14
+ super(...arguments)
13
15
  const AgentEncoder = getEncoder(protocolVersion)
14
16
 
15
- this._url = url
16
17
  this._prioritySampler = prioritySampler
17
18
  this._lookup = lookup
18
19
  this._protocolVersion = protocolVersion
19
- this._encoderForVersion = new AgentEncoder(this)
20
- }
21
-
22
- append (spans) {
23
- log.debug(() => `Encoding trace: ${JSON.stringify(spans)}`)
24
-
25
- this._encode(spans)
20
+ this._encoder = new AgentEncoder(this)
26
21
  }
27
22
 
28
23
  _sendPayload (data, count, done) {
@@ -62,26 +57,6 @@ class Writer {
62
57
  done()
63
58
  })
64
59
  }
65
-
66
- setUrl (url) {
67
- this._url = url
68
- }
69
-
70
- _encode (trace) {
71
- this._encoderForVersion.encode(trace)
72
- }
73
-
74
- flush (done = () => {}) {
75
- const count = this._encoderForVersion.count()
76
-
77
- if (count > 0) {
78
- const payload = this._encoderForVersion.makePayload()
79
-
80
- this._sendPayload(payload, count, done)
81
- } else {
82
- done()
83
- }
84
- }
85
60
  }
86
61
 
87
62
  function setHeader (headers, key, value) {
@@ -124,7 +99,7 @@ function makeRequest (version, data, count, url, lookup, needsStartupLog, cb) {
124
99
 
125
100
  log.debug(() => `Request to the agent: ${JSON.stringify(options)}`)
126
101
 
127
- request(Object.assign({ data }, options), (err, res, status) => {
102
+ request(data, options, true, (err, res, status) => {
128
103
  if (needsStartupLog) {
129
104
  // Note that logging will only happen once, regardless of how many times this is called.
130
105
  startupLog({
@@ -0,0 +1,83 @@
1
+ 'use strict'
2
+
3
+ const http = require('http')
4
+ const https = require('https')
5
+ const log = require('../../log')
6
+ const docker = require('./docker')
7
+ const { storage } = require('../../../../datadog-core')
8
+
9
+ const httpAgent = new http.Agent({ keepAlive: true })
10
+ const httpsAgent = new https.Agent({ keepAlive: true })
11
+ const containerId = docker.id()
12
+
13
+ function request (data, options, keepAlive, callback) {
14
+ if (!options.headers) {
15
+ options.headers = {}
16
+ }
17
+ const isSecure = options.protocol === 'https:'
18
+ const client = isSecure ? https : http
19
+ const dataArray = [].concat(data)
20
+ options.headers['Content-Length'] = byteLength(dataArray)
21
+
22
+ if (containerId) {
23
+ options.headers['Datadog-Container-ID'] = containerId
24
+ }
25
+
26
+ if (keepAlive) {
27
+ options.agent = isSecure ? httpsAgent : httpAgent
28
+ }
29
+
30
+ const firstRequest = retriableRequest(options, client, callback)
31
+ dataArray.forEach(buffer => firstRequest.write(buffer))
32
+
33
+ // The first request will be retried
34
+ const firstRequestErrorHandler = () => {
35
+ log.debug('Retrying request to the intake')
36
+ const retriedReq = retriableRequest(options, client, callback)
37
+ dataArray.forEach(buffer => retriedReq.write(buffer))
38
+ // The retried request will fail normally
39
+ retriedReq.on('error', e => callback(new Error(`Network error trying to reach the intake: ${e.message}`)))
40
+ retriedReq.end()
41
+ }
42
+
43
+ firstRequest.on('error', firstRequestErrorHandler)
44
+ firstRequest.end()
45
+
46
+ return firstRequest
47
+ }
48
+
49
+ function retriableRequest (options, client, callback) {
50
+ const store = storage.getStore()
51
+
52
+ storage.enterWith({ noop: true })
53
+
54
+ const timeout = options.timeout || 15000
55
+
56
+ const request = client.request(options, res => {
57
+ let responseData = ''
58
+
59
+ res.setTimeout(timeout)
60
+
61
+ res.on('data', chunk => { responseData += chunk })
62
+ res.on('end', () => {
63
+ if (res.statusCode >= 200 && res.statusCode <= 299) {
64
+ callback(null, responseData, res.statusCode)
65
+ } else {
66
+ const error = new Error(`Error from the endpoint: ${res.statusCode} ${http.STATUS_CODES[res.statusCode]}`)
67
+ error.status = res.statusCode
68
+
69
+ callback(error, null, res.statusCode)
70
+ }
71
+ })
72
+ })
73
+ request.setTimeout(timeout, request.abort)
74
+ storage.enterWith(store)
75
+
76
+ return request
77
+ }
78
+
79
+ function byteLength (data) {
80
+ return data.length > 0 ? data.reduce((prev, next) => prev + next.length, 0) : 0
81
+ }
82
+
83
+ module.exports = request
@@ -0,0 +1,36 @@
1
+ 'use strict'
2
+ const log = require('../../log')
3
+
4
+ class Writer {
5
+ constructor ({ url }) {
6
+ this._url = url
7
+ }
8
+
9
+ flush (done = () => {}) {
10
+ const count = this._encoder.count()
11
+
12
+ if (count > 0) {
13
+ const payload = this._encoder.makePayload()
14
+
15
+ this._sendPayload(payload, count, done)
16
+ } else {
17
+ done()
18
+ }
19
+ }
20
+
21
+ append (spans) {
22
+ log.debug(() => `Encoding trace: ${JSON.stringify(spans)}`)
23
+
24
+ this._encode(spans)
25
+ }
26
+
27
+ _encode (trace) {
28
+ this._encoder.encode(trace)
29
+ }
30
+
31
+ setUrl (url) {
32
+ this._url = url
33
+ }
34
+ }
35
+
36
+ module.exports = Writer
@@ -22,7 +22,6 @@ const map = {
22
22
  function format (span) {
23
23
  const formatted = formatSpan(span)
24
24
 
25
- extractError(formatted, span)
26
25
  extractRootTags(formatted, span)
27
26
  extractChunkTags(formatted, span)
28
27
  extractTags(formatted, span)
@@ -74,8 +73,8 @@ function extractTags (trace, span) {
74
73
  addTag({}, trace.metrics, tag, tags[tag] === undefined || tags[tag] ? 1 : 0)
75
74
  break
76
75
  case 'error':
77
- if (tags[tag] && (context._name !== 'fs.operation')) {
78
- trace.error = 1
76
+ if (context._name !== 'fs.operation') {
77
+ extractError(trace, tags[tag])
79
78
  }
80
79
  break
81
80
  case 'error.type':
@@ -84,6 +83,8 @@ function extractTags (trace, span) {
84
83
  // HACK: remove when implemented in the backend
85
84
  if (context._name !== 'fs.operation') {
86
85
  trace.error = 1
86
+ } else {
87
+ break
87
88
  }
88
89
  default: // eslint-disable-line no-fallthrough
89
90
  addTag(trace.meta, trace.metrics, tag, tags[tag])
@@ -122,8 +123,11 @@ function extractChunkTags (trace, span) {
122
123
  }
123
124
  }
124
125
 
125
- function extractError (trace, span) {
126
- const error = span.context()._tags['error']
126
+ function extractError (trace, error) {
127
+ if (!error) return
128
+
129
+ trace.error = 1
130
+
127
131
  if (isError(error)) {
128
132
  addTag(trace.meta, trace.metrics, 'error.msg', error.message)
129
133
  addTag(trace.meta, trace.metrics, 'error.type', error.name)
@@ -7,6 +7,7 @@ const Loader = require('./loader')
7
7
  const { isTrue } = require('./util')
8
8
  const plugins = require('./plugins')
9
9
  const Plugin = require('./plugins/plugin')
10
+ const telemetry = require('./telemetry')
10
11
 
11
12
  const disabledPlugins = process.env.DD_TRACE_DISABLED_PLUGINS
12
13
 
@@ -54,6 +55,7 @@ class Instrumenter {
54
55
 
55
56
  try {
56
57
  this._set(plugin, { name, config })
58
+ telemetry.updateIntegrations()
57
59
  } catch (e) {
58
60
  log.debug(`Could not find a plugin named "${name}".`)
59
61
  }
@@ -154,6 +156,7 @@ class Instrumenter {
154
156
 
155
157
  if (!instrumented) {
156
158
  this._instrumented.set(instrumentation, instrumented = new Set())
159
+ telemetry.updateIntegrations()
157
160
  }
158
161
 
159
162
  if (!instrumented.has(this._defaultExport(moduleExports))) {
@@ -11,7 +11,14 @@ function findRoot () {
11
11
 
12
12
  function findPkg () {
13
13
  const cwd = findRoot()
14
- const filePath = findUp('package.json', cwd)
14
+ const directory = path.resolve(cwd)
15
+ const res = path.parse(directory)
16
+
17
+ if (!res) return {}
18
+
19
+ const { root } = res
20
+
21
+ const filePath = findUp('package.json', root, directory)
15
22
 
16
23
  try {
17
24
  return JSON.parse(fs.readFileSync(filePath, 'utf8'))
@@ -20,18 +27,16 @@ function findPkg () {
20
27
  }
21
28
  }
22
29
 
23
- function findUp (name, cwd) {
24
- let directory = path.resolve(cwd)
25
- const { root } = path.parse(directory)
26
-
30
+ function findUp (name, root, directory) {
27
31
  while (true) {
28
32
  const current = path.resolve(directory, name)
29
33
 
30
34
  if (fs.existsSync(current)) return current
35
+
31
36
  if (directory === root) return
32
37
 
33
38
  directory = path.dirname(directory)
34
39
  }
35
40
  }
36
41
 
37
- module.exports = findPkg()
42
+ module.exports = Object.assign(findPkg(), { findRoot, findUp })
@@ -27,9 +27,11 @@ function getConfig (name, config = {}) {
27
27
  module.exports = class PluginManager {
28
28
  constructor (tracer) {
29
29
  this._pluginsByName = {}
30
+ this._configsByName = {}
30
31
  for (const PluginClass of Object.values(plugins)) {
31
32
  if (typeof PluginClass !== 'function') continue
32
33
  this._pluginsByName[PluginClass.name] = new PluginClass(tracer)
34
+ this._configsByName[PluginClass.name] = {}
33
35
  }
34
36
  }
35
37
 
@@ -40,25 +42,29 @@ module.exports = class PluginManager {
40
42
  pluginConfig = { enabled: pluginConfig }
41
43
  }
42
44
 
43
- this._pluginsByName[name].configure(getConfig(name, pluginConfig))
45
+ const config = {
46
+ ...this._configsByName[name],
47
+ ...pluginConfig
48
+ }
49
+
50
+ this._pluginsByName[name].configure(getConfig(name, config))
44
51
  }
45
52
 
46
53
  // like instrumenter.enable()
47
54
  configure (config) {
48
- const serviceMapping = config.serviceMapping
55
+ const { logInjection, serviceMapping } = config
49
56
 
50
57
  if (config.plugins !== false) {
51
58
  for (const name in this._pluginsByName) {
52
- const pluginConfig = {}
59
+ const pluginConfig = {
60
+ ...this._configsByName[name],
61
+ logInjection
62
+ }
53
63
  if (serviceMapping && serviceMapping[name]) {
54
64
  pluginConfig.service = serviceMapping[name]
55
65
  }
56
66
  this.configurePlugin(name, pluginConfig)
57
67
  }
58
- } else {
59
- for (const name in this._pluginsByName) {
60
- this.configurePlugin(name, false)
61
- }
62
68
  }
63
69
  }
64
70
 
@@ -14,6 +14,7 @@ module.exports = {
14
14
  'elasticsearch': require('../../../datadog-plugin-elasticsearch/src'),
15
15
  'express': require('../../../datadog-plugin-express/src'),
16
16
  'fastify': require('../../../datadog-plugin-fastify/src'),
17
+ 'find-my-way': require('../../../datadog-plugin-find-my-way/src'),
17
18
  'fs': require('../../../datadog-plugin-fs/src'),
18
19
  'google-cloud-pubsub': require('../../../datadog-plugin-google-cloud-pubsub/src'),
19
20
  'graphql': require('../../../datadog-plugin-graphql/src'),
@@ -23,10 +24,8 @@ module.exports = {
23
24
  'http2': require('../../../datadog-plugin-http2/src'),
24
25
  'ioredis': require('../../../datadog-plugin-ioredis/src'),
25
26
  'jest': require('../../../datadog-plugin-jest/src'),
26
- 'knex': require('../../../datadog-plugin-knex/src'),
27
27
  'koa': require('../../../datadog-plugin-koa/src'),
28
28
  'kafkajs': require('../../../datadog-plugin-kafkajs/src'),
29
- 'limitd-client': require('../../../datadog-plugin-limitd-client/src'),
30
29
  'memcached': require('../../../datadog-plugin-memcached/src'),
31
30
  'microgateway-core': require('../../../datadog-plugin-microgateway-core/src'),
32
31
  'mocha': require('../../../datadog-plugin-mocha/src'),
@@ -31,11 +31,8 @@ function messageProxy (message, holder) {
31
31
  module.exports = class LogPlugin extends Plugin {
32
32
  constructor (...args) {
33
33
  super(...args)
34
- this.addSub(`apm:${this.constructor.name}:log`, (arg) => {
35
- // TODO rather than checking this every time, setting it ought to enable/disable any plugin
36
- // extending from this one
37
- if (!this.tracer._logInjection) return
38
34
 
35
+ this.addSub(`apm:${this.constructor.name}:log`, (arg) => {
39
36
  const store = storage.getStore()
40
37
  const span = store && store.span
41
38
 
@@ -46,4 +43,11 @@ module.exports = class LogPlugin extends Plugin {
46
43
  arg.message = messageProxy(arg.message, holder)
47
44
  })
48
45
  }
46
+
47
+ configure (config) {
48
+ return super.configure({
49
+ ...config,
50
+ enabled: config.enabled && config.logInjection
51
+ })
52
+ }
49
53
  }
@@ -56,6 +56,14 @@ module.exports = class Plugin {
56
56
  this._subscriptions.push(new Subscription(channelName, handler))
57
57
  }
58
58
 
59
+ addError (error) {
60
+ const store = storage.getStore()
61
+
62
+ if (!store || !store.span) return
63
+
64
+ store.span.setTag('error', error)
65
+ }
66
+
59
67
  configure (config) {
60
68
  if (typeof config === 'boolean') {
61
69
  config = { enabled: config }
@@ -1,4 +1,7 @@
1
1
  const path = require('path')
2
+ const fs = require('fs')
3
+
4
+ const ignore = require('ignore')
2
5
 
3
6
  const { getGitMetadata } = require('./git')
4
7
  const { getUserProviderGitMetadata } = require('./user-provided-git')
@@ -16,6 +19,10 @@ const {
16
19
  } = require('./tags')
17
20
  const id = require('../../id')
18
21
 
22
+ const { SPAN_TYPE, RESOURCE_NAME, SAMPLING_PRIORITY } = require('../../../../../ext/tags')
23
+ const { SAMPLING_RULE_DECISION } = require('../../constants')
24
+ const { AUTO_KEEP } = require('../../../../../ext/priority')
25
+
19
26
  const TEST_FRAMEWORK = 'test.framework'
20
27
  const TEST_FRAMEWORK_VERSION = 'test.framework_version'
21
28
  const TEST_TYPE = 'test.type'
@@ -25,6 +32,7 @@ const TEST_STATUS = 'test.status'
25
32
  const TEST_PARAMETERS = 'test.parameters'
26
33
  const TEST_SKIP_REASON = 'test.skip_reason'
27
34
  const TEST_IS_RUM_ACTIVE = 'test.is_rum_active'
35
+ const TEST_CODE_OWNERS = 'test.codeowners'
28
36
 
29
37
  const ERROR_TYPE = 'error.type'
30
38
  const ERROR_MESSAGE = 'error.msg'
@@ -35,6 +43,7 @@ const CI_APP_ORIGIN = 'ciapp-test'
35
43
  const JEST_TEST_RUNNER = 'test.jest.test_runner'
36
44
 
37
45
  module.exports = {
46
+ TEST_CODE_OWNERS,
38
47
  TEST_FRAMEWORK,
39
48
  TEST_FRAMEWORK_VERSION,
40
49
  JEST_TEST_RUNNER,
@@ -53,7 +62,10 @@ module.exports = {
53
62
  getTestParametersString,
54
63
  finishAllTraceSpans,
55
64
  getTestParentSpan,
56
- getTestSuitePath
65
+ getTestSuitePath,
66
+ getCodeOwnersFileEntries,
67
+ getCodeOwnersForFilename,
68
+ getTestCommonTags
57
69
  }
58
70
 
59
71
  function getTestEnvironmentMetadata (testFramework, config) {
@@ -127,6 +139,20 @@ function getTestParentSpan (tracer) {
127
139
  'x-datadog-parent-id': '0000000000000000'
128
140
  })
129
141
  }
142
+
143
+ function getTestCommonTags (name, suite, version) {
144
+ return {
145
+ [SPAN_TYPE]: 'test',
146
+ [TEST_TYPE]: 'test',
147
+ [SAMPLING_RULE_DECISION]: 1,
148
+ [SAMPLING_PRIORITY]: AUTO_KEEP,
149
+ [TEST_NAME]: name,
150
+ [TEST_SUITE]: suite,
151
+ [RESOURCE_NAME]: `${suite}.${name}`,
152
+ [TEST_FRAMEWORK_VERSION]: version
153
+ }
154
+ }
155
+
130
156
  /**
131
157
  * We want to make sure that test suites are reported the same way for
132
158
  * every OS, so we replace `path.sep` by `/`
@@ -140,3 +166,55 @@ function getTestSuitePath (testSuiteAbsolutePath, sourceRoot) {
140
166
 
141
167
  return testSuitePath.replace(path.sep, '/')
142
168
  }
169
+
170
+ const POSSIBLE_CODEOWNERS_LOCATIONS = [
171
+ 'CODEOWNERS',
172
+ '.github/CODEOWNERS',
173
+ 'docs/CODEOWNERS',
174
+ '.gitlab/CODEOWNERS'
175
+ ]
176
+
177
+ function getCodeOwnersFileEntries (rootDir = process.cwd()) {
178
+ let codeOwnersContent
179
+
180
+ POSSIBLE_CODEOWNERS_LOCATIONS.forEach(location => {
181
+ try {
182
+ codeOwnersContent = fs.readFileSync(`${rootDir}/${location}`).toString()
183
+ } catch (e) {
184
+ // retry with next path
185
+ }
186
+ })
187
+ if (!codeOwnersContent) {
188
+ return null
189
+ }
190
+
191
+ const entries = []
192
+ const lines = codeOwnersContent.split('\n')
193
+
194
+ for (const line of lines) {
195
+ const [content] = line.split('#')
196
+ const trimmed = content.trim()
197
+ if (trimmed === '') continue
198
+ const [pattern, ...owners] = trimmed.split(/\s+/)
199
+ entries.push({ pattern, owners })
200
+ }
201
+ // Reverse because rules defined last take precedence
202
+ return entries.reverse()
203
+ }
204
+
205
+ function getCodeOwnersForFilename (filename, entries) {
206
+ if (!entries) {
207
+ return null
208
+ }
209
+ for (const entry of entries) {
210
+ try {
211
+ const isResponsible = ignore().add(entry.pattern).ignores(filename)
212
+ if (isResponsible) {
213
+ return JSON.stringify(entry.owners)
214
+ }
215
+ } catch (e) {
216
+ return null
217
+ }
218
+ }
219
+ return null
220
+ }
@@ -52,10 +52,38 @@ const web = {
52
52
  })
53
53
  },
54
54
 
55
- startSpan (tracer, config, req, res, name) {
55
+ setFramework (req, name, config) {
56
56
  const context = this.patch(req)
57
+ const span = context.span
58
+
59
+ if (!span) return
60
+
61
+ span.context()._name = `${name}.request`
62
+
63
+ web.setConfig(req, config)
64
+ },
65
+
66
+ setConfig (req, config) {
67
+ const context = contexts.get(req)
68
+ const span = context.span
69
+
57
70
  context.config = config
58
71
 
72
+ if (!config.filter(req.url)) {
73
+ span.setTag(MANUAL_DROP, true)
74
+ span.context()._trace.isRecording = false
75
+ }
76
+
77
+ if (config.service) {
78
+ span.setTag(SERVICE_NAME, config.service)
79
+ }
80
+
81
+ analyticsSampler.sample(span, config.measured, true)
82
+ },
83
+
84
+ startSpan (tracer, config, req, res, name) {
85
+ const context = this.patch(req)
86
+
59
87
  let span
60
88
 
61
89
  if (context.span) {
@@ -69,6 +97,8 @@ const web = {
69
97
  context.span = span
70
98
  context.res = res
71
99
 
100
+ this.setConfig(req, config)
101
+
72
102
  return span
73
103
  },
74
104
  wrap (req) {
@@ -83,16 +113,6 @@ const web = {
83
113
  instrument (tracer, config, req, res, name, callback) {
84
114
  const span = this.startSpan(tracer, config, req, res, name)
85
115
 
86
- if (!config.filter(req.url)) {
87
- span.setTag(MANUAL_DROP, true)
88
- }
89
-
90
- if (config.service) {
91
- span.setTag(SERVICE_NAME, config.service)
92
- }
93
-
94
- analyticsSampler.sample(span, config.measured, true)
95
-
96
116
  this.wrap(req)
97
117
 
98
118
  return callback && tracer.scope().activate(span, () => callback(span))
@@ -110,6 +130,14 @@ const web = {
110
130
  }
111
131
  },
112
132
 
133
+ setRoute (req, path) {
134
+ const context = contexts.get(req)
135
+
136
+ if (!context) return
137
+
138
+ context.paths = [path]
139
+ },
140
+
113
141
  // Remove the current route segment.
114
142
  exitRoute (req) {
115
143
  contexts.get(req).paths.pop()
@@ -231,8 +259,9 @@ const web = {
231
259
  const context = contexts.get(req)
232
260
  const span = context.span
233
261
  const error = context.error
262
+ const hasMiddlewareError = span.context()._tags['error'] || span.context()._tags['error.msg']
234
263
 
235
- if (!context.config.validateStatus(statusCode)) {
264
+ if (!hasMiddlewareError && !context.config.validateStatus(statusCode)) {
236
265
  span.setTag(ERROR, error || true)
237
266
  }
238
267
  },
@@ -6,8 +6,8 @@ const { URL } = require('url')
6
6
  const { AgentExporter } = require('./exporters/agent')
7
7
  const { FileExporter } = require('./exporters/file')
8
8
  const { ConsoleLogger } = require('./loggers/console')
9
- const CpuProfiler = require('./profilers/cpu')
10
- const HeapProfiler = require('./profilers/heap')
9
+ const WallProfiler = require('./profilers/wall')
10
+ const SpaceProfiler = require('./profilers/space')
11
11
  const { tagger } = require('./tagger')
12
12
 
13
13
  const {
@@ -64,8 +64,8 @@ class Config {
64
64
  ], this)
65
65
 
66
66
  const profilers = coalesce(options.profilers, DD_PROFILING_PROFILERS, [
67
- new CpuProfiler(),
68
- new HeapProfiler()
67
+ new WallProfiler(),
68
+ new SpaceProfiler()
69
69
  ])
70
70
 
71
71
  this.profilers = ensureProfilers(profilers, this)
@@ -100,10 +100,10 @@ function ensureExporters (exporters, options) {
100
100
 
101
101
  function getProfiler (name, options) {
102
102
  switch (name) {
103
- case 'cpu':
104
- return new CpuProfiler(options)
105
- case 'heap':
106
- return new HeapProfiler(options)
103
+ case 'wall':
104
+ return new WallProfiler(options)
105
+ case 'space':
106
+ return new SpaceProfiler(options)
107
107
  default:
108
108
  options.logger.error(`Unknown profiler "${name}"`)
109
109
  }
@@ -5,7 +5,7 @@ const { request } = require('http')
5
5
  const FormData = require('form-data')
6
6
 
7
7
  // TODO: avoid using dd-trace internals. Make this a separate module?
8
- const docker = require('../../exporters/agent/docker')
8
+ const docker = require('../../exporters/common/docker')
9
9
  const version = require('../../../lib/version')
10
10
 
11
11
  const containerId = docker.id()
@@ -1,8 +1,8 @@
1
1
  'use strict'
2
2
 
3
3
  const { Profiler } = require('./profiler')
4
- const CpuProfiler = require('./profilers/cpu')
5
- const HeapProfiler = require('./profilers/heap')
4
+ const WallProfiler = require('./profilers/wall')
5
+ const SpaceProfiler = require('./profilers/space')
6
6
  const { AgentExporter } = require('./exporters/agent')
7
7
  const { FileExporter } = require('./exporters/file')
8
8
  const { ConsoleLogger } = require('./loggers/console')
@@ -13,7 +13,7 @@ module.exports = {
13
13
  profiler,
14
14
  AgentExporter,
15
15
  FileExporter,
16
- CpuProfiler,
17
- HeapProfiler,
16
+ WallProfiler,
17
+ SpaceProfiler,
18
18
  ConsoleLogger
19
19
  }