dd-trace 2.10.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 (32) hide show
  1. package/package.json +2 -2
  2. package/packages/datadog-instrumentations/index.js +4 -0
  3. package/packages/datadog-instrumentations/src/connect.js +3 -0
  4. package/packages/datadog-instrumentations/src/fastify.js +5 -3
  5. package/packages/datadog-instrumentations/src/graphql.js +6 -4
  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/http2/client.js +67 -0
  11. package/packages/datadog-instrumentations/src/http2/server.js +3 -0
  12. package/packages/datadog-instrumentations/src/http2.js +4 -0
  13. package/packages/datadog-instrumentations/src/koa.js +11 -2
  14. package/packages/datadog-instrumentations/src/microgateway-core.js +66 -0
  15. package/packages/datadog-instrumentations/src/mocha.js +129 -63
  16. package/packages/datadog-instrumentations/src/next.js +140 -0
  17. package/packages/datadog-instrumentations/src/router.js +3 -0
  18. package/packages/datadog-plugin-graphql/src/resolve.js +12 -17
  19. package/packages/datadog-plugin-grpc/src/client.js +54 -283
  20. package/packages/datadog-plugin-grpc/src/index.js +31 -3
  21. package/packages/datadog-plugin-grpc/src/server.js +50 -145
  22. package/packages/datadog-plugin-http2/src/client.js +72 -120
  23. package/packages/datadog-plugin-http2/src/index.js +32 -3
  24. package/packages/datadog-plugin-http2/src/server.js +6 -214
  25. package/packages/datadog-plugin-microgateway-core/src/index.js +14 -145
  26. package/packages/datadog-plugin-mocha/src/index.js +8 -36
  27. package/packages/datadog-plugin-next/src/index.js +56 -168
  28. package/packages/datadog-plugin-router/src/index.js +7 -3
  29. package/packages/dd-trace/src/config.js +2 -1
  30. package/packages/dd-trace/src/opentracing/span.js +6 -3
  31. package/packages/dd-trace/src/plugins/plugin.js +3 -1
  32. package/packages/dd-trace/src/plugins/util/web.js +0 -7
@@ -1,218 +1,85 @@
1
1
  'use strict'
2
2
 
3
+ const Plugin = require('../../dd-trace/src/plugins/plugin')
4
+ const { storage } = require('../../datadog-core')
3
5
  const analyticsSampler = require('../../dd-trace/src/analytics_sampler')
4
6
  const Tags = require('../../../ext/tags')
5
7
  const { TEXT_MAP } = require('../../../ext/formats')
6
- const { ERROR } = require('../../../ext/tags')
7
- const kinds = require('./kinds')
8
8
  const { addMethodTags, addMetadataTags, getFilter } = require('./util')
9
9
 
