dd-trace 2.4.2 → 2.7.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.
Files changed (96) hide show
  1. package/LICENSE-3rdparty.csv +1 -2
  2. package/ci/init.js +6 -0
  3. package/ci/jest/env.js +16 -3
  4. package/ext/exporters.d.ts +2 -1
  5. package/ext/exporters.js +2 -1
  6. package/index.d.ts +17 -8
  7. package/package.json +20 -23
  8. package/packages/datadog-instrumentations/index.js +14 -0
  9. package/packages/datadog-instrumentations/src/connect.js +111 -0
  10. package/packages/datadog-instrumentations/src/cypress.js +8 -0
  11. package/packages/datadog-instrumentations/src/express.js +27 -0
  12. package/packages/datadog-instrumentations/src/fastify.js +187 -0
  13. package/packages/datadog-instrumentations/src/find-my-way.js +30 -0
  14. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +100 -0
  15. package/packages/datadog-instrumentations/src/http/server.js +1 -1
  16. package/packages/datadog-instrumentations/src/jest.js +175 -0
  17. package/packages/datadog-instrumentations/src/kafkajs.js +112 -0
  18. package/packages/datadog-instrumentations/src/knex.js +20 -0
  19. package/packages/datadog-instrumentations/src/koa.js +159 -0
  20. package/packages/datadog-instrumentations/src/limitd-client.js +21 -0
  21. package/packages/datadog-instrumentations/src/oracledb.js +128 -0
  22. package/packages/datadog-instrumentations/src/paperplane.js +77 -0
  23. package/packages/datadog-instrumentations/src/pg.js +2 -2
  24. package/packages/datadog-instrumentations/src/restify.js +58 -0
  25. package/packages/datadog-instrumentations/src/rhea.js +1 -1
  26. package/packages/datadog-instrumentations/src/router.js +177 -0
  27. package/packages/datadog-plugin-aws-sdk/src/helpers.js +4 -4
  28. package/packages/datadog-plugin-aws-sdk/src/index.js +1 -1
  29. package/packages/datadog-plugin-connect/src/index.js +10 -114
  30. package/packages/datadog-plugin-cucumber/src/index.js +16 -16
  31. package/packages/datadog-plugin-cypress/src/index.js +10 -5
  32. package/packages/datadog-plugin-cypress/src/plugin.js +18 -17
  33. package/packages/datadog-plugin-dns/src/index.js +12 -1
  34. package/packages/datadog-plugin-express/src/index.js +11 -25
  35. package/packages/datadog-plugin-fastify/src/index.js +17 -4
  36. package/packages/datadog-plugin-find-my-way/src/index.js +20 -0
  37. package/packages/datadog-plugin-fs/src/index.js +2 -0
  38. package/packages/datadog-plugin-google-cloud-pubsub/src/index.js +56 -111
  39. package/packages/datadog-plugin-http/src/server.js +2 -10
  40. package/packages/datadog-plugin-jest/src/index.js +101 -3
  41. package/packages/datadog-plugin-jest/src/util.js +1 -29
  42. package/packages/datadog-plugin-kafkajs/src/index.js +64 -90
  43. package/packages/datadog-plugin-koa/src/index.js +12 -164
  44. package/packages/datadog-plugin-mocha/src/index.js +14 -15
  45. package/packages/datadog-plugin-oracledb/src/index.js +34 -100
  46. package/packages/datadog-plugin-paperplane/src/index.js +14 -100
  47. package/packages/datadog-plugin-paperplane/src/logger.js +11 -0
  48. package/packages/datadog-plugin-paperplane/src/server.js +24 -0
  49. package/packages/datadog-plugin-restify/src/index.js +13 -75
  50. package/packages/datadog-plugin-router/src/index.js +67 -164
  51. package/packages/datadog-plugin-web/src/index.js +20 -0
  52. package/packages/dd-trace/lib/version.js +1 -1
  53. package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +34 -12
  54. package/packages/dd-trace/src/appsec/index.js +7 -3
  55. package/packages/dd-trace/src/appsec/recommended.json +15 -5
  56. package/packages/dd-trace/src/appsec/reporter.js +33 -3
  57. package/packages/dd-trace/src/appsec/rule_manager.js +2 -2
  58. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +32 -0
  59. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +51 -0
  60. package/packages/dd-trace/src/config.js +33 -4
  61. package/packages/dd-trace/src/encode/0.4.js +0 -1
  62. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +193 -0
  63. package/packages/dd-trace/src/encode/tags-processors.js +116 -0
  64. package/packages/dd-trace/src/exporter.js +3 -0
  65. package/packages/dd-trace/src/exporters/agent/index.js +1 -1
  66. package/packages/dd-trace/src/exporters/agent/writer.js +7 -32
  67. package/packages/dd-trace/src/exporters/{agent → common}/docker.js +0 -0
  68. package/packages/dd-trace/src/exporters/common/request.js +83 -0
  69. package/packages/dd-trace/src/exporters/common/writer.js +36 -0
  70. package/packages/dd-trace/src/exporters/{agent/scheduler.js → scheduler.js} +0 -0
  71. package/packages/dd-trace/src/format.js +9 -5
  72. package/packages/dd-trace/src/instrumenter.js +3 -0
  73. package/packages/dd-trace/src/pkg.js +11 -6
  74. package/packages/dd-trace/src/plugin_manager.js +13 -7
  75. package/packages/dd-trace/src/plugins/index.js +1 -2
  76. package/packages/dd-trace/src/plugins/log_plugin.js +8 -4
  77. package/packages/dd-trace/src/plugins/plugin.js +8 -0
  78. package/packages/dd-trace/src/plugins/util/test.js +79 -1
  79. package/packages/dd-trace/src/plugins/util/web.js +41 -12
  80. package/packages/dd-trace/src/profiling/config.js +8 -8
  81. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -1
  82. package/packages/dd-trace/src/profiling/index.js +4 -4
  83. package/packages/dd-trace/src/profiling/profilers/{heap.js → space.js} +2 -2
  84. package/packages/dd-trace/src/profiling/profilers/{cpu.js → wall.js} +3 -3
  85. package/packages/dd-trace/src/proxy.js +2 -0
  86. package/packages/dd-trace/src/span_processor.js +4 -1
  87. package/packages/dd-trace/src/telemetry.js +187 -0
  88. package/scripts/install_plugin_modules.js +1 -0
  89. package/packages/datadog-plugin-fastify/src/fastify.js +0 -198
  90. package/packages/datadog-plugin-fastify/src/find-my-way.js +0 -37
  91. package/packages/datadog-plugin-jest/src/jest-environment.js +0 -272
  92. package/packages/datadog-plugin-jest/src/jest-jasmine2.js +0 -185
  93. package/packages/datadog-plugin-knex/src/index.js +0 -23
  94. package/packages/datadog-plugin-limitd-client/src/index.js +0 -30
  95. package/packages/dd-trace/src/exporters/agent/request.js +0 -86
  96. package/scripts/postpublish.js +0 -24
