dd-trace 2.2.0 → 2.3.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 (55) hide show
  1. package/LICENSE-3rdparty.csv +0 -2
  2. package/index.d.ts +6 -12
  3. package/package.json +3 -5
  4. package/packages/datadog-instrumentations/index.js +9 -0
  5. package/packages/datadog-instrumentations/src/bunyan.js +22 -0
  6. package/packages/datadog-instrumentations/src/cucumber.js +116 -0
  7. package/packages/datadog-instrumentations/src/elasticsearch.js +15 -5
  8. package/packages/datadog-instrumentations/src/generic-pool.js +48 -0
  9. package/packages/datadog-instrumentations/src/ioredis.js +52 -0
  10. package/packages/datadog-instrumentations/src/mongoose.js +30 -0
  11. package/packages/datadog-instrumentations/src/pino.js +105 -0
  12. package/packages/datadog-instrumentations/src/redis.js +118 -0
  13. package/packages/datadog-instrumentations/src/sharedb.js +78 -0
  14. package/packages/datadog-instrumentations/src/winston.js +57 -0
  15. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +2 -2
  16. package/packages/datadog-plugin-bunyan/src/index.js +5 -22
  17. package/packages/datadog-plugin-cucumber/src/index.js +83 -128
  18. package/packages/datadog-plugin-fastify/src/find-my-way.js +0 -1
  19. package/packages/datadog-plugin-google-cloud-pubsub/src/index.js +8 -6
  20. package/packages/datadog-plugin-graphql/src/index.js +34 -28
  21. package/packages/datadog-plugin-grpc/src/client.js +20 -6
  22. package/packages/datadog-plugin-http2/src/server.js +2 -0
  23. package/packages/datadog-plugin-ioredis/src/index.js +5 -35
  24. package/packages/datadog-plugin-jest/src/jest-environment.js +26 -30
  25. package/packages/datadog-plugin-koa/src/index.js +6 -2
  26. package/packages/datadog-plugin-microgateway-core/src/index.js +1 -3
  27. package/packages/datadog-plugin-mocha/src/index.js +5 -3
  28. package/packages/datadog-plugin-mongodb-core/src/util.js +31 -7
  29. package/packages/datadog-plugin-next/src/index.js +9 -4
  30. package/packages/datadog-plugin-oracledb/src/index.js +10 -7
  31. package/packages/datadog-plugin-pino/src/index.js +5 -158
  32. package/packages/datadog-plugin-redis/src/index.js +96 -80
  33. package/packages/datadog-plugin-restify/src/index.js +18 -3
  34. package/packages/datadog-plugin-rhea/src/index.js +8 -5
  35. package/packages/datadog-plugin-router/src/index.js +23 -14
  36. package/packages/datadog-plugin-sharedb/src/index.js +47 -87
  37. package/packages/datadog-plugin-winston/src/index.js +5 -113
  38. package/packages/datadog-shimmer/src/shimmer.js +1 -1
  39. package/packages/dd-trace/lib/version.js +1 -1
  40. package/packages/dd-trace/src/appsec/index.js +2 -1
  41. package/packages/dd-trace/src/appsec/reporter.js +3 -2
  42. package/packages/dd-trace/src/config.js +7 -1
  43. package/packages/dd-trace/src/constants.js +1 -6
  44. package/packages/dd-trace/src/opentracing/propagation/text_map.js +0 -34
  45. package/packages/dd-trace/src/opentracing/tracer.js +1 -1
  46. package/packages/dd-trace/src/plugins/index.js +0 -2
  47. package/packages/dd-trace/src/plugins/log_plugin.js +49 -0
  48. package/packages/dd-trace/src/plugins/plugin.js +7 -0
  49. package/packages/dd-trace/src/plugins/util/git.js +1 -1
  50. package/packages/dd-trace/src/plugins/util/web.js +102 -84
  51. package/packages/dd-trace/src/priority_sampler.js +1 -49
  52. package/packages/dd-trace/src/scope.js +47 -23
  53. package/packages/dd-trace/src/span_processor.js +22 -7
  54. package/packages/datadog-plugin-generic-pool/src/index.js +0 -52
  55. package/packages/datadog-plugin-mongoose/src/index.js +0 -51
