newrelic 10.6.2 → 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 +66 -0
- package/README.md +11 -23
- package/THIRD_PARTY_NOTICES.md +140 -65
- package/esm-loader.mjs +1 -225
- package/index.js +22 -4
- package/lib/config/default.js +0 -8
- package/lib/context-manager/create-context-manager.js +3 -17
- package/lib/feature_flags.js +4 -3
- package/lib/instrumentation/@prisma/client.js +23 -46
- package/lib/instrumentation/{amqplib.js → amqplib/amqplib.js} +0 -28
- package/lib/instrumentation/amqplib/nr-hooks.js +20 -0
- package/lib/instrumentation/core/async-hooks.js +1 -1
- package/lib/instrumentation/core/timers.js +2 -2
- package/lib/instrumentation/grpc-js/grpc.js +11 -15
- package/lib/instrumentation/grpc-js/nr-hooks.js +17 -5
- package/lib/instrumentation/pino/nr-hooks.js +3 -4
- package/lib/instrumentation/pino/pino.js +7 -20
- package/lib/instrumentation/undici.js +71 -82
- package/lib/instrumentations.js +1 -2
- package/lib/metrics/names.js +1 -2
- package/lib/shim/message-shim.js +1 -1
- package/lib/shim/transaction-shim.js +4 -4
- package/lib/shimmer.js +62 -163
- package/lib/symbols.js +1 -0
- package/lib/transaction/trace/index.js +2 -2
- package/package.json +15 -17
- package/lib/context-manager/diagnostics/legacy-diagnostic-context-manager.js +0 -36
- package/lib/esm-shim.mjs +0 -36
|
@@ -15,7 +15,7 @@ const {
|
|
|
15
15
|
} = require('../../util/application-logging')
|
|
16
16
|
const semver = require('semver')
|
|
17
17
|
|
|
18
|
-
module.exports = function instrument(shim) {
|
|
18
|
+
module.exports = function instrument(shim, tools) {
|
|
19
19
|
const pinoVersion = shim.require('./package.json').version
|
|
20
20
|
|
|
21
21
|
if (semver.lt(pinoVersion, '7.0.0')) {
|
|
@@ -23,7 +23,6 @@ module.exports = function instrument(shim) {
|
|
|
23
23
|
return
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
const tools = shim.require('./lib/tools')
|
|
27
26
|
const agent = shim.agent
|
|
28
27
|
const config = agent.config
|
|
29
28
|
|
|
@@ -35,18 +34,6 @@ module.exports = function instrument(shim) {
|
|
|
35
34
|
const metrics = agent.metrics
|
|
36
35
|
createModuleUsageMetric('pino', metrics)
|
|
37
36
|
|
|
38
|
-
const levelUtils = shim.require('./lib/levels')
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Creates an object where the keys are the level labels and values are the level number.
|
|
42
|
-
* Pino passes in level as number but our spec needs it to be the label
|
|
43
|
-
*/
|
|
44
|
-
const levelMap = Object.entries(levelUtils.levels).reduce((levels, level) => {
|
|
45
|
-
const [label, number] = level
|
|
46
|
-
levels[number] = label
|
|
47
|
-
return levels
|
|
48
|
-
}, {})
|
|
49
|
-
|
|
50
37
|
const symbols = shim.require('./lib/symbols')
|
|
51
38
|
|
|
52
39
|
shim.wrap(tools, 'asJson', function wrapJson(shim, asJson) {
|
|
@@ -62,10 +49,10 @@ module.exports = function instrument(shim) {
|
|
|
62
49
|
*/
|
|
63
50
|
return function wrappedAsJson() {
|
|
64
51
|
const args = shim.argsToArray.apply(shim, arguments)
|
|
52
|
+
const level = this?.levels?.labels?.[args[2]]
|
|
65
53
|
|
|
66
54
|
if (isMetricsEnabled(config)) {
|
|
67
|
-
|
|
68
|
-
incrementLoggingLinesMetrics(levelMap[level], metrics)
|
|
55
|
+
incrementLoggingLinesMetrics(level, metrics)
|
|
69
56
|
}
|
|
70
57
|
|
|
71
58
|
if (isLocalDecoratingEnabled(config)) {
|
|
@@ -86,7 +73,7 @@ module.exports = function instrument(shim) {
|
|
|
86
73
|
logLine,
|
|
87
74
|
agent,
|
|
88
75
|
chindings,
|
|
89
|
-
|
|
76
|
+
level,
|
|
90
77
|
logger: shim.logger
|
|
91
78
|
})
|
|
92
79
|
|
|
@@ -110,10 +97,10 @@ module.exports = function instrument(shim) {
|
|
|
110
97
|
* @param logLine.agent
|
|
111
98
|
* @param logLine.chindings
|
|
112
99
|
* @param logLine.msg
|
|
113
|
-
* @param logLine.
|
|
100
|
+
* @param logLine.level
|
|
114
101
|
* @param logLine.logger
|
|
115
102
|
*/
|
|
116
|
-
function reformatLogLine({ logLine, msg, agent, chindings = '',
|
|
103
|
+
function reformatLogLine({ logLine, msg, agent, chindings = '', level, logger }) {
|
|
117
104
|
const metadata = agent.getLinkingMetadata()
|
|
118
105
|
|
|
119
106
|
/**
|
|
@@ -145,7 +132,7 @@ function reformatLogLine({ logLine, msg, agent, chindings = '', levelMap, logger
|
|
|
145
132
|
reformatError(formattedLog)
|
|
146
133
|
}
|
|
147
134
|
Object.assign(formattedLog, agentMeta)
|
|
148
|
-
formattedLog.level =
|
|
135
|
+
formattedLog.level = level
|
|
149
136
|
delete formattedLog.time
|
|
150
137
|
delete formattedLog.msg
|
|
151
138
|
return formattedLog
|
|
@@ -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
|
@@ -11,7 +11,7 @@ const MODULE_TYPE = require('./shim/constants').MODULE_TYPE
|
|
|
11
11
|
module.exports = function instrumentations() {
|
|
12
12
|
return {
|
|
13
13
|
'aws-sdk': { module: '@newrelic/aws-sdk' },
|
|
14
|
-
'amqplib': {
|
|
14
|
+
'amqplib': { module: './instrumentation/amqplib' },
|
|
15
15
|
'cassandra-driver': { type: MODULE_TYPE.DATASTORE },
|
|
16
16
|
'connect': { type: MODULE_TYPE.WEB_FRAMEWORK },
|
|
17
17
|
'bluebird': { type: MODULE_TYPE.PROMISE },
|
|
@@ -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/metrics/names.js
CHANGED
|
@@ -272,8 +272,7 @@ const INFINITE_TRACING = {
|
|
|
272
272
|
const FEATURES = {
|
|
273
273
|
ESM: {
|
|
274
274
|
LOADER: `${SUPPORTABILITY.FEATURES}/ESM/Loader`,
|
|
275
|
-
UNSUPPORTED_LOADER: `${SUPPORTABILITY.FEATURES}/ESM/UnsupportedLoader
|
|
276
|
-
CUSTOM_INSTRUMENTATION: `${SUPPORTABILITY.FEATURES}/ESM/CustomInstrumentation`
|
|
275
|
+
UNSUPPORTED_LOADER: `${SUPPORTABILITY.FEATURES}/ESM/UnsupportedLoader`
|
|
277
276
|
},
|
|
278
277
|
CJS: {
|
|
279
278
|
PRELOAD: `${SUPPORTABILITY.FEATURES}/CJS/Preload`,
|
package/lib/shim/message-shim.js
CHANGED
|
@@ -736,7 +736,7 @@ function recordSubscribedConsume(nodule, properties, spec) {
|
|
|
736
736
|
}
|
|
737
737
|
}
|
|
738
738
|
if (msgDesc.headers) {
|
|
739
|
-
shim.
|
|
739
|
+
shim.handleMqTracingHeaders(msgDesc.headers, tx.baseSegment, shim._transportType)
|
|
740
740
|
}
|
|
741
741
|
|
|
742
742
|
shim.logger.trace('Started message transaction %s named %s', tx.id, txName)
|
|
@@ -66,7 +66,7 @@ TransactionShim.prototype.bindCreateTransaction = bindCreateTransaction
|
|
|
66
66
|
TransactionShim.prototype.pushTransactionName = pushTransactionName
|
|
67
67
|
TransactionShim.prototype.popTransactionName = popTransactionName
|
|
68
68
|
TransactionShim.prototype.setTransactionName = setTransactionName
|
|
69
|
-
TransactionShim.prototype.
|
|
69
|
+
TransactionShim.prototype.handleMqTracingHeaders = handleMqTracingHeaders
|
|
70
70
|
TransactionShim.prototype.insertCATReplyHeader = insertCATReplyHeader
|
|
71
71
|
TransactionShim.prototype.insertCATRequestHeaders = insertCATRequestHeaders
|
|
72
72
|
|
|
@@ -204,7 +204,7 @@ function setTransactionName(name) {
|
|
|
204
204
|
/**
|
|
205
205
|
* Retrieves whatever CAT headers may be in the given headers.
|
|
206
206
|
*
|
|
207
|
-
* - `
|
|
207
|
+
* - `handleMqTracingHeaders(headers [, segment [, transportType]])`
|
|
208
208
|
*
|
|
209
209
|
* @memberof TransactionShim.prototype
|
|
210
210
|
*
|
|
@@ -218,8 +218,8 @@ function setTransactionName(name) {
|
|
|
218
218
|
* @param {string} [transportType='Unknown']
|
|
219
219
|
* The transport type that brought the headers. Usually `HTTP` or `HTTPS`.
|
|
220
220
|
*/
|
|
221
|
-
function
|
|
222
|
-
// TODO:
|
|
221
|
+
function handleMqTracingHeaders(headers, segment, transportType) {
|
|
222
|
+
// TODO: replace functionality when CAT fully removed.
|
|
223
223
|
|
|
224
224
|
if (!headers) {
|
|
225
225
|
this.logger.debug('No headers for CAT or DT processing.')
|