dd-trace 2.3.1 → 2.4.2

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 (53) 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-cassandra-driver/src/index.js +52 -224
  23. package/packages/datadog-plugin-cucumber/src/index.js +3 -1
  24. package/packages/datadog-plugin-elasticsearch/src/index.js +4 -2
  25. package/packages/datadog-plugin-http/src/client.js +112 -252
  26. package/packages/datadog-plugin-http/src/index.js +29 -3
  27. package/packages/datadog-plugin-http/src/server.js +54 -32
  28. package/packages/datadog-plugin-jest/src/jest-environment.js +3 -3
  29. package/packages/datadog-plugin-jest/src/jest-jasmine2.js +5 -3
  30. package/packages/datadog-plugin-mocha/src/index.js +96 -207
  31. package/packages/datadog-plugin-mongodb-core/src/index.js +119 -3
  32. package/packages/datadog-plugin-net/src/index.js +65 -121
  33. package/packages/datadog-plugin-next/src/index.js +10 -10
  34. package/packages/datadog-plugin-pg/src/index.js +32 -69
  35. package/packages/datadog-plugin-rhea/src/index.js +59 -225
  36. package/packages/datadog-plugin-tedious/src/index.js +38 -86
  37. package/packages/dd-trace/lib/version.js +1 -1
  38. package/packages/dd-trace/src/appsec/recommended.json +235 -315
  39. package/packages/dd-trace/src/config.js +6 -0
  40. package/packages/dd-trace/src/iitm.js +5 -1
  41. package/packages/dd-trace/src/loader.js +6 -4
  42. package/packages/dd-trace/src/noop/tracer.js +4 -0
  43. package/packages/dd-trace/src/opentracing/propagation/text_map.js +34 -1
  44. package/packages/dd-trace/src/opentracing/span.js +34 -0
  45. package/packages/dd-trace/src/plugin_manager.js +4 -0
  46. package/packages/dd-trace/src/plugins/plugin.js +3 -1
  47. package/packages/dd-trace/src/plugins/util/web.js +99 -93
  48. package/packages/dd-trace/src/proxy.js +4 -0
  49. package/packages/dd-trace/src/ritm.js +60 -25
  50. package/packages/dd-trace/src/tracer.js +16 -0
  51. package/packages/datadog-plugin-mongodb-core/src/legacy.js +0 -59
  52. package/packages/datadog-plugin-mongodb-core/src/unified.js +0 -138
  53. package/packages/datadog-plugin-mongodb-core/src/util.js +0 -143
