dd-trace 2.1.1 → 2.2.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.
package/index.d.ts CHANGED
@@ -406,6 +406,28 @@ export declare interface TracerOptions {
406
406
  * @default true
407
407
  */
408
408
  orphanable?: boolean
409
+
410
+ /**
411
+ * Configuration of the AppSec protection. Can be a boolean as an alias to `appsec.enabled`.
412
+ */
413
+ appsec?: boolean | {
414
+ /**
415
+ * Whether to enable AppSec.
416
+ * @default false
417
+ */
418
+ enabled?: boolean,
419
+
420
+ /**
421
+ * Specifies a path to a custom rules file.
422
+ */
423
+ rules?: string,
424
+
425
+ /**
426
+ * Controls the maximum amount of traces sampled by AppSec attacks, per second.
427
+ * @default 100
428
+ */
429
+ rateLimit?: number
430
+ };
409
431
  }
410
432
 
411
433
  /** @hidden */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "2.1.1",
3
+ "version": "2.2.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -1,11 +1,13 @@
1
1
  'use strict'
2
2
 
3
+ require('./src/bluebird')
4
+ require('./src/couchbase')
3
5
  require('./src/dns')
6
+ require('./src/elasticsearch')
4
7
  require('./src/memcached')
5
8
  require('./src/mysql')
6
9
  require('./src/mysql2')
7
- require('./src/bluebird')
8
- require('./src/when')
9
10
  require('./src/promise')
10
- require('./src/q')
11
11
  require('./src/promise-js')