@@ -0,0 +1,78 @@
1
+ 'use strict'
2
+
3
+ const {
4
+ channel,
5
+ addHook,
6
+ AsyncResource
7
+ } = require('./helpers/instrument')
8
+ const shimmer = require('../../datadog-shimmer')
9
+
10
+ /**
11
+ * @description The enum values in this map are not exposed from ShareDB, so the keys are hard-coded here.
12
+ * The values were derived from: https://github.com/share/sharedb/blob/master/lib/client/connection.js#L196
13
+ */
14
+ const READABLE_ACTION_NAMES = {
15
+ hs: 'handshake',
16
+ qf: 'query-fetch',
17
+ qs: 'query-subscribe',
18
+ qu: 'query-unsubscribe',
19
+ bf: 'bulk-fetch',
20
+ bs: 'bulk-subscribe',
21
+ bu: 'bulk-unsubscribe',
22
+ f: 'fetch',
23
+ s: 'subscribe',
24
+ u: 'unsubscribe',
25
+ op: 'op',
26
+ nf: 'snapshot-fetch',
27
+ nt: 'snapshot-fetch-by-ts',
28
+ p: 'presence-broadcast',
29
+ pr: 'presence-request',
30
+ ps: 'presence-subscribe',
31
+ pu: 'presence-unsubscribe'
32
+ }
33
+
34
+ addHook({ name: 'sharedb', versions: ['>=1'], file: 'lib/agent.js' }, Agent => {
35
+ const startCh = channel('apm:sharedb:request:start')
36
+ const asyncEndCh = channel('apm:sharedb:request:async-end')
37
+ const endCh = channel('apm:sharedb:request:end')
38
+ const errorCh = channel('apm:sharedb:request:error')
39
+
40
+ shimmer.wrap(Agent.prototype, '_handleMessage', origHandleMessageFn => function (request, callback) {
41
+ const asyncResource = new AsyncResource('bound-anonymous-fn')
42
+ const action = request.a
43
+
44
+ const actionName = getReadableActionName(action)
45
+
46
+ startCh.publish({ actionName, request })
47
+
48
+ callback = asyncResource.bind(callback)
49
+
50
+ arguments[1] = AsyncResource.bind(function (error, res) {
51
+ if (error) {
52
+ errorCh.publish(error)
53
+ }
54
+ asyncEndCh.publish({ request, res })
55
+
56
+ return callback.apply(this, arguments)
57
+ })
58
+
59
+ try {
60
+ return origHandleMessageFn.apply(this, arguments)
61
+ } catch (error) {
62
+ errorCh.publish(error)
63
+
64
+ throw error
65
+ } finally {
66
+ endCh.publish(undefined)
67
+ }
68
+ })
69
+ return Agent
70
+ })
71
+
72
+ function getReadableActionName (action) {
73
+ const actionName = READABLE_ACTION_NAMES[action]
74
+ if (actionName === undefined) {
75
+ return action
76
+ }
77
+ return actionName
78
+ }
@@ -0,0 +1,57 @@
1
+ 'use strict'
2
+
3
+ const {
4
+ channel,
5
+ addHook
6
+ } = require('./helpers/instrument')
7
+ const shimmer = require('../../datadog-shimmer')
8
+
9
+ const patched = new WeakSet()
10
+
11
+ addHook({ name: 'winston', file: 'lib/winston/logger.js', versions: ['>=3'] }, Logger => {
12
+ const logCh = channel('apm:winston:log')
13
+ shimmer.wrap(Logger.prototype, 'write', write => {
14
+ return function wrappedWrite (chunk, enc, cb) {
15
+ if (logCh.hasSubscribers) {
16
+ const payload = { message: chunk }
17
+ logCh.publish(payload)
18
+ arguments[0] = payload.message
19
+ }
20
+ return write.apply(this, arguments)
21
+ }
22
+ })
23
+ return Logger
24
+ })
25
+
26
+ addHook({ name: 'winston', file: 'lib/winston/logger.js', versions: ['1', '2'] }, logger => {
27
+ const logCh = channel('apm:winston:log')
28
+ if (logger.Logger.prototype.configure) {
29
+ shimmer.wrap(logger.Logger.prototype, 'configure', configure => wrapMethod(configure, logCh))
30
+ }
31
+ shimmer.wrap(logger.Logger.prototype, 'add', configure => wrapMethod(configure, logCh))
32
+ return logger
33
+ })
34
+
35
+ function wrapMethod (method, logCh) {
36
+ return function methodWithTrace () {
37
+ const result = method.apply(this, arguments)
38
+
39
+ if (logCh.hasSubscribers) {
40
+ for (const name in this.transports) {
41
+ const transport = this.transports[name]
42
+
43
+ if (patched.has(transport) || typeof transport.log !== 'function') continue
44
+
45
+ const log = transport.log
46
+ transport.log = function wrappedLog (level, msg, meta, callback) {
47
+ const payload = { message: meta || {} }
48
+ logCh.publish(payload)
49
+ arguments[2] = payload.message
50
+ log.apply(this, arguments)
51
+ }
52
+ patched.add(transport)
53
+ }
54
+ }
55
+ return result
56
+ }
57
+ }
@@ -38,8 +38,8 @@ class Sns {
38
38
  const ddInfo = {}
39
39
  tracer.inject(span, 'text_map', ddInfo)
40
40
  injectPath.MessageAttributes._datadog = {
41
- DataType: 'String',
42
- StringValue: JSON.stringify(ddInfo)
41
+ DataType: 'Binary',
42
+ BinaryValue: JSON.stringify(ddInfo) // BINARY types are automatically base64 encoded
43
43
  }
44
44
  }