@@ -1,120 +1,100 @@
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
- function createWrapSend (tracer, config) {
6
- return function wrapSend (send) {
7
- return function sendWithTrace (msg, options) {
8
- const span = startSendSpan(tracer, config, this)
9
-
10
- try {
11
- const promise = tracer.scope().activate(span, () => {
12
- return send.apply(this, arguments)
13
- })
14
-
15
- return wrapPromise(promise, span)
16
- } catch (e) {
17
- finish(span, e)
18
- throw e
19
- }
20
- }
7
+ class Amqp10Plugin extends Plugin {
8
+ static get name () {
9
+ return 'amqp10'
21
10
  }
22
- }
23
-
24
- function createWrapMessageReceived (tracer, config) {
25
- return function wrapMessageReceived (messageReceived) {
26
- return function messageReceivedWithTrace (transferFrame) {
27
- if (!transferFrame || transferFrame.aborted || transferFrame.more) {
28
- return messageReceived.apply(this, arguments)
29
- }
30
11
 
31
- const span = startReceiveSpan(tracer, config, this)
32
-
33
- return tracer.scope().activate(span, () => {
34
- messageReceived.apply(this, arguments)
35
- span.finish()
12
+ constructor (...args) {
13
+ super(...args)
14
+
15
+ this.addSub(`apm:amqp10:send:start`, ({ link }) => {
16
+ const address = getAddress(link)
17
+ const target = getShortName(link)
18
+
19
+ const store = storage.getStore()
20
+ const childOf = store ? store.span : store
21
+
22
+ const span = this.tracer.startSpan('amqp.send', {
23
+ childOf,
24
+ tags: {
25
+ 'resource.name': ['send', target].filter(v => v).join(' '),
26
+ 'span.kind': 'producer',
27
+ 'amqp.link.target.address': target,
28
+ 'amqp.link.role': 'sender',
29
+ 'out.host': address.host,
30
+ 'out.port': address.port,
31
+ 'service.name': this.config.service || `${this.tracer._service}-amqp`,
32
+ 'amqp.link.name': link.name,
33
+ 'amqp.link.handle': link.handle,
34
+ 'amqp.connection.host': address.host,
35
+ 'amqp.connection.port': address.port,
36
+ 'amqp.connection.user': address.user
37
+ }
36
38
  })
37
- }
38
- }
39
- }
40
-
41
- function startSendSpan (tracer, config, link) {
42
- const address = getAddress(link)
43
- const target = getShortName(link)
44
-
45
- const span = tracer.startSpan(`amqp.send`, {
46
- tags: {
47
- 'resource.name': ['send', target].filter(v => v).join(' '),
48
- 'span.kind': 'producer',
49
- 'amqp.link.target.address': target,
50
- 'amqp.link.role': 'sender',
51
- 'out.host': address.host,
52
- 'out.port': address.port
53
- }
54
- })
55
39
 
56
- addTags(tracer, config, span, link)
40
+ analyticsSampler.sample(span, this.config.measured)
57
41
 
58
- analyticsSampler.sample(span, config.measured)
59
-
60
- return span
61
- }
62
-
63
- function startReceiveSpan (tracer, config, link) {
64
- const source = getShortName(link)
65
- const span = tracer.startSpan(`amqp.receive`, {
66
- tags: {
67
- 'resource.name': ['receive', source].filter(v => v).join(' '),
68
- 'span.kind': 'consumer',
69
- 'span.type': 'worker',
70
- 'amqp.link.source.address': source,
71
- 'amqp.link.role': 'receiver'
72
- }
73
- })
74
-
75
- addTags(tracer, config, span, link)
42
+ this.enter(span, store)
43
+ })
76
44
 
77
- analyticsSampler.sample(span, config.measured, true)
45
+ this.addSub(`apm:amqp10:send:end`, () => {
46
+ this.exit()
47
+ })
78
48
 
79
- return span
80
- }
49
+ this.addSub(`apm:amqp10:send:error`, err => {
50
+ const span = storage.getStore().span
51
+ span.setTag('error', err)
52
+ })
81
53
 
82
- function addTags (tracer, config, span, link = {}) {
83
- const address = getAddress(link)
54
+ this.addSub(`apm:amqp10:send:async-end`, () => {
55
+ const span = storage.getStore().span
56
+ span.finish()
57
+ })
84
58
 
85
- span.addTags({
86
- 'service.name': config.service || `${tracer._service}-amqp`,
87
- 'amqp.link.name': link.name,
88
- 'amqp.link.handle': link.handle,
89
- 'amqp.connection.host': address.host,
90
- 'amqp.connection.port': address.port,
91
- 'amqp.connection.user': address.user
92
- })
59
+ this.addSub(`apm:amqp10:receive:start`, ({ link }) => {
60
+ const source = getShortName(link)
61
+ const address = getAddress(link)
62
+
63
+ const store = storage.getStore()
64
+ const childOf = store ? store.span : store
65
+
66
+ const span = this.tracer.startSpan('amqp.receive', {
67
+ childOf,
68
+ tags: {
69
+ 'resource.name': ['receive', source].filter(v => v).join(' '),
70
+ 'span.kind': 'consumer',
71
+ 'span.type': 'worker',
72
+ 'amqp.link.source.address': source,
73
+ 'amqp.link.role': 'receiver',
74
+ 'service.name': this.config.service || `${this.tracer._service}-amqp`,
75
+ 'amqp.link.name': link.name,
76
+ 'amqp.link.handle': link.handle,
77
+ 'amqp.connection.host': address.host,
78
+ 'amqp.connection.port': address.port,
79
+ 'amqp.connection.user': address.user
80
+ }
81
+ })
93
82
 
94
- return span
95
- }
83
+ analyticsSampler.sample(span, this.config.measured)
96
84
 
97
- function finish (span, error) {
98
- if (error) {
99
- span.addTags({
100
- 'error.type': error.name,
101
- 'error.msg': error.message,
102
- 'error.stack': error.stack
85
+ this.enter(span, store)
103
86
  })
104
- }
105
87
 
106
- span.finish()
107
- }
88
+ this.addSub(`apm:amqp10:receive:end`, () => {
89
+ storage.getStore().span.finish()
90
+ this.exit()
91
+ })
108
92
 
109
- function wrapPromise (promise, span) {
110
- if (!promise) {
111
- finish(span)
112
- return promise
93
+ this.addSub(`apm:amqp10:receive:error`, err => {
94
+ const span = storage.getStore().span
95
+ span.setTag('error', err)
96
+ })
113
97
  }
114
-
115
- promise.then(() => finish(span), e => finish(span, e))
116
-
117
- return promise
118
98
  }
119
99
 
120
100
  function getShortName (link) {
@@ -129,27 +109,4 @@ function getAddress (link) {
129
109
  return link.session.connection.address || {}
130
110
  }
131
111
 
132
- module.exports = [
133
- {
134
- name: 'amqp10',
135
- file: 'lib/sender_link.js',
136
- versions: ['>=3'],
137
- patch (SenderLink, tracer, config) {
138
- this.wrap(SenderLink.prototype, 'send', createWrapSend(tracer, config))
139
- },
140
- unpatch (SenderLink) {
141
- this.unwrap(SenderLink.prototype, 'send')
142
- }
143
- },
144
- {
145
- name: 'amqp10',
146
- file: 'lib/receiver_link.js',
147
- versions: ['>=3'],
148
- patch (ReceiverLink, tracer, config) {
149
- this.wrap(ReceiverLink.prototype, '_messageReceived', createWrapMessageReceived(tracer, config))
150
- },
151
- unpatch (ReceiverLink) {
152
- this.unwrap(ReceiverLink.prototype, '_messageReceived')
153
- }
154
- }
155
- ]
112
+ module.exports = Amqp10Plugin
@@ -1,74 +1,92 @@
1
1
  'use strict'
2
2
 
3
- const kebabCase = require('lodash.kebabcase')
3
+ const Plugin = require('../../dd-trace/src/plugins/plugin')
4
+ const { storage } = require('../../datadog-core')
4
5
  const analyticsSampler = require('../../dd-trace/src/analytics_sampler')
5
6
  const { TEXT_MAP } = require('../../../ext/formats')
6
7
 
7
- let methods = {}
8
-
9
- function createWrapSendImmediately (tracer, config) {
10
- return function wrapSendImmediately (sendImmediately) {
11
- return function sendImmediatelyWithTrace (method, fields) {
12
- return sendWithTrace(sendImmediately, this, arguments, tracer, config, methods[method], fields)
13
- }
8
+ class AmqplibPlugin extends Plugin {
9
+ static get name () {
10
+ return 'amqplib'
14
11
  }
15
- }
16
-
17
- function createWrapSendMessage (tracer, config) {
18
- return function wrapSendMessage (sendMessage) {
19
- return function sendMessageWithTrace (fields) {
20
- return sendWithTrace(sendMessage, this, arguments, tracer, config, 'basic.publish', fields)
21
- }
22
- }
23
- }
24
12
 
25
- function createWrapDispatchMessage (tracer, config) {
26
- return function wrapDispatchMessage (dispatchMessage) {
27
- return function dispatchMessageWithTrace (fields, message) {
28
- const childOf = extract(tracer, message)
29
- const span = tracer.startSpan('amqp.command', { childOf })
30
-
31
- addTags(this, tracer, config, span, 'basic.deliver', fields)
32
-
33
- analyticsSampler.sample(span, config.measured, true)
34
-
35
- tracer.scope().activate(span, () => {
36
- try {
37
- dispatchMessage.apply(this, arguments)
38
- } catch (e) {
39
- throw addError(span, e)
40
- } finally {
41
- span.finish()
13
+ constructor (...args) {
14
+ super(...args)
15
+
16
+ this.addSub(`apm:amqplib:command:start`, ({ channel, method, fields, message }) => {
17
+ const store = storage.getStore()
18
+ let childOf
19
+
20
+ if (method === 'basic.deliver') {
21
+ childOf = extract(this.tracer, message)
22
+ } else {
23
+ fields.headers = fields.headers || {}
24
+ childOf = store ? store.span : store
25
+ }
26
+
27
+ const span = this.tracer.startSpan('amqp.command', {
28
+ childOf,
29
+ tags: {
30
+ 'service.name': this.config.service || `${this.tracer._service}-amqp`,
31
+ 'resource.name': getResourceName(method, fields)
42
32
  }
43
33
  })
44
- }
45
- }
46
- }
47
-
48
- function sendWithTrace (send, channel, args, tracer, config, method, fields) {
49
- const childOf = tracer.scope().active()
50
- const span = tracer.startSpan('amqp.command', { childOf })
51
-
52
- fields.headers = fields.headers || {}
53
-
54
- addTags(channel, tracer, config, span, method, fields)
55
- tracer.inject(span, TEXT_MAP, fields.headers)
56
34
 
57
- analyticsSampler.sample(span, config.measured)
35
+ if (channel && channel.connection && channel.connection.stream) {
36
+ span.addTags({
37
+ 'out.host': channel.connection.stream._host,
38
+ 'out.port': channel.connection.stream.remotePort
39
+ })
40
+ }
41
+ const fieldNames = [
42
+ 'queue',
43
+ 'exchange',
44
+ 'routingKey',
45
+ 'consumerTag',
46
+ 'source',
47
+ 'destination'
48
+ ]
49
+
50
+ switch (method) {
51
+ case 'basic.publish':
52
+ span.setTag('span.kind', 'producer')
53
+ break
54
+ case 'basic.consume':
55
+ case 'basic.get':
56
+ case 'basic.deliver':
57
+ span.addTags({
58
+ 'span.kind': 'consumer',
59
+ 'span.type': 'worker'
60
+ })
61
+ break
62
+ default:
63
+ span.setTag('span.kind', 'client')
64
+ }
65
+
66
+ fieldNames.forEach(field => {
67
+ fields[field] !== undefined && span.setTag(`amqp.${field}`, fields[field])
68
+ })
69
+ if (method === 'basic.deliver') {
70
+ analyticsSampler.sample(span, this.config.measured, true)
71
+ } else {
72
+ this.tracer.inject(span, TEXT_MAP, fields.headers)
73
+ analyticsSampler.sample(span, this.config.measured)
74
+ }
75
+
76
+ this.enter(span, store)
77
+ })
58
78
 
59
- return tracer.scope().activate(span, () => {
60
- try {
61
- return send.apply(channel, args)
62
- } catch (e) {
63
- throw addError(span, e)
64
- } finally {
79
+ this.addSub(`apm:amqplib:command:end`, () => {
80
+ const span = storage.getStore().span
65
81
  span.finish()
66
- }
67
- })
68
- }
82
+ this.exit()
83
+ })
69
84
 
70
- function isCamelCase (str) {
71
- return /([A-Z][a-z0-9]+)+/.test(str)
85
+ this.addSub(`apm:amqplib:command:error`, err => {
86
+ const span = storage.getStore().span
87
+ span.setTag('error', err)
88
+ })
89
+ }
72
90
  }
73
91
 
74
92
  function getResourceName (method, fields = {}) {
@@ -82,93 +100,10 @@ function getResourceName (method, fields = {}) {
82
100
  ].filter(val => val).join(' ')
83
101
  }
84
102
 
85
- function addError (span, error) {
86
- span.addTags({
87
- 'error.type': error.name,
88
- 'error.msg': error.message,
89
- 'error.stack': error.stack
90
- })
91
-
92
- return error
93
- }
94
-
95
- function addTags (channel, tracer, config, span, method, fields) {
96
- const fieldNames = [
97
- 'queue',
98
- 'exchange',
99
- 'routingKey',
100
- 'consumerTag',
101
- 'source',
102
- 'destination'
103
- ]
104
-
105
- span.addTags({
106
- 'service.name': config.service || `${tracer._service}-amqp`,
107
- 'resource.name': getResourceName(method, fields)
108
- })
109
-
110
- if (channel && channel.connection && channel.connection.stream) {
111
- span.addTags({
112
- 'out.host': channel.connection.stream._host,
113
- 'out.port': channel.connection.stream.remotePort
114
- })
115
- }
116
-
117
- switch (method) {
118
- case 'basic.publish':
119
- span.setTag('span.kind', 'producer')
120
- break
121
- case 'basic.consume':
122
- case 'basic.get':
123
- case 'basic.deliver':
124
- span.addTags({
125
- 'span.kind': 'consumer',
126
- 'span.type': 'worker'
127
- })
128
- break
129
- default:
130
- span.setTag('span.kind', 'client')
131
- }
132
-
133
- fieldNames.forEach(field => {
134
- fields[field] !== undefined && span.setTag(`amqp.${field}`, fields[field])
135
- })
136
- }
137
-
138
103
  function extract (tracer, message) {
139
104
  return message
140
105
  ? tracer.extract(TEXT_MAP, message.properties.headers)
141
106
  : null
142
107
  }
143
108
 
144
- module.exports = [
145
- {
146
- name: 'amqplib',
147
- file: 'lib/defs.js',
148
- versions: ['>=0.5'],
149
- patch (defs, tracer, config) {
150
- methods = Object.keys(defs)
151
- .filter(key => Number.isInteger(defs[key]))
152
- .filter(key => isCamelCase(key))
153
- .reduce((acc, key) => Object.assign(acc, { [defs[key]]: kebabCase(key).replace('-', '.') }), {})
154
- },
155
- unpatch (defs) {
156
- methods = {}
157
- }
158
- },
159
- {
160
- name: 'amqplib',
161
- file: 'lib/channel.js',
162
- versions: ['>=0.5'],
163
- patch (channel, tracer, config) {
164
- this.wrap(channel.Channel.prototype, 'sendImmediately', createWrapSendImmediately(tracer, config))
165
- this.wrap(channel.Channel.prototype, 'sendMessage', createWrapSendMessage(tracer, config))
166
- this.wrap(channel.BaseChannel.prototype, 'dispatchMessage', createWrapDispatchMessage(tracer, config))
167
- },
168
- unpatch (channel) {
169
- this.unwrap(channel.Channel.prototype, 'sendImmediately')
170
- this.unwrap(channel.Channel.prototype, 'sendMessage')
171
- this.unwrap(channel.BaseChannel.prototype, 'dispatchMessage')
172
- }
173
- }
174
- ]
109
+ module.exports = AmqplibPlugin