10
- const patched = new WeakSet()
11
- const instances = new WeakMap()
12
-
13
- function createWrapMakeRequest (tracer, config, methodKind) {
14
- const filter = getFilter(config, 'metadata')
15
-
16
- return function wrapMakeRequest (makeRequest) {
17
- return function makeRequestWithTrace (path) {
18
- const args = ensureMetadata(this, arguments, 4)
19
-
20
- return callMethod(tracer, config, this, makeRequest, args, path, args[4], methodKind, filter)
21
- }
22
- }
23
- }
10
+ class GrpcClientPlugin extends Plugin {
11
+ static get name () {
12
+ return 'grpc'
13
+ }
14
+
15
+ constructor (...args) {
16
+ super(...args)
17
+
18
+ this.addSub('apm:grpc:client:request:start', ({ metadata, path, type }) => {
19
+ const metadataFilter = this.config.metadataFilter
20
+ const store = storage.getStore()
21
+ const childOf = store && store.span
22
+ const span = this.tracer.startSpan('grpc.request', {
23
+ childOf,
24
+ tags: {
25
+ [Tags.SPAN_KIND]: 'client',
26
+ 'span.type': 'http',
27
+ 'resource.name': path,
28
+ 'service.name': this.config.service || `${this.tracer._service}-grpc-client`,
29
+ 'component': 'grpc'
30
+ }
31
+ })
24
32
 
25
- function createWrapLoadPackageDefinition (tracer, config) {
26
- return function wrapLoadPackageDefinition (loadPackageDefinition) {
27
- return function loadPackageDefinitionWithTrace (packageDef) {
28
- const result = loadPackageDefinition.apply(this, arguments)
33
+ addMethodTags(span, path, type)
29
34
 
30
- if (!result) return result
35
+ if (metadata) {
36
+ addMetadataTags(span, metadata, metadataFilter, 'request')
37
+ inject(this.tracer, span, metadata)
38
+ }
31
39
 
32
- wrapPackageDefinition(tracer, config, result)
40
+ analyticsSampler.sample(span, this.config.measured)
33
41
 
34
- return result
35
- }
36
- }
37
- }
42
+ this.enter(span, store)
43
+ })
38
44
 
39
- function createWrapMakeClientConstructor (tracer, config) {
40
- return function wrapMakeClientConstructor (makeClientConstructor) {
41
- return function makeClientConstructorWithTrace (methods) {
42
- const ServiceClient = makeClientConstructor.apply(this, arguments)
45
+ this.addSub('apm:grpc:client:request:error', error => {
46
+ const store = storage.getStore()
43
47
 
44
- wrapClientConstructor(tracer, config, ServiceClient, methods)
48
+ if (!store || !store.span) return
45
49
 
46
- return ServiceClient
47
- }
48
- }
49
- }
50
-
51
- function wrapPackageDefinition (tracer, config, def) {
52
- for (const name in def) {
53
- if (def[name].format) continue
54
- if (def[name].service && def[name].prototype) {
55
- wrapClientConstructor(tracer, config, def[name], def[name].service)
56
- } else {
57
- wrapPackageDefinition(tracer, config, def[name])
58
- }
59
- }
60
- }
50
+ this.addCode(store.span, error.code)
51
+ this.addError(error)
52
+ })
61
53
 
62
- function wrapClientConstructor (tracer, config, ServiceClient, methods) {
63
- const proto = ServiceClient.prototype
54
+ this.addSub('apm:grpc:client:request:finish', ({ code, metadata }) => {
55
+ const store = storage.getStore()
64
56
 
65
- if (typeof methods !== 'object' || 'format' in methods) return
57
+ if (!store || !store.span) return
66
58
 
67
- Object.keys(methods)
68
- .forEach(name => {
69
- if (!methods[name]) return
59
+ const span = store.span
60
+ const metadataFilter = this.config.metadataFilter
70
61
 
71
- const originalName = methods[name].originalName
72
- const path = methods[name].path
73
- const methodKind = getMethodKind(methods[name])
62
+ this.addCode(span, code)
74
63
 
75
- if (methods[name]) {
76
- proto[name] = wrapMethod(tracer, config, proto[name], path, methodKind)
64
+ if (metadata && metadataFilter) {
65
+ addMetadataTags(span, metadata, metadataFilter, 'response')
77
66
  }
78
67
 
79
- if (originalName) {
80
- proto[originalName] = wrapMethod(tracer, config, proto[originalName], path, methodKind)
81
- }
68
+ store.span.finish()
82
69
  })
83
- }
84
-
85
- function wrapMethod (tracer, config, method, path, methodKind) {
86
- if (typeof method !== 'function' || patched.has(method)) {
87
- return method
88
70
  }
89
71
 
90
- const filter = getFilter(config, 'metadata')
91
-
92
- const methodWithTrace = function methodWithTrace () {
93
- const args = ensureMetadata(this, arguments, 1)
94
-
95
- return callMethod(tracer, config, this, method, args, path, args[1], methodKind, filter)
96
- }
97
-
98
- Object.assign(methodWithTrace, method)
99
-
100
- patched.add(methodWithTrace)
101
-
102
- return methodWithTrace
103
- }
104
-
105
- function wrapCallback (span, callback) {
106
- const scope = span.tracer().scope()
107
- const parent = scope.active()
108
-
109
- return function (err) {
110
- err && span.setTag(ERROR, err)
111
-
112
- if (callback) {
113
- return scope.bind(callback, parent).apply(this, arguments)
114
- }
115
- }
116
- }
117
-
118
- function wrapStream (span, call, filter) {
119
- if (!call || typeof call.emit !== 'function') return
120
-
121
- const emit = call.emit
122
-
123
- call.emit = function (eventName, ...args) {
124
- switch (eventName) {
125
- case 'error':
126
- span.setTag(ERROR, args[0] || 1)
127
-
128
- break
129
- case 'status':
130
- if (args[0]) {
131
- span.setTag('grpc.status.code', args[0].code)
132
-
133
- addMetadataTags(span, args[0].metadata, filter, 'response')
134
- }
135
-
136
- span.finish()
137
-
138
- break
139
- }
140
-
141
- return emit.apply(this, arguments)
142
- }
143
- }
144
-
145
- function callMethod (tracer, config, client, method, args, path, metadata, methodKind, filter) {
146
- const length = args.length
147
- const callback = args[length - 1]
148
- const scope = tracer.scope()
149
- const span = startSpan(tracer, config, path, methodKind)
72
+ configure (config) {
73
+ const metadataFilter = getFilter(config, 'metadata')
150
74
 
151
- if (metadata) {
152
- addMetadataTags(span, metadata, filter, 'request')
153
- inject(tracer, span, metadata)
75
+ return super.configure({ ...config, metadataFilter })
154
76
  }
155
77
 
156
- if (methodKind === kinds.unary || methodKind === kinds.client_stream) {
157
- if (typeof callback === 'function') {
158
- args[length - 1] = wrapCallback(span, callback)
159
- } else {
160
- args[length] = wrapCallback(span)
78
+ addCode (span, code) {
79
+ if (code !== undefined) {
80
+ span.setTag('grpc.status.code', code)
161
81
  }
162
82
  }
163
-
164
- const call = scope.bind(method, span).apply(client, args)
165
-
166
- wrapStream(span, call, filter)
167
-
168
- return scope.bind(call)
169
- }
170
-
171
- function startSpan (tracer, config, path, methodKind) {
172
- const scope = tracer.scope()
173
- const childOf = scope.active()
174
- const span = tracer.startSpan('grpc.request', {
175
- childOf,
176
- tags: {
177
- [Tags.SPAN_KIND]: 'client',
178
- 'span.type': 'http',
179
- 'resource.name': path,
180
- 'service.name': config.service || `${tracer._service}-grpc-client`,
181
- 'component': 'grpc'
182
- }
183
- })
184
-
185
- analyticsSampler.sample(span, config.measured)
186
- addMethodTags(span, path, methodKind)
187
-
188
- return span
189
- }
190
-
191
- function ensureMetadata (client, args, index) {
192
- const grpc = getGrpc(client)
193
-
194
- if (!client || !grpc) return args
195
-
196
- const meta = args[index]
197
- const normalized = []
198
-
199
- for (let i = 0; i < index; i++) {
200
- normalized.push(args[i])
201
- }
202
-
203
- if (!meta || !meta.constructor || meta.constructor.name !== 'Metadata') {
204
- normalized.push(new grpc.Metadata())
205
- }
206
-
207
- if (meta) {
208
- normalized.push(meta)
209
- }
210
-
211
- for (let i = index + 1; i < args.length; i++) {
212
- normalized.push(args[i])
213
- }
214
-
215
- return normalized
216
83
  }
217
84
 
218
85
  function inject (tracer, span, metadata) {
@@ -227,100 +94,4 @@ function inject (tracer, span, metadata) {
227
94
  }
228
95
  }
229
96
 
230
- function getMethodKind (definition) {
231
- if (definition.requestStream) {
232
- if (definition.responseStream) {
233
- return kinds.bidi
234
- }
235
-
236
- return kinds.client_stream
237
- }
238
-
239
- if (definition.responseStream) {
240
- return kinds.server_stream
241
- }
242
-
243
- return kinds.unary
244
- }
245
-
246
- function getGrpc (client) {
247
- let proto = client
248
-
249
- do {
250
- const instance = instances.get(proto)
251
- if (instance) return instance
252
- } while ((proto = Object.getPrototypeOf(proto)))
253
- }
254
-
255
- function patch (grpc, tracer, config) {
256
- if (config.client === false) return
257
-
258
- config = config.client || config
259
-
260
- const proto = grpc.Client.prototype
261
-
262
- instances.set(proto, grpc)
263
-
264
- this.wrap(proto, 'makeBidiStreamRequest', createWrapMakeRequest(tracer, config, kinds.bidi))
265
- this.wrap(proto, 'makeClientStreamRequest', createWrapMakeRequest(tracer, config, kinds.clientStream))
266
- this.wrap(proto, 'makeServerStreamRequest', createWrapMakeRequest(tracer, config, kinds.serverStream))
267
- this.wrap(proto, 'makeUnaryRequest', createWrapMakeRequest(tracer, config, kinds.unary))
268
- }
269
-
270
- function unpatch (grpc) {
271
- const proto = grpc.Client.prototype
272
-
273
- instances.delete(proto)
274
-
275
- this.unwrap(proto, 'makeBidiStreamRequest')
276
- this.unwrap(proto, 'makeClientStreamRequest')
277
- this.unwrap(proto, 'makeServerStreamRequest')
278
- this.unwrap(proto, 'makeUnaryRequest')
279
- }
280
-
281
- module.exports = [
282
- {
283
- name: 'grpc',
284
- versions: ['>=1.20.2'],
285
- patch,
286
- unpatch
287
- },
288
- {
289
- name: 'grpc',
290
- versions: ['>=1.20.2'],
291
- file: 'src/client.js',
292
- patch (client, tracer, config) {
293
- if (config.client === false) return
294
-
295
- config = config.client || config
296
-
297
- this.wrap(client, 'makeClientConstructor', createWrapMakeClientConstructor(tracer, config))
298
- },
299
- unpatch (client) {
300
- this.unwrap(client, 'makeClientConstructor')
301
- }
302
- },
303
- {
304
- name: '@grpc/grpc-js',
305
- versions: ['>=1.0.3'],
306
- patch,
307
- unpatch
308
- },
309
- {
310
- name: '@grpc/grpc-js',
311
- versions: ['>=1.0.3'],
312
- file: 'build/src/make-client.js',
313
- patch (client, tracer, config) {
314
- if (config.client === false) return
315
-
316
- config = config.client || config
317
-
318
- this.wrap(client, 'makeClientConstructor', createWrapMakeClientConstructor(tracer, config))
319
- this.wrap(client, 'loadPackageDefinition', createWrapLoadPackageDefinition(tracer, config))
320
- },
321
- unpatch (client) {
322
- this.unwrap(client, 'makeClientConstructor')
323
- this.unwrap(client, 'loadPackageDefinition')
324
- }
325
- }
326
- ]
97
+ module.exports = GrpcClientPlugin
@@ -1,6 +1,34 @@
1
1
  'use strict'
2
2
 
3
- const client = require('./client')
4
- const server = require('./server')
3
+ const Plugin = require('../../dd-trace/src/plugins/plugin')
4
+ const GrpcServerPlugin = require('./server')
5
+ const GrpcClientPlugin = require('./client')
5
6
 
6
- module.exports = [].concat(client, server)
7
+ class GrpcPlugin extends Plugin {
8
+ static get name () {
9
+ return 'grpc'
10
+ }
11
+
12
+ constructor (...args) {
13
+ super(...args)
14
+ this.server = new GrpcServerPlugin(...args)
15
+ this.client = new GrpcClientPlugin(...args)
16
+ }
17
+
18
+ configure (config) {
19
+ const clientConfig = config.client === false ? false : {
20
+ ...config,
21
+ ...config.client
22
+ }
23
+
24
+ const serverConfig = config.server === false ? false : {
25
+ ...config,
26
+ ...config.server
27
+ }
28
+
29
+ this.server.configure(serverConfig)
30
+ this.client.configure(clientConfig)
31
+ }
32
+ }
33
+
34
+ module.exports = GrpcPlugin
@@ -1,153 +1,88 @@
1
1
  'use strict'
2
2
 
3
+ const Plugin = require('../../dd-trace/src/plugins/plugin')
4
+ const { storage } = require('../../datadog-core')
3
5
  const analyticsSampler = require('../../dd-trace/src/analytics_sampler')
4
6
  const Tags = require('../../../ext/tags')
5
7
  const { TEXT_MAP } = require('../../../ext/formats')
6
- const { ERROR } = require('../../../ext/tags')
7
- const kinds = require('./kinds')
8
8
  const { addMethodTags, addMetadataTags, getFilter } = require('./util')
9
9
 
10
- // https://github.com/grpc/grpc/blob/master/doc/statuscodes.md
11
- const OK = 0
12
- const CANCELLED = 1
13
-
14
- function createWrapHandler (tracer, config, handler) {
15
- const filter = getFilter(config, 'metadata')
16
-
17
- return function wrapHandler (func) {
18
- const isValid = (server, args) => {
19
- if (!server || !server.type) return false
20
- if (!args[0]) return false
21
- if (server.type !== 'unary' && !isEmitter(args[0])) return false
22
- if (server.type === 'unary' && typeof args[1] !== 'function') return false
23
-
24
- return true
25
- }
10
+ class GrpcServerPlugin extends Plugin {
11
+ static get name () {
12
+ return 'http'
13
+ }
26
14
 
27
- return function funcWithTrace (call, callback) {
28
- if (!isValid(this, arguments)) return func.apply(this, arguments)
15
+ constructor (...args) {
16
+ super(...args)
29
17
 
30
- const metadata = call.metadata
31
- const type = this.type
32
- const isStream = type !== 'unary'
33
- const scope = tracer.scope()
34
- const childOf = extract(tracer, metadata)
35
- const span = tracer.startSpan('grpc.request', {
18
+ this.addSub('apm:grpc:server:request:start', ({ name, metadata, type }) => {
19
+ const metadataFilter = this.config.metadataFilter
20
+ const store = storage.getStore()
21
+ const childOf = extract(this.tracer, metadata)
22
+ const span = this.tracer.startSpan('grpc.request', {
36
23
  childOf,
37
24
  tags: {
38
25
  [Tags.SPAN_KIND]: 'server',
39
26
  'span.type': 'web',
40
- 'resource.name': handler,
41
- 'service.name': config.service || `${tracer._service}`,
27
+ 'resource.name': name,
28
+ 'service.name': this.config.service || `${this.tracer._service}`,
42
29
  'component': 'grpc'
43
30
  }
44
31
  })
45
32
 
46
- analyticsSampler.sample(span, config.measured, true)
47
- addMethodTags(span, handler, kinds[type])
48
- addMetadataTags(span, metadata, filter, 'request')
33
+ addMethodTags(span, name, type)
34
+ addMetadataTags(span, metadata, metadataFilter, 'request')
49
35
 
50
- scope.bind(call)
36
+ analyticsSampler.sample(span, this.config.measured, true)
51
37
 
52
- // Finish the span if the call was cancelled.
53
- call.once('cancelled', () => {
54
- span.setTag('grpc.status.code', CANCELLED)
55
- span.finish()
56
- })
57
-
58
- if (isStream) {
59
- wrapStream(span, call)
60
- } else {
61
- arguments[1] = wrapCallback(span, callback, filter, childOf)
62
- }
63
-
64
- return scope.bind(func, span).apply(this, arguments)
65
- }
66
- }
67
- }
68
-
69
- function createWrapRegister (tracer, config) {
70
- config = config.server || config
71
-
72
- return function wrapRegister (register) {
73
- return function registerWithTrace (name, handler, serialize, deserialize, type) {
74
- if (typeof handler === 'function') {
75
- arguments[1] = createWrapHandler(tracer, config, name)(handler)
76
- }
77
-
78
- return register.apply(this, arguments)
79
- }
80
- }
81
- }
38
+ this.enter(span, store)
39
+ })
82
40
 
83
- function wrapStream (span, call, tracer) {
84
- const emit = call.emit
41
+ this.addSub('apm:grpc:server:request:error', error => {
42
+ const store = storage.getStore()
85
43
 
86
- if (call.call && call.call.sendStatus) {
87
- call.call.sendStatus = wrapSendStatus(call.call.sendStatus, span)
88
- }
44
+ if (!store || !store.span) return
89
45
 
90
- call.emit = function (eventName, ...args) {
91
- switch (eventName) {
92
- case 'error':
93
- span.addTags({
94
- [ERROR]: args[0] || 1,
95
- 'grpc.status.code': args[0] && args[0].code
96
- })
46
+ this.addCode(store.span, error.code)
47
+ this.addError(error)
48
+ })
97
49
 
98
- span.finish()
50
+ this.addSub('apm:grpc:server:request:update', ({ code }) => {
51
+ const store = storage.getStore()
99
52
 
100
- break
53
+ if (!store || !store.span) return
101
54
 
102
- // Finish the span of the response only if it was successful.
103
- // Otherwise it'll be finished in the `error` listener.
104
- case 'finish':
105
- if (call.status) {
106
- span.setTag('grpc.status.code', call.status.code)
107
- }
55
+ this.addCode(store.span, code)
56
+ })
108
57
 
109
- if (!call.status || call.status.code === 0) {
110
- span.finish()
111
- }
58
+ this.addSub('apm:grpc:server:request:finish', ({ code, trailer } = {}) => {
59
+ const store = storage.getStore()
112
60
 
113
- break
114
- }
61
+ if (!store || !store.span) return
115
62
 
116
- return emit.apply(this, arguments)
117
- }
118
- }
63
+ const span = store.span
64
+ const metadataFilter = this.config.metadataFilter
119
65
 
120
- function wrapCallback (span, callback, filter, childOf) {
121
- const scope = span.tracer().scope()
66
+ this.addCode(span, code)
122
67
 
123
- return function (err, value, trailer, flags) {
124
- if (err instanceof Error) {
125
- if (err.code) {
126
- span.setTag('grpc.status.code', err.code)
68
+ if (trailer && metadataFilter) {
69
+ addMetadataTags(span, trailer, metadataFilter, 'response')
127
70
  }
128
71
 
129
- span.setTag(ERROR, err)
130
- } else {
131
- span.setTag('grpc.status.code', OK)
132
- }
133
-
134
- if (trailer && filter) {
135
- addMetadataTags(span, trailer, filter, 'response')
136
- }
72
+ store.span.finish()
73
+ })
74
+ }
137
75
 
138
- span.finish()
76
+ configure (config) {
77
+ const metadataFilter = getFilter(config, 'metadata')
139
78
 
140
- if (callback) {
141
- return scope.bind(callback, childOf).apply(this, arguments)
142
- }
79
+ return super.configure({ ...config, metadataFilter })
143
80
  }
144
- }
145
-
146
- function wrapSendStatus (sendStatus, span) {
147
- return function sendStatusWithTrace (status) {
148
- span.setTag('grpc.status.code', status.code)
149
81
 
150
- return sendStatus.apply(this, arguments)
82
+ addCode (span, code) {
83
+ if (code !== undefined) {
84
+ span.setTag('grpc.status.code', code)
85
+ }
151
86
  }
152
87
  }
153
88
 
@@ -157,34 +92,4 @@ function extract (tracer, metadata) {
157
92
  return tracer.extract(TEXT_MAP, metadata.getMap())
158
93
  }
159
94
 
160
- function isEmitter (obj) {
161
- return typeof obj.emit === 'function' && typeof obj.once === 'function'
162
- }
163
-
164
- module.exports = [
165
- {
166
- name: 'grpc',
167
- versions: ['>=1.20.2'],
168
- file: 'src/server.js',
169
- patch (server, tracer, config) {
170
- if (config.server === false) return
171
- this.wrap(server.Server.prototype, 'register', createWrapRegister(tracer, config))
172
- },
173
- unpatch (server) {
174
- this.unwrap(server.Server.prototype, 'register')
175
- }
176
- },
177
- {
178
- name: '@grpc/grpc-js',
179
- versions: ['>=1'],
180
- file: 'build/src/server.js',
181
- patch (server, tracer, config) {
182
- if (config.server === false) return
183
-
184
- this.wrap(server.Server.prototype, 'register', createWrapRegister(tracer, config))
185
- },
186
- unpatch (server) {
187
- this.unwrap(server.Server.prototype, 'register')
188
- }
189
- }
190
- ]
95
+ module.exports = GrpcServerPlugin