dd-trace 2.36.0 → 2.37.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 (55) hide show
  1. package/MIGRATING.md +158 -0
  2. package/README.md +18 -11
  3. package/index.d.ts +7 -0
  4. package/package.json +4 -4
  5. package/packages/datadog-instrumentations/src/cookie.js +21 -0
  6. package/packages/datadog-instrumentations/src/fetch.js +48 -0
  7. package/packages/datadog-instrumentations/src/grpc/server.js +1 -1
  8. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  9. package/packages/datadog-instrumentations/src/helpers/register.js +10 -0
  10. package/packages/datadog-instrumentations/src/jest.js +2 -3
  11. package/packages/datadog-instrumentations/src/next.js +2 -2
  12. package/packages/datadog-instrumentations/src/otel-sdk-trace.js +18 -0
  13. package/packages/datadog-plugin-fetch/src/index.js +36 -0
  14. package/packages/datadog-plugin-http/src/client.js +24 -8
  15. package/packages/datadog-plugin-mysql/src/index.js +2 -11
  16. package/packages/datadog-plugin-tedious/src/index.js +2 -2
  17. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +3 -0
  18. package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +52 -0
  19. package/packages/dd-trace/src/appsec/iast/analyzers/insecure-cookie-analyzer.js +3 -22
  20. package/packages/dd-trace/src/appsec/iast/analyzers/no-httponly-cookie-analyzer.js +12 -0
  21. package/packages/dd-trace/src/appsec/iast/analyzers/no-samesite-cookie-analyzer.js +12 -0
  22. package/packages/dd-trace/src/appsec/iast/analyzers/set-cookies-header-interceptor.js +7 -3
  23. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +3 -3
  24. package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +48 -0
  25. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +3 -3
  26. package/packages/dd-trace/src/appsec/iast/index.js +9 -2
  27. package/packages/dd-trace/src/appsec/iast/path-line.js +13 -0
  28. package/packages/dd-trace/src/appsec/iast/tags.js +6 -0
  29. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +2 -1
  30. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +13 -4
  31. package/packages/dd-trace/src/appsec/iast/taint-tracking/origin-types.js +5 -1
  32. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +24 -4
  33. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -1
  34. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +3 -0
  35. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +7 -1
  36. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -3
  37. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +5 -2
  38. package/packages/dd-trace/src/config.js +13 -0
  39. package/packages/dd-trace/src/external-logger/src/index.js +126 -0
  40. package/packages/dd-trace/src/external-logger/test/index.spec.js +147 -0
  41. package/packages/dd-trace/src/lambda/handler.js +3 -15
  42. package/packages/dd-trace/src/noop/proxy.js +4 -0
  43. package/packages/dd-trace/src/opentelemetry/context_manager.js +1 -1
  44. package/packages/dd-trace/src/plugin_manager.js +10 -7
  45. package/packages/dd-trace/src/plugins/database.js +7 -3
  46. package/packages/dd-trace/src/plugins/plugin.js +3 -1
  47. package/packages/dd-trace/src/plugins/util/exec.js +2 -2
  48. package/packages/dd-trace/src/plugins/util/git.js +51 -24
  49. package/packages/dd-trace/src/profiling/config.js +2 -0
  50. package/packages/dd-trace/src/profiling/profiler.js +13 -4
  51. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +24 -1
  52. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +18 -1
  53. package/packages/dd-trace/src/tracer.js +3 -3
  54. package/packages/dd-trace/src/util.js +1 -1
  55. package/version.js +8 -4
package/MIGRATING.md CHANGED
@@ -4,6 +4,164 @@ This guide describes the steps to upgrade dd-trace from a major version to the
4
4
  next. If you are having any issues related to migrating, please feel free to