@@ -0,0 +1,100 @@
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 requestStartCh = channel('apm:google-cloud-pubsub:request:start')
11
+ const requestFinishCh = channel('apm:google-cloud-pubsub:request:finish')
12
+ const requestErrorCh = channel('apm:google-cloud-pubsub:request:error')
13
+
14
+ const receiveStartCh = channel(`apm:google-cloud-pubsub:receive:start`)
15
+ const receiveFinishCh = channel('apm:google-cloud-pubsub:receive:finish')
16
+ const receiveErrorCh = channel('apm:google-cloud-pubsub:receive:error')
17
+
18
+ addHook({ name: '@google-cloud/pubsub', versions: ['>=1.2'] }, (obj) => {
19
+ const PubSub = obj.PubSub
20
+ const Subscription = obj.Subscription
21
+
22
+ shimmer.wrap(PubSub.prototype, 'request', request => function (cfg = { reqOpts: {} }, cb) {
23
+ if (!requestStartCh.hasSubscribers) {
24
+ return request.apply(this, arguments)
25
+ }
26
+
27
+ const innerAsyncResource = new AsyncResource('bound-anonymous-fn')
28
+ const outerAsyncResource = new AsyncResource('bound-anonymous-fn')
29
+
30
+ return innerAsyncResource.runInAsyncScope(() => {
31
+ let messages = []
32
+ if (cfg.reqOpts && cfg.method === 'publish') {
33
+ messages = cfg.reqOpts.messages
34
+ }
35
+
36
+ requestStartCh.publish({ cfg, projectId: this.projectId, messages })
37
+ cb = outerAsyncResource.bind(cb)
38
+
39
+ const fn = () => {
40
+ arguments[1] = innerAsyncResource.bind(function (error) {
41
+ if (error) {
42
+ requestErrorCh.publish(error)
43
+ }
44
+ requestFinishCh.publish(undefined)
45
+ return cb.apply(this, arguments)
46
+ })
47
+ return request.apply(this, arguments)
48
+ }
49
+
50
+ try {
51
+ return fn.apply(this, arguments)
52
+ } catch (e) {
53
+ requestErrorCh.publish(e)
54
+ throw e
55
+ }
56
+ })
57
+ })
58
+
59
+ shimmer.wrap(Subscription.prototype, 'emit', emit => function (eventName, message) {
60
+ if (eventName !== 'message' || !message) return emit.apply(this, arguments)
61
+
62
+ const asyncResource = new AsyncResource('bound-anonymous-fn')
63
+
64
+ return asyncResource.runInAsyncScope(() => {
65
+ try {
66
+ return emit.apply(this, arguments)
67
+ } catch (err) {
68
+ receiveErrorCh.publish({ err, message })
69
+ throw err
70
+ }
71
+ })
72
+ })
73
+
74
+ return obj
75
+ })
76
+
77
+ addHook({ name: '@google-cloud/pubsub', versions: ['>=1.2'], file: 'build/src/lease-manager.js' }, (obj) => {
78
+ const LeaseManager = obj.LeaseManager
79
+
80
+ shimmer.wrap(LeaseManager.prototype, '_dispense', dispense => function (message) {
81
+ if (receiveStartCh.hasSubscribers) {
82
+ receiveStartCh.publish({ message })
83
+ }
84
+ return dispense.apply(this, arguments)
85
+ })
86
+
87
+ shimmer.wrap(LeaseManager.prototype, 'remove', remove => function (message) {
88
+ receiveFinishCh.publish({ message })
89
+ return remove.apply(this, arguments)
90
+ })
91
+
92
+ shimmer.wrap(LeaseManager.prototype, 'clear', clear => function () {
93
+ for (const message of this._messages) {
94
+ receiveFinishCh.publish({ message })
95
+ }
96
+ return clear.apply(this, arguments)
97
+ })
98
+
99
+ return obj
100
+ })
@@ -9,7 +9,7 @@ const shimmer = require('../../../datadog-shimmer')
9
9
  const startServerCh = channel('apm:http:server:request:start')