45
45
  }
@@ -1,27 +1,10 @@
1
1
  'use strict'
2
2
 
3
- const { LOG } = require('../../../ext/formats')
3
+ const LogPlugin = require('../../dd-trace/src/plugins/log_plugin')
4
4
 
5
- function createWrapEmit (tracer, config) {
6
- return function wrapEmit (emit) {
7
- return function emitWithTrace (rec, noemit) {
8
- const span = tracer.scope().active()
9
-
10
- tracer.inject(span, LOG, rec)
11
-
12
- return emit.apply(this, arguments)
13
- }
14
- }
15
- }
16
-
17
- module.exports = {
18
- name: 'bunyan',
19
- versions: ['>=1'],
20
- patch (Logger, tracer, config) {
21
- if (!tracer._logInjection) return
22
- this.wrap(Logger.prototype, '_emit', createWrapEmit(tracer, config))
23
- },
24
- unpatch (Logger) {
25
- this.unwrap(Logger.prototype, '_emit')
5
+ class BunyanPlugin extends LogPlugin {
6
+ static get name () {
7
+ return 'bunyan'
26
8
  }
27
9
  }
10
+ module.exports = BunyanPlugin
@@ -1,150 +1,105 @@
1
- const { SAMPLING_RULE_DECISION } = require('../../dd-trace/src/constants')
1
+ 'use strict'
2
+
3
+ const Plugin = require('../../dd-trace/src/plugins/plugin')
4
+ const { storage } = require('../../datadog-core')
2
5
 
3
6
  const {
7
+ CI_APP_ORIGIN,
4
8
  TEST_TYPE,
5
9
  TEST_NAME,
6
10
  TEST_SUITE,
7
- TEST_STATUS,
8
- TEST_FRAMEWORK_VERSION,
9
11
  TEST_SKIP_REASON,
10
- CI_APP_ORIGIN,
12
+ TEST_FRAMEWORK_VERSION,
11
13
  ERROR_MESSAGE,
12
- getTestEnvironmentMetadata,
14
+ TEST_STATUS,
13
15
  finishAllTraceSpans,
16
+ getTestEnvironmentMetadata,
14
17
  getTestSuitePath
15
18
  } = require('../../dd-trace/src/plugins/util/test')
19
+ const { SPAN_TYPE, RESOURCE_NAME } = require('../../../ext/tags')
20
+ const { SAMPLING_RULE_DECISION } = require('../../dd-trace/src/constants')
16
21
 
17
- function setStatusFromResult (span, result, tag) {
18
- if (result.status === 1) {
19
- span.setTag(tag, 'pass')
20
- } else if (result.status === 2) {
21
- span.setTag(tag, 'skip')
22
- } else if (result.status === 4) {
23
- span.setTag(tag, 'skip')
24
- span.setTag(TEST_SKIP_REASON, 'not implemented')
25
- } else {
26
- span.setTag(tag, 'fail')
27
- span.setTag(ERROR_MESSAGE, result.message)
22
+ class CucumberPlugin extends Plugin {
23
+ static get name () {
24
+ return 'cucumber'
28
25
  }
29
- }
30
26
 
31
- function setStatusFromResultLatest (span, result, tag) {
32
- if (result.status === 'PASSED') {
33
- span.setTag(tag, 'pass')
34
- } else if (result.status === 'SKIPPED' || result.status === 'PENDING') {
35
- span.setTag(tag, 'skip')
36
- } else if (result.status === 'UNDEFINED') {
37
- span.setTag(tag, 'skip')
38
- span.setTag(TEST_SKIP_REASON, 'not implemented')
39
- } else {
40
- span.setTag(tag, 'fail')
41
- span.setTag(ERROR_MESSAGE, result.message)
42
- }
43
- }
27
+ constructor (...args) {
28
+ super(...args)
44
29
 
45
- function createWrapRun (tracer, testEnvironmentMetadata, sourceRoot, setStatus) {
46
- return function wrapRun (run) {
47
- return function handleRun () {
48
- const testName = this.pickle.name
49
- const testSuite = getTestSuitePath(this.pickle.uri, sourceRoot)
50
-
51
- const commonSpanTags = {
52
- [TEST_TYPE]: 'test',
53
- [TEST_NAME]: testName,
54
- [TEST_SUITE]: testSuite,
55
- [SAMPLING_RULE_DECISION]: 1,
56
- [TEST_FRAMEWORK_VERSION]: tracer._version,
57
- ...testEnvironmentMetadata
58
- }
30
+ const testEnvironmentMetadata = getTestEnvironmentMetadata('cucumber', this.config)
31
+ const sourceRoot = process.cwd()
32
+
33
+ this.addSub('ci:cucumber:run:start', ({ pickleName, pickleUri }) => {
34
+ const store = storage.getStore()
35
+ const childOf = store ? store.span : store
36
+ const testSuite = getTestSuitePath(pickleUri, sourceRoot)
59
37
 
60
- return tracer.trace(
61
- 'cucumber.test',
62
- {
63
- type: 'test',
64
- resource: testName,
65
- tags: commonSpanTags
66
- },
67
- (testSpan) => {
68
- testSpan.context()._trace.origin = CI_APP_ORIGIN
69
- const promise = run.apply(this, arguments)
70
- promise.then(() => {
71
- setStatus(testSpan, this.getWorstStepResult(), TEST_STATUS)
72
- }).finally(() => {
73
- finishAllTraceSpans(testSpan)
74
- })
75
- return promise
38
+ const span = this.tracer.startSpan('cucumber.test', {
39
+ childOf,
40
+ tags: {
41
+ [SPAN_TYPE]: 'test',
42
+ [RESOURCE_NAME]: pickleName,
43
+ [TEST_TYPE]: 'test',
44
+ [TEST_NAME]: pickleName,
45
+ [TEST_SUITE]: testSuite,
46
+ [SAMPLING_RULE_DECISION]: 1,
47
+ [TEST_FRAMEWORK_VERSION]: this.tracer._version,
48
+ ...testEnvironmentMetadata
76
49
  }
77
- )
78
- }
79
- }
80
- }
50
+ })
51
+ span.context()._trace.origin = CI_APP_ORIGIN
52
+ this.enter(span, store)
53
+ })
81
54
 
82
- function createWrapRunStep (tracer, getResourceName, setStatus) {
83
- return function wrapRunStep (runStep) {
84
- return function handleRunStep () {
85
- const resource = getResourceName(arguments[0])
86
- return tracer.trace(
87
- 'cucumber.step',
88
- { resource, tags: { 'cucumber.step': resource } },
89
- (span) => {
90
- const promise = runStep.apply(this, arguments)
91
- promise.then((result) => {
92
- setStatus(span, result, 'step.status')
93
- })
94
- return promise
55
+ this.addSub('ci:cucumber:run:end', () => {
56
+ this.exit()
57
+ })
58
+
59
+ this.addSub('ci:cucumber:run-step:start', ({ resource }) => {
60
+ const store = storage.getStore()
61
+ const childOf = store ? store.span : store
62
+ const span = this.tracer.startSpan('cucumber.step', {
63
+ childOf,
64
+ tags: {
65
+ 'cucumber.step': resource,
66
+ [RESOURCE_NAME]: resource
95
67
  }
96
- )
97
- }
98
- }
99
- }
68
+ })
69
+ this.enter(span, store)
70
+ })
71
+
72
+ this.addSub('ci:cucumber:run-step:end', () => {
73
+ this.exit()
74
+ })
75
+
76
+ this.addSub('ci:cucumber:run:async-end', ({ isStep, status, skipReason, errorMessage }) => {
77
+ const span = storage.getStore().span
78
+ const statusTag = isStep ? 'step.status' : TEST_STATUS
79
+
80
+ span.setTag(statusTag, status)
100
81
 
101
- module.exports = [
102
- {
103
- name: '@cucumber/cucumber',
104
- versions: ['7.0.0 - 7.2.1'],
105
- file: 'lib/runtime/pickle_runner.js',
106
- patch (PickleRunner, tracer, config) {
107
- const testEnvironmentMetadata = getTestEnvironmentMetadata('cucumber', config)
108
- const sourceRoot = process.cwd()
109
- const pl = PickleRunner.default
110
- this.wrap(
111
- pl.prototype,
112
- 'run',
113
- createWrapRun(tracer, testEnvironmentMetadata, sourceRoot, setStatusFromResult)
114
- )
115
- const getResourceName = (testStep) => {
116
- return testStep.isHook ? 'hook' : testStep.pickleStep.text
82
+ if (skipReason) {
83
+ span.setTag(TEST_SKIP_REASON, skipReason)
117
84
  }
118
- this.wrap(pl.prototype, 'runStep', createWrapRunStep(tracer, getResourceName, setStatusFromResult))
119
- },
120
- unpatch (PickleRunner) {
121
- const pl = PickleRunner.default
122
- this.unwrap(pl.prototype, 'run')
123
- this.unwrap(pl.prototype, 'runStep')
124
- }
125
- },
126
- {
127
- name: '@cucumber/cucumber',
128
- versions: ['>=7.3.0'],
129
- file: 'lib/runtime/test_case_runner.js',
130
- patch (TestCaseRunner, tracer, config) {
131
- const testEnvironmentMetadata = getTestEnvironmentMetadata('cucumber', config)
132
- const sourceRoot = process.cwd()
133
- const pl = TestCaseRunner.default
134
- this.wrap(
135
- pl.prototype,
136
- 'run',
137
- createWrapRun(tracer, testEnvironmentMetadata, sourceRoot, setStatusFromResultLatest)
138
- )
139
- const getResourceName = (testStep) => {
140
- return testStep.text
85
+
86
+ if (errorMessage) {
87
+ span.setTag(ERROR_MESSAGE, errorMessage)
88
+ }
89
+
90
+ span.finish()
91
+ if (!isStep) {
92
+ finishAllTraceSpans(span)
141
93
  }
142
- this.wrap(pl.prototype, 'runStep', createWrapRunStep(tracer, getResourceName, setStatusFromResultLatest))
143
- },
144
- unpatch (TestCaseRunner) {
145
- const pl = TestCaseRunner.default
146
- this.unwrap(pl.prototype, 'run')
147
- this.unwrap(pl.prototype, 'runStep')
148
- }
94
+ })
95
+
96
+ this.addSub('ci:cucumber:error', (err) => {
97
+ if (err) {
98
+ const span = storage.getStore().span
99
+ span.setTag('error', err)
100
+ }
101
+ })
149
102
  }
150
- ]
103
+ }
104
+
105
+ module.exports = CucumberPlugin
@@ -10,7 +10,6 @@ function createWrapOn () {
10
10
  const wrapper = function (req) {
11
11
  web.patch(req)
12
12
  web.enterRoute(req, path)
13
- req._datadog.routeEntered = true
14
13
 
15
14
  return handler.apply(this, arguments)
16
15
  }
@@ -2,6 +2,8 @@
2
2
 
3
3
  const analyticsSampler = require('../../dd-trace/src/analytics_sampler')
4
4
 
5
+ const messageSpans = new WeakMap()
6
+
5
7
  function createWrapRequest (tracer, config) {
6
8
  return function wrapRequest (request) {
7
9
  return function requestWithTrace (cfg = { reqOpts: {} }, cb) {
@@ -45,11 +47,11 @@ function createWrapRequest (tracer, config) {
45
47
  function createWrapSubscriptionEmit (tracer, config) {
46
48
  return function wrapSubscriptionEmit (emit) {
47
49
  return function emitWithTrace (eventName, message) {
48
- if (eventName !== 'message' || !message || !message._datadog_span) {
49
- return emit.apply(this, arguments)
50
- }
50
+ if (eventName !== 'message' || !message) return emit.apply(this, arguments)
51
+
52
+ const span = messageSpans.get(message)
51
53
 
52
- const span = message._datadog_span
54
+ if (!span) return emit.apply(this, arguments)
53
55
 
54
56
  return tracer.scope().activate(span, () => {
55
57
  try {
@@ -83,7 +85,7 @@ function createWrapLeaseDispense (tracer, config) {
83
85
 
84
86
  analyticsSampler.sample(span, config.measured, true)
85
87
 
86
- message._datadog_span = span
88
+ messageSpans.set(message, span)
87
89
 
88
90
  return dispense.apply(this, arguments)
89
91
  }
@@ -119,7 +121,7 @@ function getTopic (cfg) {
119
121
  }
120
122
 
121
123
  function finish (message) {
122
- const span = message._datadog_span
124
+ const span = messageSpans.get(message)
123
125
 
124
126
  if (!span) return
125
127
 
@@ -4,6 +4,11 @@ const pick = require('lodash.pick')
4
4
  const log = require('../../dd-trace/src/log')
5
5
  const analyticsSampler = require('../../dd-trace/src/analytics_sampler')
6
6
 
7
+ const contexts = new WeakMap()
8
+ const documentSources = new WeakMap()
9
+ const patchedTypes = new WeakSet()
10
+ const patchedResolvers = new WeakSet()
11
+
7
12
  let tools
8
13
 
9
14
  function createWrapExecute (tracer, config, defaultFieldResolver) {
@@ -12,11 +17,11 @@ function createWrapExecute (tracer, config, defaultFieldResolver) {
12
17
  const args = normalizeArgs(arguments, tracer, config, defaultFieldResolver)
13
18
  const schema = args.schema
14
19
  const document = args.document
15
- const source = document && document._datadog_source
20
+ const source = documentSources.get(document)
16
21
  const contextValue = args.contextValue
17
22
  const operation = getOperation(document, args.operationName)
18
23
 
19
- if (contextValue._datadog_graphql) {
24
+ if (contexts.has(contextValue)) {
20
25
  return execute.apply(this, arguments)
21
26
  }
22
27
 
@@ -26,11 +31,12 @@ function createWrapExecute (tracer, config, defaultFieldResolver) {
26
31
  }
27
32
 
28
33
  const span = startExecutionSpan(tracer, config, operation, args)
34
+ const context = { source, span, fields: {} }
29
35
 
30
- contextValue._datadog_graphql = { source, span, fields: {} }
36
+ contexts.set(contextValue, context)
31
37
 
32
38
  return call(execute, span, this, arguments, (err, res) => {
33
- finishResolvers(contextValue, config)
39
+ finishResolvers(context)
34
40
 
35
41
  setError(span, err || (res && res.errors && res.errors[0]))
36
42
  config.hooks.execute(span, args, res)
@@ -55,7 +61,7 @@ function createWrapParse (tracer, config) {
55
61
  if (!operation) return document // skip schema parsing
56
62
 
57
63
  if (source) {
58
- document._datadog_source = source.body || source
64
+ documentSources.set(document, source.body || source)
59
65
  }
60
66
 
61
67
  addDocumentTags(span, document, config)
@@ -103,11 +109,11 @@ function createWrapValidate (tracer, config) {
103
109
  }
104
110
 
105
111
  function wrapFields (type, tracer, config) {
106
- if (!type || !type._fields || type._datadog_patched) {
112
+ if (!type || !type._fields || patchedTypes.has(type)) {
107
113
  return
108
114
  }
109
115
 
110
- type._datadog_patched = true
116
+ patchedTypes.add(type)
111
117
 
112
118
  Object.keys(type._fields).forEach(key => {
113
119
  const field = type._fields[key]
@@ -136,14 +142,16 @@ function wrapFieldType (field, tracer, config) {
136
142
  }
137
143
 
138
144
  function wrapResolve (resolve, tracer, config) {
139
- if (resolve._datadog_patched || typeof resolve !== 'function') return resolve
145
+ if (typeof resolve !== 'function' || patchedResolvers.has(resolve)) return resolve
140
146
 
141
147
  const responsePathAsArray = config.collapse
142
148
  ? withCollapse(pathToArray)
143
149
  : pathToArray
144
150
 
145
151
  function resolveWithTrace (source, args, contextValue, info) {
146
- if (!contextValue._datadog_graphql) return resolve.apply(this, arguments)
152
+ const context = contexts.get(contextValue)
153
+
154
+ if (!context) return resolve.apply(this, arguments)
147
155
 
148
156
  const path = responsePathAsArray(info && info.path)
149
157
 
@@ -151,18 +159,18 @@ function wrapResolve (resolve, tracer, config) {
151
159
  const depth = path.filter(item => typeof item === 'string').length
152
160
 
153
161
  if (config.depth < depth) {
154
- const parent = getParentField(tracer, contextValue, path)
162
+ const parent = getParentField(tracer, context, path)
155
163
 
156
164
  return call(resolve, parent.span, this, arguments)
157
165
  }
158
166
  }
159
167
 
160
- const field = assertField(tracer, config, contextValue, info, path)
168
+ const field = assertField(tracer, config, context, info, path)
161
169
 
162
170
  return call(resolve, field.span, this, arguments, err => updateField(field, err))
163
171
  }
164
172
 
165
- resolveWithTrace._datadog_patched = true
173
+ patchedResolvers.add(resolveWithTrace)
166
174
 
167
175
  return resolveWithTrace
168
176
  }
@@ -191,9 +199,9 @@ function call (fn, span, thisArg, args, callback) {
191
199
  }
192
200
  }
193
201
 
194
- function getParentField (tracer, contextValue, path) {
202
+ function getParentField (tracer, context, path) {
195
203
  for (let i = path.length - 1; i > 0; i--) {
196
- const field = getField(contextValue, path.slice(0, i))
204
+ const field = getField(context, path.slice(0, i))
197
205
 
198
206
  if (field) {
199
207
  return field
@@ -201,12 +209,12 @@ function getParentField (tracer, contextValue, path) {
201
209
  }
202
210
 
203
211
  return {
204
- span: contextValue._datadog_graphql.span
212
+ span: context.span
205
213
  }
206
214
  }
207
215
 
208
- function getField (contextValue, path) {
209
- return contextValue._datadog_graphql.fields[path.join('.')]
216
+ function getField (context, path) {
217
+ return context.fields[path.join('.')]
210
218
  }
211
219
 
212
220
  function normalizeArgs (args, tracer, config, defaultFieldResolver) {
@@ -267,8 +275,8 @@ function addExecutionTags (span, config, operation, document, operationName) {
267
275
  function addDocumentTags (span, document, config) {
268
276
  const tags = {}
269
277
 
270
- if (config.source && document && document._datadog_source) {
271
- tags['graphql.source'] = document._datadog_source
278
+ if (config.source && document) {
279
+ tags['graphql.source'] = documentSources.get(document)
272
280
  }
273
281
 
274
282
  span.addTags(tags)
@@ -300,9 +308,9 @@ function startSpan (tracer, config, name, options) {
300
308
  })
301
309
  }
302
310
 
303
- function startResolveSpan (tracer, config, childOf, path, info, contextValue) {
311
+ function startResolveSpan (tracer, config, childOf, path, info, { source }) {
304
312
  const span = startSpan(tracer, config, 'resolve', { childOf })
305
- const document = contextValue._datadog_graphql.source
313
+ const document = source
306
314
  const fieldNode = info.fieldNodes.find(fieldNode => fieldNode.kind === 'Field')
307
315
 
308
316
  analyticsSampler.sample(span, config.measured)
@@ -345,9 +353,7 @@ function finish (span, finishTime) {
345
353
  span.finish(finishTime)
346
354
  }
347
355
 
348
- function finishResolvers (contextValue) {
349
- const fields = contextValue._datadog_graphql.fields
350
-
356
+ function finishResolvers ({ fields }) {
351
357
  Object.keys(fields).reverse().forEach(key => {
352
358
  const field = fields[key]
353
359
 
@@ -369,18 +375,18 @@ function withCollapse (responsePathAsArray) {
369
375
  }
370
376
  }
371
377
 
372
- function assertField (tracer, config, contextValue, info, path) {
378
+ function assertField (tracer, config, context, info, path) {
373
379
  const pathString = path.join('.')
374
- const fields = contextValue._datadog_graphql.fields
380
+ const fields = context.fields
375
381
 
376
382
  let field = fields[pathString]
377
383
 
378
384
  if (!field) {
379
- const parent = getParentField(tracer, contextValue, path)
385
+ const parent = getParentField(tracer, context, path)
380
386
 
381
387
  field = fields[pathString] = {
382
388
  parent,
383
- span: startResolveSpan(tracer, config, parent.span, path, info, contextValue),
389
+ span: startResolveSpan(tracer, config, parent.span, path, info, context),
384
390
  error: null
385
391
  }
386
392
  }