dd-trace 2.12.0 → 2.13.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 +0 -1
  2. package/ext/formats.js +3 -5
  3. package/package.json +4 -5
  4. package/packages/datadog-instrumentations/index.js +1 -52
  5. package/packages/datadog-instrumentations/src/connect.js +5 -5
  6. package/packages/datadog-instrumentations/src/fastify.js +12 -25
  7. package/packages/datadog-instrumentations/src/helpers/hooks.js +68 -0
  8. package/packages/datadog-instrumentations/src/helpers/instrument.js +5 -34
  9. package/packages/datadog-instrumentations/src/helpers/instrumentations.js +3 -0
  10. package/packages/datadog-instrumentations/src/helpers/register.js +59 -0
  11. package/packages/datadog-instrumentations/src/koa.js +5 -5
  12. package/packages/datadog-instrumentations/src/mocha.js +4 -1
  13. package/packages/datadog-instrumentations/src/restify.js +27 -5
  14. package/packages/datadog-instrumentations/src/router.js +5 -5
  15. package/packages/datadog-plugin-aws-sdk/src/base.js +1 -2
  16. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -2
  17. package/packages/datadog-plugin-mocha/src/index.js +2 -2
  18. package/packages/datadog-plugin-restify/src/index.js +7 -0
  19. package/packages/datadog-plugin-router/src/index.js +13 -8
  20. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +220 -0
  21. package/packages/dd-trace/src/config.js +6 -0
  22. package/packages/dd-trace/src/encode/0.4.js +4 -0
  23. package/packages/dd-trace/src/{profiling/exporters → exporters/common}/form-data.js +0 -0
  24. package/packages/dd-trace/src/exporters/common/request.js +49 -34
  25. package/packages/dd-trace/src/exporters/common/writer.js +8 -1
  26. package/packages/dd-trace/src/id.js +16 -13
  27. package/packages/dd-trace/src/noop/span.js +12 -12
  28. package/packages/dd-trace/src/noop/tracer.js +8 -5
  29. package/packages/dd-trace/src/opentracing/propagation/text_map.js +6 -6
  30. package/packages/dd-trace/src/opentracing/span.js +63 -49
  31. package/packages/dd-trace/src/opentracing/span_context.js +1 -5
  32. package/packages/dd-trace/src/opentracing/tracer.js +31 -36
  33. package/packages/dd-trace/src/plugin_manager.js +95 -65
  34. package/packages/dd-trace/src/plugins/index.js +57 -45
  35. package/packages/dd-trace/src/plugins/util/ci.js +34 -9
  36. package/packages/dd-trace/src/plugins/util/git.js +52 -2
  37. package/packages/dd-trace/src/plugins/util/tags.js +4 -1
  38. package/packages/dd-trace/src/plugins/util/web.js +5 -2
  39. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -1
  40. package/packages/dd-trace/src/profiling/profilers/cpu.js +3 -3
  41. package/packages/dd-trace/src/proxy.js +16 -12
  42. package/packages/dd-trace/src/startup-log.js +8 -19
  43. package/packages/dd-trace/src/telemetry.js +1 -14
  44. package/scripts/install_plugin_modules.js +17 -26
@@ -17,7 +17,8 @@ const {
17
17
  CI_WORKSPACE_PATH,
18
18
  CI_JOB_URL,
19
19
  CI_JOB_NAME,
20
- CI_STAGE_NAME
20
+ CI_STAGE_NAME,
21
+ CI_ENV_VARS
21
22
  } = require('./tags')
22
23
 
23
24
  // Receives a string with the form 'John Doe <john.doe@gmail.com>'
@@ -104,7 +105,8 @@ module.exports = {
104
105
  GIT_BRANCH: JENKINS_GIT_BRANCH,
105
106
  GIT_COMMIT: JENKINS_GIT_COMMIT,
106
107
  GIT_URL: JENKINS_GIT_REPOSITORY_URL,
107
- GIT_URL_1: JENKINS_GIT_REPOSITORY_URL_1
108
+ GIT_URL_1: JENKINS_GIT_REPOSITORY_URL_1,
109
+ DD_CUSTOM_TRACE_ID
108
110
  } = env