12
+ require('./src/q')
13
+ require('./src/when')
@@ -0,0 +1,143 @@
1
+ 'use strict'
2
+
3
+ const {
4
+ channel,
5
+ addHook,
6
+ AsyncResource
7
+ } = require('./helpers/instrument')
8
+ const shimmer = require('../../datadog-shimmer')
9
+
10
+ addHook({ name: 'couchbase', file: 'lib/bucket.js', versions: ['^2.6.5'] }, Bucket => {
11
+ const startCh = channel('apm:couchbase:query:start')
12
+ const asyncEndCh = channel('apm:couchbase:query:async-end')
13
+ const endCh = channel('apm:couchbase:query:end')
14
+ const errorCh = channel('apm:couchbase:query:error')
15
+
16
+ Bucket.prototype._maybeInvoke = wrapMaybeInvoke(Bucket.prototype._maybeInvoke)
17
+ Bucket.prototype.query = wrapQuery(Bucket.prototype.query)
18
+
19
+ shimmer.wrap(Bucket.prototype, '_n1qlReq', _n1qlReq => function (host, q, adhoc, emitter) {
20
+ if (!startCh.hasSubscribers) {
21
+ return _n1qlReq.apply(this, arguments)
22
+ }
23
+
24
+ if (!emitter || !emitter.once) return _n1qlReq.apply(this, arguments)
25
+
26
+ const n1qlQuery = q && q.statement
27
+
28
+ startCh.publish({ resource: n1qlQuery, bucket: this })
29
+
30
+ emitter.once('rows', AsyncResource.bind(() => {
31
+ asyncEndCh.publish(undefined)
32
+ }))
33
+
34
+ emitter.once('error', AsyncResource.bind((error) => {
35
+ errorCh.publish(error)
36
+ asyncEndCh.publish(undefined)
37
+ }))
38
+
39
+ try {
40
+ return _n1qlReq.apply(this, arguments)
41
+ } catch (err) {
42
+ err.stack // trigger getting the stack at the original throwing point
43
+ errorCh.publish(err)
44
+
45
+ throw err
46
+ } finally {
47
+ endCh.publish(undefined)
48
+ }
49
+ })
50
+
51
+ Bucket.prototype.upsert = wrap('apm:couchbase:upsert', Bucket.prototype.upsert)
52
+ Bucket.prototype.insert = wrap('apm:couchbase:insert', Bucket.prototype.insert)
53
+ Bucket.prototype.replace = wrap('apm:couchbase:replace', Bucket.prototype.replace)
54
+ Bucket.prototype.append = wrap('apm:couchbase:append', Bucket.prototype.append)
55
+ Bucket.prototype.prepend = wrap('apm:couchbase:prepend', Bucket.prototype.prepend)
56
+
57
+ return Bucket
58
+ })
59
+
60
+ addHook({ name: 'couchbase', file: 'lib/cluster.js', versions: ['^2.6.5'] }, Cluster => {
61
+ Cluster.prototype._maybeInvoke = wrapMaybeInvoke(Cluster.prototype._maybeInvoke)
62
+ Cluster.prototype.query = wrapQuery(Cluster.prototype.query)
63
+
64
+ return Cluster
65
+ })
66
+
67
+ function findCallbackIndex (args) {
68
+ for (let i = args.length - 1; i >= 2; i--) {
69
+ if (typeof args[i] === 'function') return i
70
+ }
71
+ return -1
72
+ }
73
+
74
+ function wrapMaybeInvoke (_maybeInvoke) {
75
+ const wrapped = function (fn, args) {
76
+ if (!Array.isArray(args)) return _maybeInvoke.apply(this, arguments)
77
+
78
+ const callbackIndex = args.length - 1
79
+ const callback = args[callbackIndex]
80
+
81
+ if (callback instanceof Function) {
82
+ args[callbackIndex] = AsyncResource.bind(callback)
83
+ }
84
+
85
+ return _maybeInvoke.apply(this, arguments)
86
+ }
87
+ return shimmer.wrap(_maybeInvoke, wrapped)
88
+ }
89
+
90
+ function wrapQuery (query) {
91
+ const wrapped = function (q, params, callback) {
92
+ callback = AsyncResource.bind(arguments[arguments.length - 1])
93
+
94
+ if (typeof callback === 'function') {
95
+ arguments[arguments.length - 1] = callback
96
+ }
97
+
98
+ const res = query.apply(this, arguments)
99
+ return res
100
+ }
101
+ return shimmer.wrap(query, wrapped)
102
+ }
103
+
104
+ function wrap (prefix, fn) {
105
+ const startCh = channel(prefix + ':start')
106
+ const endCh = channel(prefix + ':end')
107
+ const asyncEndCh = channel(prefix + ':async-end')
108
+ const errorCh = channel(prefix + ':error')
109
+
110
+ const wrapped = function (key, value, options, callback) {
111
+ if (!startCh.hasSubscribers) {
112
+ return fn.apply(this, arguments)
113
+ }
114
+
115
+ const callbackIndex = findCallbackIndex(arguments)
116
+
117
+ if (callbackIndex < 0) return fn.apply(this, arguments)
118
+
119
+ const cb = arguments[callbackIndex]
120
+
121
+ startCh.publish({ bucket: this })
122
+
123
+ arguments[callbackIndex] = function (error, result) {
124
+ if (error) {
125
+ errorCh.publish(error)
126
+ }
127
+ asyncEndCh.publish(result)
128
+ return cb.apply(this, arguments)
129
+ }
130
+
131
+ try {
132
+ return fn.apply(this, arguments)
133
+ } catch (error) {
134
+ error.stack // trigger getting the stack at the original throwing point
135
+ errorCh.publish(error)
136
+
137
+ throw error
138
+ } finally {
139
+ endCh.publish(undefined)
140
+ }
141
+ }
142
+ return shimmer.wrap(fn, wrapped)
143
+ }
@@ -0,0 +1,74 @@
1
+ 'use strict'
2
+
3
+ const {
4
+ channel,
5
+ addHook,
6
+ AsyncResource
7
+ } = require('./helpers/instrument')
8
+ const shimmer = require('../../datadog-shimmer')
9
+
10
+ const startCh = channel('apm:elasticsearch:query:start')
11
+ const asyncEndCh = channel('apm:elasticsearch:query:async-end')
12
+ const endCh = channel('apm:elasticsearch:query:end')
13
+ const errorCh = channel('apm:elasticsearch:query:error')
14
+
15
+ addHook({ name: '@elastic/elasticsearch', file: 'lib/Transport.js', versions: ['>=5.6.16'] }, Transport => {
16
+ shimmer.wrap(Transport.prototype, 'request', wrapRequest)
17
+ return Transport
18
+ })
19
+
20
+ addHook({ name: 'elasticsearch', file: 'src/lib/transport.js', versions: ['>=10'] }, Transport => {
21
+ shimmer.wrap(Transport.prototype, 'request', wrapRequest)
22
+ return Transport
23
+ })
24
+
25
+ function wrapRequest (request) {
26
+ return function (params, options, cb) {
27
+ if (!startCh.hasSubscribers) {
28
+ return request.apply(this, arguments)
29
+ }
30
+
31
+ if (!params) return request.apply(this, arguments)
32
+
33
+ const asyncResource = new AsyncResource('bound-anonymous-fn')
34
+
35
+ startCh.publish({ params })
36
+
37
+ try {
38
+ const lastIndex = arguments.length - 1
39
+ cb = arguments[lastIndex]
40
+
41
+ if (typeof cb === 'function') {
42
+ cb = asyncResource.bind(cb)
43
+
44
+ arguments[lastIndex] = AsyncResource.bind(function (error) {
45
+ finish(params, error)
46
+ return cb.apply(null, arguments)
47
+ })
48
+ return request.apply(this, arguments)
49
+ } else {
50
+ const promise = request.apply(this, arguments)
51
+ if (promise && typeof promise.then === 'function') {
52
+ promise.then(() => finish(params), e => finish(params, e))
53
+ } else {
54
+ finish(params)
55
+ }
56
+ return promise
57
+ }
58
+ } catch (err) {
59
+ err.stack // trigger getting the stack at the original throwing point
60
+ errorCh.publish(err)
61
+
62
+ throw err
63
+ } finally {
64
+ endCh.publish(undefined)
65
+ }
66
+ }
67
+ }
68
+
69
+ function finish (params, error) {
70
+ if (error) {
71
+ errorCh.publish(error)
72
+ }
73
+ asyncEndCh.publish({ params })
74
+ }
@@ -1,171 +1,74 @@
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
6
 
