dd-trace 2.9.0 → 2.11.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/package.json +6 -6
  2. package/packages/datadog-instrumentations/index.js +5 -0
  3. package/packages/datadog-instrumentations/src/connect.js +3 -0
  4. package/packages/datadog-instrumentations/src/fastify.js +21 -15
  5. package/packages/datadog-instrumentations/src/graphql.js +354 -0
  6. package/packages/datadog-instrumentations/src/grpc/client.js +250 -0
  7. package/packages/datadog-instrumentations/src/grpc/server.js +144 -0
  8. package/packages/{datadog-plugin-grpc/src/kinds.js → datadog-instrumentations/src/grpc/types.js} +0 -0
  9. package/packages/datadog-instrumentations/src/grpc.js +4 -0
  10. package/packages/datadog-instrumentations/src/http/client.js +1 -1
  11. package/packages/datadog-instrumentations/src/http2/client.js +67 -0
  12. package/packages/datadog-instrumentations/src/http2/server.js +3 -0
  13. package/packages/datadog-instrumentations/src/http2.js +4 -0
  14. package/packages/datadog-instrumentations/src/jest.js +14 -14
  15. package/packages/datadog-instrumentations/src/koa.js +12 -3
  16. package/packages/datadog-instrumentations/src/microgateway-core.js +66 -0
  17. package/packages/datadog-instrumentations/src/mocha.js +129 -63
  18. package/packages/datadog-instrumentations/src/next.js +140 -0
  19. package/packages/datadog-instrumentations/src/router.js +3 -0
  20. package/packages/datadog-instrumentations/src/tedious.js +1 -1
  21. package/packages/datadog-plugin-graphql/src/index.js +123 -412
  22. package/packages/datadog-plugin-graphql/src/resolve.js +120 -0
  23. package/packages/datadog-plugin-grpc/src/client.js +54 -283
  24. package/packages/datadog-plugin-grpc/src/index.js +31 -3
  25. package/packages/datadog-plugin-grpc/src/server.js +50 -145
  26. package/packages/datadog-plugin-http/src/client.js +10 -7
  27. package/packages/datadog-plugin-http2/src/client.js +72 -120
  28. package/packages/datadog-plugin-http2/src/index.js +32 -3
  29. package/packages/datadog-plugin-http2/src/server.js +6 -214
  30. package/packages/datadog-plugin-jest/src/util.js +13 -1
  31. package/packages/datadog-plugin-microgateway-core/src/index.js +14 -145
  32. package/packages/datadog-plugin-mocha/src/index.js +8 -36
  33. package/packages/datadog-plugin-next/src/index.js +56 -168
  34. package/packages/datadog-plugin-router/src/index.js +7 -3
  35. package/packages/dd-trace/src/config.js +3 -2
  36. package/packages/dd-trace/src/exporters/agent/writer.js +1 -1
  37. package/packages/dd-trace/src/opentracing/span.js +6 -3
  38. package/packages/dd-trace/src/plugin_manager.js +21 -0
  39. package/packages/dd-trace/src/plugins/plugin.js +3 -1
  40. package/packages/dd-trace/src/plugins/util/test.js +3 -0
  41. package/packages/dd-trace/src/plugins/util/web.js +0 -7
  42. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -1
  43. package/packages/dd-trace/src/startup-log.js +1 -1
  44. package/packages/dd-trace/src/telemetry.js +1 -1
  45. package/packages/dd-trace/lib/version.js +0 -1
@@ -1,149 +1,81 @@
1
1
  'use strict'
2
2
 
3
- // TODO: either instrument all or none of the render functions
4
-
3
+ const Plugin = require('../../dd-trace/src/plugins/plugin')
4
+ const { storage } = require('../../datadog-core')
5
5
  const analyticsSampler = require('../../dd-trace/src/analytics_sampler')
6
6
 
