newrelic 8.4.0 → 8.5.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.
- package/NEWS.md +45 -29
- package/THIRD_PARTY_NOTICES.md +61 -32
- package/lib/feature_flags.js +7 -5
- package/lib/instrumentation/core/http-outbound.js +1 -1
- package/lib/instrumentation/fastify/spec-builders.js +57 -47
- package/lib/instrumentation/fastify.js +85 -24
- package/lib/instrumentation/undici.js +242 -0
- package/lib/instrumentations.js +1 -0
- package/package.json +5 -4
package/NEWS.md
CHANGED
|
@@ -1,37 +1,53 @@
|
|
|
1
|
-
### v8.
|
|
2
|
-
|
|
1
|
+
### v8.5.0 (2021-10-12)
|
|
2
|
+
|
|
3
|
+
* Added full support for Fastify v2 and v3. Fastify instrumentation is now GA.
|
|
4
|
+
* Removed fastify feature flag.
|
|
5
|
+
* Instrumented Fastify routes by wrapping `addHook`.
|
|
6
|
+
* Added middleware mounting for fastify v3.
|
|
7
|
+
* Fixed capturing of mount point for middleware naming.
|
|
8
|
+
* Fixed the WebFramework spec definitions for Fastify middleware and route handlers to properly retrieve the IncomingMessage from a request object.
|
|
9
|
+
* Added proper definition to middleware handlers so that the relationship to consecutive middleware and route handler are siblings and not direct children.
|
|
10
|
+
|
|
11
|
+
* Added experimental instrumentation for the [undici](https://github.com/nodejs/undici) http client behind a feature flag.
|
|
12
|
+
|
|
13
|
+
To enable undici support, add the following into your config: `{ feature_flag: { undici_instrumentation: true } }`. The support for undici client is Node.js 16.x as it takes advantage of the [diagnostics_channel](https://nodejs.org/dist/latest-v16.x/docs/api/diagnostics_channel.html). Lastly, you must be using [v4.7.0+](https://github.com/nodejs/undici/releases/tag/v4.7.0) of the undici client for any of the instrumentation to work.
|
|
14
|
+
|
|
15
|
+
Note: There are currently some state issues if requests to an app are made with keep alive and you have multiple undici requests being made in parallel. In this case, set feature_flag: `{ undici_async_tracking: false }` which avoids these state issues at the cost of some broken segment nesting.
|
|
16
|
+
|
|
17
|
+
### v8.4.0 (2021-09-28)
|
|
18
|
+
|
|
3
19
|
* **Deprecation Warning**: Cross Application Tracing (CAT) has been deprecated and will be removed in a future major release. For applications that explicitly disable Distributed Tracing (DT) to leverage CAT, we recommend migrating to DT to avoid loss of cross-service visibility.
|
|
4
20
|
* Disables CAT by default. You must explicitly enable CAT along with turning off DT.
|
|
5
|
-
* Adds a deprecation warning when CAT is enabled and active (DT disabled).
|
|
6
|
-
|
|
21
|
+
* Adds a deprecation warning when CAT is enabled and active (DT disabled).
|
|
22
|
+
|
|
7
23
|
* Fixed issue with `clearTimeout` that could result in dropping parent segments or spans.
|
|
8
24
|
|
|
9
|
-
This bug resulted in some MongoDB calls being dropped from Transaction Traces and Distributed Traces (spans): https://github.com/newrelic/node-newrelic/issues/922.
|
|
10
|
-
|
|
11
|
-
* Removed warnings from agent tests for `no-var` eslint rule.
|
|
12
|
-
|
|
13
|
-
* Added support for Cassandra driver v4.0.0 and above.
|
|
14
|
-
|
|
15
|
-
* Fixed issue where DT headers would not be processed by `transaction-shim.handleCATHeaders()` when CAT was explicitly disabled. This primarily impacts `amqplib` instrumentation.
|
|
16
|
-
|
|
17
|
-
* Transitioned aws-lambda.test.js to use Tap over Mocha.
|
|
18
|
-
|
|
19
|
-
* Removed warnings from agent for `no-var` eslint rule.
|
|
20
|
-
|
|
21
|
-
* Refactored `transaction-shim`, `http` and `http-outbound` to use centralized CAT methods in `util/cat`
|
|
22
|
-
|
|
23
|
-
* Replaced http-outbound test call to use example.com to avoid unpredictable connection resets.
|
|
24
|
-
|
|
25
|
-
* Migrated sql query parser tests to tap
|
|
26
|
-
|
|
25
|
+
This bug resulted in some MongoDB calls being dropped from Transaction Traces and Distributed Traces (spans): https://github.com/newrelic/node-newrelic/issues/922.
|
|
26
|
+
|
|
27
|
+
* Removed warnings from agent tests for `no-var` eslint rule.
|
|
28
|
+
|
|
29
|
+
* Added support for Cassandra driver v4.0.0 and above.
|
|
30
|
+
|
|
31
|
+
* Fixed issue where DT headers would not be processed by `transaction-shim.handleCATHeaders()` when CAT was explicitly disabled. This primarily impacts `amqplib` instrumentation.
|
|
32
|
+
|
|
33
|
+
* Transitioned aws-lambda.test.js to use Tap over Mocha.
|
|
34
|
+
|
|
35
|
+
* Removed warnings from agent for `no-var` eslint rule.
|
|
36
|
+
|
|
37
|
+
* Refactored `transaction-shim`, `http` and `http-outbound` to use centralized CAT methods in `util/cat`
|
|
38
|
+
|
|
39
|
+
* Replaced http-outbound test call to use example.com to avoid unpredictable connection resets.
|
|
40
|
+
|
|
41
|
+
* Migrated sql query parser tests to tap
|
|
42
|
+
|
|
27
43
|
* Added more API usage examples.
|
|
28
|
-
|
|
29
|
-
* Added a README to the `examples/` folder discussing how to use the examples.
|
|
30
|
-
|
|
31
|
-
* Fixed `message-shim` test assertion to avoid flakiness based on precision differences(ms vs ns)
|
|
32
|
-
|
|
33
|
-
* Applied new lint rules barring the use of `var` and preferring the use of `const` wherever possible.
|
|
34
|
-
|
|
44
|
+
|
|
45
|
+
* Added a README to the `examples/` folder discussing how to use the examples.
|
|
46
|
+
|
|
47
|
+
* Fixed `message-shim` test assertion to avoid flakiness based on precision differences(ms vs ns)
|
|
48
|
+
|
|
49
|
+
* Applied new lint rules barring the use of `var` and preferring the use of `const` wherever possible.
|
|
50
|
+
|
|
35
51
|
### v8.3.0 (2021-09-09)
|
|
36
52
|
|
|
37
53
|
* Enabled Distributed Tracing (DT) by default.
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -41,7 +41,9 @@ code, the source code can be found at [https://github.com/newrelic/node-newrelic
|
|
|
41
41
|
* [chai](#chai)
|
|
42
42
|
* [commander](#commander)
|
|
43
43
|
* [eslint-config-prettier](#eslint-config-prettier)
|
|
44
|
+
* [eslint-plugin-disable](#eslint-plugin-disable)
|
|
44
45
|
* [eslint-plugin-header](#eslint-plugin-header)
|
|
46
|
+
* [eslint-plugin-jsdoc](#eslint-plugin-jsdoc)
|
|
45
47
|
* [eslint-plugin-node](#eslint-plugin-node)
|
|
46
48
|
* [eslint-plugin-prettier](#eslint-plugin-prettier)
|
|
47
49
|
* [eslint](#eslint)
|
|
@@ -49,7 +51,6 @@ code, the source code can be found at [https://github.com/newrelic/node-newrelic
|
|
|
49
51
|
* [generic-pool](#generic-pool)
|
|
50
52
|
* [glob](#glob)
|
|
51
53
|
* [got](#got)
|
|
52
|
-
* [http-errors](#http-errors)
|
|
53
54
|
* [husky](#husky)
|
|
54
55
|
* [jsdoc](#jsdoc)
|
|
55
56
|
* [lint-staged](#lint-staged)
|
|
@@ -2210,6 +2211,33 @@ THE SOFTWARE.
|
|
|
2210
2211
|
|
|
2211
2212
|
```
|
|
2212
2213
|
|
|
2214
|
+
### eslint-plugin-disable
|
|
2215
|
+
|
|
2216
|
+
This product includes source derived from [eslint-plugin-disable](https://github.com/mradionov/eslint-plugin-disable) ([v2.0.1](https://github.com/mradionov/eslint-plugin-disable/tree/v2.0.1)), distributed under the [MIT License](https://github.com/mradionov/eslint-plugin-disable/blob/v2.0.1/LICENSE):
|
|
2217
|
+
|
|
2218
|
+
```
|
|
2219
|
+
Copyright (c) 2015 Michael Radionov (https://github.com/mradionov)
|
|
2220
|
+
|
|
2221
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
2222
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
2223
|
+
in the Software without restriction, including without limitation the rights
|
|
2224
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
2225
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
2226
|
+
furnished to do so, subject to the following conditions:
|
|
2227
|
+
|
|
2228
|
+
The above copyright notice and this permission notice shall be included in
|
|
2229
|
+
all copies or substantial portions of the Software.
|
|
2230
|
+
|
|
2231
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
2232
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
2233
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
2234
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
2235
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
2236
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
2237
|
+
THE SOFTWARE.
|
|
2238
|
+
|
|
2239
|
+
```
|
|
2240
|
+
|
|
2213
2241
|
### eslint-plugin-header
|
|
2214
2242
|
|
|
2215
2243
|
This product includes source derived from [eslint-plugin-header](https://github.com/Stuk/eslint-plugin-header) ([v3.1.1](https://github.com/Stuk/eslint-plugin-header/tree/v3.1.1)), distributed under the [MIT License](https://github.com/Stuk/eslint-plugin-header/blob/v3.1.1/README.md):
|
|
@@ -2226,6 +2254,38 @@ The above copyright notice and this permission notice shall be included in all c
|
|
|
2226
2254
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
2227
2255
|
```
|
|
2228
2256
|
|
|
2257
|
+
### eslint-plugin-jsdoc
|
|
2258
|
+
|
|
2259
|
+
This product includes source derived from [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc) ([v36.1.0](https://github.com/gajus/eslint-plugin-jsdoc/tree/v36.1.0)), distributed under the [BSD-3-Clause License](https://github.com/gajus/eslint-plugin-jsdoc/blob/v36.1.0/LICENSE):
|
|
2260
|
+
|
|
2261
|
+
```
|
|
2262
|
+
Copyright (c) 2018, Gajus Kuizinas (http://gajus.com/)
|
|
2263
|
+
All rights reserved.
|
|
2264
|
+
|
|
2265
|
+
Redistribution and use in source and binary forms, with or without
|
|
2266
|
+
modification, are permitted provided that the following conditions are met:
|
|
2267
|
+
* Redistributions of source code must retain the above copyright
|
|
2268
|
+
notice, this list of conditions and the following disclaimer.
|
|
2269
|
+
* Redistributions in binary form must reproduce the above copyright
|
|
2270
|
+
notice, this list of conditions and the following disclaimer in the
|
|
2271
|
+
documentation and/or other materials provided with the distribution.
|
|
2272
|
+
* Neither the name of the Gajus Kuizinas (http://gajus.com/) nor the
|
|
2273
|
+
names of its contributors may be used to endorse or promote products
|
|
2274
|
+
derived from this software without specific prior written permission.
|
|
2275
|
+
|
|
2276
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
2277
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
2278
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
2279
|
+
DISCLAIMED. IN NO EVENT SHALL ANUARY BE LIABLE FOR ANY
|
|
2280
|
+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
2281
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
2282
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
2283
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
2284
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
2285
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
2286
|
+
|
|
2287
|
+
```
|
|
2288
|
+
|
|
2229
2289
|
### eslint-plugin-node
|
|
2230
2290
|
|
|
2231
2291
|
This product includes source derived from [eslint-plugin-node](https://github.com/mysticatea/eslint-plugin-node) ([v11.1.0](https://github.com/mysticatea/eslint-plugin-node/tree/v11.1.0)), distributed under the [MIT License](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/LICENSE):
|
|
@@ -2409,37 +2469,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|
|
2409
2469
|
|
|
2410
2470
|
```
|
|
2411
2471
|
|
|
2412
|
-
### http-errors
|
|
2413
|
-
|
|
2414
|
-
This product includes source derived from [http-errors](https://github.com/jshttp/http-errors) ([v1.8.0](https://github.com/jshttp/http-errors/tree/v1.8.0)), distributed under the [MIT License](https://github.com/jshttp/http-errors/blob/v1.8.0/LICENSE):
|
|
2415
|
-
|
|
2416
|
-
```
|
|
2417
|
-
|
|
2418
|
-
The MIT License (MIT)
|
|
2419
|
-
|
|
2420
|
-
Copyright (c) 2014 Jonathan Ong me@jongleberry.com
|
|
2421
|
-
Copyright (c) 2016 Douglas Christopher Wilson doug@somethingdoug.com
|
|
2422
|
-
|
|
2423
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
2424
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
2425
|
-
in the Software without restriction, including without limitation the rights
|
|
2426
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
2427
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
2428
|
-
furnished to do so, subject to the following conditions:
|
|
2429
|
-
|
|
2430
|
-
The above copyright notice and this permission notice shall be included in
|
|
2431
|
-
all copies or substantial portions of the Software.
|
|
2432
|
-
|
|
2433
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
2434
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
2435
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
2436
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
2437
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
2438
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
2439
|
-
THE SOFTWARE.
|
|
2440
|
-
|
|
2441
|
-
```
|
|
2442
|
-
|
|
2443
2472
|
### husky
|
|
2444
2473
|
|
|
2445
2474
|
This product includes source derived from [husky](https://github.com/typicode/husky) ([v6.0.0](https://github.com/typicode/husky/tree/v6.0.0)), distributed under the [MIT License](https://github.com/typicode/husky/blob/v6.0.0/LICENSE):
|
package/lib/feature_flags.js
CHANGED
|
@@ -7,13 +7,14 @@
|
|
|
7
7
|
|
|
8
8
|
// unreleased flags gating an active feature
|
|
9
9
|
exports.prerelease = {
|
|
10
|
-
express5: false,
|
|
11
10
|
await_support: true,
|
|
12
|
-
promise_segments: false,
|
|
13
|
-
reverse_naming_rules: false,
|
|
14
|
-
fastify_instrumentation: false,
|
|
15
11
|
certificate_bundle: false,
|
|
12
|
+
express5: false,
|
|
16
13
|
new_promise_tracking: false,
|
|
14
|
+
promise_segments: false,
|
|
15
|
+
reverse_naming_rules: false,
|
|
16
|
+
undici_instrumentation: false,
|
|
17
|
+
undici_async_tracking: true,
|
|
17
18
|
unresolved_promise_cleanup: true
|
|
18
19
|
}
|
|
19
20
|
|
|
@@ -29,7 +30,8 @@ exports.released = [
|
|
|
29
30
|
'serverless_mode',
|
|
30
31
|
'send_request_uri_attribute',
|
|
31
32
|
'synthetics',
|
|
32
|
-
'dt_format_w3c'
|
|
33
|
+
'dt_format_w3c',
|
|
34
|
+
'fastify_instrumentation'
|
|
33
35
|
]
|
|
34
36
|
|
|
35
37
|
// flags that are no longer used for unreleased features
|
|
@@ -96,7 +96,7 @@ module.exports = function instrumentOutbound(agent, opts, makeRequest) {
|
|
|
96
96
|
} else if (agent.config.cross_application_tracer.enabled) {
|
|
97
97
|
cat.addCatHeaders(agent.config, transaction, outboundHeaders)
|
|
98
98
|
} else {
|
|
99
|
-
logger.trace('CAT disabled, not adding headers!')
|
|
99
|
+
logger.trace('Both DT and CAT are disabled, not adding headers!')
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
if (Array.isArray(opts.headers)) {
|
|
@@ -1,19 +1,43 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2021 New Relic Corporation. All rights reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Retrieves the IncomingMessage from a Fastify request. Depending on the
|
|
10
|
+
* context of this function it either exists on `request.raw` or just `request`
|
|
11
|
+
*
|
|
12
|
+
* @param {WebFrameworkShim} shim
|
|
13
|
+
* @param {Function} fn middleware function executing
|
|
14
|
+
* @param {string} fnName name of middleware executing
|
|
15
|
+
* @param {args} args that are passed to middleware
|
|
16
|
+
* @returns {IncomingMessage}
|
|
17
|
+
*/
|
|
18
|
+
const getRequestFromFastify = (shim, fn, fnName, args) => {
|
|
19
|
+
const [request] = args
|
|
20
|
+
|
|
21
|
+
// request is Fastify request
|
|
22
|
+
// object, get IncomingMessage from .raw
|
|
10
23
|
if (request && request.raw) {
|
|
11
24
|
return request.raw
|
|
12
25
|
}
|
|
26
|
+
|
|
27
|
+
return request
|
|
13
28
|
}
|
|
14
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Retrieves the params from the Fastify request.
|
|
32
|
+
*
|
|
33
|
+
* @param {WebFrameworkShim} shim
|
|
34
|
+
* @param {Function} fn middleware function executing
|
|
35
|
+
* @param {string} fnName name of middleware executing
|
|
36
|
+
* @param {args} args that are passed to middleware
|
|
37
|
+
* @returns {object} URL params on a Fastify request
|
|
38
|
+
*/
|
|
15
39
|
const getParamsFromFastifyRequest = (shim, fn, fnName, args) => {
|
|
16
|
-
const req = args
|
|
40
|
+
const [req] = args
|
|
17
41
|
return req && req.params
|
|
18
42
|
}
|
|
19
43
|
|
|
@@ -21,32 +45,17 @@ const getParamsFromFastifyRequest = (shim, fn, fnName, args) => {
|
|
|
21
45
|
* Builds the recordMiddleware Spec for the route handler
|
|
22
46
|
*
|
|
23
47
|
* A spec is basically a specification -- or a list
|
|
24
|
-
* of
|
|
48
|
+
* of instructions to the recordMiddleware function
|
|
25
49
|
* that provide it with the information it needs to
|
|
26
50
|
* do its job. You could also think of it as a
|
|
27
51
|
* mini-DSL
|
|
52
|
+
*
|
|
53
|
+
* @param {WebFrameworkShim} shim
|
|
54
|
+
* @param {string} path URL route being executed
|
|
55
|
+
* @returns {object} spec for Fastify route handler
|
|
28
56
|
*/
|
|
29
57
|
function buildMiddlewareSpecForRouteHandler(shim, path) {
|
|
30
58
|
return {
|
|
31
|
-
/**
|
|
32
|
-
* The path to use for transaction naming
|
|
33
|
-
*/
|
|
34
|
-
route: path,
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* A function the returns the NodeJS Request Object
|
|
38
|
-
*
|
|
39
|
-
* The job of the `req` callback is to return the current NodeJS
|
|
40
|
-
* IncomingMessage object for this particular handler. Most NodeJS
|
|
41
|
-
* frameworks will pass the request to each handler -- sometimes (as
|
|
42
|
-
* is the case here) wrapped by another object.
|
|
43
|
-
*
|
|
44
|
-
* @param {any} shim the Webframework Shim
|
|
45
|
-
* @param {any} fn the handler function passed to buildMiddlewareSpec
|
|
46
|
-
* @param {any} fnName the handler function's name
|
|
47
|
-
* @param {any} args the arguments passed to the handler function
|
|
48
|
-
*/
|
|
49
|
-
req: getRawRequestFromFastifyRequest,
|
|
50
59
|
/**
|
|
51
60
|
* A function where we can wrap next, reply send, etc. methods
|
|
52
61
|
*
|
|
@@ -66,6 +75,12 @@ function buildMiddlewareSpecForRouteHandler(shim, path) {
|
|
|
66
75
|
* The isFinal param determines whether or not a path is appended for
|
|
67
76
|
* this particular piece of middleware. (i.e. if this is the final handler
|
|
68
77
|
* that is actually handling the request, the path is actually left on)
|
|
78
|
+
*
|
|
79
|
+
* @param shim
|
|
80
|
+
* @param fn
|
|
81
|
+
* @param fnName
|
|
82
|
+
* @param args
|
|
83
|
+
* @param bindSegment
|
|
69
84
|
*/
|
|
70
85
|
next: function wrapNext(shim, fn, fnName, args, bindSegment) {
|
|
71
86
|
const reply = args[1]
|
|
@@ -75,33 +90,28 @@ function buildMiddlewareSpecForRouteHandler(shim, path) {
|
|
|
75
90
|
const isFinal = true
|
|
76
91
|
bindSegment(reply, 'send', isFinal)
|
|
77
92
|
},
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
*
|
|
82
|
-
* @param {any} shim the Webframework Shim
|
|
83
|
-
* @param {any} fn the handler function passed to buildMiddlewareSpec
|
|
84
|
-
* @param {any} fnName the handler function's name
|
|
85
|
-
* @param {any} args the arguments passed to the handler function
|
|
86
|
-
*/
|
|
87
|
-
params: getParamsFromFastifyRequest
|
|
93
|
+
params: getParamsFromFastifyRequest,
|
|
94
|
+
req: getRequestFromFastify,
|
|
95
|
+
route: path
|
|
88
96
|
}
|
|
89
97
|
}
|
|
90
98
|
|
|
91
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Spec for all Fastify middleware(excluding route handlers)
|
|
101
|
+
*
|
|
102
|
+
* @param {WebFrameworkShim} shim
|
|
103
|
+
* @param {string} name metric name for middleware being executed
|
|
104
|
+
* @param route
|
|
105
|
+
* @returns {object} spec for Fastify middleware
|
|
106
|
+
*/
|
|
107
|
+
function buildMiddlewareSpecForMiddlewareFunction(shim, name, route) {
|
|
92
108
|
return {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
next:
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
const isFinal = false
|
|
101
|
-
bindSegment(next, null, isFinal)
|
|
102
|
-
},
|
|
103
|
-
|
|
104
|
-
params: getParamsFromFastifyRequest
|
|
109
|
+
name,
|
|
110
|
+
route,
|
|
111
|
+
next: shim.LAST,
|
|
112
|
+
params: getParamsFromFastifyRequest,
|
|
113
|
+
req: getRequestFromFastify,
|
|
114
|
+
type: shim.MIDDLEWARE
|
|
105
115
|
}
|
|
106
116
|
}
|
|
107
117
|
|
|
@@ -4,11 +4,33 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
|
+
|
|
7
8
|
const semver = require('semver')
|
|
8
9
|
const {
|
|
9
10
|
buildMiddlewareSpecForRouteHandler,
|
|
10
11
|
buildMiddlewareSpecForMiddlewareFunction
|
|
11
12
|
} = require('./fastify/spec-builders')
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* These are the events that occur during a fastify
|
|
16
|
+
* request
|
|
17
|
+
* see: https://www.fastify.io/docs/latest/Lifecycle/
|
|
18
|
+
*
|
|
19
|
+
* Note: preSerialization and onSend happen after the route handler
|
|
20
|
+
* executes. `onResponse` does not execute until after the client
|
|
21
|
+
* sends the response so it'll never be in scope of the transaction
|
|
22
|
+
*/
|
|
23
|
+
const REQUEST_HOOKS = [
|
|
24
|
+
'onRequest',
|
|
25
|
+
'preParsing',
|
|
26
|
+
'preValidation',
|
|
27
|
+
'preHandler',
|
|
28
|
+
'preSerialization',
|
|
29
|
+
'onSend',
|
|
30
|
+
'onResponse',
|
|
31
|
+
'onError'
|
|
32
|
+
]
|
|
33
|
+
|
|
12
34
|
/**
|
|
13
35
|
* Sets up fastify route handler
|
|
14
36
|
*
|
|
@@ -20,6 +42,9 @@ const {
|
|
|
20
42
|
* those private implementations from access, and getting
|
|
21
43
|
* at them would require a lot of gymnastics and hard to
|
|
22
44
|
* maintain code
|
|
45
|
+
*
|
|
46
|
+
* @param shim
|
|
47
|
+
* @param fastify
|
|
23
48
|
*/
|
|
24
49
|
const setupRouteHandler = (shim, fastify) => {
|
|
25
50
|
fastify.addHook('onRoute', (routeOptions) => {
|
|
@@ -27,10 +52,10 @@ const setupRouteHandler = (shim, fastify) => {
|
|
|
27
52
|
return
|
|
28
53
|
}
|
|
29
54
|
/**
|
|
30
|
-
*
|
|
55
|
+
* recordMiddleware handler call
|
|
31
56
|
*
|
|
32
57
|
* The WebFramework shim treats the main route handler like any other
|
|
33
|
-
* i.e. dont be confused by the call to
|
|
58
|
+
* i.e. dont be confused by the call to recordMiddleware -- we don't
|
|
34
59
|
* have a recordRouteHandler, everything goes through recordMiddleware
|
|
35
60
|
*/
|
|
36
61
|
const newRouteHandler = shim.recordMiddleware(
|
|
@@ -40,29 +65,25 @@ const setupRouteHandler = (shim, fastify) => {
|
|
|
40
65
|
|
|
41
66
|
routeOptions.handler = newRouteHandler
|
|
42
67
|
})
|
|
43
|
-
}
|
|
44
68
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return function wrappedFastifyUser() {
|
|
69
|
+
shim.wrap(fastify, 'addHook', function addWrapHook(shim, fn) {
|
|
70
|
+
return function wrappedAddHook() {
|
|
48
71
|
const args = shim.argsToArray.apply(shim, arguments)
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
middlewareFunction
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
args[0] = newMiddlewareFunction
|
|
72
|
+
const hookName = args[0]
|
|
73
|
+
if (REQUEST_HOOKS.includes(hookName)) {
|
|
74
|
+
const middlewareFunction = args[1]
|
|
75
|
+
const name = `${hookName}/${shim.getName(middlewareFunction)}`
|
|
76
|
+
const middlewareSpec = buildMiddlewareSpecForMiddlewareFunction(shim, name)
|
|
77
|
+
const newMiddlewareFunction = shim.recordMiddleware(middlewareFunction, middlewareSpec)
|
|
56
78
|
|
|
79
|
+
args[1] = newMiddlewareFunction
|
|
80
|
+
}
|
|
57
81
|
return fn.apply(this, args)
|
|
58
82
|
}
|
|
59
83
|
})
|
|
60
84
|
}
|
|
61
85
|
|
|
62
86
|
module.exports = function initialize(agent, fastify, moduleName, shim) {
|
|
63
|
-
if (!agent.config.feature_flag.fastify_instrumentation) {
|
|
64
|
-
return
|
|
65
|
-
}
|
|
66
87
|
shim.setFramework(shim.FASTIFY)
|
|
67
88
|
|
|
68
89
|
const fastifyVersion = shim.require('./package.json').version
|
|
@@ -73,18 +94,12 @@ module.exports = function initialize(agent, fastify, moduleName, shim) {
|
|
|
73
94
|
*/
|
|
74
95
|
const wrappedExport = shim.wrapExport(fastify, function wrapFastifyModule(shim, fn) {
|
|
75
96
|
return function wrappedFastifyModule() {
|
|
76
|
-
// normalize arguments
|
|
77
|
-
const args = shim.argsToArray.apply(shim, arguments)
|
|
78
|
-
|
|
79
97
|
// call original function get get fastify object (which is singleton-ish)
|
|
80
|
-
const fastifyForWrapping = fn.apply(this,
|
|
98
|
+
const fastifyForWrapping = fn.apply(this, arguments)
|
|
81
99
|
|
|
82
100
|
setupRouteHandler(shim, fastifyForWrapping)
|
|
83
101
|
|
|
84
|
-
|
|
85
|
-
if (!isv3Plus) {
|
|
86
|
-
setupMiddlewareHandlers(shim, fastifyForWrapping)
|
|
87
|
-
}
|
|
102
|
+
setupMiddlewareHandlers(shim, fastifyForWrapping, isv3Plus)
|
|
88
103
|
|
|
89
104
|
return fastifyForWrapping
|
|
90
105
|
}
|
|
@@ -95,10 +110,56 @@ module.exports = function initialize(agent, fastify, moduleName, shim) {
|
|
|
95
110
|
}
|
|
96
111
|
}
|
|
97
112
|
|
|
113
|
+
function setupMiddlewareHandlers(shim, fastify, isv3Plus) {
|
|
114
|
+
const mounterSpec = {
|
|
115
|
+
route: shim.FIRST,
|
|
116
|
+
wrapper: wrapMiddleware
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (isv3Plus) {
|
|
120
|
+
// Fastify v3+ does not ship with traditional Node.js middleware mounting.
|
|
121
|
+
// This style is accomplished leveraging decorators. Both middie (which was built-in in v2)
|
|
122
|
+
// and fastify-express mount a 'use' function for mounting middleware.
|
|
123
|
+
shim.wrap(fastify, 'decorate', function wrapDecorate(shim, fn) {
|
|
124
|
+
return function wrappedDecorate() {
|
|
125
|
+
const name = arguments[0]
|
|
126
|
+
if (name !== 'use') {
|
|
127
|
+
return fn.apply(this, arguments)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const args = shim.argsToArray.apply(shim, arguments)
|
|
131
|
+
args[1] = shim.wrapMiddlewareMounter(args[1], mounterSpec)
|
|
132
|
+
|
|
133
|
+
return fn.apply(this, args)
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
} else {
|
|
137
|
+
shim.wrapMiddlewareMounter(fastify, 'use', mounterSpec)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function wrapMiddleware(shim, middleware, name, route) {
|
|
142
|
+
if (shim.isWrapped(middleware)) {
|
|
143
|
+
return middleware
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// prefixing the segment name for middleware execution
|
|
147
|
+
// with the Fastify lifecycle hook
|
|
148
|
+
const segmentName = `onRequest/${name}`
|
|
149
|
+
const spec = buildMiddlewareSpecForMiddlewareFunction(shim, segmentName, route)
|
|
150
|
+
|
|
151
|
+
const newMiddlewareFunction = shim.recordMiddleware(middleware, spec)
|
|
152
|
+
|
|
153
|
+
return newMiddlewareFunction
|
|
154
|
+
}
|
|
155
|
+
|
|
98
156
|
/**
|
|
99
157
|
* module.exports = fastify
|
|
100
158
|
* module.exports.fastify = fastify
|
|
101
159
|
* module.exports.default = fastify
|
|
160
|
+
*
|
|
161
|
+
* @param original
|
|
162
|
+
* @param wrappedExport
|
|
102
163
|
*/
|
|
103
164
|
function setupExports(original, wrappedExport) {
|
|
104
165
|
wrappedExport.fastify = original.fastify
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2021 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
const cat = require('../util/cat')
|
|
9
|
+
const recordExternal = require('../metrics/recorders/http_external')
|
|
10
|
+
const logger = require('../logger').child({ component: 'undici' })
|
|
11
|
+
const NAMES = require('../metrics/names')
|
|
12
|
+
const NEWRELIC_SYNTHETICS_HEADER = 'x-newrelic-synthetics'
|
|
13
|
+
const SYMBOLS = {
|
|
14
|
+
SEGMENT: Symbol('__NR_segment'),
|
|
15
|
+
PARENT_SEGMENT: Symbol('__NR_parent_segment')
|
|
16
|
+
}
|
|
17
|
+
const { executionAsyncResource } = require('async_hooks')
|
|
18
|
+
|
|
19
|
+
let diagnosticsChannel = null
|
|
20
|
+
try {
|
|
21
|
+
diagnosticsChannel = require('diagnostics_channel')
|
|
22
|
+
} catch (e) {
|
|
23
|
+
// quick check to see if module exists
|
|
24
|
+
// module was not added until v15.x
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = function addUndiciChannels(agent, undici, modName, shim) {
|
|
28
|
+
if (!diagnosticsChannel || !agent.config.feature_flag.undici_instrumentation) {
|
|
29
|
+
logger.warn(
|
|
30
|
+
'diagnostics_channel or feature_flag.undici_instrumentation = false. Skipping undici instrumentation.'
|
|
31
|
+
)
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Retrieves the current segment in transaction(parent in our context) from executionAsyncResource
|
|
37
|
+
* or from `shim.getSegment()` then adds to the executionAsyncResource for future
|
|
38
|
+
* undici requests within same async context.
|
|
39
|
+
*
|
|
40
|
+
* It was found that when running concurrent undici requests
|
|
41
|
+
* within a transaction that the parent segment would get out of sync
|
|
42
|
+
* depending on the async context of the transaction. By using
|
|
43
|
+
* `async_hooks.executionResource` it is more reliable.
|
|
44
|
+
*
|
|
45
|
+
* Note: However, if you have concurrent undici requests in a transaction
|
|
46
|
+
* and the request to the transaction is using a keep alive there is a chance the
|
|
47
|
+
* executionAsyncResource may be incorrect because of shared connections. To revert to a more
|
|
48
|
+
* naive tracking of parent set `config.feature_flag.undici_async_tracking: false` and
|
|
49
|
+
* it will just call `shim.getSegment()`
|
|
50
|
+
*/
|
|
51
|
+
function getParentSegment() {
|
|
52
|
+
if (agent.config.feature_flag.undici_async_tracking) {
|
|
53
|
+
const resource = executionAsyncResource()
|
|
54
|
+
|
|
55
|
+
if (!resource[SYMBOLS.PARENT_SEGMENT]) {
|
|
56
|
+
const parent = shim.getSegment()
|
|
57
|
+
resource[SYMBOLS.PARENT_SEGMENT] = parent
|
|
58
|
+
}
|
|
59
|
+
return resource[SYMBOLS.PARENT_SEGMENT]
|
|
60
|
+
}
|
|
61
|
+
return shim.getSegment()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* This event occurs after the Undici Request is created
|
|
66
|
+
* We will check current segment for opaque and also attach
|
|
67
|
+
* relevant headers to outgoing http request
|
|
68
|
+
*
|
|
69
|
+
* @param {object} params
|
|
70
|
+
* @param {object} params.request undici request object
|
|
71
|
+
*/
|
|
72
|
+
diagnosticsChannel.channel('undici:request:create').subscribe(({ request }) => {
|
|
73
|
+
const parent = getParentSegment()
|
|
74
|
+
request[SYMBOLS.PARENT_SEGMENT] = parent
|
|
75
|
+
if (!parent || (parent && parent.opaque)) {
|
|
76
|
+
logger.trace(
|
|
77
|
+
'Not capturing data for outbound request (%s) because parent segment opaque (%s)',
|
|
78
|
+
request.path,
|
|
79
|
+
parent && parent.name
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const transaction = parent.transaction
|
|
86
|
+
const outboundHeaders = Object.create(null)
|
|
87
|
+
if (agent.config.encoding_key && transaction.syntheticsHeader) {
|
|
88
|
+
outboundHeaders[NEWRELIC_SYNTHETICS_HEADER] = transaction.syntheticsHeader
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (agent.config.distributed_tracing.enabled) {
|
|
92
|
+
transaction.insertDistributedTraceHeaders(outboundHeaders)
|
|
93
|
+
} else if (agent.config.cross_application_tracer.enabled) {
|
|
94
|
+
cat.addCatHeaders(agent.config, transaction, outboundHeaders)
|
|
95
|
+
} else {
|
|
96
|
+
logger.trace('Both DT and CAT are disabled, not adding headers!')
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// eslint-disable-next-line guard-for-in
|
|
100
|
+
for (const key in outboundHeaders) {
|
|
101
|
+
request.addHeader(key, outboundHeaders[key])
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* This event occurs right before the data is written to the socket.
|
|
107
|
+
* Undici has some abstracted headers that are only created at this time, one
|
|
108
|
+
* is the `host` header which we need to name the Undici segment. So in this
|
|
109
|
+
* handler we create, start and set the segment active, name it, and
|
|
110
|
+
* attach the url/procedure/request.parameters
|
|
111
|
+
*
|
|
112
|
+
* @param {object} params
|
|
113
|
+
* @param {object} params.request undicie request object
|
|
114
|
+
* @param {TLSSocket | net.Socket} socket active socket connection
|
|
115
|
+
*/
|
|
116
|
+
diagnosticsChannel.channel('undici:client:sendHeaders').subscribe(({ request, socket }) => {
|
|
117
|
+
const parentSegment = request[SYMBOLS.PARENT_SEGMENT]
|
|
118
|
+
if (!parentSegment || (parentSegment && parentSegment.opaque)) {
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const port = socket.remotePort
|
|
123
|
+
const isHttps = socket.servername
|
|
124
|
+
let urlString
|
|
125
|
+
if (isHttps) {
|
|
126
|
+
urlString = `https://${socket.servername}`
|
|
127
|
+
urlString += port === 443 ? request.path : `:${port}${request.path}`
|
|
128
|
+
} else {
|
|
129
|
+
urlString = `http://${socket._host}`
|
|
130
|
+
urlString += port === 80 ? request.path : `:${port}${request.path}`
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const url = new URL(urlString)
|
|
134
|
+
|
|
135
|
+
const name = NAMES.EXTERNAL.PREFIX + url.host + url.pathname
|
|
136
|
+
const segment = shim.createSegment(name, recordExternal(url.host, 'undici'), parentSegment)
|
|
137
|
+
if (segment) {
|
|
138
|
+
segment.start()
|
|
139
|
+
shim.setActiveSegment(segment)
|
|
140
|
+
segment.addAttribute('url', `${url.protocol}//${url.host}${url.pathname}`)
|
|
141
|
+
|
|
142
|
+
url.searchParams.forEach((value, key) => {
|
|
143
|
+
segment.addSpanAttribute(`request.parameters.${key}`, value)
|
|
144
|
+
})
|
|
145
|
+
segment.addAttribute('procedure', request.method || 'GET')
|
|
146
|
+
request[SYMBOLS.SEGMENT] = segment
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* This event occurs after the response headers have been received.
|
|
152
|
+
* We will add the relevant http response attributes to active segment.
|
|
153
|
+
* Also add CAT specific keys to active segment.
|
|
154
|
+
*
|
|
155
|
+
* @param {object} params
|
|
156
|
+
* @param {object} params.request undici request object
|
|
157
|
+
* @param {object} params.response { statusCode, headers, statusText }
|
|
158
|
+
*/
|
|
159
|
+
diagnosticsChannel.channel('undici:request:headers').subscribe(({ request, response }) => {
|
|
160
|
+
const activeSegment = request[SYMBOLS.SEGMENT]
|
|
161
|
+
if (!activeSegment) {
|
|
162
|
+
return
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
activeSegment.addSpanAttribute('http.statusCode', response.statusCode)
|
|
166
|
+
activeSegment.addSpanAttribute('http.statusText', response.statusText)
|
|
167
|
+
|
|
168
|
+
if (
|
|
169
|
+
agent.config.cross_application_tracer.enabled &&
|
|
170
|
+
!agent.config.distributed_tracing.enabled
|
|
171
|
+
) {
|
|
172
|
+
try {
|
|
173
|
+
const { appData } = cat.extractCatHeaders(response.headers)
|
|
174
|
+
const decodedAppData = cat.parseAppData(agent.config, appData)
|
|
175
|
+
const attrs = activeSegment.getAttributes()
|
|
176
|
+
const url = new URL(attrs.url)
|
|
177
|
+
cat.assignCatToSegment(decodedAppData, activeSegment, url.host)
|
|
178
|
+
} catch (err) {
|
|
179
|
+
logger.warn(err, 'Cannot add CAT data to segment')
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* This event occurs after the response body has been received.
|
|
186
|
+
* We will end the active segment and set the active back to parent before request
|
|
187
|
+
*
|
|
188
|
+
* @param {object} params.request undici request object
|
|
189
|
+
*/
|
|
190
|
+
diagnosticsChannel.channel('undici:request:trailers').subscribe(({ request }) => {
|
|
191
|
+
endAndRestoreSegment(request)
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* This event occurs right before the request emits an error.
|
|
196
|
+
* We will end the active segment and set the active back to parent before request.
|
|
197
|
+
* We will also log errors to NR
|
|
198
|
+
*
|
|
199
|
+
* Note: This event occurs before the error handler so we will always log it for now.
|
|
200
|
+
*/
|
|
201
|
+
diagnosticsChannel.channel('undici:request:error').subscribe(({ request, error }) => {
|
|
202
|
+
endAndRestoreSegment(request, error)
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Gets the active and parent from given ctx(request, client connector)
|
|
207
|
+
* and ends active and restores parent to active. If an error exists
|
|
208
|
+
* it will add the error to the transaction
|
|
209
|
+
*
|
|
210
|
+
* @param {object} ctx request or client connector
|
|
211
|
+
* @param {Error} error
|
|
212
|
+
*/
|
|
213
|
+
function endAndRestoreSegment(ctx, error) {
|
|
214
|
+
const activeSegment = ctx[SYMBOLS.SEGMENT]
|
|
215
|
+
const parentSegment = ctx[SYMBOLS.PARENT_SEGMENT]
|
|
216
|
+
if (activeSegment) {
|
|
217
|
+
activeSegment.end()
|
|
218
|
+
|
|
219
|
+
if (error) {
|
|
220
|
+
handleError(activeSegment, error)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (parentSegment) {
|
|
224
|
+
shim.setActiveSegment(parentSegment)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Adds the error to the active transaction
|
|
231
|
+
*
|
|
232
|
+
* @param {TraceSegment} activeSegment
|
|
233
|
+
* @param {Error} error
|
|
234
|
+
*/
|
|
235
|
+
function handleError(activeSegment, error) {
|
|
236
|
+
logger.trace(error, 'Captured outbound error on behalf of the user.')
|
|
237
|
+
const tx = activeSegment.transaction
|
|
238
|
+
shim.agent.errors.add(tx, error)
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
module.exports.SYMBOLS = SYMBOLS
|
package/lib/instrumentations.js
CHANGED
|
@@ -31,6 +31,7 @@ module.exports = function instrumentations() {
|
|
|
31
31
|
'redis': { type: MODULE_TYPE.DATASTORE },
|
|
32
32
|
'restify': { type: MODULE_TYPE.WEB_FRAMEWORK },
|
|
33
33
|
'superagent': { module: '@newrelic/superagent' },
|
|
34
|
+
'undici': { type: MODULE_TYPE.TRANSACTION },
|
|
34
35
|
'oracle': { type: null },
|
|
35
36
|
'vision': { type: MODULE_TYPE.WEB_FRAMEWORK },
|
|
36
37
|
'when': { type: null }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "newrelic",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.5.0",
|
|
4
4
|
"author": "New Relic Node.js agent team <nodejs@newrelic.com>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"contributors": [
|
|
@@ -134,8 +134,8 @@
|
|
|
134
134
|
"docs": "npm ci && jsdoc -c ./jsdoc-conf.json --private -r .",
|
|
135
135
|
"integration": "npm run prepare-test && npm run sub-install && time tap test/integration/**/**/*.tap.js --timeout=180 --no-coverage --reporter classic",
|
|
136
136
|
"prepare-test": "npm run ca-gen && npm run ssl && npm run docker-env",
|
|
137
|
-
"lint": "eslint ./*.js lib test bin",
|
|
138
|
-
"lint:fix": "eslint --fix, ./*.js lib test bin",
|
|
137
|
+
"lint": "eslint ./*.js lib test bin examples",
|
|
138
|
+
"lint:fix": "eslint --fix, ./*.js lib test bin examples",
|
|
139
139
|
"public-docs": "npm ci && jsdoc -c ./jsdoc-conf.json --tutorials examples/shim api.js lib/shim/ lib/transaction/handle.js && cp examples/shim/*.png out/",
|
|
140
140
|
"publish-docs": "./bin/publish-docs.sh",
|
|
141
141
|
"services": "./bin/docker-services.sh",
|
|
@@ -187,14 +187,15 @@
|
|
|
187
187
|
"commander": "^7.0.0",
|
|
188
188
|
"eslint": "^7.32.0",
|
|
189
189
|
"eslint-config-prettier": "^8.3.0",
|
|
190
|
+
"eslint-plugin-disable": "^2.0.1",
|
|
190
191
|
"eslint-plugin-header": "^3.1.1",
|
|
192
|
+
"eslint-plugin-jsdoc": "^36.1.0",
|
|
191
193
|
"eslint-plugin-node": "^11.1.0",
|
|
192
194
|
"eslint-plugin-prettier": "^3.4.0",
|
|
193
195
|
"express": "*",
|
|
194
196
|
"generic-pool": "^3.6.1",
|
|
195
197
|
"glob": "^7.1.2",
|
|
196
198
|
"got": "^8.0.1",
|
|
197
|
-
"http-errors": "^1.7.3",
|
|
198
199
|
"husky": "^6.0.0",
|
|
199
200
|
"jsdoc": "^3.6.3",
|
|
200
201
|
"lint-staged": "^11.0.0",
|