newrelic 9.7.0 → 9.7.2
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 +42 -18
- package/THIRD_PARTY_NOTICES.md +203 -2
- package/api.js +155 -103
- package/lib/agent.js +29 -82
- package/lib/collector/api.js +234 -201
- package/lib/config/attribute-filter.js +35 -25
- package/lib/config/default.js +45 -19
- package/lib/config/index.js +260 -199
- package/lib/environment.js +16 -12
- package/lib/errors/error-collector.js +124 -55
- package/lib/errors/index.js +59 -49
- package/lib/instrumentation/@hapi/hapi.js +56 -50
- package/lib/instrumentation/@node-redis/client.js +50 -41
- package/lib/instrumentation/amqplib.js +116 -151
- package/lib/instrumentation/core/{async_hooks.js → async-hooks.js} +26 -11
- package/lib/instrumentation/core/globals.js +1 -1
- package/lib/instrumentation/core/http-outbound.js +193 -78
- package/lib/instrumentation/core/timers.js +106 -59
- package/lib/instrumentation/grpc-js/grpc.js +20 -23
- package/lib/instrumentation/mongodb/common.js +87 -85
- package/lib/instrumentation/redis.js +112 -90
- package/lib/instrumentation/undici.js +204 -192
- package/lib/instrumentation/{when.js → when/constants.js} +13 -10
- package/lib/instrumentation/when/contextualizer.js +168 -0
- package/lib/instrumentation/when/index.js +354 -0
- package/lib/instrumentation/when/nr-hooks.js +15 -0
- package/lib/instrumentations.js +1 -1
- package/lib/shim/shim.js +2 -0
- package/lib/shim/webframework-shim.js +19 -0
- package/lib/symbols.js +1 -0
- package/lib/system-info.js +240 -163
- package/lib/util/async-each-limit.js +30 -0
- package/lib/util/attributes.js +159 -0
- package/lib/util/code-level-metrics.js +58 -0
- package/lib/util/deep-equal.js +11 -144
- package/package.json +5 -4
- package/lib/instrumentation/promise.js +0 -572
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
/* eslint sonarjs/cognitive-complexity: ["error", 40] -- TODO: https://issues.newrelic.com/browse/NEWRELIC-5252 */
|
|
9
|
-
|
|
10
8
|
const recordExternal = require('../../metrics/recorders/http_external')
|
|
11
9
|
const cat = require('../../util/cat')
|
|
12
10
|
const urltils = require('../../util/urltils')
|
|
@@ -15,6 +13,7 @@ const shimmer = require('../../shimmer')
|
|
|
15
13
|
const url = require('url')
|
|
16
14
|
const copy = require('../../util/copy')
|
|
17
15
|
const symbols = require('../../symbols')
|
|
16
|
+
const http = require('http')
|
|
18
17
|
|
|
19
18
|
const NAMES = require('../../metrics/names')
|
|
20
19
|
|
|
@@ -25,27 +24,73 @@ const DEFAULT_SSL_PORT = 443
|
|
|
25
24
|
const NEWRELIC_SYNTHETICS_HEADER = 'x-newrelic-synthetics'
|
|
26
25
|
|
|
27
26
|
/**
|
|
28
|
-
*
|
|
27
|
+
* Determines the default port to 80 if protocol is undefined or http:
|
|
28
|
+
* Otherwise it assigns it as 443
|
|
29
29
|
*
|
|
30
|
-
* @param {object} agent instantiation of lib/agent.js
|
|
31
30
|
* @param {object} opts HTTP request options
|
|
32
|
-
* @
|
|
33
|
-
* @returns {object} The instrumented outbound HTTP request.
|
|
31
|
+
* @returns {number} default port
|
|
34
32
|
*/
|
|
35
|
-
|
|
33
|
+
function getDefaultPort(opts) {
|
|
34
|
+
return !opts.protocol || opts.protocol === 'http:' ? DEFAULT_HTTP_PORT : DEFAULT_SSL_PORT
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Determines the port based on http opts
|
|
39
|
+
*
|
|
40
|
+
* @param {object} opts HTTP request options
|
|
41
|
+
* @param {number} defaultPort the default port
|
|
42
|
+
* @returns {number} port
|
|
43
|
+
*/
|
|
44
|
+
function getPort(opts, defaultPort) {
|
|
45
|
+
let port = opts.port || opts.defaultPort
|
|
46
|
+
if (!port) {
|
|
47
|
+
port = defaultPort
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return port
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Determines the default hostname based on http opts
|
|
55
|
+
*
|
|
56
|
+
* @param {object} opts HTTP request options
|
|
57
|
+
* @returns {string} default host
|
|
58
|
+
*/
|
|
59
|
+
function getDefaultHostName(opts) {
|
|
60
|
+
return opts.hostname || opts.host || DEFAULT_HOST
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Parses http opts to an object
|
|
65
|
+
* If string will call url.parse, otherwise it will
|
|
66
|
+
* do a shallow copy
|
|
67
|
+
*
|
|
68
|
+
* @param {string|object} opts a url string or HTTP request options
|
|
69
|
+
* @returns {object} parsed http opts
|
|
70
|
+
*/
|
|
71
|
+
function parseOpts(opts) {
|
|
36
72
|
if (typeof opts === 'string') {
|
|
37
73
|
opts = url.parse(opts)
|
|
38
74
|
} else {
|
|
39
75
|
opts = copy.shallow(opts)
|
|
40
76
|
}
|
|
41
77
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
78
|
+
return opts
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Instruments an outbound HTTP request.
|
|
83
|
+
*
|
|
84
|
+
* @param {Agent} agent instantiation of lib/agent.js
|
|
85
|
+
* @param {object} opts HTTP request options
|
|
86
|
+
* @param {Function} makeRequest function for issuing actual HTTP request
|
|
87
|
+
* @returns {object} The instrumented outbound HTTP request.
|
|
88
|
+
*/
|
|
89
|
+
module.exports = function instrumentOutbound(agent, opts, makeRequest) {
|
|
90
|
+
opts = parseOpts(opts)
|
|
91
|
+
const defaultPort = getDefaultPort(opts)
|
|
92
|
+
let hostname = getDefaultHostName(opts)
|
|
93
|
+
const port = getPort(opts, defaultPort)
|
|
49
94
|
|
|
50
95
|
if (!hostname || port < 1) {
|
|
51
96
|
logger.warn('Invalid host name (%s) or port (%s) for outbound request.', hostname, port)
|
|
@@ -74,79 +119,144 @@ module.exports = function instrumentOutbound(agent, opts, makeRequest) {
|
|
|
74
119
|
recordExternal(hostname, 'http'),
|
|
75
120
|
parent,
|
|
76
121
|
false,
|
|
77
|
-
instrumentRequest
|
|
122
|
+
instrumentRequest.bind(null, agent, opts, makeRequest, hostname)
|
|
78
123
|
)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Injects DT/CAT headers, creates segment for outbound http request.
|
|
128
|
+
* Instruments the request.emit to properly handle the response of the
|
|
129
|
+
* outbound http request
|
|
130
|
+
*
|
|
131
|
+
* @param {Agent} agent New Relic agent
|
|
132
|
+
* @param {string|object} opts a url string or HTTP request options
|
|
133
|
+
* @param {Function} makeRequest function to make request
|
|
134
|
+
* @param {string} hostname host of outbound request
|
|
135
|
+
* @param {TraceSegment} segment outbound http segment
|
|
136
|
+
* @returns {http.IncomingMessage} request actual http outbound request
|
|
137
|
+
*/
|
|
138
|
+
function instrumentRequest(agent, opts, makeRequest, hostname, segment) {
|
|
139
|
+
const transaction = segment.transaction
|
|
140
|
+
const outboundHeaders = Object.create(null)
|
|
79
141
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
142
|
+
if (agent.config.encoding_key && transaction.syntheticsHeader) {
|
|
143
|
+
outboundHeaders[NEWRELIC_SYNTHETICS_HEADER] = transaction.syntheticsHeader
|
|
144
|
+
}
|
|
83
145
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
146
|
+
maybeAddDtCatHeaders(agent, transaction, outboundHeaders, !!opts?.headers?.[symbols.disableDT])
|
|
147
|
+
opts.headers = assignOutgoingHeaders(opts.headers, outboundHeaders)
|
|
87
148
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
149
|
+
const request = applySegment(opts, makeRequest, hostname, segment)
|
|
150
|
+
|
|
151
|
+
instrumentRequestEmit(agent, hostname, segment, request)
|
|
152
|
+
|
|
153
|
+
return request
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Depending on configuration it will either add DT or CAT headers to the
|
|
158
|
+
* outgoing headers
|
|
159
|
+
*
|
|
160
|
+
* @param {Agent} agent Node.js agent
|
|
161
|
+
* @param {Transaction} transaction active transaction
|
|
162
|
+
* @param {object} outboundHeaders headers that are getting attached to external http call
|
|
163
|
+
* @param {boolean} hasDtSym flag to tell if the disableDT header exists on headers
|
|
164
|
+
*/
|
|
165
|
+
// TODO: abstract header logic shared with TransactionShim#insertCATRequestHeaders
|
|
166
|
+
function maybeAddDtCatHeaders(agent, transaction, outboundHeaders, hasDtSym = false) {
|
|
167
|
+
if (agent.config.distributed_tracing.enabled) {
|
|
168
|
+
if (hasDtSym) {
|
|
169
|
+
logger.trace('Distributed tracing disabled by instrumentation.')
|
|
97
170
|
} else {
|
|
98
|
-
|
|
171
|
+
transaction.insertDistributedTraceHeaders(outboundHeaders)
|
|
99
172
|
}
|
|
173
|
+
} else if (agent.config.cross_application_tracer.enabled) {
|
|
174
|
+
cat.addCatHeaders(agent.config, transaction, outboundHeaders)
|
|
175
|
+
} else {
|
|
176
|
+
logger.trace('Both DT and CAT are disabled, not adding headers!')
|
|
177
|
+
}
|
|
178
|
+
}
|
|
100
179
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
180
|
+
/**
|
|
181
|
+
* Assigns new headers for outgoing request
|
|
182
|
+
*
|
|
183
|
+
* @param {object|Array} currentHeaders current headers from request options headers
|
|
184
|
+
* @param {object} outboundHeaders headers to assign to outgoing request
|
|
185
|
+
* @returns {object|Array} properly formatted headers
|
|
186
|
+
*/
|
|
187
|
+
function assignOutgoingHeaders(currentHeaders, outboundHeaders) {
|
|
188
|
+
let headers
|
|
189
|
+
|
|
190
|
+
if (Array.isArray(currentHeaders)) {
|
|
191
|
+
headers = currentHeaders.slice()
|
|
192
|
+
Array.prototype.push.apply(
|
|
193
|
+
headers,
|
|
194
|
+
Object.keys(outboundHeaders).map(function getHeaderTuples(key) {
|
|
195
|
+
return [key, outboundHeaders[key]]
|
|
196
|
+
})
|
|
197
|
+
)
|
|
198
|
+
} else {
|
|
199
|
+
headers = Object.assign(Object.create(null), currentHeaders, outboundHeaders)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return headers
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Starts the http outbound segment and attaches relevant attributes to the segment/span.
|
|
207
|
+
*
|
|
208
|
+
* @param {string|object} opts a url string or HTTP request options
|
|
209
|
+
* @param {Function} makeRequest function to make request
|
|
210
|
+
* @param {string} hostname host of outbound request
|
|
211
|
+
* @param {TraceSegment} segment outbound http segment
|
|
212
|
+
* @returns {http.IncomingMessage} request actual http outbound request
|
|
213
|
+
*/
|
|
214
|
+
function applySegment(opts, makeRequest, hostname, segment) {
|
|
215
|
+
segment.start()
|
|
216
|
+
const request = makeRequest(opts)
|
|
217
|
+
const parsed = urltils.scrubAndParseParameters(request.path)
|
|
218
|
+
const proto = parsed.protocol || opts.protocol || 'http:'
|
|
219
|
+
segment.name += parsed.path
|
|
220
|
+
request[symbols.segment] = segment
|
|
221
|
+
|
|
222
|
+
if (parsed.parameters) {
|
|
223
|
+
// Scrub and parse returns on object with a null prototype.
|
|
224
|
+
// eslint-disable-next-line guard-for-in
|
|
225
|
+
for (const key in parsed.parameters) {
|
|
226
|
+
segment.addSpanAttribute(`request.parameters.${key}`, parsed.parameters[key])
|
|
111
227
|
}
|
|
228
|
+
}
|
|
229
|
+
segment.addAttribute('url', `${proto}//${hostname}${parsed.path}`)
|
|
230
|
+
segment.addAttribute('procedure', opts.method || 'GET')
|
|
231
|
+
return request
|
|
232
|
+
}
|
|
112
233
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
234
|
+
/**
|
|
235
|
+
* Wrap the emit method. We're doing a special wrapper instead of using
|
|
236
|
+
* `tracer.bindEmitter` because we want to do some logic based on certain
|
|
237
|
+
* events.
|
|
238
|
+
*
|
|
239
|
+
* @param {Agent} agent New Relic agent
|
|
240
|
+
* @param {string} hostname host of outbound request
|
|
241
|
+
* @param {TraceSegment} segment outbound http segment
|
|
242
|
+
* @param {http.IncomingMessage} request actual http outbound request
|
|
243
|
+
*/
|
|
244
|
+
function instrumentRequestEmit(agent, hostname, segment, request) {
|
|
245
|
+
shimmer.wrapMethod(request, 'request.emit', 'emit', function wrapEmit(emit) {
|
|
246
|
+
const boundEmit = agent.tracer.bindFunction(emit, segment)
|
|
247
|
+
return function wrappedRequestEmit(evnt, arg) {
|
|
248
|
+
if (evnt === 'error') {
|
|
249
|
+
segment.end()
|
|
250
|
+
handleError(segment, request, arg)
|
|
251
|
+
} else if (evnt === 'response') {
|
|
252
|
+
handleResponse(segment, hostname, arg)
|
|
125
253
|
}
|
|
254
|
+
|
|
255
|
+
return boundEmit.apply(this, arguments)
|
|
126
256
|
}
|
|
127
|
-
|
|
128
|
-
segment.addAttribute('procedure', opts.method || 'GET')
|
|
129
|
-
|
|
130
|
-
// Wrap the emit method. We're doing a special wrapper instead of using
|
|
131
|
-
// `tracer.bindEmitter` because we want to do some logic based on certain
|
|
132
|
-
// events.
|
|
133
|
-
shimmer.wrapMethod(request, 'request.emit', 'emit', function wrapEmit(emit) {
|
|
134
|
-
const boundEmit = agent.tracer.bindFunction(emit, segment)
|
|
135
|
-
return function wrappedRequestEmit(evnt, arg) {
|
|
136
|
-
if (evnt === 'error') {
|
|
137
|
-
segment.end()
|
|
138
|
-
handleError(segment, request, arg)
|
|
139
|
-
} else if (evnt === 'response') {
|
|
140
|
-
handleResponse(segment, hostname, request, arg)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return boundEmit.apply(this, arguments)
|
|
144
|
-
}
|
|
145
|
-
})
|
|
146
|
-
_makeNonEnumerable(request, 'emit')
|
|
257
|
+
})
|
|
147
258
|
|
|
148
|
-
|
|
149
|
-
}
|
|
259
|
+
_makeNonEnumerable(request, 'emit')
|
|
150
260
|
}
|
|
151
261
|
|
|
152
262
|
/**
|
|
@@ -175,10 +285,9 @@ function handleError(segment, req, error) {
|
|
|
175
285
|
*
|
|
176
286
|
* @param {object} segment TraceSegment instance
|
|
177
287
|
* @param {string} hostname host of the HTTP request
|
|
178
|
-
* @param {object}
|
|
179
|
-
* @param {object} res http.IncomingMessage
|
|
288
|
+
* @param {object} res http.ServerResponse
|
|
180
289
|
*/
|
|
181
|
-
function handleResponse(segment, hostname,
|
|
290
|
+
function handleResponse(segment, hostname, res) {
|
|
182
291
|
// Add response attributes for spans
|
|
183
292
|
segment.addSpanAttribute('http.statusCode', res.statusCode)
|
|
184
293
|
segment.addSpanAttribute('http.statusText', res.statusMessage)
|
|
@@ -204,6 +313,12 @@ function handleResponse(segment, hostname, req, res) {
|
|
|
204
313
|
_makeNonEnumerable(res, 'emit')
|
|
205
314
|
}
|
|
206
315
|
|
|
316
|
+
/**
|
|
317
|
+
* Makes a property non-enumerable
|
|
318
|
+
*
|
|
319
|
+
* @param {object} obj object that contains property that needs to be non-enumerable
|
|
320
|
+
* @param {string} prop property to make non-enumerable
|
|
321
|
+
*/
|
|
207
322
|
function _makeNonEnumerable(obj, prop) {
|
|
208
323
|
try {
|
|
209
324
|
const desc = Object.getOwnPropertyDescriptor(obj, prop)
|
|
@@ -5,73 +5,114 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
/* eslint sonarjs/cognitive-complexity: ["error", 16] -- TODO: https://issues.newrelic.com/browse/NEWRELIC-5252 */
|
|
9
|
-
|
|
10
8
|
const symbols = require('../../symbols')
|
|
9
|
+
const Timers = require('timers')
|
|
11
10
|
|
|
12
11
|
module.exports = initialize
|
|
13
12
|
|
|
14
|
-
function initialize(agent, timers,
|
|
15
|
-
|
|
16
|
-
instrumentProcessMethods(shim, process)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
instrumentTimerMethods(timers)
|
|
13
|
+
function initialize(agent, timers, _moduleName, shim) {
|
|
14
|
+
const isAsyncLocalContext = agent.config.feature_flag.async_local_context
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
instrumentTimerMethods(global)
|
|
16
|
+
if (!isAsyncLocalContext) {
|
|
17
|
+
instrumentProcessMethods(shim, process)
|
|
18
|
+
instrumentSetImmediate(shim, [timers, global])
|
|
25
19
|
}
|
|
26
20
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
shim.record(nodule, asynchronizers, recordAsynchronizers)
|
|
21
|
+
instrumentTimerMethods(shim, [timers, global])
|
|
22
|
+
}
|
|
31
23
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Sets up instrumentation for setImmediate on both timers and global.
|
|
26
|
+
*
|
|
27
|
+
* We do not want to create segments for setImmediate calls,
|
|
28
|
+
* as the object allocation may incur too much overhead in some situations
|
|
29
|
+
*
|
|
30
|
+
* @param {Shim} shim instance of shim
|
|
31
|
+
* @param {Array<Timers,global>} pkgs array with references to timers and global
|
|
32
|
+
*/
|
|
33
|
+
function instrumentSetImmediate(shim, pkgs) {
|
|
34
|
+
pkgs.forEach((nodule) => {
|
|
35
|
+
if (shim.isWrapped(nodule.setImmediate)) {
|
|
36
|
+
return
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
shim.wrap(nodule, '
|
|
39
|
+
shim.wrap(nodule, 'setImmediate', function wrapSetImmediate(shim, fn) {
|
|
40
|
+
return function wrappedSetImmediate() {
|
|
41
|
+
const segment = shim.getActiveSegment()
|
|
42
|
+
if (!segment) {
|
|
43
|
+
return fn.apply(this, arguments)
|
|
44
|
+
}
|
|
39
45
|
|
|
40
|
-
|
|
41
|
-
|
|
46
|
+
const args = shim.argsToArray.apply(shim, arguments, segment)
|
|
47
|
+
shim.bindSegment(args, shim.FIRST)
|
|
42
48
|
|
|
43
|
-
|
|
44
|
-
return function wrappedSetImmediate() {
|
|
45
|
-
const segment = shim.getActiveSegment()
|
|
46
|
-
if (!segment) {
|
|
47
|
-
return fn.apply(this, arguments)
|
|
49
|
+
return fn.apply(this, args)
|
|
48
50
|
}
|
|
51
|
+
})
|
|
49
52
|
|
|
50
|
-
|
|
51
|
-
|
|
53
|
+
copySymbols(shim, nodule, 'setImmediate')
|
|
54
|
+
})
|
|
55
|
+
}
|
|
52
56
|
|
|
53
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Sets up instrumentation for setTimeout, setInterval and clearTimeout
|
|
59
|
+
* on timers and global.
|
|
60
|
+
*
|
|
61
|
+
* @param {Shim} shim instance of shim
|
|
62
|
+
* @param {Array<Timers,global>} pkgs array with references to timers and global
|
|
63
|
+
*/
|
|
64
|
+
function instrumentTimerMethods(shim, pkgs) {
|
|
65
|
+
pkgs.forEach((nodule) => {
|
|
66
|
+
if (shim.isWrapped(nodule.setTimeout)) {
|
|
67
|
+
return
|
|
54
68
|
}
|
|
55
|
-
}
|
|
56
69
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
}
|
|
70
|
+
const asynchronizers = ['setTimeout', 'setInterval']
|
|
71
|
+
shim.record(nodule, asynchronizers, recordAsynchronizers)
|
|
72
|
+
shim.wrap(nodule, 'clearTimeout', wrapClearTimeout)
|
|
73
|
+
makeWrappedPromisifyCompatible(shim, nodule)
|
|
74
|
+
})
|
|
75
|
+
}
|
|
65
76
|
|
|
66
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Ignores the segment when clearTimeout is called
|
|
79
|
+
*
|
|
80
|
+
* @param {Shim} _shim instance of shim
|
|
81
|
+
* @param {Function} fn clearTimeout
|
|
82
|
+
* @returns {Function} wrapped clearTimeout
|
|
83
|
+
*/
|
|
84
|
+
function wrapClearTimeout(_shim, fn) {
|
|
85
|
+
return function wrappedClearTimeout(timer) {
|
|
86
|
+
if (timer && timer._onTimeout) {
|
|
87
|
+
const segment = timer._onTimeout[symbols.segment]
|
|
88
|
+
if (segment && !segment.opaque) {
|
|
89
|
+
segment.ignore = true
|
|
90
|
+
}
|
|
67
91
|
}
|
|
68
|
-
}
|
|
69
92
|
|
|
70
|
-
|
|
71
|
-
return { name: 'timers.' + name, callback: shim.FIRST }
|
|
93
|
+
return fn.apply(this, arguments)
|
|
72
94
|
}
|
|
73
95
|
}
|
|
74
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Defines the spec for setTimeout and setInterval
|
|
99
|
+
*
|
|
100
|
+
* @param {Shim} shim instance of shim
|
|
101
|
+
* @param {Function} _fn original function
|
|
102
|
+
* @param {string} name name of function
|
|
103
|
+
* @returns {object} spec defining how to instrument
|
|
104
|
+
*/
|
|
105
|
+
function recordAsynchronizers(shim, _fn, name) {
|
|
106
|
+
return { name: 'timers.' + name, callback: shim.FIRST }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Instruments core process methods: nextTick, _nextDomainTick, _tickDomainCallback
|
|
111
|
+
* Note: This does not get registered when the context manager is async local
|
|
112
|
+
*
|
|
113
|
+
* @param {Shim} shim instance of shim
|
|
114
|
+
* @param {process} process global process object
|
|
115
|
+
*/
|
|
75
116
|
function instrumentProcessMethods(shim, process) {
|
|
76
117
|
const processMethods = ['nextTick', '_nextDomainTick', '_tickDomainCallback']
|
|
77
118
|
|
|
@@ -96,21 +137,27 @@ function instrumentProcessMethods(shim, process) {
|
|
|
96
137
|
})
|
|
97
138
|
}
|
|
98
139
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Copies the symbols from original setTimeout and setInterval onto the wrapped functions
|
|
142
|
+
*
|
|
143
|
+
* @param {Shim} shim instance of shim
|
|
144
|
+
* @param {Timers} nodule Timers class
|
|
145
|
+
*/
|
|
146
|
+
function makeWrappedPromisifyCompatible(shim, nodule) {
|
|
147
|
+
copySymbols(shim, nodule, 'setTimeout')
|
|
148
|
+
copySymbols(shim, nodule, 'setInterval')
|
|
149
|
+
}
|
|
104
150
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
151
|
+
/**
|
|
152
|
+
* Helper to copy symbols from original function to wrapped one
|
|
153
|
+
*
|
|
154
|
+
* @param {Shim} shim instance of shim
|
|
155
|
+
* @param {Timers} nodule Timers class
|
|
156
|
+
* @param {string} name name of function
|
|
157
|
+
*/
|
|
158
|
+
function copySymbols(shim, nodule, name) {
|
|
159
|
+
const originalFunction = shim.getOriginal(nodule[name])
|
|
160
|
+
Object.getOwnPropertySymbols(originalFunction).forEach((symbol) => {
|
|
161
|
+
nodule[name][symbol] = originalFunction[symbol]
|
|
108
162
|
})
|
|
109
|
-
|
|
110
|
-
if (!shim.agent.config.feature_flag.async_local_context) {
|
|
111
|
-
const originalSetImmediate = shim.getOriginal(timers.setImmediate)
|
|
112
|
-
Object.getOwnPropertySymbols(originalSetImmediate).forEach((symbol) => {
|
|
113
|
-
timers.setImmediate[symbol] = originalSetImmediate[symbol]
|
|
114
|
-
})
|
|
115
|
-
}
|
|
116
163
|
}
|
|
@@ -12,11 +12,23 @@ const DESTINATION = DESTINATIONS.TRANS_EVENT | DESTINATIONS.ERROR_EVENT
|
|
|
12
12
|
const semver = require('semver')
|
|
13
13
|
|
|
14
14
|
module.exports = function instrument(shim) {
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
|
|
15
|
+
const grpcVersion = shim.require('./package.json').version
|
|
16
|
+
const genericShim = shim.makeSpecializedShim(shim.GENERIC, 'grpc-client-interceptor')
|
|
17
|
+
|
|
18
|
+
if (semver.gte(grpcVersion, '1.8.0')) {
|
|
19
|
+
const resolvingCall = genericShim.require('./build/src/resolving-call')
|
|
20
|
+
genericShim.wrap(resolvingCall.ResolvingCall.prototype, 'start', wrapStart)
|
|
21
|
+
} else {
|
|
22
|
+
const callStream = genericShim.require('./build/src/call-stream')
|
|
23
|
+
genericShim.wrap(callStream.Http2CallStream.prototype, 'start', wrapStart)
|
|
24
|
+
}
|
|
18
25
|
|
|
19
26
|
const webFrameworkShim = shim.makeSpecializedShim(shim.WEB_FRAMEWORK, 'server')
|
|
27
|
+
if (semver.lt(grpcVersion, '1.4.0')) {
|
|
28
|
+
shim.logger.debug('gRPC server-side instrumentation only supported on grpc-js >=1.4.0')
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
|
|
20
32
|
const server = webFrameworkShim.require('./build/src/server')
|
|
21
33
|
webFrameworkShim.setFramework('gRPC')
|
|
22
34
|
webFrameworkShim.wrap(server.Server.prototype, 'register', wrapRegister)
|
|
@@ -41,9 +53,11 @@ function wrapStart(shim, original) {
|
|
|
41
53
|
|
|
42
54
|
const channel = this.channel
|
|
43
55
|
const authorityName = (channel.target && channel.target.path) || channel.getDefaultAuthority
|
|
56
|
+
// in 1.8.0 this changed from methodName to method
|
|
57
|
+
const method = this.methodName || this.method
|
|
44
58
|
|
|
45
59
|
const segment = shim.createSegment({
|
|
46
|
-
name: `External/${authorityName}${
|
|
60
|
+
name: `External/${authorityName}${method}`,
|
|
47
61
|
opaque: true,
|
|
48
62
|
recorder: recordExternal(authorityName, 'gRPC')
|
|
49
63
|
})
|
|
@@ -89,10 +103,10 @@ function wrapStart(shim, original) {
|
|
|
89
103
|
|
|
90
104
|
const protocol = 'grpc'
|
|
91
105
|
|
|
92
|
-
const url = `${protocol}://${authorityName}${
|
|
106
|
+
const url = `${protocol}://${authorityName}${method}`
|
|
93
107
|
|
|
94
108
|
segment.addAttribute('http.url', url)
|
|
95
|
-
segment.addAttribute('http.method',
|
|
109
|
+
segment.addAttribute('http.method', method)
|
|
96
110
|
|
|
97
111
|
if (originalListener && originalListener.onReceiveStatus) {
|
|
98
112
|
const onReceiveStatuts = shim.bindSegment(originalListener.onReceiveStatus, segment)
|
|
@@ -212,20 +226,3 @@ function shouldTrackError(statusCode, config) {
|
|
|
212
226
|
!config.grpc.ignore_status_codes.includes(statusCode)
|
|
213
227
|
)
|
|
214
228
|
}
|
|
215
|
-
|
|
216
|
-
module.exports = function instrument(shim) {
|
|
217
|
-
const genericShim = shim.makeSpecializedShim(shim.GENERIC, 'call-stream')
|
|
218
|
-
const callStream = genericShim.require('./build/src/call-stream')
|
|
219
|
-
genericShim.wrap(callStream.Http2CallStream.prototype, 'start', wrapStart)
|
|
220
|
-
|
|
221
|
-
const webFrameworkShim = shim.makeSpecializedShim(shim.WEB_FRAMEWORK, 'server')
|
|
222
|
-
const grpcVersion = shim.require('./package.json').version
|
|
223
|
-
if (semver.lt(grpcVersion, '1.4.0')) {
|
|
224
|
-
shim.logger.debug('gRPC server-side instrumentation only supported on grpc-js >=1.4.0')
|
|
225
|
-
return
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const server = webFrameworkShim.require('./build/src/server')
|
|
229
|
-
webFrameworkShim.setFramework('gRPC')
|
|
230
|
-
webFrameworkShim.wrap(server.Server.prototype, 'register', wrapRegister)
|
|
231
|
-
}
|