dd-trace 2.8.0 → 2.10.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 (32) hide show
  1. package/ci/init.js +22 -6
  2. package/ci/jest/env.js +19 -7
  3. package/ext/tags.d.ts +1 -0
  4. package/ext/tags.js +2 -1
  5. package/index.d.ts +4 -2
  6. package/package.json +5 -5
  7. package/packages/datadog-core/src/storage/async_resource.js +1 -1
  8. package/packages/datadog-instrumentations/index.js +1 -0
  9. package/packages/datadog-instrumentations/src/aws-sdk.js +5 -4
  10. package/packages/datadog-instrumentations/src/fastify.js +84 -92
  11. package/packages/datadog-instrumentations/src/graphql.js +352 -0
  12. package/packages/datadog-instrumentations/src/http/client.js +1 -1
  13. package/packages/datadog-instrumentations/src/jest.js +14 -14
  14. package/packages/datadog-instrumentations/src/koa.js +10 -7
  15. package/packages/datadog-instrumentations/src/tedious.js +1 -1
  16. package/packages/datadog-plugin-graphql/src/index.js +123 -412
  17. package/packages/datadog-plugin-graphql/src/resolve.js +125 -0
  18. package/packages/datadog-plugin-http/src/client.js +10 -7
  19. package/packages/datadog-plugin-http2/src/server.js +3 -1
  20. package/packages/datadog-plugin-jest/src/util.js +13 -1
  21. package/packages/datadog-plugin-mysql/src/index.js +18 -7
  22. package/packages/dd-trace/src/appsec/index.js +3 -3
  23. package/packages/dd-trace/src/config.js +1 -1
  24. package/packages/dd-trace/src/exporters/agent/writer.js +1 -1
  25. package/packages/dd-trace/src/plugin_manager.js +21 -0
  26. package/packages/dd-trace/src/plugins/util/test.js +3 -0
  27. package/packages/dd-trace/src/plugins/util/web.js +3 -1
  28. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -1
  29. package/packages/dd-trace/src/startup-log.js +1 -1
  30. package/packages/dd-trace/src/telemetry.js +1 -1
  31. package/scripts/install_plugin_modules.js +2 -4
  32. package/packages/dd-trace/lib/version.js +0 -1
package/ci/init.js CHANGED
@@ -1,3 +1,5 @@
1
+ /* eslint-disable no-console */
2
+
1
3
  const path = require('path')
2
4
  const tracer = require('../packages/dd-trace')
3
5
  const { ORIGIN_KEY } = require('../packages/dd-trace/src/constants')
@@ -11,9 +13,22 @@ const options = {
11
13
  }
12
14
  }
13
15
 
