dd-trace 2.11.0 → 3.0.0-pre.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 (45) hide show
  1. package/LICENSE-3rdparty.csv +0 -1
  2. package/ci/init.js +2 -26
  3. package/ci/jest/env.js +2 -3
  4. package/index.d.ts +3 -10
  5. package/package.json +4 -5
  6. package/packages/datadog-core/src/storage/async_hooks.js +4 -4
  7. package/packages/datadog-core/src/storage/async_resource.js +14 -4
  8. package/packages/datadog-instrumentations/src/connect.js +4 -4
  9. package/packages/datadog-instrumentations/src/couchbase.js +166 -61
  10. package/packages/datadog-instrumentations/src/fastify.js +12 -25
  11. package/packages/datadog-instrumentations/src/graphql.js +17 -5
  12. package/packages/datadog-instrumentations/src/koa.js +4 -4
  13. package/packages/datadog-instrumentations/src/mocha.js +88 -18
  14. package/packages/datadog-instrumentations/src/restify.js +4 -8
  15. package/packages/datadog-instrumentations/src/router.js +4 -4
  16. package/packages/datadog-plugin-couchbase/src/index.js +8 -10
  17. package/packages/datadog-plugin-graphql/src/resolve.js +2 -0
  18. package/packages/datadog-plugin-grpc/src/client.js +2 -2
  19. package/packages/datadog-plugin-grpc/src/server.js +2 -2
  20. package/packages/datadog-plugin-http/src/client.js +1 -1
  21. package/packages/datadog-plugin-http/src/server.js +4 -9
  22. package/packages/datadog-plugin-http2/src/client.js +1 -1
  23. package/packages/datadog-plugin-mocha/src/index.js +80 -3
  24. package/packages/datadog-plugin-next/src/index.js +1 -1
  25. package/packages/datadog-plugin-router/src/index.js +39 -10
  26. package/packages/dd-trace/src/config.js +8 -0
  27. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +111 -15
  28. package/packages/dd-trace/src/exporters/common/request.js +43 -34
  29. package/packages/dd-trace/src/noop/tracer.js +0 -4
  30. package/packages/dd-trace/src/plugin_manager.js +53 -33
  31. package/packages/dd-trace/src/plugins/index.js +0 -1
  32. package/packages/dd-trace/src/plugins/util/test.js +32 -1
  33. package/packages/dd-trace/src/plugins/util/web.js +73 -20
  34. package/packages/dd-trace/src/profiling/config.js +10 -2
  35. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -2
  36. package/packages/dd-trace/src/profiling/exporters/form-data.js +53 -0
  37. package/packages/dd-trace/src/profiling/index.js +2 -0
  38. package/packages/dd-trace/src/profiling/profiler.js +6 -1
  39. package/packages/dd-trace/src/profiling/profilers/cpu.js +126 -0
  40. package/packages/dd-trace/src/proxy.js +0 -19
  41. package/packages/dd-trace/src/scope.js +1 -126
  42. package/packages/dd-trace/src/tracer.js +0 -4
  43. package/cypress/plugin.js +0 -5
  44. package/cypress/support.js +0 -1
  45. package/packages/datadog-plugin-fs/src/index.js +0 -548
@@ -6,6 +6,7 @@ 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')
9
10
  const WallProfiler = require('./profilers/wall')
10
11
  const SpaceProfiler = require('./profilers/space')
11
12
  const { tagger } = require('./tagger')