10
10
  const endServerCh = channel('apm:http:server:request:end')
11
11
  const errorServerCh = channel('apm:http:server:request:error')
12
- const asyncEndServerCh = channel('apm:http:server:request:async-end')
12
+ const asyncEndServerCh = channel('apm:http:server:request:finish')
13
13
 
14
14
  addHook({ name: 'https' }, http => {
15
15
  // http.ServerResponse not present on https
@@ -0,0 +1,175 @@
1
+ 'use strict'
2
+
3
+ const { addHook, channel, AsyncResource } = require('./helpers/instrument')
4
+ const shimmer = require('../../datadog-shimmer')
5
+
6
+ const testStartCh = channel('ci:jest:test:start')
7
+ const testSkippedCh = channel('ci:jest:test:skip')
8
+ const testRunEndCh = channel('ci:jest:test:end')
9
+ const testErrCh = channel('ci:jest:test:err')
10
+ const testSuiteEnd = channel('ci:jest:test-suite:end')
11
+
12
+ const {
13
+ getTestSuitePath,
14
+ getTestParametersString
15
+ } = require('../../dd-trace/src/plugins/util/test')
16
+
17
+ const { getFormattedJestTestParameters } = require('../../datadog-plugin-jest/src/util')
18
+
19
+ const specStatusToTestStatus = {
20
+ 'pending': 'skip',
21
+ 'disabled': 'skip',
22
+ 'todo': 'skip',
23
+ 'passed': 'pass',
24
+ 'failed': 'fail'
25
+ }
26
+
27
+ const asyncResources = new WeakMap()
28
+ const originalTestFns = new WeakMap()
29
+
30
+ // based on https://github.com/facebook/jest/blob/main/packages/jest-circus/src/formatNodeAssertErrors.ts#L41
31
+ function formatJestError (errors) {
32
+ let error
33
+ if (Array.isArray(errors)) {
34
+ const [originalError, asyncError] = errors
35
+ if (originalError === null || !originalError.stack) {
36
+ error = asyncError
37
+ error.message = originalError
38
+ } else {
39
+ error = originalError
40
+ }
41
+ } else {
42
+ error = errors
43
+ }
44
+ return error
45
+ }
46
+
47
+ function getWrappedEnvironment (BaseEnvironment) {
48
+ return class DatadogEnvironment extends BaseEnvironment {
49
+ constructor (config, context) {
50
+ super(config, context)
51
+ const rootDir = config.globalConfig ? config.globalConfig.rootDir : config.rootDir
52
+ this.testSuite = getTestSuitePath(context.testPath, rootDir)
53
+ this.nameToParams = {}
54
+ this.global._ddtrace = global._ddtrace
55
+ }
56
+ async teardown () {
57
+ super.teardown().finally(() => {
58
+ testSuiteEnd.publish()
59
+ })
60
+ }
61
+
62
+ async handleTestEvent (event, state) {
63
+ if (super.handleTestEvent) {
64
+ await super.handleTestEvent(event, state)
65
+ }
66
+
67
+ const globalExpect = this.global.expect
68
+ const setNameToParams = (name, params) => { this.nameToParams[name] = params }
69
+
70
+ if (event.name === 'setup') {
71
+ shimmer.wrap(this.global.test, 'each', each => function () {
72
+ const testParameters = getFormattedJestTestParameters(arguments)
73
+ const eachBind = each.apply(this, arguments)
74
+ return function () {
75
+ const [testName] = arguments
76
+ setNameToParams(testName, testParameters)
77
+ return eachBind.apply(this, arguments)
78
+ }
79
+ })
80
+ }
81
+ if (event.name === 'test_start') {
82
+ const testParameters = getTestParametersString(this.nameToParams, event.test.name)
83
+
84
+ // Async resource for this test is created here
85
+ // It is used later on by the test_done handler
86
+ const asyncResource = new AsyncResource('bound-anonymous-fn')
87
+ asyncResources.set(event.test, asyncResource)
88
+ asyncResource.runInAsyncScope(() => {
89
+ testStartCh.publish({
90
+ name: globalExpect.getState().currentTestName,
91
+ suite: this.testSuite,
92
+ runner: 'jest-circus',
93
+ testParameters
94
+ })
95
+ originalTestFns.set(event.test, event.test.fn)
96
+ event.test.fn = asyncResource.bind(event.test.fn)
97
+ })
98
+ }
99
+ if (event.name === 'test_done') {
100
+ const asyncResource = asyncResources.get(event.test)
101
+ asyncResource.runInAsyncScope(() => {
102
+ let status = 'pass'
103
+ if (event.test.errors && event.test.errors.length) {
104
+ status = 'fail'
105
+ const formattedError = formatJestError(event.test.errors[0])
106
+ testErrCh.publish(formattedError)
107
+ }
108
+ testRunEndCh.publish(status)
109
+ // restore in case it is retried
110
+ event.test.fn = originalTestFns.get(event.test)
111
+ })
112
+ }
113
+ if (event.name === 'test_skip' || event.name === 'test_todo') {
114
+ testSkippedCh.publish({
115
+ name: globalExpect.getState().currentTestName,
116
+ suite: this.testSuite,
117
+ runner: 'jest-circus'
118
+ })
119
+ }
120
+ }
121
+ }
122
+ }
123
+
124
+ function getTestEnvironment (pkg) {
125
+ if (pkg.default) {
126
+ const wrappedTestEnvironment = getWrappedEnvironment(pkg.default)
127
+ pkg.default = wrappedTestEnvironment
128
+ pkg.TestEnvironment = wrappedTestEnvironment
129
+ return pkg
130
+ }
131
+ return getWrappedEnvironment(pkg)
132
+ }
133
+
134
+ addHook({
135
+ name: 'jest-environment-node',
136
+ versions: ['>=24.8.0']
137
+ }, getTestEnvironment)
138
+
139
+ addHook({
140
+ name: 'jest-environment-jsdom',
141
+ versions: ['>=24.8.0']
142
+ }, getTestEnvironment)
143
+
144
+ addHook({
145
+ name: 'jest-jasmine2',
146
+ versions: ['>=24.8.0'],
147
+ file: 'build/jasmineAsyncInstall.js'
148
+ }, (jasmineAsyncInstallExport) => {
149
+ return function (globalConfig, globalInput) {
150
+ globalInput._ddtrace = global._ddtrace
151
+ shimmer.wrap(globalInput.jasmine.Spec.prototype, 'execute', execute => function (onComplete) {
152
+ const asyncResource = new AsyncResource('bound-anonymous-fn')
153
+ asyncResource.runInAsyncScope(() => {
154
+ const testSuite = getTestSuitePath(this.result.testPath, globalConfig.rootDir)
155
+ testStartCh.publish({
156
+ name: this.getFullName(),
157
+ suite: testSuite,
158
+ runner: 'jest-jasmine2'
159
+ })
160
+ const spec = this
161
+ const callback = asyncResource.bind(function () {
162
+ if (spec.result.failedExpectations && spec.result.failedExpectations.length) {
163
+ const formattedError = formatJestError(spec.result.failedExpectations[0].error)
164
+ testErrCh.publish(formattedError)
165
+ }
166
+ testRunEndCh.publish(specStatusToTestStatus[spec.result.status])
167
+ onComplete.apply(this, arguments)
168
+ })
169
+ arguments[0] = callback
170
+ execute.apply(this, arguments)
171
+ })
172
+ })
173
+ return jasmineAsyncInstallExport.default(globalConfig, globalInput)
174
+ }
175
+ })
@@ -0,0 +1,112 @@
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 producerStartCh = channel('apm:kafkajs:produce:start')
11
+ const producerFinishCh = channel('apm:kafkajs:produce:finish')
12
+ const producerErrorCh = channel('apm:kafkajs:produce:error')
13
+
14
+ const consumerStartCh = channel('apm:kafkajs:consume:start')
15
+ const consumerFinishCh = channel('apm:kafkajs:consume:finish')
16
+ const consumerErrorCh = channel('apm:kafkajs:consume:error')
17
+
18
+ addHook({ name: 'kafkajs', versions: ['>=1.4'] }, (obj) => {
19
+ const Kafka = obj.Kafka
20
+ shimmer.wrap(Kafka.prototype, 'producer', createProducer => function () {
21
+ const producer = createProducer.apply(this, arguments)
22
+ const send = producer.send
23
+
24
+ producer.send = function () {
25
+ const innerAsyncResource = new AsyncResource('bound-anonymous-fn')
26
+
27
+ return innerAsyncResource.runInAsyncScope(() => {
28
+ if (!producerStartCh.hasSubscribers) {
29
+ return send.apply(this, arguments)
30
+ }
31
+
32
+ try {
33
+ const { topic, messages = [] } = arguments[0]
34
+ for (const message of messages) {
35
+ if (typeof message === 'object') {
36
+ message.headers = message.headers || {}
37
+ }
38
+ }
39
+ producerStartCh.publish({ topic, messages })
40
+
41
+ const result = send.apply(this, arguments)
42
+
43
+ result.then(
44
+ innerAsyncResource.bind(() => producerFinishCh.publish(undefined)),
45
+ innerAsyncResource.bind(err => {
46
+ if (err) {
47
+ producerErrorCh.publish(err)
48
+ }
49
+ producerFinishCh.publish(undefined)
50
+ })
51
+ )
52
+
53
+ return result
54
+ } catch (e) {
55
+ producerErrorCh.publish(e)
56
+ producerFinishCh.publish(undefined)
57
+ throw e
58
+ }
59
+ })
60
+ }
61
+ return producer
62
+ })
63
+
64
+ shimmer.wrap(Kafka.prototype, 'consumer', createConsumer => function () {
65
+ if (!consumerStartCh.hasSubscribers) {
66
+ return createConsumer.apply(this, arguments)
67
+ }
68
+
69
+ const consumer = createConsumer.apply(this, arguments)
70
+ const run = consumer.run
71
+
72
+ consumer.run = function ({ eachMessage, ...runArgs }) {
73
+ if (typeof eachMessage !== 'function') return run({ eachMessage, ...runArgs })
74
+
75
+ return run({
76
+ eachMessage: function (...eachMessageArgs) {
77
+ const innerAsyncResource = new AsyncResource('bound-anonymous-fn')
78
+ return innerAsyncResource.runInAsyncScope(() => {
79
+ const { topic, partition, message } = eachMessageArgs[0]
80
+ consumerStartCh.publish({ topic, partition, message })
81
+ try {
82
+ const result = eachMessage.apply(this, eachMessageArgs)
83
+
84
+ if (result && typeof result.then === 'function') {
85
+ result.then(
86
+ innerAsyncResource.bind(() => consumerFinishCh.publish(undefined)),
87
+ innerAsyncResource.bind(err => {
88
+ if (err) {
89
+ consumerErrorCh.publish(err)
90
+ }
91
+ consumerFinishCh.publish(undefined)
92
+ })
93
+ )
94
+ } else {
95
+ consumerFinishCh.publish(undefined)
96
+ }
97
+
98
+ return result
99
+ } catch (e) {
100
+ consumerErrorCh.publish(e)
101
+ consumerFinishCh.publish(undefined)
102
+ throw e
103
+ }
104
+ })
105
+ },
106
+ ...runArgs
107
+ })
108
+ }
109
+ return consumer
110
+ })
111
+ return obj
112
+ })
@@ -0,0 +1,20 @@
1
+ 'use strict'
2
+
3
+ const { addHook } = require('./helpers/instrument')
4
+ const { wrapThen } = require('./helpers/promise')
5
+ const shimmer = require('../../datadog-shimmer')
6
+
7
+ patch('lib/query/builder.js')
8
+ patch('lib/raw.js')
9
+ patch('lib/schema/builder.js')
10
+
11
+ function patch (file) {
12
+ addHook({
13
+ name: 'knex',
14
+ versions: ['>=0.8.0'],
15
+ file
16
+ }, Builder => {
17
+ shimmer.wrap(Builder.prototype, 'then', wrapThen)
18
+ return Builder
19
+ })
20
+ }
@@ -0,0 +1,159 @@
1
+ 'use strict'
2
+
3
+ const shimmer = require('../../datadog-shimmer')
4
+ const { addHook, channel, AsyncResource } = require('./helpers/instrument')
5
+
6
+ const enterChannel = channel('apm:koa:middleware:enter')
7
+ const errorChannel = channel('apm:koa:middleware:error')
8
+ const exitChannel = channel('apm:koa:middleware:exit')
9
+ const handleChannel = channel('apm:koa:request:handle')
10
+ const routeChannel = channel('apm:koa:request:route')
11
+
12
+ const originals = new WeakMap()
13
+
14
+ function wrapCallback (callback) {
15
+ return function callbackWithTrace () {
16
+ const handleRequest = callback.apply(this, arguments)
17
+
18
+ if (typeof handleRequest !== 'function') return handleRequest
19
+
20
+ return function handleRequestWithTrace (req, res) {
21
+ handleChannel.publish({ req, res })
22
+
23
+ return handleRequest.apply(this, arguments)
24
+ }
25
+ }
26
+ }
27
+
28
+ function wrapUse (use) {
29
+ return function useWithTrace () {
30
+ const result = use.apply(this, arguments)
31
+
32
+ if (!Array.isArray(this.middleware)) return result
33
+
34
+ const fn = this.middleware.pop()
35
+
36
+ this.middleware.push(wrapMiddleware(fn))
37
+
38
+ return result
39
+ }
40
+ }
41
+
42
+ function wrapRegister (register) {
43
+ return function registerWithTrace (path, methods, middleware, opts) {
44
+ const route = register.apply(this, arguments)
45
+
46
+ if (!Array.isArray(path) && route && Array.isArray(route.stack)) {
47
+ wrapStack(route)
48
+ }
49
+
50
+ return route
51
+ }
52
+ }
53
+
54
+ function wrapRouterUse (use) {
55
+ return function useWithTrace () {
56
+ const router = use.apply(this, arguments)
57
+
58
+ router.stack.forEach(wrapStack)
59
+
60
+ return router
61
+ }
62
+ }
63
+
64
+ function wrapStack (layer) {
65
+ layer.stack = layer.stack.map(middleware => {
66
+ if (typeof middleware !== 'function') return middleware
67
+
68
+ const original = originals.get(middleware)
69
+
70
+ middleware = original || middleware
71
+
72
+ const handler = shimmer.wrap(middleware, wrapMiddleware(middleware, layer))
73
+
74
+ originals.set(handler, middleware)
75
+
76
+ return handler
77
+ })
78
+ }
79
+
80
+ function wrapMiddleware (fn, layer) {
81
+ if (typeof fn !== 'function') return fn
82
+
83
+ const name = fn.name
84
+
85
+ return function (ctx, next) {
86
+ if (!ctx || !enterChannel.hasSubscribers) return fn.apply(this, arguments)
87
+
88
+ const middlewareResource = new AsyncResource('bound-anonymous-fn')
89
+ const req = ctx.req
90
+
91
+ return middlewareResource.runInAsyncScope(() => {
92
+ enterChannel.publish({ req, name })
93
+
94
+ if (typeof next === 'function') {
95
+ arguments[1] = AsyncResource.bind(next)
96
+ }
97
+
98
+ try {
99
+ const result = fn.apply(this, arguments)
100
+
101
+ if (result && typeof result.then === 'function') {
102
+ return result.then(
103
+ result => {
104
+ exit(ctx, layer)
105
+ return result
106
+ },
107
+ err => {
108
+ exit(ctx, layer, err)
109
+ throw err
110
+ }
111
+ )
112
+ } else {
113
+ exit(ctx, layer)
114
+ return result
115
+ }
116
+ } catch (e) {
117
+ exit(ctx, layer, e)
118
+ throw e
119
+ }
120
+ })
121
+ }
122
+ }
123
+
124
+ function exit (ctx, layer, error) {
125
+ if (error) {
126
+ errorChannel.publish(error)
127
+ }
128
+
129
+ const req = ctx.req
130
+ const route = ctx.routePath || (layer && layer.path)
131
+
132
+ // TODO: make sure that the parent class cannot override this in `enter`
133
+ if (route) {
134
+ routeChannel.publish({ req, route })
135
+ }
136
+
137
+ exitChannel.publish(ctx)
138
+ }
139
+
140
+ addHook({ name: 'koa', versions: ['>=2'] }, Koa => {
141
+ shimmer.wrap(Koa.prototype, 'callback', wrapCallback)
142
+ shimmer.wrap(Koa.prototype, 'use', wrapUse)
143
+
144
+ return Koa
145
+ })
146
+
147
+ addHook({ name: '@koa/router', versions: ['>=8'] }, Router => {
148
+ shimmer.wrap(Router.prototype, 'register', wrapRegister)
149
+ shimmer.wrap(Router.prototype, 'use', wrapRouterUse)
150
+
151
+ return Router
152
+ })
153
+
154
+ addHook({ name: 'koa-router', versions: ['>=7'] }, Router => {
155
+ shimmer.wrap(Router.prototype, 'register', wrapRegister)
156
+ shimmer.wrap(Router.prototype, 'use', wrapRouterUse)
157
+
158
+ return Router
159
+ })
@@ -0,0 +1,21 @@
1
+ 'use strict'
2
+
3
+ const { addHook, AsyncResource } = require('./helpers/instrument')
4
+ const shimmer = require('../../datadog-shimmer')
5
+
6
+ function wrapRequest (original) {
7
+ return function () {
8
+ const id = arguments.length - 1
9
+ arguments[id] = AsyncResource.bind(arguments[id])
10
+ return original.apply(this, arguments)
11
+ }
12
+ }
13
+
14
+ addHook({
15
+ name: 'limitd-client',
16
+ versions: ['>=2.8']
17
+ }, LimitdClient => {
18
+ shimmer.wrap(LimitdClient.prototype, '_directRequest', wrapRequest)
19
+ shimmer.wrap(LimitdClient.prototype, '_retriedRequest', wrapRequest)
20
+ return LimitdClient
21
+ })