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,145 +1,89 @@
1
1
  'use strict'
2
2
 
3
- const tx = require('../../dd-trace/src/plugins/util/tx')
4
- const analyticsSampler = require('../../dd-trace/src/analytics_sampler')
3
+ const Plugin = require('../../dd-trace/src/plugins/plugin')
5
4
  const { storage } = require('../../datadog-core')
5
+ const analyticsSampler = require('../../dd-trace/src/analytics_sampler')
6
6
 
7
- function createWrapConnect (tracer, config) {
8
- return function wrapConnect (connect) {
9
- return function connectWithTrace () {
10
- const store = storage.getStore()
11
-
12
- if (store && store.noop) return connect.apply(this, arguments)
13
-
14
- const scope = tracer.scope()
15
- const options = getOptions(arguments)
16
- const lastIndex = arguments.length - 1
17
- const callback = arguments[lastIndex]
18
-
19
- if (!options) return connect.apply(this, arguments)
20
-
21
- if (typeof callback === 'function') {
22
- arguments[lastIndex] = scope.bind(callback)
23
- }
24
-
25
- const span = options.path
26
- ? wrapIpc(tracer, config, this, options)
27
- : wrapTcp(tracer, config, this, options)
28
-
29
- analyticsSampler.sample(span, config.measured)
30
-
31
- return scope.bind(connect, span).apply(this, arguments)
32
- }
7
+ class NetPlugin extends Plugin {
8
+ static get name () {
9
+ return 'net'
33
10
  }
34
- }
35
11
 
36
- function wrapTcp (tracer, config, socket, options) {
37
- const host = options.host || 'localhost'
38
- const port = options.port || 0
39
- const family = options.family || 4
12
+ constructor (...args) {
13
+ super(...args)
40
14
 
41
- const span = startSpan(tracer, config, 'tcp', {
42
- 'resource.name': [host, port].filter(val => val).join(':'),
43
- 'tcp.remote.host': host,
44
- 'tcp.remote.port': port,
45
- 'tcp.family': `IPv${family}`,
46
- 'out.host': host,
47
- 'out.port': port
48
- })
49
-
50
- setupListeners(socket, span, 'tcp')
15
+ this.addSub(`apm:net:ipc:start`, ({ options }) => {
16
+ const store = storage.getStore()
17
+ const childOf = store ? store.span : store
18
+
19
+ const span = this.tracer.startSpan('ipc.connect', {
20
+ childOf,
21
+ tags: {
22
+ 'resource.name': options.path,
23
+ 'ipc.path': options.path,
24
+ 'span.kind': 'client',
25
+ 'service.name': this.config.service || this.tracer._service
26
+ }
27
+ })
51
28
 
52
- return span
53
- }
29
+ analyticsSampler.sample(span, this.config.measured)
30
+ this.enter(span, store)
31
+ })
54
32
 
55
- function wrapIpc (tracer, config, socket, options) {
56
- const span = startSpan(tracer, config, 'ipc', {
57
- 'resource.name': options.path,
58
- 'ipc.path': options.path
59
- })
33
+ this.addSub(`apm:net:ipc:end`, this.exit.bind(this))
60
34
 
61
- setupListeners(socket, span, 'ipc')
35
+ this.addSub(`apm:net:ipc:error`, errorHandler)
62
36
 
63
- return span
64
- }
37
+ this.addSub(`apm:net:ipc:async-end`, defaultAsyncEnd)
65
38
 
66
- function startSpan (tracer, config, protocol, tags) {
67
- const childOf = tracer.scope().active()
68
- const span = tracer.startSpan(`${protocol}.connect`, {
69
- childOf,
70
- tags: Object.assign({
71
- 'span.kind': 'client',
72
- 'service.name': config.service || tracer._service
73
- }, tags)
74
- })
75
-
76
- return span
77
- }
78
-
79
- function getOptions (args) {
80
- if (!args[0]) return
81
-
82
- switch (typeof args[0]) {
83
- case 'object':
84
- if (Array.isArray(args[0])) return getOptions(args[0])
85
- return args[0]
86
- case 'string':
87
- if (isNaN(parseFloat(args[0]))) {
88
- return {
89
- path: args[0]
39
+ this.addSub(`apm:net:tcp:start`, ({ options }) => {
40
+ const store = storage.getStore()
41
+ const childOf = store ? store.span : store
42
+
43
+ const host = options.host || 'localhost'
44
+ const port = options.port || 0
45
+ const family = options.family || 4
46
+
47
+ const span = this.tracer.startSpan('tcp.connect', {
48
+ childOf,
49
+ tags: {
50
+ 'resource.name': [host, port].filter(val => val).join(':'),
51
+ 'tcp.remote.host': host,
52
+ 'tcp.remote.port': port,
53
+ 'tcp.family': `IPv${family}`,
54
+ 'out.host': host,
55
+ 'out.port': port,
56
+ 'span.kind': 'client',
57
+ 'service.name': this.config.service || this.tracer._service
90
58
  }
91
- }
92
- case 'number': // eslint-disable-line no-fallthrough
93
- return {
94
- port: args[0],
95
- host: typeof args[1] === 'string' ? args[1] : 'localhost'
96
- }
97
- }
98
- }
59
+ })
99
60
 
100
- function setupListeners (socket, span, protocol) {
101
- const events = ['connect', 'error', 'close', 'timeout']
61
+ analyticsSampler.sample(span, this.config.measured)
62
+ this.enter(span, store)
63
+ })
102
64
 
103
- const wrapListener = tx.wrap(span)
65
+ this.addSub(`apm:net:tcp:end`, this.exit.bind(this))
104
66
 
105
- const localListener = () => {
106
- span.addTags({
107
- 'tcp.local.address': socket.localAddress,
108
- 'tcp.local.port': socket.localPort
109
- })
110
- }
67
+ this.addSub(`apm:net:tcp:error`, errorHandler)
111
68
 
112
- const cleanupListener = () => {
113
- socket.removeListener('connect', localListener)
69
+ this.addSub(`apm:net:tcp:async-end`, defaultAsyncEnd)
114
70
 
115
- events.forEach(event => {
116
- socket.removeListener(event, wrapListener)
117
- socket.removeListener(event, cleanupListener)
71
+ this.addSub(`apm:net:tcp:connection`, ({ socket }) => {
72
+ const span = storage.getStore().span
73
+ span.addTags({
74
+ 'tcp.local.address': socket.localAddress,
75
+ 'tcp.local.port': socket.localPort
76
+ })
118
77
  })
119
78
  }
120
-
121
- if (protocol === 'tcp') {
122
- socket.once('connect', localListener)
123
- }
124
-
125
- events.forEach(event => {
126
- socket.once(event, wrapListener)
127
- socket.once(event, cleanupListener)
128
- })
129
79
  }
130
80
 
131
- module.exports = {
132
- name: 'net',
133
- patch (net, tracer, config) {
134
- require('dns') // net will otherwise get an unpatched version for DNS lookups
135
-
136
- tracer.scope().bind(net.Socket.prototype)
137
-
138
- this.wrap(net.Socket.prototype, 'connect', createWrapConnect(tracer, config))
139
- },
140
- unpatch (net, tracer) {
141
- tracer.scope().unbind(net.Socket.prototype)
81
+ function defaultAsyncEnd () {
82
+ storage.getStore().span.finish()
83
+ }
142
84
 
143
- this.unwrap(net.Socket.prototype, 'connect')
144
- }
85
+ function errorHandler (error) {
86
+ storage.getStore().span.setTag('error', error)
145
87
  }
88
+
89
+ module.exports = NetPlugin
@@ -20,15 +20,15 @@ function createWrapHandleApiRequest (tracer, config) {
20
20
  return trace(tracer, config, req, res, () => {
21
21
  const promise = handleApiRequest.apply(this, arguments)
22
22
 
23
- promise.then(handled => {
24
- if (!handled) return
23
+ return promise.then(handled => {
24
+ if (!handled) return handled
25
25
 
26
26
  const page = getPageFromPath(pathname, this.dynamicRoutes)
27
27
 
28
28
  addPage(req, page)
29
- })
30
29
 
31
- return promise
30
+ return handled
31
+ })
32
32
  })
33
33
  }
34
34
  }
@@ -118,12 +118,10 @@ function trace (tracer, config, req, res, handler) {
118
118
  // TODO: Use CLS when it will be available in core.
119
119
  span._nextReq = req
120
120
 
121
- promise.then(
122
- () => finish(span, config, req, res),
123
- err => finish(span, config, req, res, err)
121
+ return promise.then(
122
+ result => finish(span, config, req, res, result),
123
+ err => finish(span, config, req, res, null, err)
124
124
  )
125
-
126
- return promise
127
125
  }
128
126
 
129
127
  function addPage (req, page) {
@@ -137,13 +135,15 @@ function addPage (req, page) {
137
135
  })
138
136
  }
139
137
 
140
- function finish (span, config, req, res, err) {
138
+ function finish (span, config, req, res, result, err) {
141
139
  span.setTag('error', err || !config.validateStatus(res.statusCode))
142
140
  span.addTags({
143
141
  'http.status_code': res.statusCode
144
142
  })
145
143
  config.hooks.request(span, req, res)
146
144
  span.finish()
145
+
146
+ return result || err
147
147
  }
148
148
 
149
149
  function normalizeConfig (config) {
@@ -1,44 +1,32 @@
1
1
  'use strict'
2
2
 
3
- const Tags = require('opentracing').Tags
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
 
6
- const OPERATION_NAME = 'pg.query'
7
+ class PGPlugin extends Plugin {
8
+ static get name () {
9
+ return 'pg'
10
+ }
11
+
12
+ constructor (...args) {
13
+ super(...args)
7
14
 
8
- function createWrapQuery (tracer, config) {
9
- return function wrapQuery (query) {
10
- return function queryWithTrace () {
11
- const scope = tracer.scope()
12
- const childOf = scope.active()
13
- const params = this.connectionParameters
14
- const service = getServiceName(tracer, config, params)
15
- const span = tracer.startSpan(OPERATION_NAME, {
15
+ this.addSub(`apm:pg:query:start`, ({ params, statement }) => {
16
+ const service = getServiceName(this.tracer, this.config, params)
17
+ const store = storage.getStore()
18
+ const childOf = store ? store.span : store
19
+ const span = this.tracer.startSpan('pg.query', {
16
20
  childOf,
17
21
  tags: {
18
- [Tags.SPAN_KIND]: Tags.SPAN_KIND_RPC_CLIENT,
19
22
  'service.name': service,
20
23
  'span.type': 'sql',
21
24
  'span.kind': 'client',
22
- 'db.type': 'postgres'
25
+ 'db.type': 'postgres',
26
+ 'resource.name': statement
23
27
  }
24
28
  })
25
29
 
26
- analyticsSampler.sample(span, config.measured)
27
-
28
- const retval = scope.bind(query, span).apply(this, arguments)
29
- const queryQueue = this.queryQueue || this._queryQueue
30
- const activeQuery = this.activeQuery || this._activeQuery
31
- const pgQuery = queryQueue[queryQueue.length - 1] || activeQuery
32
-
33
- if (!pgQuery) {
34
- return retval
35
- }
36
-
37
- const originalCallback = pgQuery.callback
38
- const statement = pgQuery.text
39
-
40
- span.setTag('resource.name', statement)
41
-
42
30
  if (params) {
43
31
  span.addTags({
44
32
  'db.name': params.database,
@@ -48,26 +36,23 @@ function createWrapQuery (tracer, config) {
48
36
  })
49
37
  }
50
38
 
51
- const finish = (error) => {
52
- span.setTag('error', error)
53
- span.finish()
54
- }
39
+ analyticsSampler.sample(span, this.config.measured)
40
+ this.enter(span, store)
41
+ })
55
42
 
56
- if (originalCallback) {
57
- pgQuery.callback = scope.bind((err, res) => {
58
- finish(err)
59
- originalCallback(err, res)
60
- }, childOf)
61
- } else if (pgQuery.once) {
62
- pgQuery
63
- .once('error', finish)
64
- .once('end', () => finish())
65
- } else {
66
- pgQuery.then(() => finish(), finish)
67
- }
43
+ this.addSub(`apm:pg:query:end`, () => {
44
+ this.exit()
45
+ })
46
+
47
+ this.addSub(`apm:pg:query:error`, err => {
48
+ const span = storage.getStore().span
49
+ span.setTag('error', err)
50
+ })
68
51
 
69
- return retval
70
- }
52
+ this.addSub(`apm:pg:query:async-end`, () => {
53
+ const span = storage.getStore().span
54
+ span.finish()
55
+ })
71
56
  }
72
57
  }
73
58
 
@@ -81,26 +66,4 @@ function getServiceName (tracer, config, params) {
81
66
  }
82
67
  }
83
68
 
84
- module.exports = [
85
- {
86
- name: 'pg',
87
- versions: ['>=4'],
88
- patch (pg, tracer, config) {
89
- this.wrap(pg.Client.prototype, 'query', createWrapQuery(tracer, config))
90
- },
91
- unpatch (pg) {
92
- this.unwrap(pg.Client.prototype, 'query')
93
- }
94
- },
95
- {
96
- name: 'pg',
97
- versions: ['>=4'],
98
- file: 'lib/native/index.js',
99
- patch (Client, tracer, config) {
100
- this.wrap(Client.prototype, 'query', createWrapQuery(tracer, config))
101
- },
102
- unpatch (Client) {
103
- this.unwrap(Client.prototype, 'query')
104
- }
105
- }
106
- ]
69
+ module.exports = PGPlugin