109
111
 
110
112
  tags = {
@@ -114,7 +116,8 @@ module.exports = {
114
116
  [CI_PROVIDER_NAME]: 'jenkins',
115
117
  [GIT_COMMIT_SHA]: JENKINS_GIT_COMMIT,
116
118
  [GIT_REPOSITORY_URL]: JENKINS_GIT_REPOSITORY_URL || JENKINS_GIT_REPOSITORY_URL_1,
117
- [CI_WORKSPACE_PATH]: WORKSPACE
119
+ [CI_WORKSPACE_PATH]: WORKSPACE,
120
+ [CI_ENV_VARS]: JSON.stringify({ DD_CUSTOM_TRACE_ID })
118
121
  }
119
122
 
120
123
  const isTag = JENKINS_GIT_BRANCH && JENKINS_GIT_BRANCH.includes('tags')
@@ -152,7 +155,9 @@ module.exports = {
152
155
  CI_JOB_NAME: GITLAB_CI_JOB_NAME,
153
156
  CI_COMMIT_MESSAGE,
154
157
  CI_COMMIT_TIMESTAMP,
155
- CI_COMMIT_AUTHOR
158
+ CI_COMMIT_AUTHOR,
159
+ CI_PROJECT_URL: GITLAB_PROJECT_URL,
160
+ CI_JOB_ID: GITLAB_CI_JOB_ID
156
161
  } = env
157
162
 
158
163
  const { name, email } = parseEmailAndName(CI_COMMIT_AUTHOR)
@@ -174,7 +179,12 @@ module.exports = {
174
179
  [GIT_COMMIT_MESSAGE]: CI_COMMIT_MESSAGE,
175
180
  [GIT_COMMIT_AUTHOR_NAME]: name,
176
181
  [GIT_COMMIT_AUTHOR_EMAIL]: email,
177
- [GIT_COMMIT_AUTHOR_DATE]: CI_COMMIT_TIMESTAMP
182
+ [GIT_COMMIT_AUTHOR_DATE]: CI_COMMIT_TIMESTAMP,
183
+ [CI_ENV_VARS]: JSON.stringify({
184
+ CI_PROJECT_URL: GITLAB_PROJECT_URL,
185
+ CI_PIPELINE_ID: GITLAB_PIPELINE_ID,
186
+ CI_JOB_ID: GITLAB_CI_JOB_ID
187
+ })
178
188
  }
179
189
  }
180
190
 
@@ -188,7 +198,8 @@ module.exports = {
188
198
  CIRCLE_TAG,
189
199
  CIRCLE_SHA1,
190
200
  CIRCLE_REPOSITORY_URL,
191
- CIRCLE_JOB
201
+ CIRCLE_JOB,
202
+ CIRCLE_BUILD_NUM
192
203
  } = env
193
204
 
194
205
  const pipelineUrl = `https://app.circleci.com/pipelines/workflows/${CIRCLE_WORKFLOW_ID}`
@@ -203,7 +214,11 @@ module.exports = {
203
214
  [GIT_REPOSITORY_URL]: CIRCLE_REPOSITORY_URL,
204
215
  [CI_JOB_URL]: CIRCLE_BUILD_URL,
205
216
  [CI_WORKSPACE_PATH]: CIRCLE_WORKING_DIRECTORY,
206
- [CIRCLE_TAG ? GIT_TAG : GIT_BRANCH]: CIRCLE_TAG || CIRCLE_BRANCH
217
+ [CIRCLE_TAG ? GIT_TAG : GIT_BRANCH]: CIRCLE_TAG || CIRCLE_BRANCH,
218
+ [CI_ENV_VARS]: JSON.stringify({
219
+ CIRCLE_WORKFLOW_ID,
220
+ CIRCLE_BUILD_NUM
221
+ })
207
222
  }
208
223
  }
209
224
 
