dd-trace 2.3.0 → 2.4.1

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 (52) hide show
  1. package/ci/init.js +26 -2
  2. package/index.d.ts +51 -0
  3. package/package.json +2 -2
  4. package/packages/datadog-instrumentations/index.js +10 -0
  5. package/packages/datadog-instrumentations/src/amqp10.js +70 -0
  6. package/packages/datadog-instrumentations/src/amqplib.js +58 -0
  7. package/packages/datadog-instrumentations/src/cassandra-driver.js +191 -0
  8. package/packages/datadog-instrumentations/src/cucumber.js +27 -12
  9. package/packages/datadog-instrumentations/src/helpers/hook.js +44 -0
  10. package/packages/datadog-instrumentations/src/helpers/instrument.js +31 -58
  11. package/packages/datadog-instrumentations/src/http/client.js +170 -0
  12. package/packages/datadog-instrumentations/src/http/server.js +61 -0
  13. package/packages/datadog-instrumentations/src/http.js +4 -0
  14. package/packages/datadog-instrumentations/src/mocha.js +139 -0
  15. package/packages/datadog-instrumentations/src/mongodb-core.js +179 -0
  16. package/packages/datadog-instrumentations/src/net.js +117 -0
  17. package/packages/datadog-instrumentations/src/pg.js +75 -0
  18. package/packages/datadog-instrumentations/src/rhea.js +224 -0
  19. package/packages/datadog-instrumentations/src/tedious.js +66 -0
  20. package/packages/datadog-plugin-amqp10/src/index.js +79 -122
  21. package/packages/datadog-plugin-amqplib/src/index.js +77 -142
  22. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +2 -2
  23. package/packages/datadog-plugin-cassandra-driver/src/index.js +52 -224
  24. package/packages/datadog-plugin-cucumber/src/index.js +3 -1
  25. package/packages/datadog-plugin-http/src/client.js +111 -254
  26. package/packages/datadog-plugin-http/src/index.js +29 -3
  27. package/packages/datadog-plugin-http/src/server.js +49 -32
  28. package/packages/datadog-plugin-jest/src/jest-jasmine2.js +5 -3
  29. package/packages/datadog-plugin-mocha/src/index.js +96 -207
  30. package/packages/datadog-plugin-mongodb-core/src/index.js +119 -3
  31. package/packages/datadog-plugin-net/src/index.js +65 -121
  32. package/packages/datadog-plugin-next/src/index.js +10 -10
  33. package/packages/datadog-plugin-pg/src/index.js +32 -69
  34. package/packages/datadog-plugin-rhea/src/index.js +59 -225
  35. package/packages/datadog-plugin-tedious/src/index.js +38 -86
  36. package/packages/dd-trace/lib/version.js +1 -1
  37. package/packages/dd-trace/src/appsec/recommended.json +137 -116
  38. package/packages/dd-trace/src/config.js +6 -0
  39. package/packages/dd-trace/src/iitm.js +5 -1
  40. package/packages/dd-trace/src/loader.js +6 -4
  41. package/packages/dd-trace/src/noop/tracer.js +4 -0
  42. package/packages/dd-trace/src/opentracing/propagation/text_map.js +34 -1
  43. package/packages/dd-trace/src/opentracing/span.js +34 -0
  44. package/packages/dd-trace/src/plugin_manager.js +4 -0
  45. package/packages/dd-trace/src/plugins/plugin.js +3 -1
  46. package/packages/dd-trace/src/plugins/util/web.js +99 -93
  47. package/packages/dd-trace/src/proxy.js +4 -0
  48. package/packages/dd-trace/src/ritm.js +60 -25
  49. package/packages/dd-trace/src/tracer.js +16 -0
  50. package/packages/datadog-plugin-mongodb-core/src/legacy.js +0 -59
  51. package/packages/datadog-plugin-mongodb-core/src/unified.js +0 -138
  52. package/packages/datadog-plugin-mongodb-core/src/util.js +0 -143
@@ -1,201 +1,79 @@
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
 