14
- if (process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED && (process.env.DATADOG_API_KEY || process.env.DD_API_KEY)) {
15
- options.experimental = {
16
- exporter: 'datadog'
16
+ let shouldInit = true
17
+
18
+ const isAgentlessEnabled = process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED &&
19
+ process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED !== 'false' &&
20
+ process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED !== '0'
21
+
22
+ if (isAgentlessEnabled) {
23
+ if (process.env.DATADOG_API_KEY || process.env.DD_API_KEY) {
24
+ options.experimental = {
25
+ exporter: 'datadog'
26
+ }
27
+ } else {
28
+ console.error(`DD_CIVISIBILITY_AGENTLESS_ENABLED is set, \
29
+ but neither DD_API_KEY nor DATADOG_API_KEY are set in your environment, \
30
+ so dd-trace will not be initialized.`)
31
+ shouldInit = false
17
32
  }
18
33
  }
19
34
 
@@ -36,8 +51,9 @@ try {
36
51
  // ignore error and let the tracer initialize anyway
37
52
  }
38
53
 
39
- tracer.init(options)
40
-
41
- tracer.use('fs', false)
54
+ if (shouldInit) {
55
+ tracer.init(options)
56
+ tracer.use('fs', false)
57
+ }
42
58
 
43
59
  module.exports = tracer
package/ci/jest/env.js CHANGED
@@ -1,3 +1,5 @@
1
+ /* eslint-disable no-console */
2
+
1
3
  const tracer = require('../../packages/dd-trace')
2
4
  const { ORIGIN_KEY } = require('../../packages/dd-trace/src/constants')
3
5
 
@@ -8,13 +10,23 @@ const options = {
8
10
  }
9
11
  }
10
12
 
11
- if (process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED && (process.env.DATADOG_API_KEY || process.env.DD_API_KEY)) {
12
- tracer.init({
13
- ...options,
14
- experimental: {
15
- exporter: 'datadog'
16
- }
17
- })
13
+ const isAgentlessEnabled = process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED &&
14
+ process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED !== 'false' &&
15
+ process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED !== '0'
16
+
17
+ if (isAgentlessEnabled) {
18
+ if (process.env.DATADOG_API_KEY || process.env.DD_API_KEY) {
19
+ tracer.init({
20
+ ...options,
21
+ experimental: {
22
+ exporter: 'datadog'
23
+ }
24
+ })
25
+ } else {
26
+ console.error(`DD_CIVISIBILITY_AGENTLESS_ENABLED is set, \
27
+ but neither DD_API_KEY nor DATADOG_API_KEY are set in your environment, \
28
+ so dd-trace will not be initialized.`)
29
+ }
18
30
  } else {
19
31
  tracer.init({
20
32
  ...options,
package/ext/tags.d.ts CHANGED
@@ -15,6 +15,7 @@ declare const tags: {
15
15
  HTTP_ROUTE: 'http.route'
16
16
  HTTP_REQUEST_HEADERS: 'http.request.headers'
17
17
  HTTP_RESPONSE_HEADERS: 'http.response.headers'
18
+ HTTP_USERAGENT: 'http.useragent'
18
19
  }
19
20
 
20
21
  export = tags
package/ext/tags.js CHANGED
@@ -19,7 +19,8 @@ const tags = {
19
19
  HTTP_STATUS_CODE: 'http.status_code',
20
20
  HTTP_ROUTE: 'http.route',
21
21
  HTTP_REQUEST_HEADERS: 'http.request.headers',
22
- HTTP_RESPONSE_HEADERS: 'http.response.headers'
22
+ HTTP_RESPONSE_HEADERS: 'http.response.headers',
23
+ HTTP_USERAGENT: 'http.useragent'
23
24
  }
24
25
 
25
26
  // Deprecated
package/index.d.ts CHANGED
@@ -1210,13 +1210,15 @@ declare namespace plugins {
1210
1210
  * This plugin automatically instruments the
1211
1211
  * [mysql](https://github.com/mysqljs/mysql) module.
1212
1212
  */
1213
- interface mysql extends Instrumentation {}
1213
+ interface mysql extends Instrumentation {
1214
+ service?: string | ((params: any) => string);
1215
+ }
1214
1216
 
1215
1217
  /**
1216
1218
  * This plugin automatically instruments the
1217
1219
  * [mysql2](https://github.com/brianmario/mysql2) module.
1218
1220
  */
1219
- interface mysql2 extends Instrumentation {}
1221
+ interface mysql2 extends mysql {}
1220
1222
 
1221
1223
  /**
1222
1224
  * This plugin automatically instruments the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "2.8.0",
3
+ "version": "2.10.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -59,9 +59,9 @@
59
59
  },
60
60
  "dependencies": {
61
61
  "@datadog/native-appsec": "^1.2.0",
62
- "@datadog/native-metrics": "^1.2.0",
63
- "@datadog/pprof": "^0.4.0",
64
- "@datadog/sketches-js": "^1.0.4",
62
+ "@datadog/native-metrics": "^1.4.0",
63
+ "@datadog/pprof": "^0.5.1",
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",
@@ -106,8 +106,8 @@
106
106
  "jszip": "^3.5.0",
107
107
  "mkdirp": "^0.5.1",
108
108
  "mocha": "8",
109
- "multer": "^1.4.2",
110
109
  "msgpack-lite": "^0.1.26",
110
+ "multer": "^1.4.5-lts.1",
111
111
  "nock": "^11.3.3",
112
112
  "nyc": "^15.1.0",
113
113
  "proxyquire": "^1.8.0",
@@ -69,7 +69,7 @@ class AsyncResourceStorage {
69
69
  }
70
70
 
71
71
  _executionAsyncResource () {
72
- return executionAsyncResource()
72
+ return executionAsyncResource() || {}
73
73
  }
74
74
  }
75
75
 
@@ -16,6 +16,7 @@ require('./src/fastify')
16
16
  require('./src/find-my-way')
17
17
  require('./src/generic-pool')
18
18
  require('./src/google-cloud-pubsub')
19
+ require('./src/graphql')
19
20
  require('./src/hapi')
20
21
  require('./src/http')
21
22
  require('./src/ioredis')
@@ -15,13 +15,14 @@ function wrapRequest (send) {
15
15
  const channelSuffix = getChannelSuffix(serviceIdentifier)
16
16
  const startCh = channel(`apm:aws:request:start:${channelSuffix}`)
17
17
  if (!startCh.hasSubscribers) return send.apply(this, arguments)
18
+ const innerAr = new AsyncResource('apm:aws:request:inner')
18
19
  const outerAr = new AsyncResource('apm:aws:request:outer')
19
20
 
20
- this.on('complete', response => {
21
- channel(`apm:aws:request:complete:${channelSuffix}`).publish({ response })
22
- })
21
+ return innerAr.runInAsyncScope(() => {
22
+ this.on('complete', innerAr.bind(response => {
23
+ channel(`apm:aws:request:complete:${channelSuffix}`).publish({ response })
24
+ }))
23
25
 
24
- return new AsyncResource('apm:aws:request:inner').runInAsyncScope(() => {
25
26
  startCh.publish({
26
27
  serviceIdentifier,
27
28
  operation: this.operation,
@@ -1,6 +1,5 @@
1
1
  'use strict'
2
2
 
3
- const methods = require('methods').concat('all')
4
3
  const shimmer = require('../../datadog-shimmer')
5
4
  const { addHook, channel, AsyncResource } = require('./helpers/instrument')
6
5
 
@@ -8,26 +7,28 @@ const errorChannel = channel('apm:fastify:middleware:error')
8
7
  const handleChannel = channel('apm:fastify:request:handle')
9
8
 
10
9
  const requestResources = new WeakMap()
10
+ const parsingResources = new WeakMap()
11
11
 
12
- function wrapFastify (fastify) {
12
+ function wrapFastify (fastify, hasParsingEvents) {
13
13
  if (typeof fastify !== 'function') return fastify
14
14
 
15
15
  return function fastifyWithTrace () {
16
16
  const app = fastify.apply(this, arguments)
17
17
 
18
- if (!app) return app
18
+ if (!app || typeof app.addHook !== 'function') return app
19
19
 
20
- if (typeof app.addHook === 'function') {
21
- app.addHook('onRequest', onRequest)
22
- app.addHook = wrapAddHook(app.addHook)
23
- app.addHook('preHandler', preHandler)
24
- }
20
+ app.addHook('onRequest', onRequest)
21
+ app.addHook('preHandler', preHandler)
25
22
 
26
- methods.forEach(method => {
27
- app[method] = wrapMethod(app[method])
28
- })
23
+ if (hasParsingEvents) {
24
+ app.addHook('preParsing', preParsing)
25
+ app.addHook('preValidation', preValidation)
26
+ } else {
27
+ app.addHook('onRequest', preParsing)
28
+ app.addHook('preHandler', preValidation)
29
+ }
29
30
 
30
- app.route = wrapRoute(app.route)
31
+ app.addHook = wrapAddHook(app.addHook)
31
32
 
32
33
  return app
33
34
  }
@@ -45,114 +46,102 @@ function wrapAddHook (addHook) {
45
46
 
46
47
  if (!requestResource) return fn.apply(this, arguments)
47
48
 
48
- return requestResource.runInAsyncScope(() => {
49
- const hookResource = new AsyncResource('bound-anonymous-fn')
49
+ try {
50
+ if (typeof done === 'function') {
51
+ done = arguments[arguments.length - 1]
50
52
 
51
- try {
52
- if (typeof done === 'function') {
53
- done = arguments[arguments.length - 1]
53
+ arguments[arguments.length - 1] = function (err) {
54
+ publishError(err, requestResource)
54
55
 
55
- arguments[arguments.length - 1] = hookResource.bind(function (err) {
56
- errorChannel.publish(err)
57
- return done.apply(this, arguments)
58
- })
56
+ if (name === 'onRequest' || name === 'preParsing') {
57
+ const parsingResource = new AsyncResource('bound-anonymous-fn')
59
58
 
60
- return hookResource.bind(fn).apply(this, arguments)
61
- } else {
62
- const promise = hookResource.bind(fn).apply(this, arguments)
59
+ parsingResources.set(req, parsingResource)
63
60
 
64
- if (promise && typeof promise.catch === 'function') {
65
- return promise.catch(err => {
66
- errorChannel.publish(err)
67
- throw err
61
+ return parsingResource.runInAsyncScope(() => {
62
+ return done.apply(this, arguments)
68
63
  })
64
+ } else {
65
+ return done.apply(this, arguments)
69
66
  }
67
+ }
70
68
 
71
- return promise
69
+ return fn.apply(this, arguments)
70
+ } else {
71
+ const promise = fn.apply(this, arguments)
72
+
73
+ if (promise && typeof promise.catch === 'function') {
74
+ return promise.catch(err => publishError(err, requestResource))
72
75
  }
73
- } catch (e) {
74
- errorChannel.publish(e)
75
- throw e
76
+
77
+ return promise
76
78
  }
77
- })
79
+ } catch (e) {
80
+ throw publishError(e, requestResource)
81
+ }
78
82
  })
79
83
 
80
84
  return addHook.apply(this, arguments)
81
85
  }
82
86
  }
83
87
 
84
- function onRequest (request, reply, next) {
85
- if (typeof next !== 'function') return
88
+ function onRequest (request, reply, done) {
89
+ if (typeof done !== 'function') return
86
90
 
87
91
  const req = getReq(request)
88
92
  const res = getRes(reply)
93
+ const requestResource = new AsyncResource('bound-anonymous-fn')
89
94
 
90
- requestResources.set(req, new AsyncResource('bound-anonymous-fn'))
91
- handleChannel.publish({ req, res })
95
+ requestResources.set(req, requestResource)
92
96
 
93
- return next()
97
+ return requestResource.runInAsyncScope(() => {
98
+ handleChannel.publish({ req, res })
99
+ return done()
100
+ })
94
101
  }
95
102
 
96
- function preHandler (request, reply, next) {
97
- if (typeof next !== 'function') return
98
- if (!reply || typeof reply.send !== 'function') return next()
103
+ function preHandler (request, reply, done) {
104
+ if (typeof done !== 'function') return
105
+ if (!reply || typeof reply.send !== 'function') return done()
99
106
 
100
107
  const req = getReq(request)
108
+ const requestResource = requestResources.get(req)
101
109
 
102
- reply.send = requestResources.get(req).bind(wrapSend(reply.send))
110
+ reply.send = wrapSend(reply.send, requestResource)
103
111
 
104
- next()
112
+ done()
105
113
  }
106
114
 
107
- function wrapSend (send) {
108
- return function sendWithTrace (payload) {
109
- if (payload instanceof Error) {
110
- errorChannel.publish(payload)
111
- }
112
-
113
- return send.apply(this, arguments)
114
- }
115
- }
116
-
117
- function wrapRoute (route) {
118
- if (typeof route !== 'function') return route
115
+ function preValidation (request, reply, done) {
116
+ const req = getReq(request)
117
+ const parsingResource = parsingResources.get(req)
119
118
 
120
- return function routeWithTrace (opts) {
121
- opts.handler = wrapHandler(opts.handler)
119
+ if (!parsingResource) return done()
122
120
 
123
- return route.apply(this, arguments)
124
- }
121
+ parsingResource.runInAsyncScope(() => done())
125
122
  }
126
123
 
127
- function wrapMethod (method) {
128
- if (typeof method !== 'function') return method
129
-
130
- return function methodWithTrace (url, opts, handler) {
131
- const lastIndex = arguments.length - 1
132
-
133
- handler = arguments[lastIndex]
124
+ function preParsing (request, reply, payload, done) {
125
+ if (typeof done !== 'function') {
126
+ done = payload
127
+ }
134
128
 
135
- if (typeof handler === 'function') {
136
- arguments[lastIndex] = wrapHandler(handler)
137
- } else if (handler) {
138
- arguments[lastIndex].handler = wrapHandler(handler.handler)
139
- }
129
+ const req = getReq(request)
130
+ const parsingResource = new AsyncResource('bound-anonymous-fn')
140
131
 
141
- return method.apply(this, arguments)
142
- }
132
+ parsingResources.set(req, parsingResource)
133
+ parsingResource.runInAsyncScope(() => done())
143
134
  }
144
135
 
145
- function wrapHandler (handler) {
146
- if (!handler || typeof handler !== 'function' || handler.name === 'handlerWithTrace') {
147
- return handler
148
- }
149
-
150
- return function handlerWithTrace (request, reply) {
151
- const req = getReq(request)
136
+ function wrapSend (send, resource) {
137
+ return function sendWithTrace (payload) {
138
+ if (payload instanceof Error) {
139
+ resource.runInAsyncScope(() => {
140
+ errorChannel.publish(payload)
141
+ })
142
+ }
152
143
 
153
- return requestResources.get(req).runInAsyncScope(() => {
154
- return handler.apply(this, arguments)
155
- })
144
+ return send.apply(this, arguments)
156
145
  }
157
146
  }
158
147
 
@@ -164,16 +153,15 @@ function getRes (reply) {
164
153
  return reply && (reply.raw || reply.res || reply)
165
154
  }
166
155
 
167
- addHook({ name: 'fastify', versions: ['>=3.25.2'] }, fastify => {
168
- const wrapped = shimmer.wrap(fastify, wrapFastify(fastify, false))
169
-
170
- wrapped.fastify = wrapped
171
- wrapped.default = wrapped
156
+ function publishError (error, resource) {
157
+ resource.runInAsyncScope(() => {
158
+ errorChannel.publish(error)
159
+ })
172
160
 
173
- return wrapped
174
- })
161
+ return error
162
+ }
175
163
 
176
- addHook({ name: 'fastify', versions: ['3 - 3.25.1'] }, fastify => {
164
+ addHook({ name: 'fastify', versions: ['>=3'] }, fastify => {
177
165
  const wrapped = shimmer.wrap(fastify, wrapFastify(fastify, true))
178
166
 
179
167
  wrapped.fastify = wrapped
@@ -182,6 +170,10 @@ addHook({ name: 'fastify', versions: ['3 - 3.25.1'] }, fastify => {
182
170
  return wrapped
183
171
  })
184
172
 
185
- addHook({ name: 'fastify', versions: ['1 - 2'] }, fastify => {
173
+ addHook({ name: 'fastify', versions: ['2'] }, fastify => {
186
174
  return shimmer.wrap(fastify, wrapFastify(fastify, true))
187
175
  })
176
+
177
+ addHook({ name: 'fastify', versions: ['1'] }, fastify => {
178
+ return shimmer.wrap(fastify, wrapFastify(fastify, false))
179
+ })