7
- const contexts = new WeakMap()
8
-
9
- function createWrapHandleRequest (tracer, config) {
10
- return function wrapHandleRequest (handleRequest) {
11
- return function handleRequestWithTrace (req, res, pathname, query) {
12
- return trace(tracer, config, req, res, () => handleRequest.apply(this, arguments))
13
- }
7
+ class NextPlugin extends Plugin {
8
+ static get name () {
9
+ return 'next'
14
10
  }
15
- }
16
-
17
- function createWrapHandleApiRequest (tracer, config) {
18
- return function wrapHandleApiRequest (handleApiRequest) {
19
- return function handleApiRequestWithTrace (req, res, pathname, query) {
20
- return trace(tracer, config, req, res, () => {
21
- const promise = handleApiRequest.apply(this, arguments)
22
-
23
- return promise.then(handled => {
24
- if (!handled) return handled
25
11
 
26
- const page = getPageFromPath(pathname, this.dynamicRoutes)
27
-
28
- addPage(req, page)
29
-
30
- return handled
31
- })
12
+ constructor (...args) {
13
+ super(...args)
14
+
15
+ this._requests = new WeakMap()
16
+
17
+ this.addSub('apm:next:request:start', ({ req, res }) => {
18
+ const store = storage.getStore()
19
+ const childOf = store ? store.span : store
20
+ const span = this.tracer.startSpan('next.request', {
21
+ childOf,
22
+ tags: {
23
+ 'service.name': this.config.service || this.tracer._service,
24
+ 'resource.name': 'test',
25
+ 'span.type': 'web',
26
+ 'span.kind': 'server',
27
+ 'http.method': req.method
28
+ }
32
29
  })
33
- }
34
- }
35
- }
36
30
 
37
- function createWrapRenderToResponse (tracer, config) {
38
- return function wrapRenderToResponse (renderToResponse) {
39
- return function renderToResponseWithTrace (ctx) {
40
- return trace(tracer, config, ctx.req, ctx.res, () => renderToResponse.apply(this, arguments))
41
- }
42
- }
43
- }
31
+ analyticsSampler.sample(span, this.config.measured, true)
44
32
 
45
- function createWrapRenderErrorToResponse (tracer, config) {
46
- return function wrapRenderErrorToResponse (renderErrorToResponse) {
47
- return function renderErrorToResponseWithTrace (ctx) {
48
- return trace(tracer, config, ctx.req, ctx.res, () => renderErrorToResponse.apply(this, arguments))
49
- }
50
- }
51
- }
33
+ this.enter(span, store)
52
34
 
53
- function createWrapRenderToHTML (tracer, config) {
54
- return function wrapRenderToHTML (renderToHTML) {
55
- return function renderToHTMLWithTrace (req, res, pathname, query, parsedUrl) {
56
- return trace(tracer, config, req, res, () => renderToHTML.apply(this, arguments))
57
- }
58
- }
59
- }
35
+ this._requests.set(span, req)
36
+ })
60
37
 
61
- function createWrapRenderErrorToHTML (tracer, config) {
62
- return function wrapRenderErrorToHTML (renderErrorToHTML) {
63
- return function renderErrorToHTMLWithTrace (err, req, res, pathname, query) {
64
- return trace(tracer, config, req, res, () => renderErrorToHTML.apply(this, arguments))
65
- }
66
- }
67
- }
38
+ this.addSub('apm:next:request:error', this.addError)
68
39
 
69
- function createWrapFindPageComponents (tracer, config) {
70
- return function wrapFindPageComponents (findPageComponents) {
71
- return function findPageComponentsWithTrace (pathname, query) {
72
- const result = findPageComponents.apply(this, arguments)
73
- const span = tracer.scope().active()
74
- const req = span && span._nextReq
40
+ this.addSub('apm:next:request:finish', ({ req, res }) => {
41
+ const store = storage.getStore()
75
42
 
76
- if (result) {
77
- addPage(req, pathname)
78
- }
43
+ if (!store) return
79
44
 
80
- return result
81
- }
82
- }
83
- }
84
-
85
- function getPageFromPath (page, dynamicRoutes = []) {
86
- for (const dynamicRoute of dynamicRoutes) {
87
- if (dynamicRoute.page.startsWith('/api') && dynamicRoute.match(page)) {
88
- return dynamicRoute.page
89
- }
90
- }
91
-
92
- return page
93
- }
94
-
95
- function trace (tracer, config, req, res, handler) {
96
- const scope = tracer.scope()
97
- const context = contexts.get(req)
98
-
99
- if (context) return scope.activate(context.span, handler)
100
-
101
- const childOf = scope.active()
102
- const tags = {
103
- 'service.name': config.service || tracer._service,
104
- 'resource.name': req.method,
105
- 'span.type': 'web',
106
- 'span.kind': 'server',
107
- 'http.method': req.method
108
- }
109
- const span = tracer.startSpan('next.request', { childOf, tags })
45
+ const span = store.span
46
+ const error = span.context()._tags['error']
110
47
 
111
- analyticsSampler.sample(span, config.measured, true)
48
+ if (!this.config.validateStatus(res.statusCode) && !error) {
49
+ span.setTag('error', true)
50
+ }
112
51
 
113
- contexts.set(req, { span })
52
+ span.addTags({
53
+ 'http.status_code': res.statusCode
54
+ })
114
55
 
115
- const promise = scope.activate(span, handler)
56
+ this.config.hooks.request(span, req, res)
116
57
 
117
- // HACK: Store the request object on the span for findPageComponents.
118
- // TODO: Use CLS when it will be available in core.
119
- span._nextReq = req
58
+ span.finish()
59
+ })
120
60
 
121
- return promise.then(
122
- result => finish(span, config, req, res, result),
123
- err => finish(span, config, req, res, null, err)
124
- )
125
- }
61
+ this.addSub('apm:next:page:load', ({ page }) => {
62
+ const store = storage.getStore()
126
63
 
127
- function addPage (req, page) {
128
- const context = contexts.get(req)
64
+ if (!store) return
129
65
 
130
- if (!context) return
131
-
132
- context.span.addTags({
133
- 'resource.name': `${req.method} ${page}`.trim(),
134
- 'next.page': page
135
- })
136
- }
66
+ const span = store.span
67
+ const req = this._requests.get(span)
137
68
 
138
- function finish (span, config, req, res, result, err) {
139
- span.setTag('error', err || !config.validateStatus(res.statusCode))
140
- span.addTags({
141
- 'http.status_code': res.statusCode
142
- })
143
- config.hooks.request(span, req, res)
144
- span.finish()
69
+ span.addTags({
70
+ 'resource.name': `${req.method} ${page}`.trim(),
71
+ 'next.page': page
72
+ })
73
+ })
74
+ }
145
75
 
146
- return result || err
76
+ configure (config) {
77
+ return super.configure(normalizeConfig(config))
78
+ }
147
79
  }
148
80
 
149
81
  function normalizeConfig (config) {
@@ -162,48 +94,4 @@ function getHooks (config) {
162
94
  return { request }
163
95
  }
164
96
 
165
- module.exports = [
166
- {
167
- name: 'next',
168
- versions: ['>=9.5 <11.1'],
169
- file: 'dist/next-server/server/next-server.js',
170
- patch ({ default: Server }, tracer, config) {
171
- config = normalizeConfig(config)
172
-
173
- this.wrap(Server.prototype, 'handleRequest', createWrapHandleRequest(tracer, config))
174
- this.wrap(Server.prototype, 'handleApiRequest', createWrapHandleApiRequest(tracer, config))
175
- this.wrap(Server.prototype, 'renderToHTML', createWrapRenderToHTML(tracer, config))
176
- this.wrap(Server.prototype, 'renderErrorToHTML', createWrapRenderErrorToHTML(tracer, config))
177
- this.wrap(Server.prototype, 'findPageComponents', createWrapFindPageComponents(tracer, config))
178
- },
179
- unpatch ({ default: Server }) {
180
- this.unwrap(Server.prototype, 'handleRequest')
181
- this.unwrap(Server.prototype, 'handleApiRequest')
182
- this.unwrap(Server.prototype, 'renderToHTML')
183
- this.unwrap(Server.prototype, 'renderErrorToHTML')
184
- this.unwrap(Server.prototype, 'findPageComponents')
185
- }
186
- },
187
-
188
- {
189
- name: 'next',
190
- versions: ['>=11.1'],
191
- file: 'dist/server/next-server.js',
192
- patch ({ default: Server }, tracer, config) {
193
- config = normalizeConfig(config)
194
-
195
- this.wrap(Server.prototype, 'handleRequest', createWrapHandleRequest(tracer, config))
196
- this.wrap(Server.prototype, 'handleApiRequest', createWrapHandleApiRequest(tracer, config))
197
- this.wrap(Server.prototype, 'renderToResponse', createWrapRenderToResponse(tracer, config))
198
- this.wrap(Server.prototype, 'renderErrorToResponse', createWrapRenderErrorToResponse(tracer, config))
199
- this.wrap(Server.prototype, 'findPageComponents', createWrapFindPageComponents(tracer, config))
200
- },
201
- unpatch ({ default: Server }) {
202
- this.unwrap(Server.prototype, 'handleRequest')
203
- this.unwrap(Server.prototype, 'handleApiRequest')
204
- this.unwrap(Server.prototype, 'renderToResponse')
205
- this.unwrap(Server.prototype, 'renderErrorToResponse')
206
- this.unwrap(Server.prototype, 'findPageComponents')
207
- }
208
- }
209
- ]
97
+ module.exports = NextPlugin
@@ -32,10 +32,14 @@ class RouterPlugin extends WebPlugin {
32
32
  if (!context) return
33
33
 
34
34
  context.stack.pop()
35
+ })
35
36
 
36
- if (context.middleware.length > 0) {
37
- context.middleware.pop().finish()
38
- }
37
+ this.addSub(`apm:${this.constructor.name}:middleware:exit`, ({ req }) => {
38
+ const context = this._contexts.get(req)
39
+
40
+ if (!context || context.middleware.length === 0) return
41
+
42
+ context.middleware.pop().finish()
39
43
  })
40
44
 
41
45
  this.addSub(`apm:${this.constructor.name}:middleware:error`, this.addError)
@@ -93,7 +93,7 @@ class Config {
93
93
  )
94
94
  const DD_TRACE_TELEMETRY_ENABLED = coalesce(
95
95
  process.env.DD_TRACE_TELEMETRY_ENABLED,
96
- true
96
+ !process.env.AWS_LAMBDA_FUNCTION_NAME
97
97
  )
98
98
  const DD_TRACE_DEBUG = coalesce(
99
99
  process.env.DD_TRACE_DEBUG,
@@ -237,7 +237,8 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
237
237
  }
238
238
  this.lookup = options.lookup
239
239
  this.startupLogs = isTrue(DD_TRACE_STARTUP_LOGS)
240
- this.telemetryEnabled = isTrue(DD_TRACE_TELEMETRY_ENABLED)
240
+ // Disabled for CI Visibility's agentless
241
+ this.telemetryEnabled = DD_TRACE_EXPORTER !== 'datadog' && isTrue(DD_TRACE_TELEMETRY_ENABLED)
241
242
  this.protocolVersion = DD_TRACE_AGENT_PROTOCOL_VERSION
242
243
  this.appsec = {
243
244
  enabled: isTrue(DD_APPSEC_ENABLED),
@@ -4,7 +4,7 @@ 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
- const tracerVersion = require('../../../lib/version')
7
+ const tracerVersion = require('../../../../../package.json').version
8
8
  const BaseWriter = require('../common/writer')
9
9
 
10
10
  const METRIC_PREFIX = 'datadog.tracer.node.exporter.agent'
@@ -13,7 +13,10 @@ const metrics = require('../metrics')
13
13
  const log = require('../log')
14
14
  const { storage } = require('../../../datadog-core')
15
15
 
16
- const { DD_TRACE_EXPERIMENTAL_STATE_TRACKING } = process.env
16
+ const {
17
+ DD_TRACE_EXPERIMENTAL_STATE_TRACKING,
18
+ DD_TRACE_EXPERIMENTAL_SPAN_COUNTS
19
+ } = process.env
17
20
 
18
21
  const unfinishedRegistry = createRegistry('unfinished')
19
22
  const finishedRegistry = createRegistry('finished')
@@ -41,7 +44,7 @@ class DatadogSpan extends Span {
41
44
 
42
45
  this._startTime = fields.startTime || this._getTime()
43
46
 
44
- if (this._debug && unfinishedRegistry) {
47
+ if (DD_TRACE_EXPERIMENTAL_SPAN_COUNTS && finishedRegistry) {
45
48
  metrics.increment('runtime.node.spans.unfinished')
46
49
  metrics.increment('runtime.node.spans.unfinished.by.name', `span_name:${operationName}`)
47
50
 
@@ -137,7 +140,7 @@ class DatadogSpan extends Span {
137
140
  }
138
141
  }
139
142
 
140
- if (this._debug && finishedRegistry) {
143
+ if (DD_TRACE_EXPERIMENTAL_SPAN_COUNTS && finishedRegistry) {
141
144
  metrics.decrement('runtime.node.spans.unfinished')
142
145
  metrics.decrement('runtime.node.spans.unfinished.by.name', `span_name:${this._name}`)
143
146
  metrics.increment('runtime.node.spans.finished')
@@ -2,6 +2,7 @@
2
2
 
3
3
  const { isTrue } = require('./util')
4
4
  const plugins = require('./plugins')
5
+ const log = require('./log')
5
6
 
6
7
  // instrument everything that needs Plugin System V2 instrumentation
7
8
  require('../../datadog-instrumentations')
@@ -21,6 +22,15 @@ function getConfig (name, config = {}) {
21
22
  return config
22
23
  }
23
24
 
25
+ // TODO: maybe needs to DRY up as well, but depending on how the remaining old plugins
26
+ // are migrated to the new system, can stay here for now, since this is the level
27
+ // this check maybe should be happening on, even if it deals with env variabls
28
+ const disabledPlugins = process.env.DD_TRACE_DISABLED_PLUGINS
29
+
30
+ const collectDisabledPlugins = () => {
31
+ return new Set(disabledPlugins && disabledPlugins.split(',').map(plugin => plugin.trim()))
32
+ }
33
+
24
34
  // TODO actually ... should we be looking at envrionment variables this deep down in the code?
25
35
 
26
36
  // TODO this must always be a singleton.
@@ -28,7 +38,18 @@ module.exports = class PluginManager {
28
38
  constructor (tracer) {
29
39
  this._pluginsByName = {}
30
40
  this._configsByName = {}
41
+
42
+ const _disabledPlugins = collectDisabledPlugins()
43
+
31
44
  for (const PluginClass of Object.values(plugins)) {
45
+ /**
46
+ * disabling the plugin here instead of in `configure` so we don't waste subscriber
47
+ * resources on a plugin that will eventually be disabled anyways
48
+ */
49
+ if (_disabledPlugins.has(PluginClass.name)) {
50
+ log.debug(`Plugin "${PluginClass.name}" was disabled via configuration option.`)
51
+ continue
52
+ }
32
53
  if (typeof PluginClass !== 'function') continue
33
54
  this._pluginsByName[PluginClass.name] = new PluginClass(tracer)
34
55
  this._configsByName[PluginClass.name] = {}
@@ -53,7 +53,9 @@ module.exports = class Plugin {
53
53
 
54
54
  if (!store || !store.span) return
55
55
 
56
- store.span.setTag('error', error)
56
+ if (!store.span._spanContext._tags['error']) {
57
+ store.span.setTag('error', error || 1)
58
+ }
57
59
  }
58
60
 
59
61
  configure (config) {
@@ -34,6 +34,7 @@ const TEST_PARAMETERS = 'test.parameters'
34
34
  const TEST_SKIP_REASON = 'test.skip_reason'
35
35
  const TEST_IS_RUM_ACTIVE = 'test.is_rum_active'
36
36
  const TEST_CODE_OWNERS = 'test.codeowners'
37
+ const TEST_SOURCE_FILE = 'test.source.file'
37
38
  const LIBRARY_VERSION = 'library_version'
38
39
 
39
40
  const ERROR_TYPE = 'error.type'
@@ -56,6 +57,7 @@ module.exports = {
56
57
  TEST_PARAMETERS,
57
58
  TEST_SKIP_REASON,
58
59
  TEST_IS_RUM_ACTIVE,
60
+ TEST_SOURCE_FILE,
59
61
  ERROR_TYPE,
60
62
  ERROR_MESSAGE,
61
63
  ERROR_STACK,
@@ -151,6 +153,7 @@ function getTestCommonTags (name, suite, version) {
151
153
  [SAMPLING_PRIORITY]: AUTO_KEEP,
152
154
  [TEST_NAME]: name,
153
155
  [TEST_SUITE]: suite,
156
+ [TEST_SOURCE_FILE]: suite,
154
157
  [RESOURCE_NAME]: `${suite}.${name}`,
155
158
  [TEST_FRAMEWORK_VERSION]: version,
156
159
  [LIBRARY_VERSION]: ddTraceVersion
@@ -106,7 +106,6 @@ const web = {
106
106
  const context = contexts.get(req)
107
107
  if (!context.instrumented) {
108
108
  this.wrapEnd(context)
109
- this.wrapEvents(context)
110
109
  context.instrumented = true
111
110
  }
112
111
  },
@@ -355,12 +354,6 @@ const web = {
355
354
  ends.set(this, scope.bind(value, context.span))
356
355
  }
357
356
  })
358
- },
359
- wrapEvents (context) {
360
- const scope = context.tracer.scope()
361
- const res = context.res
362
-
363
- scope.bind(res, context.span)
364
357
  }
365
358
  }
366
359
 
@@ -6,7 +6,7 @@ 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')
9
- const version = require('../../../lib/version')
9
+ const version = require('../../../../../package.json').version
10
10
 
11
11
  const containerId = docker.id()
12
12
 
@@ -4,7 +4,7 @@ const mainLogger = require('./log')
4
4
 
5
5
  const os = require('os')
6
6
  const { inspect } = require('util')
7
- const tracerVersion = require('../lib/version')
7
+ const tracerVersion = require('../../../package.json').version
8
8
  const requirePackageJson = require('./require-package-json')
9
9
 
10
10
  const logger = Object.create(mainLogger)
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const tracerVersion = require('../lib/version')
3
+ const tracerVersion = require('../../../package.json').version
4
4
  const pkg = require('./pkg')
5
5
  const containerId = require('./exporters/common/docker').id()
6
6
  const requirePackageJson = require('./require-package-json')
@@ -1 +0,0 @@
1
- module.exports = '2.9.0'