5
- const dd = Symbol('datadog')
6
- const circularBufferConstructor = Symbol('circularBufferConstructor')
7
- const inFlightDeliveries = Symbol('inFlightDeliveries')
7
+ class RheaPlugin extends Plugin {
8
+ static get name () {
9
+ return 'rhea'
10
+ }
8
11
 
9
- const patched = new WeakSet()
12
+ constructor (...args) {
13
+ super(...args)
10
14
 
11
- function createWrapSend (tracer, config, instrumenter) {
12
- return function wrapSend (send) {
13
- return function sendWithTrace (msg, tag, format) {
14
- if (!canTrace(this)) {
15
- // we can't handle disconnects or ending spans, so we can't safely instrument
16
- return send.apply(this, arguments)
17
- }
18
- const name = getResourceNameFromSender(this)
19
- const { host, port } = getHostAndPort(this.connection)
20
- return tracer.trace('amqp.send', {
15
+ this.addSub(`apm:rhea:send:start`, ({ targetAddress, host, port, msg }) => {
16
+ const store = storage.getStore()
17
+ const childOf = store ? store.span : store
18
+ const name = targetAddress || 'amq.topic'
19
+ const span = this.tracer.startSpan('amqp.send', {
20
+ childOf,
21
21
  tags: {
22
22
  'component': 'rhea',
23
23
  'resource.name': name,
24
- 'service.name': config.service || `${tracer._service}-amqp-producer`,
24
+ 'service.name': this.config.service || `${this.tracer._service}-amqp-producer`,
25
25
  'span.kind': 'producer',
26
26
  'amqp.link.target.address': name,
27
27
  'amqp.link.role': 'sender',
28
28
  'out.host': host,
29
29
  'out.port': port
30
30
  }
31
- }, (span, done) => {
32
- analyticsSampler.sample(span, config.measured)
33
- addDeliveryAnnotations(msg, tracer, span)
34
- const delivery = send.apply(this, arguments)
35
- delivery[dd] = { done, span }
36
- addToInFlightDeliveries(this.connection, delivery)
37
- return delivery
38
31
  })
39
- }
40
- }
41
- }
42
-
43
- function createWrapConnectionDispatch (tracer, config) {
44
- return function wrapDispatch (dispatch) {
45
- return function dispatchWithTrace (eventName, obj) {
46
- if (eventName === 'disconnected') {
47
- const error = obj.error || this.saved_error
48
- if (this[inFlightDeliveries]) {
49
- this[inFlightDeliveries].forEach(delivery => {
50
- const { span } = delivery[dd]
51
- span.addTags({ error })
52
- finish(delivery, null)
53
- })
54
- }
55
- }
56
- return dispatch.apply(this, arguments)
57
- }
58
- }
59
- }
32
+ analyticsSampler.sample(span, this.config.measured)
33
+ addDeliveryAnnotations(msg, this.tracer, span)
60
34
 
61
- function createWrapReceiverDispatch (tracer, config, instrumenter) {
62
- return function wrapDispatch (dispatch) {
63
- return function dispatchWithTrace (eventName, msgObj) {
64
- if (!canTrace(this)) {
65
- // we can't handle disconnects or ending spans, so we can't safely instrument
66
- return dispatch.apply(this, arguments)
67
- }
68
- if (eventName === 'message' && msgObj) {
69
- const name = getResourceNameFromMessage(msgObj)
70
- const childOf = getAnnotations(msgObj, tracer)
71
- return tracer.trace('amqp.receive', {
72
- type: 'worker',
73
- tags: {
74
- 'component': 'rhea',
75
- 'resource.name': name,
76
- 'service.name': config.service || tracer._service,
77
- 'span.kind': 'consumer',
78
- 'amqp.link.source.address': name,
79
- 'amqp.link.role': 'receiver'
80
- },
81
- childOf
82
- }, (span, done) => {
83
- analyticsSampler.sample(span, config.measured, true)
84
- if (msgObj.delivery) {
85
- msgObj.delivery[dd] = { done, span }
86
- msgObj.delivery.update = wrapDeliveryUpdate(msgObj.delivery.update)
87
- addToInFlightDeliveries(this.connection, msgObj.delivery)
88
- }
89
- return dispatch.apply(this, arguments)
90
- })
91
- }
35
+ this.enter(span, store)
36
+ })
92
37
 
93
- return dispatch.apply(this, arguments)
94
- }
95
- }
96
- }
38
+ this.addSub(`apm:rhea:receive:start`, ({ msgObj, connection }) => {
39
+ const name = getResourceNameFromMessage(msgObj)
97
40
 
98
- function createWrapCircularBufferPopIf () {
99
- return function wrapCircularBufferPopIf (popIf) {
100
- return function wrappedPopIf (fn) {
101
- arguments[0] = entry => {
102
- const shouldPop = fn(entry)
103
- if (shouldPop && entry[dd]) {
104
- const remoteState = entry.remote_state
105
- const state = remoteState && remoteState.constructor
106
- ? entry.remote_state.constructor.composite_type : undefined
107
- finish(entry, state)
108
- }
109
- return shouldPop
110
- }
111
- return popIf.apply(this, arguments)
112
- }
113
- }
114
- }
115
-
116
- function wrapDeliveryUpdate (update) {
117
- return function wrappedUpdate (settled, stateData) {
118
- if (this[dd]) {
119
- const state = getStateFromData(stateData)
120
- this[dd].span.setTag('amqp.delivery.state', state)
121
- }
122
- return update.apply(this, arguments)
123
- }
124
- }
125
-
126
- function patchCircularBuffer (proto, instrumenter) {
127
- Object.defineProperty(proto, 'outgoing', {
128
- configurable: true,
129
- get () {},
130
- set (outgoing) {
131
- delete proto.outgoing // removes the setter on the prototype
132
- this.outgoing = outgoing // assigns on the instance, like normal
133
- if (outgoing) {
134
- let CircularBuffer
135
- if (outgoing.deliveries) {
136
- CircularBuffer = outgoing.deliveries.constructor
137
- }
138
- if (CircularBuffer && !patched.has(CircularBuffer.prototype)) {
139
- instrumenter.wrap(CircularBuffer.prototype, 'pop_if', createWrapCircularBufferPopIf())
140
- patched.add(CircularBuffer.prototype)
141
- const Session = proto.constructor
142
- if (Session) {
143
- Session[circularBufferConstructor] = CircularBuffer
144
- }
41
+ const store = storage.getStore()
42
+ const childOf = extractTextMap(msgObj, this.tracer)
43
+ const span = this.tracer.startSpan('amqp.receive', {
44
+ childOf,
45
+ tags: {
46
+ 'span.type': 'worker',
47
+ 'component': 'rhea',
48
+ 'resource.name': name,
49
+ 'service.name': this.config.service || this.tracer._service,
50
+ 'span.kind': 'consumer',
51
+ 'amqp.link.source.address': name,
52
+ 'amqp.link.role': 'receiver'
145
53
  }
146
- }
147
- }
148
- })
149
- }
54
+ })
55
+ analyticsSampler.sample(span, this.config.measured, true)
150
56
 
151
- function addToInFlightDeliveries (connection, delivery) {
152
- let deliveries = connection[inFlightDeliveries]
153
- if (!deliveries) {
154
- deliveries = new Set()
155
- connection[inFlightDeliveries] = deliveries
156
- }
157
- deliveries.add(delivery)
158
- delivery[dd].connection = connection
159
- }
57
+ this.enter(span, store)
58
+ })
160
59
 
161
- function getHostAndPort (connection) {
162
- let host
163
- let port
164
- if (connection && connection.options) {
165
- host = connection.options.host
166
- port = connection.options.port
167
- }
168
- return { host, port }
169
- }
60
+ this.addSub(`apm:rhea:error`, error => {
61
+ storage.getStore().span.setTag('error', error)
62
+ })
170
63
 
171
- function addDeliveryAnnotations (msg, tracer, span) {
172
- if (msg) {
173
- msg.delivery_annotations = msg.delivery_annotations || {}
174
- tracer.inject(span, 'text_map', msg.delivery_annotations)
175
- }
176
- }
64
+ this.addSub(`apm:rhea:async-end`, () => {
65
+ const span = storage.getStore().span
66
+ span.finish()
67
+ })
177
68
 
178
- function getStateFromData (stateData) {
179
- if (stateData && stateData.descriptor && stateData.descriptor) {
180
- switch (stateData.descriptor.value) {
181
- case 0x24: return 'accepted'
182
- case 0x25: return 'rejected'
183
- case 0x26: return 'released'
184
- case 0x27: return 'modified'
185
- }
186
- }
187
- }
69
+ this.addSub(`apm:rhea:end`, () => {
70
+ this.exit()
71
+ })
188
72
 
189
- function finish (delivery, state) {
190
- if (delivery[dd]) {
191
- if (state) {
192
- delivery[dd].span.setTag('amqp.delivery.state', state)
193
- }
194
- delivery[dd].done()
195
- if (delivery[dd].connection && delivery[dd].connection[inFlightDeliveries]) {
196
- delivery[dd].connection[inFlightDeliveries].delete(delivery)
197
- }
198
- delete delivery[dd]
73
+ this.addSub(`apm:rhea:dispatch`, ({ state }) => {
74
+ const span = storage.getStore().span
75
+ span.setTag('amqp.delivery.state', state)
76
+ })
199
77
  }
200
78
  }
201
79
 
@@ -211,62 +89,18 @@ function getResourceNameFromMessage (msgObj) {
211
89
  return resourceName
212
90
  }
213
91
 
214
- function getResourceNameFromSender (sender) {
215
- let resourceName = 'amq.topic'
216
- if (sender.options && sender.options.target && sender.options.target.address) {
217
- resourceName = sender.options.target.address
218
- }
219
- return resourceName
220
- }
221
-
222
- function getAnnotations (msgObj, tracer) {
92
+ function extractTextMap (msgObj, tracer) {
223
93
  if (msgObj.message) {
224
94
  return tracer.extract('text_map', msgObj.message.delivery_annotations)
225
95
  }
226
96
  }
227
97
 
228
- function canTrace (link) {
229
- return link.connection && link.session && link.session.outgoing
230
- }
98
+ function addDeliveryAnnotations (msg, tracer, span) {
99
+ if (msg) {
100
+ msg.delivery_annotations = msg.delivery_annotations || {}
231
101
 
232
- module.exports = [
233
- {
234
- name: 'rhea',
235
- versions: ['>=1'],
236
- file: 'lib/link.js',
237
- patch ({ Sender, Receiver }, tracer, config) {
238
- this.wrap(Sender.prototype, 'send', createWrapSend(tracer, config, this))
239
- this.wrap(Receiver.prototype, 'dispatch', createWrapReceiverDispatch(tracer, config, this))
240
- },
241
- unpatch ({ Sender, Receiver }, tracer) {
242
- this.unwrap(Sender.prototype, 'send')
243
- this.unwrap(Receiver.prototype, 'dispatch')
244
- }
245
- },
246
- {
247
- name: 'rhea',
248
- versions: ['>=1'],
249
- file: 'lib/connection.js',
250
- patch (Connection, tracer, config) {
251
- this.wrap(Connection.prototype, 'dispatch', createWrapConnectionDispatch(tracer, config))
252
- },
253
- unpatch (Connection, tracer) {
254
- this.unwrap(Connection.prototype, 'dispatch')
255
- }
256
- },
257
- {
258
- name: 'rhea',
259
- versions: ['>=1'],
260
- file: 'lib/session.js',
261
- patch (Session, tracer, config) {
262
- patchCircularBuffer(Session.prototype, this)
263
- },
264
- unpatch (Session, tracer) {
265
- const CircularBuffer = Session[circularBufferConstructor]
266
- if (CircularBuffer) {
267
- patched.delete(CircularBuffer.prototype)
268
- this.unwrap(CircularBuffer.prototype, 'pop_if')
269
- }
270
- }
102
+ tracer.inject(span, 'text_map', msg.delivery_annotations)
271
103
  }
272
- ]
104
+ }
105
+
106
+ module.exports = RheaPlugin
@@ -1,102 +1,54 @@
1
1
  'use strict'
2
2
 
3
- const Tags = require('../../../ext/tags')
4
- const Kinds = require('../../../ext/kinds')
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
- const tx = require('../../dd-trace/src/plugins/util/tx')
7
6
 
8
- function createWrapMakeRequest (tracer, config) {
9
- return function wrapMakeRequest (makeRequest) {
10
- return function makeRequestWithTrace (request) {
11
- const connectionConfig = this.config
12
- const scope = tracer.scope()
13
- const childOf = scope.active()
14
- const queryOrProcedure = getQueryOrProcedure(request)
7
+ class TediousPlugin extends Plugin {
8
+ static get name () {
9
+ return 'tedious'
10
+ }
15
11
 
16
- if (!queryOrProcedure) {
17
- return makeRequest.apply(this, arguments)
18
- }
12
+ constructor (...args) {
13
+ super(...args)
19
14
 
20
- const span = tracer.startSpan('tedious.request', {
15
+ this.addSub(`apm:tedious:request:start`, ({ queryOrProcedure, connectionConfig }) => {
16
+ const store = storage.getStore()
17
+ const childOf = store ? store.span : store
18
+ const span = this.tracer.startSpan('tedious.request', {
21
19
  childOf,
22
20
  tags: {
23
- [Tags.SPAN_KIND]: Kinds.CLIENT,
21
+ 'span.kind': 'client',
24
22
  'db.type': 'mssql',
25
23
  'span.type': 'sql',
26
24
  'component': 'tedious',
27
- 'service.name': config.service || `${tracer._service}-mssql`,
28
- 'resource.name': queryOrProcedure
25
+ 'service.name': this.config.service || `${this.tracer._service}-mssql`,
26
+ 'resource.name': queryOrProcedure,
27
+ 'out.host': connectionConfig.server,
28
+ 'out.port': connectionConfig.options.port,
29
+ 'db.user': connectionConfig.userName || connectionConfig.authentication.options.userName,
30
+ 'db.name': connectionConfig.options.database,
31
+ 'db.instance': connectionConfig.options.instanceName
29
32
  }
30
33
  })
31
-
32
- addConnectionTags(span, connectionConfig)
33
- addDatabaseTags(span, connectionConfig)
34
-
35
- analyticsSampler.sample(span, config.measured)
36
- request.callback = tx.wrap(span, request.callback)
37
-
38
- return scope.bind(makeRequest, span).apply(this, arguments)
39
- }
40
- }
41
- }
42
-
43
- function createWrapGetRowStream (tracer) {
44
- return function wrapGetRowStream (getRowStream) {
45
- return function getRowStreamWithTrace () {
46
- const scope = tracer.scope()
47
-
48
- const rowToPacketTransform = getRowStream.apply(this, arguments)
49
- return scope.bind(rowToPacketTransform)
50
- }
34
+ analyticsSampler.sample(span, this.config.measured)
35
+ this.enter(span, store)
36
+ })
37
+
38
+ this.addSub(`apm:tedious:request:end`, () => {
39
+ this.exit()
40
+ })
41
+
42
+ this.addSub(`apm:tedious:request:error`, err => {
43
+ const span = storage.getStore().span
44
+ span.setTag('error', err)
45
+ })
46
+
47
+ this.addSub(`apm:tedious:request:async-end`, () => {
48
+ const span = storage.getStore().span
49
+ span.finish()
50
+ })
51
51
  }
52
52
  }
53
53
 
54
- function getQueryOrProcedure (request) {
55
- if (!request.parameters) return
56
-
57
- const statement = request.parametersByName.statement || request.parametersByName.stmt
58
-
59
- if (!statement) {
60
- return request.sqlTextOrProcedure
61
- }
62
-
63
- return statement.value
64
- }
65
-
66
- function addConnectionTags (span, connectionConfig) {
67
- span.setTag('out.host', connectionConfig.server)
68
- span.setTag('out.port', connectionConfig.options.port)
69
- }
70
-
71
- function addDatabaseTags (span, connectionConfig) {
72
- span.setTag('db.user', connectionConfig.userName || connectionConfig.authentication.options.userName)
73
- span.setTag('db.name', connectionConfig.options.database)
74
- span.setTag('db.instance', connectionConfig.options.instanceName)
75
- }
76
-
77
- module.exports = [
78
- {
79
- name: 'tedious',
80
- versions: [ '>=1.0.0' ],
81
- patch (tedious, tracer, config) {
82
- this.wrap(tedious.Connection.prototype, 'makeRequest', createWrapMakeRequest(tracer, config))
83
-
84
- if (tedious.BulkLoad && tedious.BulkLoad.prototype.getRowStream) {
85
- this.wrap(tedious.BulkLoad.prototype, 'getRowStream', createWrapGetRowStream(tracer))
86
- }
87
-
88
- tracer.scope().bind(tedious.Request.prototype)
89
- tracer.scope().bind(tedious.Connection.prototype)
90
- },
91
- unpatch (tedious, tracer) {
92
- this.unwrap(tedious.Connection.prototype, 'makeRequest')
93
-
94
- if (tedious.BulkLoad) {
95
- this.unwrap(tedious.BulkLoad.prototype, 'getRowStream')
96
- }
97
-
98
- tracer.scope().unbind(tedious.Request.prototype)
99
- tracer.scope().unbind(tedious.Connection.prototype)
100
- }
101
- }
102
- ]
54
+ module.exports = TediousPlugin
@@ -1 +1 @@
1
- module.exports = '2.3.0'
1
+ module.exports = '2.4.1'