7
- function startSpan (tracer, config, operation, resource) {
8
- const childOf = tracer.scope().active()
9
- const span = tracer.startSpan(`couchbase.${operation}`, {
10
- childOf,
11
- tags: {
7
+ class CouchBasePlugin extends Plugin {
8
+ static get name () {
9
+ return 'couchbase'
10
+ }
11
+
12
+ addSubs (func, start, asyncEnd = defaultAsyncEnd) {
13
+ this.addSub(`apm:couchbase:${func}:start`, start)
14
+ this.addSub(`apm:couchbase:${func}:end`, this.exit.bind(this))
15
+ this.addSub(`apm:couchbase:${func}:error`, errorHandler)
16
+ this.addSub(`apm:couchbase:${func}:async-end`, asyncEnd)
17
+ }
18
+
19
+ startSpan (operation, customTags, store, bucket) {
20
+ const tags = {
12
21
  'db.type': 'couchbase',
13
22
  'component': 'couchbase',
14
- 'service.name': config.service || `${tracer._service}-couchbase`,
15
- 'resource.name': resource,
16
- [Tags.SPAN_KIND]: Kinds.CLIENT
23
+ 'service.name': this.config.service || `${this.tracer._service}-couchbase`,
24
+ 'resource.name': `couchbase.${operation}`,
25
+ 'span.kind': 'client'
17
26
  }
18
- })
19
-
20
- analyticsSampler.sample(span, config.measured)
21
-
22
- return span
23
- }
24
-
25
- function onRequestFinish (emitter, span) {
26
- emitter.once('rows', () => {
27
- span.finish()
28
- })
29
- emitter.once('error', (err) => {
30
- span.setTag(Tags.ERROR, err)
31
- span.finish()
32
- })
33
- }
34
-
35
- function createWrapMaybeInvoke (tracer) {
36
- return function wrapMaybeInvoke (_maybeInvoke) {
37
- return function maybeInvokeWithTrace (fn, args) {
38
- if (!Array.isArray(args)) return _maybeInvoke.apply(this, arguments)
39
27
 
40
- const scope = tracer.scope()
41
- const callbackIndex = args.length - 1
42
- const callback = args[callbackIndex]
43
-
44
- if (callback instanceof Function) {
45
- args[callbackIndex] = scope.bind(callback)
46
- }
47
-
48
- return scope.bind(_maybeInvoke).apply(this, arguments)
28
+ for (const tag in customTags) {
29
+ tags[tag] = customTags[tag]
49
30
  }
50
- }
51
- }
52
-
53
- function createWrapQuery (tracer) {
54
- return function wrapQuery (query) {
55
- return function queryWithTrace (q, params, callback) {
56
- const scope = tracer.scope()
31
+ const span = this.tracer.startSpan(`couchbase.${operation}`, {
32
+ childOf: store ? store.span : null,
33
+ tags
34
+ })
57
35
 
58
- callback = arguments[arguments.length - 1]
36
+ span.setTag('couchbase.bucket.name', bucket.name || bucket._name)
59
37
 
60
- if (typeof callback === 'function') {
61
- arguments[arguments.length - 1] = scope.bind(callback)
62
- }
63
-
64
- return scope.bind(query.apply(this, arguments))
65
- }
38
+ analyticsSampler.sample(span, this.config.measured)
39
+ return span
66
40
  }
67
- }
68
-
69
- function createWrapN1qlReq (tracer, config) {
70
- return function wrapN1qlReq (_n1qlReq) {
71
- return function n1qlReqWithTrace (host, q, adhoc, emitter) {
72
- if (!emitter || !emitter.once) return _n1qlReq.apply(this, arguments)
73
-
74
- const scope = tracer.scope()
75
- const n1qlQuery = q && q.statement
76
- const span = startSpan(tracer, config, 'query', n1qlQuery)
77
41
 
78
- span.setTag('span.type', 'sql')
42
+ constructor (...args) {
43
+ super(...args)
79
44
 
80
- addBucketTag(span, this)
81
- onRequestFinish(emitter, span)
45
+ this.addSubs('query', ({ resource, bucket }) => {
46
+ const store = storage.getStore()
47
+ const span = this.startSpan('query', { 'span.type': 'sql', 'resource.name': resource }, store, bucket)
48
+ this.enter(span, store)
49
+ })
82
50
 
83
- return scope.bind(_n1qlReq, span).apply(this, arguments)
84
- }
51
+ this._addCommandSubs('upsert')
52
+ this._addCommandSubs('insert')
53
+ this._addCommandSubs('replace')
54
+ this._addCommandSubs('append')
55
+ this._addCommandSubs('prepend')
85
56
  }
86
- }
87
-
88
- function createWrapStore (tracer, config, operation) {
89
- return function wrapStore (store) {
90
- return function storeWithTrace (key, value, options, callback) {
91
- const callbackIndex = findCallbackIndex(arguments)
92
-
93
- if (callbackIndex < 0) return store.apply(this, arguments)
94
-
95
- const scope = tracer.scope()
96
- const span = startSpan(tracer, config, operation)
97
-
98
- addBucketTag(span, this)
99
-
100
- arguments[callbackIndex] = wrapCallback(span, arguments[callbackIndex])
101
-
102
- return scope.bind(store, span).apply(this, arguments)
103
- }
57
+ _addCommandSubs (name) {
58
+ this.addSubs(name, ({ bucket }) => {
59
+ const store = storage.getStore()
60
+ const span = this.startSpan(name, {}, store, bucket)
61
+ this.enter(span, store)
62
+ })
104
63
  }
105
64
  }
106
65
 
107
- function addBucketTag (span, bucket) {
108
- span.setTag('couchbase.bucket.name', bucket.name || bucket._name)
109
- }
110
-
111
- function findCallbackIndex (args) {
112
- for (let i = args.length - 1; i >= 2; i--) {
113
- if (typeof args[i] === 'function') return i
114
- }
115
-
116
- return -1
66
+ function defaultAsyncEnd () {
67
+ storage.getStore().span.finish()
117
68
  }
118
69
 
119
- function wrapCallback (span, callback) {
120
- return function (err, result) {
121
- span.setTag('error', err)
122
- span.finish()
123
-
124
- return callback.apply(this, arguments)
125
- }
70
+ function errorHandler (error) {
71
+ storage.getStore().span.setTag('error', error)
126
72
  }
127
73
 
128
- module.exports = [
129
- {
130
- name: 'couchbase',
131
- versions: ['^2.6.5'],
132
- file: 'lib/bucket.js',
133
- patch (Bucket, tracer, config) {
134
- tracer.scope().bind(Bucket.prototype)
135
-
136
- this.wrap(Bucket.prototype, '_maybeInvoke', createWrapMaybeInvoke(tracer, config))
137
- this.wrap(Bucket.prototype, 'query', createWrapQuery(tracer))
138
- this.wrap(Bucket.prototype, '_n1qlReq', createWrapN1qlReq(tracer, config))
139
- this.wrap(Bucket.prototype, 'upsert', createWrapStore(tracer, config, 'upsert'))
140
- this.wrap(Bucket.prototype, 'insert', createWrapStore(tracer, config, 'insert'))
141
- this.wrap(Bucket.prototype, 'replace', createWrapStore(tracer, config, 'replace'))
142
- this.wrap(Bucket.prototype, 'append', createWrapStore(tracer, config, 'append'))
143
- this.wrap(Bucket.prototype, 'prepend', createWrapStore(tracer, config, 'prepend'))
144
- },
145
- unpatch (Bucket, tracer) {
146
- tracer.scope().unbind(Bucket.prototype)
147
-
148
- this.unwrap(Bucket.prototype, '_maybeInvoke')
149
- this.unwrap(Bucket.prototype, 'query')
150
- this.unwrap(Bucket.prototype, '_n1qlReq')
151
- this.unwrap(Bucket.prototype, 'upsert')
152
- this.unwrap(Bucket.prototype, 'insert')
153
- this.unwrap(Bucket.prototype, 'replace')
154
- this.unwrap(Bucket.prototype, 'append')
155
- this.unwrap(Bucket.prototype, 'prepend')
156
- }
157
- },
158
- {
159
- name: 'couchbase',
160
- versions: ['^2.6.5'],
161
- file: 'lib/cluster.js',
162
- patch (Cluster, tracer, config) {
163
- this.wrap(Cluster.prototype, '_maybeInvoke', createWrapMaybeInvoke(tracer, config))
164
- this.wrap(Cluster.prototype, 'query', createWrapQuery(tracer))
165
- },
166
- unpatch (Cluster) {
167
- this.unwrap(Cluster.prototype, '_maybeInvoke')
168
- this.unwrap(Cluster.prototype, 'query')
169
- }
170
- }
171
- ]
74
+ module.exports = CouchBasePlugin
@@ -1,23 +1,29 @@
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
- function createWrapRequest (tracer, config) {
7
- config = normalizeConfig(config)
8
- return function wrapRequest (request) {
9
- return function requestWithTrace (params, options, cb) {
10
- if (!params) return request.apply(this, arguments)
7
+ class ElasticsearchPlugin extends Plugin {
8
+ static get name () {
9
+ return 'elasticsearch'
10
+ }
11
+
12
+ constructor (...args) {
13
+ super(...args)
14
+
15
+ this.addSub('apm:elasticsearch:query:start', ({ params }) => {
16
+ this.config = normalizeConfig(this.config)
11
17
 
12
- const lastIndex = arguments.length - 1
18
+ const store = storage.getStore()
19
+ const childOf = store ? store.span : store
13
20
  const body = getBody(params.body || params.bulkBody)
14
- const childOf = tracer.scope().active()
15
- const span = tracer.startSpan('elasticsearch.query', {
21
+ const span = this.tracer.startSpan('elasticsearch.query', {
16
22
  childOf,
17
23
  tags: {
18
- [Tags.SPAN_KIND]: Tags.SPAN_KIND_RPC_CLIENT,
19
- [Tags.DB_TYPE]: 'elasticsearch',
20
- 'service.name': config.service || `${tracer._service}-elasticsearch`,
24
+ 'db.type': 'elasticsearch',
25
+ 'span.kind': 'client',
26
+ 'service.name': this.config.service || `${this.tracer._service}-elasticsearch`,
21
27
  'resource.name': `${params.method} ${quantizePath(params.path)}`,
22
28
  'span.type': 'elasticsearch',
23
29
  'elasticsearch.url': params.path,
@@ -26,57 +32,25 @@ function createWrapRequest (tracer, config) {
26
32
  'elasticsearch.params': JSON.stringify(params.querystring || params.query)
27
33
  }
28
34
  })
35
+ analyticsSampler.sample(span, this.config.measured)
36
+ this.enter(span, store)
37
+ })
29
38
 
30
- analyticsSampler.sample(span, config.measured)
31
-
32
- cb = arguments[lastIndex]
33
-
34
- if (typeof cb === 'function') {
35
- arguments[lastIndex] = wrapCallback(tracer, span, params, config, cb)
36
-
37
- return tracer.scope().activate(span, () => request.apply(this, arguments))
38
- } else {
39
- const promise = request.apply(this, arguments)
40
-
41
- if (promise && typeof promise.then === 'function') {
42
- promise.then(() => finish(span, params, config), e => finish(span, params, config, e))
43
- } else {
44
- finish(span, params, config)
45
- }
46
-
47
- return promise
48
- }
49
- }
50
- }
51
- }
39
+ this.addSub('apm:elasticsearch:query:end', () => {
40
+ this.exit()
41
+ })
52
42
 
53
- function wrapCallback (tracer, span, params, config, done) {
54
- return tracer.scope().bind(function (err) {
55
- finish(span, params, config, err)
56
- done.apply(null, arguments)
57
- })
58
- }
43
+ this.addSub('apm:elasticsearch:query:error', err => {
44
+ const span = storage.getStore().span
45
+ span.setTag('error', err)
46
+ })
59
47
 
60
- function finish (span, params, config, err) {
61
- if (err) {
62
- span.addTags({
63
- 'error.type': err.name,
64
- 'error.msg': err.message,
65
- 'error.stack': err.stack
48
+ this.addSub('apm:elasticsearch:query:async-end', ({ params }) => {
49
+ const span = storage.getStore().span
50
+ this.config.hooks.query(span, params)
51
+ span.finish()
66
52
  })
67
53
  }
68
-
69
- config.hooks.query(span, params)
70
-
71
- span.finish()
72
- }
73
-
74
- function quantizePath (path) {
75
- return path && path.replace(/[0-9]+/g, '?')
76
- }
77
-
78
- function getBody (body) {
79
- return body && JSON.stringify(body)
80
54
  }
81
55
 
82
56
  function normalizeConfig (config) {
@@ -94,27 +68,12 @@ function getHooks (config) {
94
68
  return { query }
95
69
  }
96
70
 
97
- module.exports = [
98
- {
99
- name: 'elasticsearch',
100
- file: 'src/lib/transport.js',
101
- versions: ['>=10'],
102
- patch (Transport, tracer, config) {
103
- this.wrap(Transport.prototype, 'request', createWrapRequest(tracer, config))
104
- },
105
- unpatch (Transport) {
106
- this.unwrap(Transport.prototype, 'request')
107
- }
108
- },
109
- {
110
- name: '@elastic/elasticsearch',
111
- file: 'lib/Transport.js',
112
- versions: ['>=5.6.16'], // initial version of this module
113
- patch (Transport, tracer, config) {
114
- this.wrap(Transport.prototype, 'request', createWrapRequest(tracer, config))
115
- },
116
- unpatch (Transport) {
117
- this.unwrap(Transport.prototype, 'request')
118
- }
119
- }
120
- ]
71
+ function getBody (body) {
72
+ return body && JSON.stringify(body)
73
+ }
74
+
75
+ function quantizePath (path) {
76
+ return path && path.replace(/[0-9]+/g, '?')
77
+ }
78
+
79
+ module.exports = ElasticsearchPlugin
@@ -165,7 +165,28 @@ function getRes (reply) {
165
165
  module.exports = [
166
166
  {
167
167
  name: 'fastify',
168
- versions: ['>=1'],
168
+ versions: ['>=3'],
169
+ patch (fastify, tracer, config) {
170
+ // `fastify` is a function so we return a wrapper that will replace its export.
171
+ const wrapped = this.wrapExport(fastify, createWrapFastify(tracer, config)(fastify))
172
+
173
+ wrapped.fastify = wrapped
174
+ wrapped.default = wrapped
175
+
176
+ return wrapped
177
+ },
178
+ unpatch (fastify) {
179
+ const unwrapped = this.unwrapExport(fastify)
180
+
181
+ unwrapped.fastify = unwrapped
182
+ unwrapped.default = unwrapped
183
+
184
+ return unwrapped
185
+ }
186
+ },
187
+ {
188
+ name: 'fastify',
189
+ versions: ['1 - 2'],
169
190
  patch (fastify, tracer, config) {
170
191
  // `fastify` is a function so we return a wrapper that will replace its export.
171
192
  return this.wrapExport(fastify, createWrapFastify(tracer, config)(fastify))
@@ -2,6 +2,8 @@
2
2
 
3
3
  const { LOG } = require('../../../ext/formats')
4
4
 
5
+ const hasOwn = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop)
6
+
5
7
  function chunkProxy (chunk, holder) {
6
8
  return new Proxy(chunk, {
7
9
  get (target, p, receiver) {
@@ -15,7 +17,8 @@ function chunkProxy (chunk, holder) {
15
17
  }
16
18
  },
17
19
  ownKeys (target) {
18
- return ['dd', ...Reflect.ownKeys(target)]
20
+ const ownKeys = Reflect.ownKeys(target)
21
+ return hasOwn(target, 'dd') ? ownKeys : ['dd', ...ownKeys]
19
22
  },
20
23
  getOwnPropertyDescriptor (target, p) {
21
24
  return Reflect.getOwnPropertyDescriptor(p === 'dd' ? holder : target, p)
@@ -1 +1 @@
1
- module.exports = '2.1.1'
1
+ module.exports = '2.2.0'
@@ -76,6 +76,10 @@ function incomingHttpEndTranslator (data) {
76
76
  }
77
77
 
78
78
  // TODO: temporary express instrumentation, will use express plugin later
79
+ if (data.req.body !== undefined && data.req.body !== null) {
80
+ payload[addresses.HTTP_INCOMING_BODY] = data.req.body
81
+ }
82
+
79
83
  if (data.req.query && typeof data.req.query === 'object') {
80
84
  payload[addresses.HTTP_INCOMING_QUERY] = data.req.query
81
85
  }
@@ -5,32 +5,25 @@ const log = require('./log')
5
5
  function add (carrier, keyValuePairs) {
6
6
  if (!carrier || !keyValuePairs) return
7
7
 
8
- if (typeof keyValuePairs === 'string') {
9
- return add(
10
- carrier,
11
- keyValuePairs
12
- .split(',')
13
- .filter(tag => tag.indexOf(':') !== -1)
14
- .reduce((prev, next) => {
15
- const tag = next.split(':')
16
- const key = tag[0].trim()
17
- const value = tag.slice(1).join(':').trim()
18
-
19
- prev[key] = value
20
-
21
- return prev
22
- }, {})
23
- )
24
- }
25
-
26
8
  if (Array.isArray(keyValuePairs)) {
27
9
  return keyValuePairs.forEach(tags => add(carrier, tags))
28
10
  }
29
11
 
30
12
  try {
31
- Object.keys(keyValuePairs).forEach(key => {
32
- carrier[key] = keyValuePairs[key]
33
- })
13
+ if (typeof keyValuePairs === 'string') {
14
+ const segments = keyValuePairs.split(',')
15
+ for (const segment of segments) {
16
+ const separatorIndex = segment.indexOf(':')
17
+ if (separatorIndex === -1) continue
18
+
19
+ const key = segment.slice(0, separatorIndex)
20
+ const value = segment.slice(separatorIndex + 1)
21
+
22
+ carrier[key.trim()] = value.trim()
23
+ }
24
+ } else {
25
+ Object.assign(carrier, keyValuePairs)
26
+ }
34
27
  } catch (e) {
35
28
  log.error(e)
36
29
  }
@@ -21,7 +21,7 @@ class DatadogTracer extends Tracer {
21
21
  }
22
22
 
23
23
  trace (name, options, fn) {
24
- options = Object.assign({}, {
24
+ options = Object.assign({
25
25
  childOf: this.scope().active()
26
26
  }, options)
27
27
 
package/NOTICE DELETED
@@ -1,4 +0,0 @@
1
- Datadog dd-trace-js
2
- Copyright 2016-Present Datadog, Inc.
3
-
4
- This product includes software developed at Datadog, Inc. (https://www.datadoghq.com/).
@@ -1,13 +0,0 @@
1
- 'use strict'
2
-
3
- const spawnWrap = require('spawn-wrap')
4
- const path = require('path')
5
-
6
- spawnWrap(['--require', path.join(__dirname, '..', 'init.js')])
7
-
8
- const { spawn } = require('child_process')
9
-
10
- const [command, ...argv] = process.argv.slice(2)
11
- spawn(command, argv, {
12
- stdio: 'inherit'
13
- })