@@ -243,7 +258,13 @@ module.exports = {
243
258
  [GIT_REPOSITORY_URL]: repositoryURL,
244
259
  [CI_JOB_URL]: jobUrl,
245
260
  [CI_WORKSPACE_PATH]: GITHUB_WORKSPACE,
246
- [refKey]: ref
261
+ [refKey]: ref,
262
+ [CI_ENV_VARS]: JSON.stringify({
263
+ GITHUB_SERVER_URL,
264
+ GITHUB_REPOSITORY,
265
+ GITHUB_RUN_ID,
266
+ GITHUB_RUN_ATTEMPT
267
+ })
247
268
  }
248
269
  }
249
270
 
@@ -443,7 +464,11 @@ module.exports = {
443
464
  [refKey]: ref,
444
465
  [GIT_COMMIT_AUTHOR_NAME]: BUILDKITE_BUILD_AUTHOR,
445
466
  [GIT_COMMIT_AUTHOR_EMAIL]: BUILDKITE_BUILD_AUTHOR_EMAIL,
446
- [GIT_COMMIT_MESSAGE]: BUILDKITE_MESSAGE
467
+ [GIT_COMMIT_MESSAGE]: BUILDKITE_MESSAGE,
468
+ [CI_ENV_VARS]: JSON.stringify({
469
+ BUILDKITE_BUILD_ID,
470
+ BUILDKITE_JOB_ID
471
+ })
447
472
  }
448
473
  }
449
474
 
@@ -1,5 +1,7 @@
1
- const { sanitizedExec } = require('./exec')
1
+ const { execSync } = require('child_process')
2
+ const os = require('os')
2
3
 
4
+ const { sanitizedExec } = require('./exec')
3
5
  const {
4
6
  GIT_COMMIT_SHA,
5
7
  GIT_BRANCH,
@@ -15,6 +17,48 @@ const {
15
17
  CI_WORKSPACE_PATH
16
18
  } = require('./tags')
17
19
 
20
+ function getRepositoryUrl () {
21
+ return sanitizedExec('git config --get remote.origin.url', { stdio: 'pipe' })
22
+ }
23
+
24
+ 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
+ }
30
+
31
+ function getCommitsToUpload (commitsToExclude) {
32
+ let gitCommandToGetCommitsToUpload =
33
+ 'git rev-list --objects --no-object-names --filter=blob:none --since="1 month ago" HEAD'
34
+
35
+ commitsToExclude.forEach(commit => {
36
+ gitCommandToGetCommitsToUpload = `${gitCommandToGetCommitsToUpload} ^${commit}`
37
+ })
38
+
39
+ return execSync(gitCommandToGetCommitsToUpload, { stdio: 'pipe' })
40
+ .toString()
41
+ .split('\n')
42
+ .filter(commit => !!commit)
43
+ }
44
+
45
+ // Generates pack files to upload and
46
+ // returns the ordered list of packfiles' paths
47
+ function generatePackFilesForCommits (commitsToUpload) {
48
+ const tmpFolder = os.tmpdir()
49
+
50
+ const prefix = Math.floor(Math.random() * 10000)
51
+ const path = `${tmpFolder}/${prefix}`
52
+
53
+ const orderedCommits =
54
+ execSync(
55
+ `git pack-objects --compression=9 --max-pack-size=3m ${path}`,
56
+ { input: commitsToUpload.join('\n') }
57
+ ).toString().split('\n').filter(commit => !!commit)
58
+
59
+ return orderedCommits.map(commit => `${path}-${commit}.pack`)
60
+ }
61
+
18
62
  // If there is ciMetadata, it takes precedence.