5
5
  open an issue or contact our [support](https://www.datadoghq.com/support/) team.
6
6
 
7
+ ## 3.0 to 4.0
8
+
9
+ ### Node 14 is no longer supported
10
+
11
+ Node.js 14 has reached EOL in April 2023 and is no longer supported. Generally
12
+ speaking, we highly recommend always keeping Node.js up to date regardless of
13
+ our support policy.
14
+
15
+ ### The `orphanable` option was removed
16
+
17
+ This option was only useful internally for a single integration that has since
18
+ been removed. It was never useful for manual instrumentation since all that is
19
+ needed to orphan a span on creation is to use
20
+ `tracer.trace('web.request', { childOf: null })`.
21
+
22
+ ### Support for `jest-jasmine2` has been removed
23
+
24
+ The default test runner for Jest was changed to `jest-circus` around 2 years ago and
25
+ is no longer supported by our Jest integration for CI Visibility. We recommend
26
+ switching to `jest-circus` to anyone still using `jest-jasmine2`.
27
+
28
+ ### Support for older Next.js versions was removed
29
+
30
+ We now support only Next.js 10.2 and up.
31
+
32
+ ### W3C headers are now prioritized over Datadog headers
33
+
34
+ As we move towards open standards, we have decided to prioritize W3C Trace
35
+ Context headers over our own vendor-specific headers for context propagation
36
+ across services. For most applications this shouldn't change anything and
37
+ distributed tracing should continue to work seamlessly.
38
+
39
+ In some rare cases it's possible that some of the services involved in a trace
40
+ are not instrumented by Datadog at all which can cause spans within the trace to
41
+ become disconnected. While the data would still be available in the UI, the
42
+ relationship between spans would no longer be visible. This can be addressed by
43
+ restoring the previous behaviour using
44
+ `DD_TRACE_PROPAGATION_STYLE='datadog,tracecontext'`.
45
+
46
+ ## 2.0 to 3.0
47
+
48
+ ### Node 12 is no longer supported
49
+
50
+ Node.js 12 has been EOL since April 2022 and is no longer supported. Generally
51
+ speaking, we highly recommend always keeping Node.js up to date regardless of our
52
+ support policy.
53
+
54
+ ### HTTP query string reported by default
55
+
56
+ HTTP query strings are now reported by default as part of the `http.url` tag.
57
+ This change is considered breaking only because there might be sensitive data
58
+ in the query string. A default regular expression based obfuscator is provided
59
+ for common use cases like API keys, but if your use case is not covered, the
60
+ [DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP](https://datadoghq.dev/dd-trace-js/#tracer-settings)
61
+ environment variable can be used to control what is obfuscated, and a value of
62
+ `.*` would redact the query string entirely.
63
+
64
+ ### HTTP operation name change
65
+
66
+ The HTTP integration now uses `web.request` for incoming requests and continues
67
+ to use `http.request` for outgoing requests. When using a supported web
68
+ framework like Express, this change will have no effect because the root span
69
+ would already have an operation name override like `express.request`.
70
+ Any [monitor](https://docs.datadoghq.com/monitors/create/types/apm/?tab=apmmetrics)
71
+ on `http.request` for incoming requests should be updated to `web.request`.
72
+
73
+ With this change, both operation names also appear under the main service name
74
+ and are no longer split between the server service name and a separate client
75
+ service name suffixed with `-http-client`.
76
+
77
+ ### gRPC operation name change
78
+
79
+ The gRPC integration now uses `grpc.server` for incoming requests and
80
+ `grpc.client` for outgoing requests. Any
81
+ [monitor](https://docs.datadoghq.com/monitors/create/types/apm/?tab=apmmetrics)
82
+ on `grpc.request` should be updated to one of these.
83
+
84
+ With this change, both operation names also appear under the main service name
85
+ and are no longer split between the server service name and a separate client
86
+ service name suffixed with `-http-client`.
87
+
88
+ ### Removal of `fs` integration
89
+
90
+ The `fs` integration was removed as it was originally added without an actual
91
+ use case, and it's been problematic ever since. It's noisy, the output is
92
+ confusing when using streams, errors that are handled higher in the stack end up
93
+ being captured, etc.
94
+
95
+ If you had any use for file system instrumentation, please let us know so we can
96
+ provide an alternative.
97
+
98
+ ### Scope binding for promises and event emitters
99
+
100
+ It's no longer possible to bind promises using `tracer.scope().bind(promise)` or
101
+ event emitters using `tracer.scope().bind(emitter)`. These were historically
102
+ added mostly for internal use, and changes to context propagation over the years
103
+ made them unnecessary, both internally and externaly. If one of these is used
104
+ anywhere, the call will simply be ignored and no binding will occur.
105
+
106
+ To bind the `then` handler of a promise, bind the function directly directly:
107
+
108
+ ```js
109
+ promise.then(tracer.scope().bind(handler))
110
+ ```
111
+
112
+ To bind all listeners for an event, wrap the call to `emit` directly instead:
113
+
114
+ ```js
115
+ tracer.scope().activate(span, () => {
116
+ emitter.emit('event')
117
+ })
118
+ ```
119
+
120
+ To bind individual listeners, bind the listener function directly instead:
121
+
122
+ ```js
123
+ emitter.on('event', tracer.scope().bind(listener, span))
124
+ ```
125
+
126
+ ### Removed APIs
127
+
128
+ The following APIs have been deprecated for a long time and have now been
129
+ completely removed:
130
+
131
+ - `tracer.currentSpan()`
132
+ - `tracer.bindEmitter()`
133
+
134
+ Since these have not been recommended nor publicly documented for years at this
135
+ point, there should be no impact as no application is expected to be using them.
136
+
137
+ ### CI Visibility new entrypoints
138
+
139
+ #### Cypress
140
+
141
+ `dd-trace/cypress/plugin` and `dd-trace/cypress/support` are removed, so you won't
142
+ be able to use them for your `cypress` instrumentation. Use `dd-trace/ci/cypress/plugin`
143
+ and `dd-trace/ci/cypress/support` instead for your plugin and support configuration
144
+ respectively.
145
+
146
+ #### Jest
147
+
148
+ The use of `'dd-trace/ci/jest/env'` in [`testEnvironment`](https://jestjs.io/docs/configuration#testenvironment-string)
149
+ is no longer supported.
150
+ To instrument `jest` tests now, add `'-r dd-trace/ci/init'` to the `NODE_OPTIONS` environment
151
+ variable passed to the process running the tests, for example, `NODE_OPTIONS='-r dd-trace/ci/init' yarn test`.
152
+
153
+ #### Mocha
154
+
155
+ The use of `--require dd-trace/ci/init` as a `mocha` flag is no longer supported.
156
+ To instrument `mocha` tests now, add `'-r dd-trace/ci/init'` to the `NODE_OPTIONS` environment
157
+ variable passed to the process running the tests, for example, `NODE_OPTIONS='-r dd-trace/ci/init' yarn test`.
158
+
159
+ #### Cucumber
160
+
161
+ The use of `--require-module dd-trace/ci/init` as a `cucumber-js` flag is no longer supported.
162
+ To instrument `cucumber-js` tests now, add `'-r dd-trace/ci/init'` to the `NODE_OPTIONS` environment
163
+ variable passed to the process running the tests, for example, `NODE_OPTIONS='-r dd-trace/ci/init' yarn test`.
164
+
7
165
  ## 1.0 to 2.0
8
166
 
9
167
  ### Configuration
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # `dd-trace`: Node.js APM Tracer Library
2
2
 
3
- [![npm v3](https://img.shields.io/npm/v/dd-trace/latest?color=blue&label=dd-trace%40v3&logo=npm)](https://www.npmjs.com/package/dd-trace)
3
+ [![npm v4](https://img.shields.io/npm/v/dd-trace/latest?color=blue&label=dd-trace%40v4&logo=npm)](https://www.npmjs.com/package/dd-trace)
4
+ [![npm v3](https://img.shields.io/npm/v/dd-trace/latest-node14?color=blue&label=dd-trace%40v3&logo=npm)](https://www.npmjs.com/package/dd-trace/v/latest-node12)
4
5
  [![npm v2](https://img.shields.io/npm/v/dd-trace/latest-node12?color=blue&label=dd-trace%40v2&logo=npm)](https://www.npmjs.com/package/dd-trace/v/latest-node12)
5
6
  [![npm dev](https://img.shields.io/npm/v/dd-trace/dev?color=orange&label=dd-trace%40dev&logo=npm)](https://www.npmjs.com/package/dd-trace/v/dev)
6
7
  [![codecov](https://codecov.io/gh/DataDog/dd-trace-js/branch/master/graph/badge.svg)](https://codecov.io/gh/DataDog/dd-trace-js)
@@ -28,27 +29,28 @@ Most of the documentation for `dd-trace` is available on these webpages:
28
29
  | :---: | :---: | :---: | :---: | :---: | :---: |
29
30
  | [`v1`](https://github.com/DataDog/dd-trace-js/tree/v1.x) | ![npm v1](https://img.shields.io/npm/v/dd-trace/legacy-v1?color=white&label=%20&style=flat-square) | `>= v12` | **End of Life** | 2021-07-13 | 2022-02-25 |
30
31
  | [`v2`](https://github.com/DataDog/dd-trace-js/tree/v2.x) | ![npm v2](https://img.shields.io/npm/v/dd-trace/latest-node12?color=white&label=%20&style=flat-square) | `>= v12` | **Maintenance** | 2022-01-28 | 2023-08-15 |
31
- | [`v3`](https://github.com/DataDog/dd-trace-js/tree/v3.x) | ![npm v3](https://img.shields.io/npm/v/dd-trace/latest?color=white&label=%20&style=flat-square) | `>= v14` | **Current** | 2022-08-15 | Unknown |
32
+ | [`v3`](https://github.com/DataDog/dd-trace-js/tree/v3.x) | ![npm v3](https://img.shields.io/npm/v/dd-trace/latest-node14?color=white&label=%20&style=flat-square) | `>= v14` | **Maintenance** | 2022-08-15 | 2024-05-15 |
33
+ | [`v4`](https://github.com/DataDog/dd-trace-js/tree/v4.x) | ![npm v4](https://img.shields.io/npm/v/dd-trace/latest?color=white&label=%20&style=flat-square) | `>= v16` | **Current** | 2023-05-12 | Unknown |
32
34
 
33
- We currently maintain two release lines, namely `v2` and `v3`.
34
- Features and bug fixes that are merged are released to the `v3` line and, if appropriate, also the `v2` line.
35
+ We currently maintain three release lines, namely `v2`, `v3` and `v4`.
36
+ Features and bug fixes that are merged are released to the `v4` line and, if appropriate, also the `v2` and `v3` line.
35
37
 
36
- For any new projects it is recommended to use the `v3` release line:
38
+ For any new projects it is recommended to use the `v4` release line:
37
39
 
38
40
  ```sh
39
41
  $ npm install dd-trace
40
42
  $ yarn add dd-trace
41
43
  ```
42
44
 
43
- However, existing projects that already use the `v2` release line, or projects that need to support Node.js v12, may use the `v2` release line.
45
+ However, existing projects that already use the `v2` or `v3` release lines, or projects that need to support EOL versions of Node.js, may continue to use these release lines.
44
46
  This is done by specifying the version when installing the package.
45
- Note that we also publish to npm using a `latest-node12` tag that can also be used for install:
47
+ Note that we also publish to npm using a `latest-node12` and `latest-node14` tag that can also be used for install:
46
48
 
47
49
  ```sh
48
- $ npm install dd-trace@2
49
- $ yarn add dd-trace@2
50
- $ npm install dd-trace@latest-node12
51
- $ yarn add dd-trace@latest-node12
50
+ $ npm install dd-trace@3
51
+ $ yarn add dd-trace@3
52
+ $ npm install dd-trace@latest-node14
53
+ $ yarn add dd-trace@latest-node14
52
54
  ```
53
55
 
54
56
  Any backwards-breaking functionality that is introduced into the library will result in an increase of the major version of the library and therefore a new release line.
@@ -153,6 +155,11 @@ $ yarn lint
153
155
 
154
156
  ### Experimental ESM Support
155
157
 
158
+ > **Warning**
159
+ >
160
+ > ESM support has been temporarily disabled starting from Node 20 as significant
161
+ > changes are in progress.
162
+
156
163
  ESM support is currently in the experimental stages, while CJS has been supported
157
164
  since inception. This means that code loaded using `require()` should work fine
158
165
  but code loaded using `import` might not always work.
package/index.d.ts CHANGED
@@ -759,6 +759,7 @@ interface Plugins {
759
759
  "elasticsearch": plugins.elasticsearch;
760
760
  "express": plugins.express;
761
761
  "fastify": plugins.fastify;
762
+ "fetch": plugins.fetch;
762
763
  "fs": plugins.fs;
763
764
  "generic-pool": plugins.generic_pool;
764
765
  "google-cloud-pubsub": plugins.google_cloud_pubsub;
@@ -1103,6 +1104,12 @@ declare namespace plugins {
1103
1104
  */
1104
1105
  interface fastify extends HttpServer {}
1105
1106
 
1107
+ /**
1108
+ * This plugin automatically instruments the
1109
+ * [fetch](https://nodejs.org/api/globals.html#fetch) global.
1110
+ */
1111
+ interface fetch extends HttpClient {}
1112
+
1106
1113
  /**
1107
1114
  * This plugin automatically instruments the
1108
1115
  * [fs](https://nodejs.org/api/fs.html) module.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "2.36.0",
3
+ "version": "2.37.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -19,7 +19,7 @@
19
19
  "test:appsec:ci": "nyc --no-clean --include \"packages/dd-trace/src/appsec/**/*.js\" --exclude \"packages/dd-trace/test/appsec/**/*.plugin.spec.js\" -- npm run test:appsec",
20
20
  "test:appsec:plugins": "mocha --colors --exit -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/dd-trace/test/appsec/**/*.@($(echo $PLUGINS)).plugin.spec.js\"",
21
21
  "test:appsec:plugins:ci": "yarn services && nyc --no-clean --include \"packages/dd-trace/test/appsec/**/*.@($(echo $PLUGINS)).plugin.spec.js\" -- npm run test:appsec:plugins",
22
- "test:trace:core": "tap packages/dd-trace/test/*.spec.js \"packages/dd-trace/test/{ci-visibility,encode,exporters,opentelemetry,opentracing,plugins,telemetry}/**/*.spec.js\"",
22
+ "test:trace:core": "tap packages/dd-trace/test/*.spec.js \"packages/dd-trace/test/{ci-visibility,config,encode,exporters,opentelemetry,opentracing,plugins,telemetry}/**/*.spec.js\"",
23
23
  "test:trace:core:ci": "npm run test:trace:core -- --coverage --nyc-arg=--include=\"packages/dd-trace/src/**/*.js\"",
24
24
  "test:instrumentations": "mocha --colors -r 'packages/dd-trace/test/setup/mocha.js' 'packages/datadog-instrumentations/test/**/*.spec.js'",
25
25
  "test:instrumentations:ci": "nyc --no-clean --include 'packages/datadog-instrumentations/src/**/*.js' -- npm run test:instrumentations",
@@ -68,9 +68,9 @@
68
68
  "dependencies": {
69
69
  "@datadog/native-appsec": "^3.2.0",
70
70
  "@datadog/native-iast-rewriter": "2.0.1",
71
- "@datadog/native-iast-taint-tracking": "^1.4.1",
71
+ "@datadog/native-iast-taint-tracking": "^1.5.0",
72
72
  "@datadog/native-metrics": "^1.6.0",
73
- "@datadog/pprof": "^2.2.1",
73
+ "@datadog/pprof": "2.2.3",
74
74
  "@datadog/sketches-js": "^2.1.0",
75
75
  "@types/node": "<18.13",
76
76
  "@opentelemetry/api": "^1.0.0",
@@ -0,0 +1,21 @@
1
+ 'use strict'
2
+
3
+ const shimmer = require('../../datadog-shimmer')
4
+ const { channel, addHook } = require('./helpers/instrument')
5
+
6
+ const cookieParseCh = channel('datadog:cookie:parse:finish')
7
+
8
+ function wrapParse (originalParse) {
9
+ return function () {
10
+ const cookies = originalParse.apply(this, arguments)
11
+ if (cookieParseCh.hasSubscribers && cookies) {
12
+ cookieParseCh.publish({ cookies })
13
+ }
14
+ return cookies
15
+ }
16
+ }
17
+
18
+ addHook({ name: 'cookie', versions: ['>=0.4'] }, cookie => {
19
+ shimmer.wrap(cookie, 'parse', wrapParse)
20
+ return cookie
21
+ })
@@ -0,0 +1,48 @@
1
+ 'use strict'
2
+
3
+ const shimmer = require('../../datadog-shimmer')
4
+ const { channel } = require('./helpers/instrument')
5
+
6
+ const startChannel = channel('apm:fetch:request:start')
7
+ const finishChannel = channel('apm:fetch:request:finish')
8
+ const errorChannel = channel('apm:fetch:request:error')
9
+
10
+ function wrapFetch (fetch, Request) {
11
+ if (typeof fetch !== 'function') return fetch
12
+
13
+ return function (input, init) {
14
+ if (!startChannel.hasSubscribers) return fetch.apply(this, arguments)
15
+
16
+ const req = new Request(input, init)
17
+ const headers = req.headers
18
+ const message = { req, headers }
19
+
20
+ startChannel.publish(message)
21
+
22
+ // Request object is read-only so we need new objects to change headers.
23
+ arguments[0] = message.req
24
+ arguments[1] = { headers: message.headers }
25
+
26
+ return fetch.apply(this, arguments)
27
+ .then(
28
+ res => {
29
+ finishChannel.publish({ req, res })
30
+
31
+ return res
32
+ },
33
+ err => {
34
+ if (err.name !== 'AbortError') {
35
+ errorChannel.publish(err)
36
+ }
37
+
38
+ finishChannel.publish({ req })
39
+
40
+ throw err
41
+ }
42
+ )
43
+ }
44
+ }
45
+
46
+ if (globalThis.fetch) {
47
+ globalThis.fetch = shimmer.wrap(fetch, wrapFetch(fetch, globalThis.Request))
48
+ }
@@ -107,7 +107,7 @@ function wrapStream (call, requestResource, onCancel) {
107
107
  function wrapCallback (callback, call, requestResource, parentResource, onCancel) {
108
108
  return function (err, value, trailer, flags) {
109
109
  requestResource.runInAsyncScope(() => {
110
- if (err instanceof Error) {
110
+ if (err) {
111
111
  errorChannel.publish(err)
112
112
  finishChannel.publish(err)
113
113
  } else {
@@ -14,6 +14,7 @@ module.exports = {
14
14
  '@koa/router': () => require('../koa'),
15
15
  '@node-redis/client': () => require('../redis'),
16
16
  '@opensearch-project/opensearch': () => require('../opensearch'),
17
+ '@opentelemetry/sdk-trace-node': () => require('../otel-sdk-trace'),
17
18
  '@redis/client': () => require('../redis'),
18
19
  'amqp10': () => require('../amqp10'),
19
20
  'amqplib': () => require('../amqplib'),
@@ -25,6 +26,7 @@ module.exports = {
25
26
  'child_process': () => require('../child-process'),
26
27
  'node:child_process': () => require('../child-process'),
27
28
  'connect': () => require('../connect'),
29
+ 'cookie': () => require('../cookie'),
28
30
  'couchbase': () => require('../couchbase'),
29
31
  'crypto': () => require('../crypto'),
30
32
  'cypress': () => require('../cypress'),
@@ -7,16 +7,26 @@ const Hook = require('./hook')
7
7
  const requirePackageJson = require('../../../dd-trace/src/require-package-json')
8
8
  const log = require('../../../dd-trace/src/log')
9
9
 
10
+ const { DD_TRACE_DISABLED_INSTRUMENTATIONS = '' } = process.env
11
+
10
12
  const hooks = require('./hooks')
11
13
  const instrumentations = require('./instrumentations')
12
14
  const names = Object.keys(hooks)
13
15
  const pathSepExpr = new RegExp(`\\${path.sep}`, 'g')
16
+ const disabledInstrumentations = new Set(
17
+ DD_TRACE_DISABLED_INSTRUMENTATIONS ? DD_TRACE_DISABLED_INSTRUMENTATIONS.split(',') : []
18
+ )
14
19
 
15
20
  const loadChannel = channel('dd-trace:instrumentation:load')
16
21
 
22
+ // Globals
23
+ require('../fetch')
24
+
17
25
  // TODO: make this more efficient
18
26
 
19
27
  for (const packageName of names) {
28
+ if (disabledInstrumentations.has(packageName)) continue
29
+
20
30
  Hook([packageName], (moduleExports, moduleName, moduleBaseDir, moduleVersion) => {
21
31
  moduleName = moduleName.replace(pathSepExpr, '/')
22
32
 
@@ -1,10 +1,8 @@
1
1
  'use strict'
2
- const semver = require('semver')
3
2
 
4
3
  const { addHook, channel, AsyncResource } = require('./helpers/instrument')
5
4
  const shimmer = require('../../datadog-shimmer')
6
5
  const log = require('../../dd-trace/src/log')
7
- const { version: ddTraceVersion } = require('../../../package.json')
8
6
  const {
9
7
  getCoveredFilenamesFromCoverage,
10
8
  JEST_WORKER_TRACE_PAYLOAD_CODE,
@@ -18,6 +16,7 @@ const {
18
16
  getJestTestName,
19
17
  getJestSuitesToRun
20
18
  } = require('../../datadog-plugin-jest/src/util')
19
+ const { DD_MAJOR } = require('../../../version')
21
20
 
22
21
  const testSessionStartCh = channel('ci:jest:session:start')
23
22
  const testSessionFinishCh = channel('ci:jest:session:finish')
@@ -481,7 +480,7 @@ function jasmineAsyncInstallWraper (jasmineAsyncInstallExport, jestVersion) {
481
480
  }
482
481
  }
483
482
 
484
- if (semver.lt(ddTraceVersion, '4.0.0')) {
483
+ if (DD_MAJOR < 4) {
485
484
  addHook({
486
485
  name: 'jest-jasmine2',
487
486
  versions: ['>=24.8.0'],
@@ -4,7 +4,7 @@
4
4
 
5
5
  const { channel, addHook, AsyncResource } = require('./helpers/instrument')
6
6
  const shimmer = require('../../datadog-shimmer')
7
- const { MAJOR } = require('../../../version')
7
+ const { DD_MAJOR } = require('../../../version')
8
8
 
9
9
  const startChannel = channel('apm:next:request:start')
10
10
  const finishChannel = channel('apm:next:request:finish')
@@ -171,7 +171,7 @@ addHook({ name: 'next', versions: ['>=11.1 <13.2'], file: 'dist/server/next-serv
171
171
 
172
172
  addHook({
173
173
  name: 'next',
174
- versions: MAJOR >= 4 ? ['>=10.2 <11.1'] : ['>=9.5 <11.1'],
174
+ versions: DD_MAJOR >= 4 ? ['>=10.2 <11.1'] : ['>=9.5 <11.1'],
175
175
  file: 'dist/next-server/server/next-server.js'
176
176
  }, nextServer => {
177
177
  const Server = nextServer.default
@@ -0,0 +1,18 @@
1
+ 'use strict'
2
+
3
+ const { addHook } = require('./helpers/instrument')
4
+ const shimmer = require('../../datadog-shimmer')
5
+ const tracer = require('../../dd-trace')
6
+
7
+ if (process.env.DD_TRACE_OTEL_ENABLED) {
8
+ addHook({
9
+ name: '@opentelemetry/sdk-trace-node',
10
+ file: 'build/src/NodeTracerProvider.js',
11
+ versions: ['*']
12
+ }, (mod) => {
13
+ shimmer.wrap(mod, 'NodeTracerProvider', () => {
14
+ return tracer.TracerProvider
15
+ })
16
+ return mod
17
+ })
18
+ }
@@ -0,0 +1,36 @@
1
+ 'use strict'
2
+
3
+ const HttpClientPlugin = require('../../datadog-plugin-http/src/client')
4
+ const { HTTP_HEADERS } = require('../../../ext/formats')
5
+
6
+ class FetchPlugin extends HttpClientPlugin {
7
+ static get id () { return 'fetch' }
8
+
9
+ addTraceSub (eventName, handler) {
10
+ this.addSub(`apm:${this.constructor.id}:${this.operation}:${eventName}`, handler)
11
+ }
12
+
13
+ start (message) {
14
+ const req = message.req
15
+ const options = new URL(req.url)
16
+ const headers = options.headers = Object.fromEntries(req.headers.entries())
17
+
18
+ const args = { options }
19
+
20
+ super.start({ args })
21
+
22
+ message.req = new globalThis.Request(req, { headers })
23
+ }
24
+
25
+ _inject (span, headers) {
26
+ const carrier = {}
27
+
28
+ this.tracer.inject(span, HTTP_HEADERS, carrier)
29
+
30
+ for (const name in carrier) {
31
+ headers.append(name, carrier[name])
32
+ }
33
+ }
34
+ }
35
+
36
+ module.exports = FetchPlugin
@@ -24,15 +24,17 @@ class HttpClientPlugin extends ClientPlugin {
24
24
  this.addSub(`apm:${this.constructor.id}:client:${this.operation}:${eventName}`, handler)
25
25
  }
26
26
 
27
- start ({ args, http }) {
27
+ start ({ args, http = {} }) {
28
28
  const store = storage.getStore()
29
29
  const options = args.options
30
- const agent = options.agent || options._defaultAgent || http.globalAgent
30
+ const agent = options.agent || options._defaultAgent || http.globalAgent || {}
31
31
  const protocol = options.protocol || agent.protocol || 'http:'
32
32
  const hostname = options.hostname || options.host || 'localhost'
33
33
  const host = options.port ? `${hostname}:${options.port}` : hostname
34
- const path = options.path ? options.path.split(/[?#]/)[0] : '/'
34
+ const pathname = options.path || options.pathname
35
+ const path = pathname ? pathname.split(/[?#]/)[0] : '/'
35
36
  const uri = `${protocol}//${host}${path}`
37
+
36
38
  const allowed = this.config.filter(uri)
37
39
 
38
40
  const method = (options.method || 'GET').toUpperCase()
@@ -71,9 +73,11 @@ class HttpClientPlugin extends ClientPlugin {
71
73
  finish ({ req, res }) {
72
74
  const span = storage.getStore().span
73
75
  if (res) {
74
- span.setTag(HTTP_STATUS_CODE, res.statusCode)
76
+ const status = res.status || res.statusCode
77
+
78
+ span.setTag(HTTP_STATUS_CODE, status)
75
79
 
76
- if (!this.config.validateStatus(res.statusCode)) {
80
+ if (!this.config.validateStatus(status)) {
77
81
  span.setTag('error', 1)
78
82
  }
79
83
 
@@ -106,8 +110,14 @@ class HttpClientPlugin extends ClientPlugin {
106
110
  }
107
111
 
108
112
  function addResponseHeaders (res, span, config) {
113
+ if (!res.headers) return
114
+
115
+ const headers = typeof res.headers.entries === 'function'
116
+ ? Object.fromEntries(res.headers.entries())
117
+ : res.headers
118
+
109
119
  config.headers.forEach(key => {
110
- const value = res.headers[key]
120
+ const value = headers[key]
111
121
 
112
122
  if (value) {
113
123
  span.setTag(`${HTTP_RESPONSE_HEADERS}.${key}`, value)
@@ -116,8 +126,12 @@ function addResponseHeaders (res, span, config) {
116
126
  }
117
127
 
118
128
  function addRequestHeaders (req, span, config) {
129
+ const headers = req.headers && typeof req.headers.entries === 'function'
130
+ ? Object.fromEntries(req.headers.entries())
131
+ : req.headers || req.getHeaders()
132
+
119
133
  config.headers.forEach(key => {
120
- const value = req.getHeader(key)
134
+ const value = headers[key]
121
135
 
122
136
  if (value) {
123
137
  span.setTag(`${HTTP_REQUEST_HEADERS}.${key}`, Array.isArray(value) ? value.toString() : value)
@@ -193,7 +207,9 @@ function hasAmazonSignature (options) {
193
207
  }
194
208
  }
195
209
 
196
- return options.path && options.path.toLowerCase().indexOf('x-amz-signature=') !== -1
210
+ const search = options.search || options.path
211
+
212
+ return search && search.toLowerCase().indexOf('x-amz-signature=') !== -1
197
213
  }
198
214
 
199
215
  function getServiceName (tracer, config, options) {
@@ -8,9 +8,8 @@ class MySQLPlugin extends DatabasePlugin {
8
8
  static get system () { return 'mysql' }
9
9
 
10
10
  start (payload) {
11
- const service = getServiceName(this.config, payload.conf)
12
-
13
- this.startSpan(`${this.system}.query`, {
11
+ const service = this.serviceName(this.config, payload.conf, this.system)
12
+ this.startSpan(this.operationName(), {
14
13
  service,
15
14
  resource: payload.sql,
16
15
  type: 'sql',
@@ -27,12 +26,4 @@ class MySQLPlugin extends DatabasePlugin {
27
26
  }
28
27
  }
29
28
 
30
- function getServiceName (config, dbConfig) {
31
- if (typeof config.service === 'function') {
32
- return config.service(dbConfig)
33
- }
34
-
35
- return config.service
36
- }
37
-
38
29
  module.exports = MySQLPlugin
@@ -9,8 +9,8 @@ class TediousPlugin extends DatabasePlugin {
9
9
  static get system () { return 'mssql' }
10
10
 
11
11
  start ({ queryOrProcedure, connectionConfig }) {
12
- this.startSpan('tedious.request', {
13
- service: this.config.service,
12
+ this.startSpan(this.operationName(), {
13
+ service: this.serviceName(this.config, this.system),
14
14
  resource: queryOrProcedure,
15
15
  type: 'sql',
16
16
  kind: 'client',
@@ -4,9 +4,12 @@ module.exports = {
4
4
  'COMMAND_INJECTION_ANALYZER': require('./command-injection-analyzer'),
5
5
  'INSECURE_COOKIE_ANALYZER': require('./insecure-cookie-analyzer'),
6
6
  'LDAP_ANALYZER': require('./ldap-injection-analyzer'),
7
+ 'NO_HTTPONLY_COOKIE_ANALYZER': require('./no-httponly-cookie-analyzer'),
8
+ 'NO_SAMESITE_COOKIE_ANALYZER': require('./no-samesite-cookie-analyzer'),
7
9
  'PATH_TRAVERSAL_ANALYZER': require('./path-traversal-analyzer'),
8
10
  'SQL_INJECTION_ANALYZER': require('./sql-injection-analyzer'),
9
11
  'SSRF': require('./ssrf-analyzer'),
12
+ 'UNVALIDATED_REDIRECT_ANALYZER': require('./unvalidated-redirect-analyzer'),
10
13
  'WEAK_CIPHER_ANALYZER': require('./weak-cipher-analyzer'),
11
14
  'WEAK_HASH_ANALYZER': require('./weak-hash-analyzer')
12
15
  }