dd-trace 2.11.0 → 2.12.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.
@@ -6,7 +6,6 @@ require,@datadog/sketches-js,Apache license 2.0,Copyright 2020 Datadog Inc.
6
6
  require,@types/node,MIT,Copyright Authors
7
7
  require,crypto-randomuuid,MIT,Copyright 2021 Node.js Foundation and contributors
8
8
  require,diagnostics_channel,MIT,Copyright 2021 Simon D.
9
- require,form-data,MIT,Copyright 2012 Felix Geisendörfer and contributors
10
9
  require,ignore,MIT,Copyright 2013 Kael Zhang and contributors
11
10
  require,import-in-the-middle,Apache license 2.0,Copyright 2021 Datadog Inc.
12
11
  require,koalas,MIT,Copyright 2013-2017 Brian Woodward
package/index.d.ts CHANGED
@@ -313,10 +313,10 @@ export declare interface TracerOptions {
313
313
  };
314
314
 
315
315
  /**
316
- * Experimental features can be enabled all at once by using true or individually using key / value pairs.
316
+ * Experimental features can be enabled individually using key / value pairs.
317
317
  * @default {}
318
318
  */
319
- experimental?: boolean | {
319
+ experimental?: {
320
320
  b3?: boolean
321
321
  traceparent?: boolean
322
322
 
@@ -1216,7 +1216,7 @@ declare namespace plugins {
1216
1216
 
1217
1217
  /**
1218
1218
  * This plugin automatically instruments the
1219
- * [mysql2](https://github.com/brianmario/mysql2) module.
1219
+ * [mysql2](https://github.com/sidorares/node-mysql2) module.
1220
1220
  */
1221
1221
  interface mysql2 extends mysql {}
1222
1222
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "2.11.0",
3
+ "version": "2.12.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -59,15 +59,14 @@
59
59
  },
60
60
  "dependencies": {
61
61
  "@datadog/native-appsec": "^1.2.1",
62
- "@datadog/native-metrics": "^1.4.0",
63
- "@datadog/pprof": "^0.5.1",
62
+ "@datadog/native-metrics": "^1.4.1",
63
+ "@datadog/pprof": "^1.0.0",
64
64
  "@datadog/sketches-js": "^1.0.5",
65
65
  "@types/node": ">=12",
66
66
  "crypto-randomuuid": "^1.0.0",
67
67
  "diagnostics_channel": "^1.1.0",
68
- "form-data": "^3.0.0",
69
68
  "ignore": "^5.2.0",
70
- "import-in-the-middle": "^1.2.1",
69
+ "import-in-the-middle": "^1.3.0",
71
70
  "koalas": "^1.0.2",
72
71
  "limiter": "^1.1.4",
73
72
  "lodash.kebabcase": "^4.1.1",
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { createHook, executionAsyncId } = require('async_hooks')
3
+ const { executionAsyncId } = require('async_hooks')
4
4
  const AsyncResourceStorage = require('./async_resource')
5
5
 
6
6
  class AsyncHooksStorage extends AsyncResourceStorage {
@@ -17,10 +17,10 @@ class AsyncHooksStorage extends AsyncResourceStorage {
17
17
  }
18
18
 
19
19
  _createHook () {
20
- return createHook({
21
- init: this._init.bind(this),
20
+ return {
21
+ ...super._createHook(),
22
22
  destroy: this._destroy.bind(this)
23
- })
23
+ }
24
24
  }
25
25
 
26
26
  _init (asyncId, type, triggerAsyncId, resource) {
@@ -1,12 +1,16 @@
1
1
  'use strict'
2
2
 
3
3
  const { createHook, executionAsyncResource } = require('async_hooks')
4
+ const { channel } = require('diagnostics_channel')
5
+
6
+ const beforeCh = channel('dd-trace:storage:before')
7
+ const afterCh = channel('dd-trace:storage:after')
4
8
 
5
9
  class AsyncResourceStorage {
6
10
  constructor () {
7
11
  this._ddResourceStore = Symbol('ddResourceStore')
8
12
  this._enabled = false
9
- this._hook = this._createHook()
13
+ this._hook = createHook(this._createHook())
10
14
  }
11
15
 
12
16
  disable () {
@@ -48,9 +52,15 @@ class AsyncResourceStorage {
48
52
  }
49
53
 
50
54
  _createHook () {
51
- return createHook({
52
- init: this._init.bind(this)
53
- })
55
+ return {
56
+ init: this._init.bind(this),
57
+ before () {
58
+ beforeCh.publish()
59
+ },
60
+ after () {
61
+ afterCh.publish()
62
+ }
63
+ }
54
64
  }
55
65
 
56
66
  _enable () {
@@ -7,70 +7,23 @@ const {
7
7
  } = require('./helpers/instrument')
8
8
  const shimmer = require('../../datadog-shimmer')
9
9
 
10
- addHook({ name: 'couchbase', file: 'lib/bucket.js', versions: ['^2.6.5'] }, Bucket => {
11
- const startCh = channel('apm:couchbase:query:start')
12
- const finishCh = channel('apm:couchbase:query:finish')
13
- const errorCh = channel('apm:couchbase:query:error')
14
-
15
- Bucket.prototype._maybeInvoke = wrapMaybeInvoke(Bucket.prototype._maybeInvoke)
16
- Bucket.prototype.query = wrapQuery(Bucket.prototype.query)
17
-
18
- shimmer.wrap(Bucket.prototype, '_n1qlReq', _n1qlReq => function (host, q, adhoc, emitter) {
19
- if (!startCh.hasSubscribers) {
20
- return _n1qlReq.apply(this, arguments)
21
- }
22
-
23
- if (!emitter || !emitter.once) return _n1qlReq.apply(this, arguments)
24
-
25
- const n1qlQuery = q && q.statement
26
-
27
- const asyncResource = new AsyncResource('bound-anonymous-fn')
28
- return asyncResource.runInAsyncScope(() => {
29
- startCh.publish({ resource: n1qlQuery, bucket: this })
30
-
31
- emitter.once('rows', asyncResource.bind(() => {
32
- finishCh.publish(undefined)
33
- }))
34
-
35
- emitter.once('error', asyncResource.bind((error) => {
36
- errorCh.publish(error)
37
- finishCh.publish(undefined)
38
- }))
39
-
40
- try {
41
- return _n1qlReq.apply(this, arguments)
42
- } catch (err) {
43
- err.stack // trigger getting the stack at the original throwing point
44
- errorCh.publish(err)
45
-
46
- throw err
47
- }
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--) {
10
+ function findCallbackIndex (args, lowerbound = 2) {
11
+ for (let i = args.length - 1; i >= lowerbound; i--) {
69
12
  if (typeof args[i] === 'function') return i
70
13
  }
71
14
  return -1
72
15
  }
73
16
 
17
+ // handles n1ql and string queries
18
+ function getQueryResource (q) {
19
+ return q && (typeof q === 'string' ? q : q.statement)
20
+ }
21
+
22
+ function wrapAllNames (names, action) {
23
+ names.forEach(name => action(name))
24
+ }
25
+
26
+ // semver >=2 <3
74
27
  function wrapMaybeInvoke (_maybeInvoke) {
75
28
  const wrapped = function (fn, args) {
76
29
  if (!Array.isArray(args)) return _maybeInvoke.apply(this, arguments)
@@ -106,7 +59,7 @@ function wrap (prefix, fn) {
106
59
  const finishCh = channel(prefix + ':finish')
107
60
  const errorCh = channel(prefix + ':error')
108
61
 
109
- const wrapped = function (key, value, options, callback) {
62
+ const wrapped = function () {
110
63
  if (!startCh.hasSubscribers) {
111
64
  return fn.apply(this, arguments)
112
65
  }
@@ -121,7 +74,7 @@ function wrap (prefix, fn) {
121
74
  return asyncResource.runInAsyncScope(() => {
122
75
  const cb = callbackResource.bind(arguments[callbackIndex])
123
76
 
124
- startCh.publish({ bucket: this })
77
+ startCh.publish({ bucket: { name: this.name || this._name } })
125
78
 
126
79
  arguments[callbackIndex] = asyncResource.bind(function (error, result) {
127
80
  if (error) {
@@ -143,3 +96,155 @@ function wrap (prefix, fn) {
143
96
  }
144
97
  return shimmer.wrap(fn, wrapped)
145
98
  }
99
+
100
+ // semver >=3
101
+
102
+ function wrapCBandPromise (fn, name, startData, thisArg, args) {
103
+ const startCh = channel(`apm:couchbase:${name}:start`)
104
+ const finishCh = channel(`apm:couchbase:${name}:finish`)
105
+ const errorCh = channel(`apm:couchbase:${name}:error`)
106
+
107
+ if (!startCh.hasSubscribers) return fn.apply(thisArg, args)
108
+
109
+ const asyncResource = new AsyncResource('bound-anonymous-fn')
110
+ const callbackResource = new AsyncResource('bound-anonymous-fn')
111
+
112
+ return asyncResource.runInAsyncScope(() => {
113
+ startCh.publish(startData)
114
+
115
+ try {
116
+ const cbIndex = findCallbackIndex(args, 1)
117
+ if (cbIndex >= 0) {
118
+ // v3 offers callback or promises event handling
119
+ // NOTE: this does not work with v3.2.0-3.2.1 cluster.query, as there is a bug in the couchbase source code
120
+ const cb = callbackResource.bind(args[cbIndex])
121
+ args[cbIndex] = asyncResource.bind(function (error, result) {
122
+ if (error) {
123
+ errorCh.publish(error)
124
+ }
125
+ finishCh.publish({ result })
126
+ return cb.apply(thisArg, arguments)
127
+ })
128
+ }
129
+ const res = fn.apply(thisArg, args)
130
+
131
+ // semver >=3 will always return promise by default
132
+ res.then(
133
+ asyncResource.bind((result) => finishCh.publish({ result })),
134
+ asyncResource.bind((err) => errorCh.publish(err)))
135
+ return res
136
+ } catch (e) {
137
+ e.stack
138
+ errorCh.publish(e)
139
+ throw e
140
+ }
141
+ })
142
+ }
143
+
144
+ function wrapWithName (name) {
145
+ return function (operation) {
146
+ return function () { // no arguments used by us
147
+ return wrapCBandPromise(operation, name, {
148
+ collection: { name: this._name || '_default' },
149
+ bucket: { name: this._scope._bucket._name }
150
+ }, this, arguments)
151
+ }
152
+ }
153
+ }
154
+
155
+ function wrapV3Query (query) {
156
+ return function (q) {
157
+ const resource = getQueryResource(q)
158
+ return wrapCBandPromise(query, 'query', { resource }, this, arguments)
159
+ }
160
+ }
161
+
162
+ // semver >=2 <3
163
+ addHook({ name: 'couchbase', file: 'lib/bucket.js', versions: ['^2.6.5'] }, Bucket => {
164
+ const startCh = channel('apm:couchbase:query:start')
165
+ const finishCh = channel('apm:couchbase:query:finish')
166
+ const errorCh = channel('apm:couchbase:query:error')
167
+
168
+ Bucket.prototype._maybeInvoke = wrapMaybeInvoke(Bucket.prototype._maybeInvoke)
169
+ Bucket.prototype.query = wrapQuery(Bucket.prototype.query)
170
+
171
+ shimmer.wrap(Bucket.prototype, '_n1qlReq', _n1qlReq => function (host, q, adhoc, emitter) {
172
+ if (!startCh.hasSubscribers) {
173
+ return _n1qlReq.apply(this, arguments)
174
+ }
175
+
176
+ if (!emitter || !emitter.once) return _n1qlReq.apply(this, arguments)
177
+
178
+ const n1qlQuery = getQueryResource(q)
179
+
180
+ const asyncResource = new AsyncResource('bound-anonymous-fn')
181
+ return asyncResource.runInAsyncScope(() => {
182
+ startCh.publish({ resource: n1qlQuery, bucket: { name: this.name || this._name } })
183
+
184
+ emitter.once('rows', asyncResource.bind(() => {
185
+ finishCh.publish(undefined)
186
+ }))
187
+
188
+ emitter.once('error', asyncResource.bind((error) => {
189
+ errorCh.publish(error)
190
+ finishCh.publish(undefined)
191
+ }))
192
+
193
+ try {
194
+ return _n1qlReq.apply(this, arguments)
195
+ } catch (err) {
196
+ err.stack // trigger getting the stack at the original throwing point
197
+ errorCh.publish(err)
198
+
199
+ throw err
200
+ }
201
+ })
202
+ })
203
+
204
+ wrapAllNames(['upsert', 'insert', 'replace', 'append', 'prepend'], name => {
205
+ Bucket.prototype[name] = wrap(`apm:couchbase:${name}`, Bucket.prototype[name])
206
+ })
207
+
208
+ return Bucket
209
+ })
210
+
211
+ addHook({ name: 'couchbase', file: 'lib/cluster.js', versions: ['^2.6.5'] }, Cluster => {
212
+ Cluster.prototype._maybeInvoke = wrapMaybeInvoke(Cluster.prototype._maybeInvoke)
213
+ Cluster.prototype.query = wrapQuery(Cluster.prototype.query)
214
+
215
+ return Cluster
216
+ })
217
+
218
+ // semver >=3 <3.2.0
219
+
220
+ addHook({ name: 'couchbase', file: 'lib/collection.js', versions: ['>=3.0.0 <3.2.0'] }, Collection => {
221
+ wrapAllNames(['upsert', 'insert', 'replace'], name => {
222
+ shimmer.wrap(Collection.prototype, name, wrapWithName(name))
223
+ })
224
+
225
+ return Collection
226
+ })
227
+
228
+ addHook({ name: 'couchbase', file: 'lib/cluster.js', versions: ['>=3.0.0 <3.2.0'] }, Cluster => {
229
+ shimmer.wrap(Cluster.prototype, 'query', wrapV3Query)
230
+ return Cluster
231
+ })
232
+
233
+ // semver >=3.2.0
234
+
235
+ addHook({ name: 'couchbase', file: 'dist/collection.js', versions: ['>=3.2.0'] }, collection => {
236
+ const Collection = collection.Collection
237
+
238
+ wrapAllNames(['upsert', 'insert', 'replace'], name => {
239
+ shimmer.wrap(Collection.prototype, name, wrapWithName(name))
240
+ })
241
+
242
+ return collection
243
+ })
244
+
245
+ addHook({ name: 'couchbase', file: 'dist/cluster.js', versions: ['3.2.0 - 3.2.1', '>=3.2.2'] }, cluster => {
246
+ const Cluster = cluster.Cluster
247
+
248
+ shimmer.wrap(Cluster.prototype, 'query', wrapV3Query)
249
+ return cluster
250
+ })
@@ -17,12 +17,15 @@ const patchedTypes = new WeakSet()
17
17
  /** CHANNELS */
18
18
 
19
19
  // execute channels
20
- const startResolveCh = channel('apm:graphql:resolve:start')
21
20
  const startExecuteCh = channel('apm:graphql:execute:start')
22
21
  const finishExecuteCh = channel('apm:graphql:execute:finish')
22
+ const executeErrorCh = channel('apm:graphql:execute:error')
23
+
24
+ // resolve channels
25
+ const startResolveCh = channel('apm:graphql:resolve:start')
23
26
  const finishResolveCh = channel('apm:graphql:resolve:finish')
24
27
  const updateFieldCh = channel('apm:graphql:resolve:updateField')
25
- const executeErrorCh = channel('apm:graphql:execute:error')
28
+ const resolveErrorCh = channel('apm:graphql:resolve:error')
26
29
 
27
30
  // parse channels
28
31
  const parseStartCh = channel('apm:graphql:parser:start')
@@ -124,7 +127,9 @@ function wrapValidate (validate) {
124
127
  let errors
125
128
  try {
126
129
  errors = validate.apply(this, arguments)
127
- validateErrorCh.publish(errors && errors[0])
130
+ if (errors && errors[0]) {
131
+ validateErrorCh.publish(errors && errors[0])
132
+ }
128
133
  return errors
129
134
  } catch (err) {
130
135
  err.stack
@@ -177,7 +182,12 @@ function wrapExecute (execute) {
177
182
  return callInAsyncScope(exe, asyncResource, this, arguments, (err, res) => {
178
183
  if (finishResolveCh.hasSubscribers) finishResolvers(context)
179
184
 
180
- executeErrorCh.publish(err || (res && res.errors && res.errors[0]))
185
+ const error = err || (res && res.errors && res.errors[0])
186
+
187
+ if (error) {
188
+ executeErrorCh.publish(error)
189
+ }
190
+
181
191
  finishExecuteCh.publish({ res, args })
182
192
  })
183
193
  })
@@ -331,7 +341,9 @@ function finishResolvers ({ fields }) {
331
341
  const field = fields[key]
332
342
  const asyncResource = field.asyncResource
333
343
  asyncResource.runInAsyncScope(() => {
334
- executeErrorCh.publish(field.error)
344
+ if (field.error) {
345
+ resolveErrorCh.publish(field.error)
346
+ }
335
347
  finishResolveCh.publish(field.finishTime)
336
348
  })
337
349
  })
@@ -6,8 +6,31 @@ const errorCh = channel('ci:mocha:test:error')
6
6
  const skipCh = channel('ci:mocha:test:skip')
7
7
  const testFinishCh = channel('ci:mocha:test:finish')
8
8
  const parameterizedTestCh = channel('ci:mocha:test:parameterize')
9
+
10
+ const testRunStartCh = channel('ci:mocha:run:start')
9
11
  const testRunFinishCh = channel('ci:mocha:run:finish')
10
12
 
13
+ const testSuiteStartCh = channel('ci:mocha:test-suite:start')
14
+ const testSuiteFinishCh = channel('ci:mocha:test-suite:finish')
15
+ const testSuiteErrorCh = channel('ci:mocha:test-suite:error')
16
+
17
+ // TODO: remove when root hooks and fixtures are implemented
18
+ const patched = new WeakSet()
19
+
20
+ const testToAr = new WeakMap()
21
+ const originalFns = new WeakMap()
22
+ const testSuiteToAr = new WeakMap()
23
+
24
+ function getTestStatus (test) {
25
+ if (test.pending) {
26
+ return 'skip'
27
+ }
28
+ if (test.state !== 'failed' && !test.timedOut) {
29
+ return 'pass'
30
+ }
31
+ return 'fail'
32
+ }
33
+
11
34
  function isRetry (test) {
12
35
  return test._currentRetry !== undefined && test._currentRetry !== 0
13
36
  }
@@ -23,12 +46,6 @@ function getTestAsyncResource (test) {
23
46
  return testToAr.get(originalFn)
24
47
  }
25
48
 
26
- // TODO: remove when root hooks and fixtures are implemented
27
- const patched = new WeakSet()
28
-
29
- const testToAr = new WeakMap()
30
- const originalFns = new WeakMap()
31
-
32
49
  function mochaHook (Runner) {
33
50
  if (patched.has(Runner)) return Runner
34
51
 
@@ -39,6 +56,59 @@ function mochaHook (Runner) {
39
56
  return run.apply(this, arguments)
40
57
  }
41
58
 
59
+ const testRunAsyncResource = new AsyncResource('bound-anonymous-fn')
60
+
61
+ this.once('end', testRunAsyncResource.bind(function () {
62
+ let status = 'pass'
63
+ if (this.stats) {
64
+ status = this.stats.failures === 0 ? 'pass' : 'fail'
65
+ } else if (this.failures !== 0) {
66
+ status = 'fail'
67
+ }
68
+ testRunFinishCh.publish(status)
69
+ }))
70
+
71
+ this.once('start', testRunAsyncResource.bind(function () {
72
+ const processArgv = process.argv.slice(2).join(' ')
73
+ const command = `mocha ${processArgv}`
74
+ testRunStartCh.publish(command)
75
+ }))
76
+
77
+ this.on('suite', function (suite) {
78
+ if (suite.root) {
79
+ return
80
+ }
81
+ const asyncResource = new AsyncResource('bound-anonymous-fn')
82
+
83
+ testSuiteToAr.set(suite, asyncResource)
84
+
85
+ asyncResource.runInAsyncScope(() => {
86
+ testSuiteStartCh.publish(suite)
87
+ })
88
+ })
89
+
90
+ this.on('suite end', function (suite) {
91
+ if (suite.root) {
92
+ return
93
+ }
94
+ let status = 'pass'
95
+ if (suite.pending) {
96
+ status = 'skip'
97
+ } else {
98
+ suite.eachTest(test => {
99
+ if (test.state === 'failed' || test.timedOut) {
100
+ status = 'fail'
101
+ }
102
+ })
103
+ }
104
+
105
+ const asyncResource = testSuiteToAr.get(suite)
106
+ asyncResource.runInAsyncScope(() => {
107
+ // get suite status
108
+ testSuiteFinishCh.publish(status)
109
+ })
110
+ })
111
+
42
112
  this.on('test', (test) => {
43
113
  if (isRetry(test)) {
44
114
  return
@@ -52,14 +122,7 @@ function mochaHook (Runner) {
52
122
 
53
123
  this.on('test end', (test) => {
54
124
  const asyncResource = getTestAsyncResource(test)
55
- let status
56
- if (test.pending) {
57
- status = 'skip'
58
- } else if (test.state !== 'failed' && !test.timedOut) {
59
- status = 'pass'
60
- } else {
61
- status = 'fail'
62
- }
125
+ const status = getTestStatus(test)
63
126
 
64
127
  // if there are afterEach to be run, we don't finish the test yet
65
128
  if (!test.parent._afterEach.length) {
@@ -75,9 +138,10 @@ function mochaHook (Runner) {
75
138
  if (test && hook.parent._afterEach.includes(hook)) { // only if it's an afterEach
76
139
  const isLastAfterEach = hook.parent._afterEach.indexOf(hook) === hook.parent._afterEach.length - 1
77
140
  if (isLastAfterEach) {
141
+ const status = getTestStatus(test)
78
142
  const asyncResource = getTestAsyncResource(test)
79
143
  asyncResource.runInAsyncScope(() => {
80
- testFinishCh.publish('pass')
144
+ testFinishCh.publish(status)
81
145
  })
82
146
  }
83
147
  }
@@ -100,6 +164,15 @@ function mochaHook (Runner) {
100
164
  } else {
101
165
  errorCh.publish(err)
102
166
  }
167
+ // we propagate the error to the suite
168
+ const testSuiteAsyncResource = testSuiteToAr.get(test.parent)
169
+ if (testSuiteAsyncResource) {
170
+ const testSuiteError = new Error(`Test "${test.fullTitle()}" failed with message "${err.message}"`)
171
+ testSuiteError.stack = err.stack
172
+ testSuiteAsyncResource.runInAsyncScope(() => {
173
+ testSuiteErrorCh.publish(testSuiteError)
174
+ })
175
+ }
103
176
  })
104
177
  }
105
178
  })
@@ -127,9 +200,6 @@ function mochaHook (Runner) {
127
200
  if (!testRunFinishCh.hasSubscribers) {
128
201
  return runTests.apply(this, arguments)
129
202
  }
130
- this.once('end', AsyncResource.bind(() => {
131
- testRunFinishCh.publish()
132
- }))
133
203
  return runTests.apply(this, arguments)
134
204
  })
135
205
 
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const shimmer = require('../../datadog-shimmer')
4
- const { addHook, channel, AsyncResource } = require('./helpers/instrument')
4
+ const { addHook, channel } = require('./helpers/instrument')
5
5
  const handlers = ['use', 'pre']
6
6
  const methods = ['del', 'get', 'head', 'opts', 'post', 'put', 'patch']
7
7
 
@@ -9,14 +9,14 @@ const handleChannel = channel('apm:restify:request:handle')
9
9
  const routeChannel = channel('apm:restify:request:route')
10
10
 
11
11
  function wrapSetupRequest (setupRequest) {
12
- return function setupRequestWithTrace (req, res) {
12
+ return function (req, res) {
13
13
  handleChannel.publish({ req, res })
14
14
  return setupRequest.apply(this, arguments)
15
15
  }
16
16
  }
17
17
 
18
18
  function wrapMethod (method) {
19
- return function methodWithTrace (path) {
19
+ return function (path) {
20
20
  const middleware = wrapMiddleware(Array.prototype.slice.call(arguments, 1))
21
21
 
22
22
  return method.apply(this, [path].concat(middleware))
@@ -24,7 +24,7 @@ function wrapMethod (method) {
24
24
  }
25
25
 
26
26
  function wrapHandler (method) {
27
- return function methodWithTrace () {
27
+ return function () {
28
28
  return method.apply(this, wrapMiddleware(arguments))
29
29
  }
30
30
  }
@@ -37,10 +37,6 @@ function wrapFn (fn) {
37
37
  if (Array.isArray(fn)) return wrapMiddleware(fn)
38
38
 
39
39
  return function (req, res, next) {
40
- if (typeof next === 'function') {
41
- arguments[2] = AsyncResource.bind(next)
42
- }
43
-
44
40
  if (req.route) {
45
41
  routeChannel.publish({ req, route: req.route })
46
42
  }
@@ -11,11 +11,11 @@ class CouchBasePlugin extends Plugin {
11
11
 
12
12
  addSubs (func, start, finish = defaultFinish) {
13
13
  this.addSub(`apm:couchbase:${func}:start`, start)
14
- this.addSub(`apm:couchbase:${func}:error`, errorHandler)
14
+ this.addSub(`apm:couchbase:${func}:error`, this.addError)
15
15
  this.addSub(`apm:couchbase:${func}:finish`, finish)
16
16
  }
17
17
 
18
- startSpan (operation, customTags, store, bucket) {
18
+ startSpan (operation, customTags, store, { bucket, collection }) {
19
19
  const tags = {
20
20
  'db.type': 'couchbase',
21
21
  'component': 'couchbase',
@@ -32,7 +32,8 @@ class CouchBasePlugin extends Plugin {
32
32
  tags
33
33
  })
34
34
 
35
- span.setTag('couchbase.bucket.name', bucket.name || bucket._name)
35
+ if (bucket) span.setTag(`couchbase.bucket.name`, bucket.name)
36
+ if (collection) span.setTag(`couchbase.collection.name`, collection.name)
36
37
 
37
38
  analyticsSampler.sample(span, this.config.measured)
38
39
  return span
@@ -43,7 +44,8 @@ class CouchBasePlugin extends Plugin {
43
44
 
44
45
  this.addSubs('query', ({ resource, bucket }) => {
45
46
  const store = storage.getStore()
46
- const span = this.startSpan('query', { 'span.type': 'sql', 'resource.name': resource }, store, bucket)
47
+ const span = this.startSpan('query', { 'span.type': 'sql', 'resource.name': resource },
48
+ store, { bucket })
47
49
  this.enter(span, store)
48
50
  })
49
51
 
@@ -54,9 +56,9 @@ class CouchBasePlugin extends Plugin {
54
56
  this._addCommandSubs('prepend')
55
57
  }
56
58
  _addCommandSubs (name) {
57
- this.addSubs(name, ({ bucket }) => {
59
+ this.addSubs(name, ({ bucket, collection }) => {
58
60
  const store = storage.getStore()
59
- const span = this.startSpan(name, {}, store, bucket)
61
+ const span = this.startSpan(name, {}, store, { bucket, collection })
60
62
  this.enter(span, store)
61
63
  })
62
64
  }
@@ -66,8 +68,4 @@ function defaultFinish () {
66
68
  storage.getStore().span.finish()
67
69
  }
68
70
 
69
- function errorHandler (error) {
70
- storage.getStore().span.setTag('error', error)
71
- }
72
-
73
71
  module.exports = CouchBasePlugin
@@ -77,6 +77,8 @@ class GraphQLResolvePlugin extends Plugin {
77
77
  })
78
78
  })
79
79
 
80
+ this.addSub('apm:graphql:resolve:error', this.addError)
81
+
80
82
  this.addSub('apm:graphql:resolve:finish', finishTime => {
81
83
  const span = storage.getStore().span
82
84
  span.finish(finishTime)