19
63
  function getGitMetadata (ciMetadata) {
20
64
  const {
@@ -57,4 +101,10 @@ function getGitMetadata (ciMetadata) {
57
101
  }
58
102
  }
59
103
 
60
- module.exports = { getGitMetadata }
104
+ module.exports = {
105
+ getGitMetadata,
106
+ getLatestCommits,
107
+ getRepositoryUrl,
108
+ generatePackFilesForCommits,
109
+ getCommitsToUpload
110
+ }
@@ -20,6 +20,8 @@ const CI_JOB_URL = 'ci.job.url'
20
20
  const CI_JOB_NAME = 'ci.job.name'
21
21
  const CI_STAGE_NAME = 'ci.stage.name'
22
22
 
23
+ const CI_ENV_VARS = '_dd.ci.env_vars'
24
+
23
25
  module.exports = {
24
26
  GIT_COMMIT_SHA,
25
27
  GIT_BRANCH,
@@ -40,5 +42,6 @@ module.exports = {
40
42
  CI_WORKSPACE_PATH,
41
43
  CI_JOB_URL,
42
44
  CI_JOB_NAME,
43
- CI_STAGE_NAME
45
+ CI_STAGE_NAME,
46
+ CI_ENV_VARS
44
47
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  const uniq = require('lodash.uniq')
4
4
  const analyticsSampler = require('../../analytics_sampler')
5
- const FORMAT_HTTP_HEADERS = require('opentracing').FORMAT_HTTP_HEADERS
5
+ const FORMAT_HTTP_HEADERS = 'http_headers'
6
6
  const log = require('../../log')
7
7
  const tags = require('../../../../../ext/tags')
8
8
  const types = require('../../../../../ext/types')
@@ -270,7 +270,10 @@ const web = {
270
270
  addError (req, error) {
271
271
  if (error instanceof Error) {
272
272
  const context = contexts.get(req)
273
- context.error = error
273
+
274
+ if (context) {
275
+ context.error = error
276
+ }
274
277
  }
275
278
  },
276
279
 
@@ -2,10 +2,10 @@
2
2
 
3
3
  const retry = require('retry')
4
4
  const { request } = require('http')
5
- const FormData = require('./form-data')
6
5
 
7
6
  // TODO: avoid using dd-trace internals. Make this a separate module?
8
7
  const docker = require('../../exporters/common/docker')
8
+ const FormData = require('../../exporters/common/form-data')
9
9
  const version = require('../../../../../package.json').version
10
10
 
11
11
  const containerId = docker.id()
@@ -20,7 +20,7 @@ function getStartedSpans (activeSpan) {
20
20
  }
21
21
 
22
22
  function getSpanContextTags (span) {
23
- return span._context()._tags
23
+ return span.context()._tags
24
24
  }
25
25
 
26
26
  function isWebServerSpan (tags) {
@@ -55,13 +55,13 @@ class NativeCpuProfiler {
55
55
  const active = getActiveSpan()
56
56
  if (!active) return
57
57
 
58
- const activeCtx = active._context()
58
+ const activeCtx = active.context()
59
59
  if (!activeCtx) return
60
60
 
61
61
  const spans = getStartedSpans(active)
62
62
  if (!spans || !spans.length) return
63
63
 
64
- const firstCtx = spans[0]._context()
64
+ const firstCtx = spans[0].context()
65
65
  if (!firstCtx) return
66
66
 
67
67
  const labels = {
@@ -1,26 +1,22 @@
1
1
  'use strict'
2
2
 
3
- const BaseTracer = require('opentracing').Tracer
4
3
  const NoopTracer = require('./noop/tracer')
5
4
  const DatadogTracer = require('./tracer')
6
5
  const Config = require('./config')
7
- const Instrumenter = require('./instrumenter')
8
- const PluginManager = require('./plugin_manager')
9
6
  const metrics = require('./metrics')
10
7
  const log = require('./log')
11
8
  const { isFalse } = require('./util')
12
- const { setStartupLogInstrumenter } = require('./startup-log')
9
+ const { setStartupLogPluginManager } = require('./startup-log')
13
10
  const telemetry = require('./telemetry')
11
+ const PluginManager = require('./plugin_manager')
12
+ const { sendGitMetadata } = require('./ci-visibility/exporters/git/git_metadata')
14
13
 
15
14
  const noop = new NoopTracer()
16
15
 
17
- class Tracer extends BaseTracer {
16
+ class Tracer {
18
17
  constructor () {
19
- super()
20
-
21
18
  this._initialized = false
22
19
  this._tracer = noop
23
- this._instrumenter = new Instrumenter(this)
24
20
  this._pluginManager = new PluginManager(this)
25
21
  this._deprecate = method => log.deprecate(`tracer.${method}`, [
26
22
  `tracer.${method}() is deprecated.`,
@@ -61,10 +57,19 @@ class Tracer extends BaseTracer {
61
57
  }
62
58
 
63
59
  this._tracer = new DatadogTracer(config)
64
- this._instrumenter.enable(config)
65
60
  this._pluginManager.configure(config)
66
- setStartupLogInstrumenter(this._instrumenter)
67
- telemetry.start(config, this._instrumenter, this._pluginManager)
61
+ setStartupLogPluginManager(this._pluginManager)
62
+ telemetry.start(config, this._pluginManager)
63
+ }
64
+
65
+ if (config.isGitUploadEnabled) {
66
+ sendGitMetadata(config.site, (err) => {
67
+ if (err) {
68
+ log.error(`Error uploading git metadata: ${err}`)
69
+ } else {
70
+ log.debug('Successfully uploaded git metadata')
71
+ }
72
+ })
68
73
  }
69
74
  } catch (e) {
70
75
  log.error(e)
@@ -74,7 +79,6 @@ class Tracer extends BaseTracer {
74
79
  }
75
80
 
76
81
  use () {
77
- this._instrumenter.use(...arguments)
78
82
  this._pluginManager.configurePlugin(...arguments)
79
83
  return this
80
84
  }
@@ -5,38 +5,27 @@ const mainLogger = require('./log')
5
5
  const os = require('os')
6
6
  const { inspect } = require('util')
7
7
  const tracerVersion = require('../../../package.json').version
8
- const requirePackageJson = require('./require-package-json')
9
8
 
10
9
  const logger = Object.create(mainLogger)
11
10
  logger._enabled = true
12
11
 
13
12
  let config
14
- let instrumenter
13
+ let pluginManager
15
14
  let samplingRules = []
16
-
17
15
  let alreadyRan = false
18
16
 
19
17
  function getIntegrationsAndAnalytics () {
20
18
  const integrations = new Set()
21
19
  const extras = {}
22
- for (const plugin of instrumenter._instrumented.keys()) {
23
- if (plugin.versions) {
24
- try {
25
- const version = requirePackageJson(plugin.name, module).version
26
- integrations.add(`${plugin.name}@${version}`)
27
- } catch (e) {
28
- integrations.add(plugin.name)
29
- }
30
- } else {
31
- integrations.add(plugin.name)
32
- }
20
+ for (const pluginName in pluginManager._pluginsByName) {
21
+ integrations.add(pluginName)
33
22
  }
34
23
  extras.integrations_loaded = Array.from(integrations)
35
24
  return extras
36
25
  }
37
26
 
38
27
  function startupLog ({ agentError } = {}) {
39
- if (!config || !instrumenter) {
28
+ if (!config || !pluginManager) {
40
29
  return
41
30
  }
42
31
 
@@ -106,7 +95,7 @@ function startupLog ({ agentError } = {}) {
106
95
  }
107
96
 
108
97
  config = undefined
109
- instrumenter = undefined
98
+ pluginManager = undefined
110
99
  samplingRules = undefined
111
100
  }
112
101
 
@@ -114,8 +103,8 @@ function setStartupLogConfig (aConfig) {
114
103
  config = aConfig
115
104
  }
116
105
 
117
- function setStartupLogInstrumenter (theInstrumenter) {
118
- instrumenter = theInstrumenter
106
+ function setStartupLogPluginManager (thePluginManager) {
107
+ pluginManager = thePluginManager
119
108
  }
120
109
 
121
110
  function setSamplingRules (theRules) {
@@ -125,6 +114,6 @@ function setSamplingRules (theRules) {
125
114
  module.exports = {
126
115
  startupLog,
127
116
  setStartupLogConfig,
128
- setStartupLogInstrumenter,
117
+ setStartupLogPluginManager,
129
118
  setSamplingRules
130
119
  }
@@ -9,7 +9,6 @@ const os = require('os')
9
9
  const request = require('./exporters/common/request')
10
10
 
11
11
  let config
12
- let instrumenter
13
12
  let pluginManager
14
13
 
15
14
  let seqId = 0
@@ -20,17 +19,6 @@ const sentIntegrations = new Set()
20
19
 
21
20
  function getIntegrations () {
22
21
  const newIntegrations = []
23
- for (const plugin of instrumenter._instrumented.keys()) {
24
- if (sentIntegrations.has(plugin.name)) {
25
- continue
26
- }
27
- newIntegrations.push({
28
- name: plugin.name,
29
- enabled: true,
30
- auto_enabled: true
31
- })
32
- sentIntegrations.add(plugin.name)
33
- }
34
22
  for (const pluginName in pluginManager._pluginsByName) {
35
23
  if (sentIntegrations.has(pluginName)) {
36
24
  continue
@@ -146,12 +134,11 @@ function sendData (reqType, payload = {}) {
146
134
  })
147
135
  }
148
136
 
149
- function start (aConfig, theInstrumenter, thePluginManager) {
137
+ function start (aConfig, thePluginManager) {
150
138
  if (!aConfig.telemetryEnabled) {
151
139
  return
152
140
  }
153
141
  config = aConfig
154
- instrumenter = theInstrumenter
155
142
  pluginManager = thePluginManager
156
143
  application = createAppObject()
157
144
  host = createHostObject()
@@ -7,8 +7,6 @@ const semver = require('semver')
7
7
  const proxyquire = require('proxyquire')
8
8
  const exec = require('./helpers/exec')
9
9
  const childProcess = require('child_process')
10
- const plugins = require('../packages/dd-trace/src/plugins')
11
- const Plugin = require('../packages/dd-trace/src/plugins/plugin')
12
10
  const externals = require('../packages/dd-trace/test/plugins/externals')
13
11
 
14
12
  const requirePackageJsonPath = require.resolve('../packages/dd-trace/src/require-package-json')
@@ -16,6 +14,9 @@ const requirePackageJsonPath = require.resolve('../packages/dd-trace/src/require
16
14
  const workspaces = new Set()
17
15
  const versionLists = {}
18
16
  const deps = {}
17
+ const names = []
18
+ const filter = process.env.hasOwnProperty('PLUGINS') && process.env.PLUGINS.split('|')
19
+
19
20
  Object.keys(externals).forEach(external => externals[external].forEach(thing => {
20
21
  if (thing.dep) {
21
22
  if (!deps[external]) {
@@ -29,7 +30,10 @@ fs.readdirSync(path.join(__dirname, '../packages/datadog-instrumentations/src'))
29
30
  .filter(file => file.endsWith('js'))
30
31
  .forEach(file => {
31
32
  file = file.replace('.js', '')
32
- plugins[file] = { name: file, prototype: Object.create(Plugin.prototype) }
33
+
34
+ if (!filter || filter.includes(file)) {
35
+ names.push(file)
36
+ }
33
37
  })
34
38
 
35
39
  run()
@@ -42,32 +46,19 @@ async function run () {
42
46
  }
43
47
 
44
48
  async function assertVersions () {
45
- let filter = []
46
- let names = Object.keys(plugins)
47
-
48
- if (process.env.hasOwnProperty('PLUGINS')) {
49
- filter = process.env.PLUGINS.split('|')
50
- names = names.filter(name => ~filter.indexOf(name))
51
- }
52
-
53
49
  const internals = names
54
50
  .map(key => {
55
- const plugin = plugins[key]
56
- if (plugin.prototype instanceof Plugin) {
57
- const instrumentations = []
58
- const name = plugin.name
59
-
60
- try {
61
- loadInstFile(`${name}/server.js`, instrumentations)
62
- loadInstFile(`${name}/client.js`, instrumentations)
63
- } catch (e) {
64
- loadInstFile(`${name}.js`, instrumentations)
65
- }
66
-
67
- return instrumentations
68
- } else {
69
- return plugin
51
+ const instrumentations = []
52
+ const name = key
53
+
54
+ try {
55
+ loadInstFile(`${name}/server.js`, instrumentations)
56
+ loadInstFile(`${name}/client.js`, instrumentations)
57
+ } catch (e) {
58
+ loadInstFile(`${name}.js`, instrumentations)
70
59
  }
60
+
61
+ return instrumentations
71
62
  })
72
63
  .reduce((prev, next) => prev.concat(next), [])
73
64