@@ -13,6 +14,7 @@ const { tagger } = require('./tagger')
13
14
  const {
14
15
  DD_PROFILING_ENABLED,
15
16
  DD_PROFILING_PROFILERS,
17
+ DD_PROFILING_ENDPOINT_COLLECTION_ENABLED,
16
18
  DD_ENV,
17
19
  DD_TAGS,
18
20
  DD_SERVICE,
@@ -37,6 +39,8 @@ class Config {
37
39
  DD_PROFILING_UPLOAD_TIMEOUT, 60 * 1000)
38
40
  const sourceMap = coalesce(options.sourceMap,
39
41
  DD_PROFILING_SOURCE_MAP, true)
42
+ const endpointCollection = coalesce(options.endpointCollection,
43
+ DD_PROFILING_ENDPOINT_COLLECTION_ENABLED, false)
40
44
 
41
45
  this.enabled = String(enabled) !== 'false'
42
46
  this.service = service
@@ -53,6 +57,7 @@ class Config {
53
57
  this.flushInterval = flushInterval
54
58
  this.uploadTimeout = uploadTimeout
55
59
  this.sourceMap = sourceMap
60
+ this.endpointCollection = endpointCollection
56
61
 
57
62
  const hostname = coalesce(options.hostname, DD_AGENT_HOST, 'localhost')
58
63
  const port = coalesce(options.port, DD_TRACE_AGENT_PORT, 8126)
@@ -64,8 +69,8 @@ class Config {
64
69
  ], this)
65
70
 
66
71
  const profilers = coalesce(options.profilers, DD_PROFILING_PROFILERS, [
67
- new WallProfiler(),
68
- new SpaceProfiler()
72
+ new WallProfiler(this),
73
+ new SpaceProfiler(this)
69
74
  ])
70
75
 
71
76
  this.profilers = ensureProfilers(profilers, this)
@@ -100,10 +105,13 @@ function ensureExporters (exporters, options) {
100
105
 
101
106
  function getProfiler (name, options) {
102
107
  switch (name) {
108
+ case 'cpu':
103
109
  case 'wall':
104
110
  return new WallProfiler(options)
105
111
  case 'space':
106
112
  return new SpaceProfiler(options)
113
+ case 'cpu-experimental':
114
+ return new CpuProfiler(options)
107
115
  default:
108
116
  options.logger.error(`Unknown profiler "${name}"`)
109
117
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  const retry = require('retry')
4
4
  const { request } = require('http')
5
- const FormData = require('form-data')
5
+ const FormData = require('./form-data')
6
6
 
7
7
  // TODO: avoid using dd-trace internals. Make this a separate module?
8
8
  const docker = require('../../exporters/common/docker')
@@ -22,7 +22,6 @@ function sendRequest (options, form, callback) {
22
22
  })
23
23
  req.on('error', callback)
24
24
  if (form) form.pipe(req)
25
- req.end()
26
25
  }
27
26
 
28
27
  function getBody (stream, callback) {
@@ -0,0 +1,53 @@
1
+ 'use strict'
2
+
3
+ const { Readable } = require('stream')
4
+ const id = require('../../id')
5
+
6
+ class FormData extends Readable {
7
+ constructor () {
8
+ super()
9
+
10
+ this._boundary = id().toString()
11
+ this._data = []
12
+ }
13
+
14
+ append (key, value, options = {}) {
15
+ this._appendBoundary()
16
+
17
+ if (options.filename) {
18
+ this._appendFile(key, value, options)
19
+ } else {
20
+ this._appendMetadata(key, value, options)
21
+ }
22
+ }
23
+
24
+ getHeaders () {
25
+ return { 'Content-Type': 'multipart/form-data; boundary=' + this._boundary }
26
+ }
27
+
28
+ _appendBoundary () {
29
+ this._data.push(`--${this._boundary}\r\n`)
30
+ }
31
+
32
+ _appendMetadata (key, value) {
33
+ this._data.push(`Content-Disposition: form-data; name="${key}"\r\n\r\n${value}\r\n`)
34
+ }
35
+
36
+ _appendFile (key, value, { filename, contentType = 'application/octet-stream' }) {
37
+ this._data.push(`Content-Disposition: form-data; name="${key}"; filename="${filename}"\r\n`)
38
+ this._data.push(`Content-Type: ${contentType}\r\n\r\n`)
39
+ this._data.push(value)
40
+ this._data.push('\r\n')
41
+ }
42
+
43
+ _read () {
44
+ this.push(this._data.shift())
45
+
46
+ if (this._data.length === 0) {
47
+ this.push(`--${this._boundary}--\r\n`)
48
+ this.push(null)
49
+ }
50
+ }
51
+ }
52
+
53
+ module.exports = FormData
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const { Profiler } = require('./profiler')
4
+ const CpuProfiler = require('./profilers/cpu')
4
5
  const WallProfiler = require('./profilers/wall')
5
6
  const SpaceProfiler = require('./profilers/space')
6
7
  const { AgentExporter } = require('./exporters/agent')
@@ -13,6 +14,7 @@ module.exports = {
13
14
  profiler,
14
15
  AgentExporter,
15
16
  FileExporter,
17
+ CpuProfiler,
16
18
  WallProfiler,
17
19
  SpaceProfiler,
18
20
  ConsoleLogger
@@ -91,7 +91,12 @@ class Profiler extends EventEmitter {
91
91
  if (!profile) continue
92
92
 
93
93
  profiles[profiler.type] = await profiler.encode(profile)
94
- this._logger.debug(`Collected ${profiler.type} profile: ` + JSON.stringify(profile))
94
+ this._logger.debug(() => {
95
+ const profileJson = JSON.stringify(profile, (key, value) => {
96
+ return typeof value === 'bigint' ? value.toString() : value
97
+ })
98
+ return `Collected ${profiler.type} profile: ` + profileJson
99
+ })
95
100
  }
96
101
 
97
102
  this._capture(this._config.flushInterval)
@@ -0,0 +1,126 @@
1
+ 'use strict'
2
+
3
+ const { storage } = require('../../../../datadog-core')
4
+
5
+ const dc = require('diagnostics_channel')
6
+
7
+ const beforeCh = dc.channel('dd-trace:storage:before')
8
+ const afterCh = dc.channel('dd-trace:storage:after')
9
+
10
+ function getActiveSpan () {
11
+ const store = storage.getStore()
12
+ if (!store) return
13
+ return store.span
14
+ }
15
+
16
+ function getStartedSpans (activeSpan) {
17
+ const context = activeSpan.context()
18
+ if (!context) return
19
+ return context._trace.started
20
+ }
21
+
22
+ function getSpanContextTags (span) {
23
+ return span._context()._tags
24
+ }
25
+
26
+ function isWebServerSpan (tags) {
27
+ return tags['span.type'] === 'web'
28
+ }
29
+
30
+ function endpointNameFromTags (tags) {
31
+ return tags['resource.name'] || [
32
+ tags['http.method'],
33
+ tags['http.route']
34
+ ].filter(v => v).join(' ')
35
+ }
36
+
37
+ class NativeCpuProfiler {
38
+ constructor (options = {}) {
39
+ this.type = 'cpu'
40
+ this._frequency = options.frequency || 99
41
+ this._mapper = undefined
42
+ this._pprof = undefined
43
+ this._started = false
44
+ this._cpuProfiler = undefined
45
+ this._endpointCollection = options.endpointCollection
46
+
47
+ // Bind to this so the same value can be used to unsubscribe later
48
+ this._enter = this._enter.bind(this)
49
+ this._exit = this._exit.bind(this)
50
+ }
51
+
52
+ _enter () {
53
+ if (!this._cpuProfiler) return
54
+
55
+ const active = getActiveSpan()
56
+ if (!active) return
57
+
58
+ const activeCtx = active._context()
59
+ if (!activeCtx) return
60
+
61
+ const spans = getStartedSpans(active)
62
+ if (!spans || !spans.length) return
63
+
64
+ const firstCtx = spans[0]._context()
65
+ if (!firstCtx) return
66
+
67
+ const labels = {
68
+ 'local root span id': firstCtx.toSpanId(),
69
+ 'span id': activeCtx.toSpanId()
70
+ }
71
+
72
+ if (this._endpointCollection) {
73
+ const webServerTags = spans
74
+ .map(getSpanContextTags)
75
+ .filter(isWebServerSpan)[0]
76
+
77
+ if (webServerTags) {
78
+ labels['trace endpoint'] = endpointNameFromTags(webServerTags)
79
+ }
80
+ }
81
+
82
+ this._cpuProfiler.labels = labels
83
+ }
84
+
85
+ _exit () {
86
+ if (!this._cpuProfiler) return
87
+ this._cpuProfiler.labels = {}
88
+ }
89
+
90
+ start ({ mapper } = {}) {
91
+ if (this._started) return
92
+ this._started = true
93
+
94
+ this._mapper = mapper
95
+ if (!this._pprof) {
96
+ this._pprof = require('@datadog/pprof')
97
+ this._cpuProfiler = new this._pprof.CpuProfiler()
98
+ }
99
+
100
+ this._cpuProfiler.start(this._frequency)
101
+
102
+ this._enter()
103
+ beforeCh.subscribe(this._enter)
104
+ afterCh.subscribe(this._exit)
105
+ }
106
+
107
+ profile () {
108
+ if (!this._started) return
109
+ return this._cpuProfiler.profile()
110
+ }
111
+
112
+ encode (profile) {
113
+ return this._pprof.encode(profile)
114
+ }
115
+
116
+ stop () {
117
+ if (!this._started) return
118
+ this._started = false
119
+
120
+ this._cpuProfiler.stop()
121
+ beforeCh.unsubscribe(this._enter)
122
+ afterCh.unsubscribe(this._exit)
123
+ }
124
+ }
125
+
126
+ module.exports = NativeCpuProfiler
@@ -22,11 +22,6 @@ class Tracer extends BaseTracer {
22
22
  this._tracer = noop
23
23
  this._instrumenter = new Instrumenter(this)
24
24
  this._pluginManager = new PluginManager(this)
25
- this._deprecate = method => log.deprecate(`tracer.${method}`, [
26
- `tracer.${method}() is deprecated.`,
27
- 'Please use tracer.startSpan() and tracer.scope() instead.',
28
- 'See: https://datadog.github.io/dd-trace-js/#manual-instrumentation.'
29
- ].join(' '))
30
25
  }
31
26
 
32
27
  init (options) {
@@ -126,20 +121,6 @@ class Tracer extends BaseTracer {
126
121
  return this._tracer.scope.apply(this._tracer, arguments)
127
122
  }
128
123
 
129
- currentSpan () {
130
- this._deprecate('currentSpan')
131
- return this._tracer.currentSpan.apply(this._tracer, arguments)
132
- }
133
-
134
- bind (callback) {
135
- this._deprecate('bind')
136
- return callback
137
- }
138
-
139
- bindEmitter () {
140
- this._deprecate('bindEmitter')
141
- }
142
-
143
124
  getRumData () {
144
125
  return this._tracer.getRumData.apply(this._tracer, arguments)
145
126
  }
@@ -2,13 +2,9 @@
2
2
 
3
3
  const { storage } = require('../../datadog-core')
4
4
 
5
- // TODO: deprecate binding event emitters in 3.0
5
+ // TODO: refactor bind to use shimmer once the new internal tracer lands
6
6
 
7
7
  const originals = new WeakMap()
8
- const listenerMaps = new WeakMap()
9
- const emitterSpans = new WeakMap()
10
- const emitterScopes = new WeakMap()
11
- const emitters = new WeakSet()
12
8
 
13
9
  class Scope {
14
10
  active () {
@@ -39,7 +35,6 @@ class Scope {
39
35
  }
40
36
 
41
37
  bind (target, span) {
42
- target = this._bindEmitter(target, span)
43
38
  target = this._bindPromise(target, span)
44
39
  target = this._bindFn(target, span)
45
40
 
@@ -49,7 +44,6 @@ class Scope {
49
44
  unbind (target) {
50
45
  target = this._unbindFn(target)
51
46
  target = this._unbindPromise(target)
52
- target = this._unbindEmitter(target)
53
47
 
54
48
  return target
55
49
  }
@@ -77,37 +71,6 @@ class Scope {
77
71
  return originals.get(fn) || fn
78
72
  }
79
73
 
80
- _bindEmitter (emitter, span) {
81
- if (!this._isEmitter(emitter)) return emitter
82
- if (!emitters.has(emitter)) {
83
- Scope._wrapEmitter(emitter)
84
- }
85
- emitterSpans.set(emitter, span)
86
- emitterScopes.set(emitter, this)
87
- return emitter
88
- }
89
-
90
- // Occasionally we want to wrap a prototype rather than emitter instances,
91
- // so we're exposing this as a static method. This gives us a faster
92
- // path for binding instances of known EventEmitter subclasses.
93
- static _wrapEmitter (emitter) {
94
- wrapMethod(emitter, 'addListener', wrapAddListener)
95
- wrapMethod(emitter, 'prependListener', wrapAddListener)
96
- wrapMethod(emitter, 'on', wrapAddListener)
97
- wrapMethod(emitter, 'once', wrapAddListener)
98
- wrapMethod(emitter, 'removeListener', wrapRemoveListener)
99
- wrapMethod(emitter, 'off', wrapRemoveListener)
100
- wrapMethod(emitter, 'removeAllListeners', wrapRemoveAllListeners)
101
- emitters.add(emitter)
102
- }
103
-
104
- _unbindEmitter (emitter) {
105
- if (!this._isEmitter(emitter)) return emitter
106
- emitterScopes.delete(emitter)
107
- emitterSpans.delete(emitter)
108
- return emitter
109
- }
110
-
111
74
  _bindPromise (promise, span) {
112
75
  if (!this._isPromise(promise)) return promise
113
76
 
@@ -128,31 +91,11 @@ class Scope {
128
91
  return span !== undefined ? span : this.active()
129
92
  }
130
93
 
131
- _isEmitter (emitter) {
132
- return emitter &&
133
- typeof emitter.emit === 'function' &&
134
- typeof emitter.on === 'function' &&
135
- typeof emitter.addListener === 'function' &&
136
- typeof emitter.removeListener === 'function'
137
- }
138
-
139
94
  _isPromise (promise) {
140
95
  return promise && typeof promise.then === 'function'
141
96
  }
142
97
  }
143
98
 
144
- function getScope (emitter) {
145
- return emitterScopes.get(emitter) || emitterScopes.get(emitter.constructor.prototype)
146
- }
147
-
148
- function getSpan (emitter) {
149
- return emitterSpans.get(emitter) || emitterSpans.get(emitter.constructor.prototype)
150
- }
151
-
152
- function hasScope (emitter) {
153
- return emitterScopes.has(emitter) || emitterScopes.has(emitter.constructor.prototype)
154
- }
155
-
156
99
  function wrapThen (then, scope, span) {
157
100
  return function thenWithTrace (onFulfilled, onRejected) {
158
101
  const args = new Array(arguments.length)
@@ -165,74 +108,6 @@ function wrapThen (then, scope, span) {
165
108
  }
166
109
  }
167
110
 
168
- function wrapAddListener (addListener) {
169
- return function addListenerWithTrace (eventName, listener) {
170
- const scope = getScope(this)
171
- if (!scope || !listener || originals.has(listener) || listener.listener) {
172
- return addListener.apply(this, arguments)
173
- }
174
- const span = getSpan(this)
175
-
176
- const bound = scope.bind(listener, scope._spanOrActive(span))
177
- const listenerMap = listenerMaps.get(this) || {}
178
-
179
- listenerMaps.set(this, listenerMap)
180
-
181
- if (!listenerMap[eventName]) {
182
- listenerMap[eventName] = new WeakMap()
183
- }
184
-
185
- const events = listenerMap[eventName]
186
-
187
- if (!events.has(listener)) {
188
- events.set(listener, [])
189
- }
190
-
191
- events.get(listener).push(bound)
192
-
193
- return addListener.call(this, eventName, bound)
194
- }
195
- }
196
-
197
- function wrapRemoveListener (removeListener) {
198
- return function removeListenerWithTrace (eventName, listener) {
199
- if (!hasScope(this)) {
200
- return removeListener.apply(this, arguments)
201
- }
202
-
203
- const listenerMap = listenerMaps.get(this)
204
- const listeners = listenerMap && listenerMap[eventName]
205
-
206
- if (!listener || !listeners || !listeners.has(listener)) {
207
- return removeListener.apply(this, arguments)
208
- }
209
-
210
- for (const bound of listeners.get(listener)) {
211
- removeListener.call(this, eventName, bound)
212
- }
213
-
214
- listeners.delete(listener)
215
-
216
- return removeListener.apply(this, arguments)
217
- }
218
- }
219
-
220
- function wrapRemoveAllListeners (removeAllListeners) {
221
- return function removeAllListenersWithTrace (eventName) {
222
- const listenerMap = listenerMaps.get(this)
223
-
224
- if (hasScope(this) && listenerMap) {
225
- if (eventName) {
226
- delete listenerMap[eventName]
227
- } else {
228
- listenerMaps.delete(this)
229
- }
230
- }
231
-
232
- return removeAllListeners.apply(this, arguments)
233
- }
234
- }
235
-
236
111
  function wrapMethod (target, name, wrapper, ...args) {
237
112
  if (!target[name] || originals.has(target[name])) return
238
113
 
@@ -107,10 +107,6 @@ class DatadogTracer extends Tracer {
107
107
  return this._scope
108
108
  }
109
109
 
110
- currentSpan () {
111
- return this.scope().active()
112
- }
113
-
114
110
  getRumData () {
115
111
  if (!this._enableGetRumData) {
116
112
  return ''
package/cypress/plugin.js DELETED
@@ -1,5 +0,0 @@
1
- require('..').init({
2
- startupLogs: false
3
- })
4
-
5
- module.exports = require('../packages/datadog-plugin-cypress/src/plugin')
@@ -1 +0,0 @@
1
- require('../packages/datadog-plugin-cypress/src/support')