newrelic 11.0.0 → 11.1.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 +18 -0
- package/THIRD_PARTY_NOTICES.md +2 -2
- package/lib/feature_flags.js +2 -2
- package/lib/instrumentation/undici.js +71 -82
- package/lib/instrumentations.js +0 -1
- package/lib/shimmer.js +8 -8
- package/lib/symbols.js +1 -0
- package/lib/transaction/trace/index.js +2 -2
- package/package.json +3 -3
package/NEWS.md
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
### v11.1.0 (2023-09-07)
|
|
2
|
+
|
|
3
|
+
#### Features
|
|
4
|
+
|
|
5
|
+
* Added instrumentation for fetch. ([#1776](https://github.com/newrelic/node-newrelic/pull/1776)) ([980b4dc](https://github.com/newrelic/node-newrelic/commit/980b4dc31d085cafc45961a157f76cb73768741a))
|
|
6
|
+
* Removed undici feature flag. This will now instrument undici by default. ([#1772](https://github.com/newrelic/node-newrelic/pull/1772)) ([683b254](https://github.com/newrelic/node-newrelic/commit/683b254c1c4686527a37e628f80eed9fcc03cb37))
|
|
7
|
+
* Updated undici instrumentation to create segment on request create instead of after connection and opening socket to more accurately record time it takes to make an undici request. ([#1770](https://github.com/newrelic/node-newrelic/pull/1770)) ([3f494f8](https://github.com/newrelic/node-newrelic/commit/3f494f8ad8dd1350fbe034e9c4a582a40228bc45))
|
|
8
|
+
|
|
9
|
+
#### Performance Improvements
|
|
10
|
+
|
|
11
|
+
* **Trace:** optimise getTotalTimeDurationInMillis function to push to an array instead of concat arrays. ([#1774](https://github.com/newrelic/node-newrelic/pull/1774)) ([6ecde97](https://github.com/newrelic/node-newrelic/commit/6ecde97a5efeef4d816b2e82ba762f2130914658))
|
|
12
|
+
* Thanks @infinity-naveen for your contribution 🎉
|
|
13
|
+
|
|
14
|
+
#### Miscellaneous Chores
|
|
15
|
+
|
|
16
|
+
* Updated Next.js plugin versioned tests to use main now that require-in-the-middle fixes have been merged. ([#1768](https://github.com/newrelic/node-newrelic/pull/1768)) ([6a72d1f](https://github.com/newrelic/node-newrelic/commit/6a72d1fb452ea2655c35d7cd008fa78935821ab8))
|
|
17
|
+
* Upgraded `@newrelic/test-utilities` and removed unused shimmer.patchModule and shimmer.unpatchModule ([#1769](https://github.com/newrelic/node-newrelic/pull/1769)) ([96620ef](https://github.com/newrelic/node-newrelic/commit/96620efa725f0f548b683825cb3cefff270fb252))
|
|
18
|
+
|
|
1
19
|
### v11.0.0 (2023-08-28)
|
|
2
20
|
|
|
3
21
|
#### ⚠ BREAKING CHANGES
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -1892,7 +1892,7 @@ This product includes source derived from [@newrelic/newrelic-oss-cli](https://g
|
|
|
1892
1892
|
|
|
1893
1893
|
### @newrelic/test-utilities
|
|
1894
1894
|
|
|
1895
|
-
This product includes source derived from [@newrelic/test-utilities](https://github.com/newrelic/node-test-utilities) ([v8.
|
|
1895
|
+
This product includes source derived from [@newrelic/test-utilities](https://github.com/newrelic/node-test-utilities) ([v8.1.0](https://github.com/newrelic/node-test-utilities/tree/v8.1.0)), distributed under the [Apache-2.0 License](https://github.com/newrelic/node-test-utilities/blob/v8.1.0/LICENSE):
|
|
1896
1896
|
|
|
1897
1897
|
```
|
|
1898
1898
|
Apache License
|
|
@@ -2218,7 +2218,7 @@ THE SOFTWARE.
|
|
|
2218
2218
|
|
|
2219
2219
|
### c8
|
|
2220
2220
|
|
|
2221
|
-
This product includes source derived from [c8](https://github.com/bcoe/c8) ([
|
|
2221
|
+
This product includes source derived from [c8](https://github.com/bcoe/c8) ([v8.0.1](https://github.com/bcoe/c8/tree/v8.0.1)), distributed under the [ISC License](https://github.com/bcoe/c8/blob/v8.0.1/LICENSE.txt):
|
|
2222
2222
|
|
|
2223
2223
|
```
|
|
2224
2224
|
Copyright (c) 2017, Contributors
|
package/lib/feature_flags.js
CHANGED
|
@@ -10,7 +10,6 @@ exports.prerelease = {
|
|
|
10
10
|
express5: false,
|
|
11
11
|
promise_segments: false,
|
|
12
12
|
reverse_naming_rules: false,
|
|
13
|
-
undici_instrumentation: false,
|
|
14
13
|
undici_async_tracking: true,
|
|
15
14
|
unresolved_promise_cleanup: true,
|
|
16
15
|
legacy_context_manager: false
|
|
@@ -33,7 +32,8 @@ exports.released = [
|
|
|
33
32
|
'fastify_instrumentation',
|
|
34
33
|
'await_support',
|
|
35
34
|
'certificate_bundle',
|
|
36
|
-
'async_local_context'
|
|
35
|
+
'async_local_context',
|
|
36
|
+
'undici_instrumentation'
|
|
37
37
|
]
|
|
38
38
|
|
|
39
39
|
// flags that are no longer used for unreleased features
|
|
@@ -12,48 +12,38 @@ const NAMES = require('../metrics/names')
|
|
|
12
12
|
const NEWRELIC_SYNTHETICS_HEADER = 'x-newrelic-synthetics'
|
|
13
13
|
const symbols = require('../symbols')
|
|
14
14
|
const { executionAsyncResource } = require('async_hooks')
|
|
15
|
-
const
|
|
16
|
-
const net = require('net')
|
|
17
|
-
|
|
18
|
-
let diagnosticsChannel = null
|
|
19
|
-
try {
|
|
20
|
-
diagnosticsChannel = require('diagnostics_channel')
|
|
21
|
-
} catch (e) {
|
|
22
|
-
// quick check to see if module exists
|
|
23
|
-
// module was not added until v15.x
|
|
24
|
-
}
|
|
15
|
+
const diagnosticsChannel = require('diagnostics_channel')
|
|
25
16
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
registerHookPoints(shim)
|
|
35
|
-
}
|
|
17
|
+
const channels = [
|
|
18
|
+
{ channel: diagnosticsChannel.channel('undici:request:create'), hook: requestCreateHook },
|
|
19
|
+
{ channel: diagnosticsChannel.channel('undici:request:headers'), hook: requestHeadersHook },
|
|
20
|
+
{ channel: diagnosticsChannel.channel('undici:request:trailers'), hook: endAndRestoreSegment },
|
|
21
|
+
{ channel: diagnosticsChannel.channel('undici:request:error'), hook: endAndRestoreSegment }
|
|
22
|
+
]
|
|
36
23
|
|
|
37
24
|
/**
|
|
38
25
|
* Subscribes to all relevant undici hook points
|
|
39
26
|
* See: https://github.com/nodejs/undici/blob/main/docs/api/DiagnosticsChannel.md
|
|
40
27
|
*
|
|
41
|
-
* @param
|
|
28
|
+
* @param agent
|
|
29
|
+
* @param _undici
|
|
30
|
+
* @param _modName
|
|
31
|
+
* @param shim
|
|
42
32
|
*/
|
|
43
|
-
function
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
33
|
+
module.exports = function addUndiciChannels(agent, _undici, _modName, shim) {
|
|
34
|
+
channels.forEach(({ channel, hook }) => {
|
|
35
|
+
if (!channel.hasSubscribers) {
|
|
36
|
+
channel.subscribe(hook.bind(null, shim))
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports.unsubscribe = function unsubscribe() {
|
|
42
|
+
channels.forEach(({ channel, hook }) => {
|
|
43
|
+
if (channel.hasSubscribers) {
|
|
44
|
+
channel.unsubscribe(hook)
|
|
45
|
+
}
|
|
46
|
+
})
|
|
57
47
|
}
|
|
58
48
|
|
|
59
49
|
/**
|
|
@@ -90,29 +80,14 @@ function getParentSegment(shim) {
|
|
|
90
80
|
}
|
|
91
81
|
|
|
92
82
|
/**
|
|
93
|
-
*
|
|
94
|
-
* We will check current segment for opaque and also attach
|
|
95
|
-
* relevant headers to outgoing http request
|
|
83
|
+
* Injects relevant DT headers for the external request
|
|
96
84
|
*
|
|
97
|
-
* @param {
|
|
98
|
-
* @param {
|
|
85
|
+
* @param {object} params object to fn
|
|
86
|
+
* @param {Shim} params.transaction current transaction
|
|
99
87
|
* @param {object} params.request undici request object
|
|
88
|
+
* @param {object} params.config agent config
|
|
100
89
|
*/
|
|
101
|
-
function
|
|
102
|
-
const { config } = shim.agent
|
|
103
|
-
const parent = getParentSegment(shim)
|
|
104
|
-
request[symbols.parentSegment] = parent
|
|
105
|
-
if (!parent || (parent && parent.opaque)) {
|
|
106
|
-
logger.trace(
|
|
107
|
-
'Not capturing data for outbound request (%s) because parent segment opaque (%s)',
|
|
108
|
-
request.path,
|
|
109
|
-
parent && parent.name
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
return
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const transaction = parent.transaction
|
|
90
|
+
function addDTHeaders({ transaction, config, request }) {
|
|
116
91
|
const outboundHeaders = Object.create(null)
|
|
117
92
|
if (config.encoding_key && transaction.syntheticsHeader) {
|
|
118
93
|
outboundHeaders[NEWRELIC_SYNTHETICS_HEADER] = transaction.syntheticsHeader
|
|
@@ -133,37 +108,19 @@ function requestCreateHook(shim, { request }) {
|
|
|
133
108
|
}
|
|
134
109
|
|
|
135
110
|
/**
|
|
136
|
-
*
|
|
137
|
-
* Undici has some abstracted headers that are only created at this time, one
|
|
138
|
-
* is the `host` header which we need to name the Undici segment. So in this
|
|
139
|
-
* handler we create, start and set the segment active, name it, and
|
|
140
|
-
* attach the url/procedure/request.parameters
|
|
111
|
+
* Creates the external segment with url, procedure and request.parameters attributes
|
|
141
112
|
*
|
|
142
|
-
* @param {
|
|
143
|
-
* @param {
|
|
113
|
+
* @param {object} params object to fn
|
|
114
|
+
* @param {Shim} params.shim instance of shim
|
|
144
115
|
* @param {object} params.request undici request object
|
|
145
|
-
* @param {
|
|
116
|
+
* @param {object} params.parentSegment current active, about to be parent of external segment
|
|
146
117
|
*/
|
|
147
|
-
function
|
|
148
|
-
const
|
|
149
|
-
if (!parentSegment || (parentSegment && parentSegment.opaque)) {
|
|
150
|
-
return
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const port = socket.remotePort
|
|
154
|
-
const isHttps = socket.servername
|
|
155
|
-
let urlString
|
|
156
|
-
if (isHttps) {
|
|
157
|
-
urlString = `https://${socket.servername}`
|
|
158
|
-
urlString += port === 443 ? request.path : `:${port}${request.path}`
|
|
159
|
-
} else {
|
|
160
|
-
urlString = `http://${socket._host}`
|
|
161
|
-
urlString += port === 80 ? request.path : `:${port}${request.path}`
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const url = new URL(urlString)
|
|
165
|
-
|
|
118
|
+
function createExternalSegment({ shim, request, parentSegment }) {
|
|
119
|
+
const url = new URL(request.origin + request.path)
|
|
166
120
|
const name = NAMES.EXTERNAL.PREFIX + url.host + url.pathname
|
|
121
|
+
// Metrics for `External/<host>` will have a suffix of undici
|
|
122
|
+
// We will have to see if this matters for people only using fetch
|
|
123
|
+
// It's undici under the hood so ¯\_(ツ)_/¯
|
|
167
124
|
const segment = shim.createSegment(name, recordExternal(url.host, 'undici'), parentSegment)
|
|
168
125
|
if (segment) {
|
|
169
126
|
segment.start()
|
|
@@ -178,6 +135,38 @@ function responseHeadersHook(shim, { request, socket }) {
|
|
|
178
135
|
}
|
|
179
136
|
}
|
|
180
137
|
|
|
138
|
+
/**
|
|
139
|
+
* This event occurs after the Undici Request is created.
|
|
140
|
+
* We will check current segment for opaque before creating the
|
|
141
|
+
* external segment with the standard url/procedure/request.parameters
|
|
142
|
+
* attributes. We will also attach relevant DT headers to outgoing http request.
|
|
143
|
+
*
|
|
144
|
+
* @param {Shim} shim instance of shim
|
|
145
|
+
* @param {object} params object from undici hook
|
|
146
|
+
* @param {object} params.request undici request object
|
|
147
|
+
*/
|
|
148
|
+
function requestCreateHook(shim, { request }) {
|
|
149
|
+
const { config } = shim.agent
|
|
150
|
+
const parentSegment = getParentSegment(shim)
|
|
151
|
+
request[symbols.parentSegment] = parentSegment
|
|
152
|
+
if (!parentSegment || (parentSegment && parentSegment.opaque)) {
|
|
153
|
+
logger.trace(
|
|
154
|
+
'Not capturing data for outbound request (%s) because parent segment opaque (%s)',
|
|
155
|
+
request.path,
|
|
156
|
+
parentSegment && parentSegment.name
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
return
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
try {
|
|
163
|
+
addDTHeaders({ transaction: parentSegment.transaction, config, request })
|
|
164
|
+
createExternalSegment({ shim, request, parentSegment })
|
|
165
|
+
} catch (err) {
|
|
166
|
+
logger.warn(err, 'Unable to create external segment')
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
181
170
|
/**
|
|
182
171
|
* This event occurs after the response headers have been received.
|
|
183
172
|
* We will add the relevant http response attributes to active segment.
|
package/lib/instrumentations.js
CHANGED
|
@@ -36,7 +36,6 @@ module.exports = function instrumentations() {
|
|
|
36
36
|
'@redis/client': { type: MODULE_TYPE.DATASTORE },
|
|
37
37
|
'restify': { type: MODULE_TYPE.WEB_FRAMEWORK },
|
|
38
38
|
'superagent': { module: '@newrelic/superagent' },
|
|
39
|
-
'undici': { type: MODULE_TYPE.TRANSACTION },
|
|
40
39
|
'@hapi/vision': { type: MODULE_TYPE.WEB_FRAMEWORK },
|
|
41
40
|
'when': { module: './instrumentation/when' },
|
|
42
41
|
'winston': { type: MODULE_TYPE.GENERIC },
|
package/lib/shimmer.js
CHANGED
|
@@ -18,6 +18,7 @@ let pkgsToHook = []
|
|
|
18
18
|
|
|
19
19
|
const NAMES = require('./metrics/names')
|
|
20
20
|
const symbols = require('./symbols')
|
|
21
|
+
const { unsubscribe } = require('./instrumentation/undici')
|
|
21
22
|
|
|
22
23
|
const MODULE_TYPE = shims.constants.MODULE_TYPE
|
|
23
24
|
|
|
@@ -328,6 +329,12 @@ const shimmer = (module.exports = {
|
|
|
328
329
|
const globalsFilepath = path.join(__dirname, 'instrumentation', 'core', 'globals.js')
|
|
329
330
|
_firstPartyInstrumentation(agent, globalsFilepath, globalShim, global, 'globals')
|
|
330
331
|
|
|
332
|
+
// Since this just registers subscriptions to diagnostics_channel events from undici
|
|
333
|
+
// We register this as core and it'll work for both fetch and undici
|
|
334
|
+
const undiciPath = path.join(__dirname, 'instrumentation', 'undici.js')
|
|
335
|
+
const undiciShim = shims.createShimFromType(MODULE_TYPE.TRANSACTION, agent, 'undici', 'undici')
|
|
336
|
+
_firstPartyInstrumentation(agent, undiciPath, undiciShim)
|
|
337
|
+
|
|
331
338
|
// Instrument each of the core modules.
|
|
332
339
|
for (const [mojule, core] of Object.entries(CORE_INSTRUMENTATION)) {
|
|
333
340
|
const filePath = path.join(__dirname, 'instrumentation', 'core', core.file)
|
|
@@ -344,14 +351,6 @@ const shimmer = (module.exports = {
|
|
|
344
351
|
_firstPartyInstrumentation(agent, filePath, shim, uninstrumented, mojule)
|
|
345
352
|
}
|
|
346
353
|
},
|
|
347
|
-
// TODO: remove the following methods once test-utilities have been updated and released
|
|
348
|
-
// with the new registerHooks and removeHooks methods
|
|
349
|
-
patchModule(agent) {
|
|
350
|
-
shimmer.registerHooks(agent)
|
|
351
|
-
},
|
|
352
|
-
unpatchModule() {
|
|
353
|
-
shimmer.removeHooks()
|
|
354
|
-
},
|
|
355
354
|
registerHooks(agent) {
|
|
356
355
|
this._ritm = new Hook(pkgsToHook, function onHook(exports, name, basedir) {
|
|
357
356
|
return _postLoad(agent, exports, name, basedir)
|
|
@@ -372,6 +371,7 @@ const shimmer = (module.exports = {
|
|
|
372
371
|
}
|
|
373
372
|
|
|
374
373
|
pkgsToHook = []
|
|
374
|
+
unsubscribe()
|
|
375
375
|
},
|
|
376
376
|
|
|
377
377
|
bootstrapInstrumentation: function bootstrapInstrumentation(agent) {
|
package/lib/symbols.js
CHANGED
|
@@ -18,6 +18,7 @@ module.exports = {
|
|
|
18
18
|
offTheRecord: Symbol('offTheRecord'),
|
|
19
19
|
original: Symbol('original'),
|
|
20
20
|
wrapped: Symbol('shimWrapped'),
|
|
21
|
+
parentSegment: Symbol('parentSegment'),
|
|
21
22
|
prismaConnection: Symbol('prismaConnection'),
|
|
22
23
|
prismaModelCall: Symbol('modelCall'),
|
|
23
24
|
segment: Symbol('segment'),
|
|
@@ -218,13 +218,13 @@ Trace.prototype.getTotalTimeDurationInMillis = function getTotalTimeDurationInMi
|
|
|
218
218
|
if (this.root.children.length === 0) {
|
|
219
219
|
return 0
|
|
220
220
|
}
|
|
221
|
-
|
|
221
|
+
const segments = this.root.getChildren()
|
|
222
222
|
let totalTimeInMillis = 0
|
|
223
223
|
|
|
224
224
|
while (segments.length !== 0) {
|
|
225
225
|
const segment = segments.pop()
|
|
226
226
|
totalTimeInMillis += segment.getExclusiveDurationInMillis()
|
|
227
|
-
|
|
227
|
+
segment.getChildren().forEach((childSegment) => segments.push(childSegment))
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
if (!this.transaction.isActive()) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "newrelic",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.1.0",
|
|
4
4
|
"author": "New Relic Node.js agent team <nodejs@newrelic.com>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"contributors": [
|
|
@@ -202,12 +202,12 @@
|
|
|
202
202
|
"devDependencies": {
|
|
203
203
|
"@newrelic/eslint-config": "^0.3.0",
|
|
204
204
|
"@newrelic/newrelic-oss-cli": "^0.1.2",
|
|
205
|
-
"@newrelic/test-utilities": "^8.
|
|
205
|
+
"@newrelic/test-utilities": "^8.1.0",
|
|
206
206
|
"@octokit/rest": "^18.0.15",
|
|
207
207
|
"@slack/bolt": "^3.7.0",
|
|
208
208
|
"ajv": "^6.12.6",
|
|
209
209
|
"async": "^3.2.4",
|
|
210
|
-
"c8": "^
|
|
210
|
+
"c8": "^8.0.1",
|
|
211
211
|
"chai": "^4.1.2",
|
|
212
212
|
"clean-jsdoc-theme": "^4.2.4",
|
|
213
213
|
"commander": "^7.0.0",
|