newrelic 9.5.0 → 9.7.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 +14 -0
- package/api.js +2 -0
- package/bin/test-naming-rules.js +1 -1
- package/esm-loader.mjs +1 -3
- package/index.js +6 -5
- package/lib/adaptive-sampler.js +1 -2
- package/lib/agent.js +2 -0
- package/lib/aggregators/event-aggregator.js +2 -2
- package/lib/attributes.js +2 -4
- package/lib/collector/api.js +20 -12
- package/lib/collector/facts.js +1 -3
- package/lib/collector/parse-response.js +3 -1
- package/lib/collector/remote-method.js +10 -10
- package/lib/config/attribute-filter.js +14 -16
- package/lib/config/default.js +544 -286
- package/lib/config/formatters.js +108 -0
- package/lib/config/harvest-config-validator.js +3 -5
- package/lib/config/index.js +74 -93
- package/lib/environment.js +6 -5
- package/lib/errors/error-collector.js +6 -3
- package/lib/errors/helper.js +10 -18
- package/lib/errors/index.js +12 -6
- package/lib/grpc/connection.js +12 -5
- package/lib/header-attributes.js +4 -2
- package/lib/header-processing.js +2 -2
- package/lib/instrumentation/@hapi/hapi.js +231 -1
- package/lib/instrumentation/{vision.js → @hapi/vision.js} +0 -0
- package/lib/instrumentation/@node-redis/client.js +2 -0
- package/lib/instrumentation/amqplib.js +2 -0
- package/lib/instrumentation/core/async_hooks.js +3 -4
- package/lib/instrumentation/core/globals.js +12 -10
- package/lib/instrumentation/core/http-outbound.js +17 -17
- package/lib/instrumentation/core/http.js +16 -27
- package/lib/instrumentation/core/timers.js +5 -1
- package/lib/instrumentation/fastify.js +1 -3
- package/lib/instrumentation/grpc-js/grpc.js +14 -3
- package/lib/instrumentation/memcached.js +5 -0
- package/lib/instrumentation/mongodb/common.js +3 -0
- package/lib/instrumentation/mongodb/v2-mongo.js +6 -3
- package/lib/instrumentation/mongodb.js +1 -1
- package/lib/instrumentation/mysql/mysql.js +6 -5
- package/lib/instrumentation/nr-winston-transport.js +3 -4
- package/lib/instrumentation/promise.js +22 -18
- package/lib/instrumentation/redis.js +2 -0
- package/lib/instrumentation/undici.js +12 -15
- package/lib/instrumentations.js +1 -1
- package/lib/metrics/mapper.js +2 -3
- package/lib/metrics/metric-aggregator.js +1 -3
- package/lib/metrics/names.js +19 -15
- package/lib/metrics/normalizer/rule.js +6 -7
- package/lib/metrics/normalizer/tx_segment.js +3 -2
- package/lib/metrics/normalizer.js +5 -3
- package/lib/parse-proc-cpuinfo.js +11 -6
- package/lib/serverless/api-gateway.js +3 -4
- package/lib/serverless/aws-lambda.js +3 -3
- package/lib/shim/conglomerate-shim.js +2 -3
- package/lib/shim/constants.js +1 -16
- package/lib/shim/datastore-shim.js +24 -105
- package/lib/shim/index.js +7 -0
- package/lib/shim/message-shim.js +2 -0
- package/lib/shim/promise-shim.js +66 -59
- package/lib/shim/shim.js +44 -89
- package/lib/shim/transaction-shim.js +1 -1
- package/lib/shim/webframework-shim.js +4 -8
- package/lib/shimmer.js +29 -23
- package/lib/spans/map-to-streaming-type.js +0 -2
- package/lib/spans/span-context.js +2 -0
- package/lib/spans/span-event-aggregator.js +2 -2
- package/lib/spans/span-event.js +2 -2
- package/lib/spans/span-streamer.js +4 -0
- package/lib/spans/streaming-span-event-aggregator.js +2 -4
- package/lib/spans/streaming-span-event.js +3 -2
- package/lib/symbols.js +26 -0
- package/lib/system-info.js +4 -7
- package/lib/timer.js +8 -6
- package/lib/transaction/dt-payload.js +4 -3
- package/lib/transaction/handle.js +12 -2
- package/lib/transaction/index.js +19 -18
- package/lib/transaction/name-state.js +17 -2
- package/lib/transaction/trace/aggregator.js +4 -12
- package/lib/transaction/trace/index.js +7 -5
- package/lib/transaction/trace/segment.js +6 -11
- package/lib/transaction/tracecontext.js +10 -6
- package/lib/transaction/tracer/index.js +35 -43
- package/lib/transaction/transaction-event-aggregator.js +1 -3
- package/lib/util/arity.js +4 -9
- package/lib/util/attribute-types.js +1 -2
- package/lib/util/byte-limit.js +1 -3
- package/lib/util/cat.js +16 -13
- package/lib/util/codec.js +0 -2
- package/lib/util/copy.js +1 -2
- package/lib/util/deep-equal.js +7 -0
- package/lib/util/flatten.js +4 -6
- package/lib/util/hashes.js +1 -3
- package/lib/util/process-version.js +2 -3
- package/lib/util/properties.js +2 -51
- package/lib/util/stream-sink.js +2 -0
- package/lib/util/urltils.js +4 -10
- package/newrelic.js +1 -1
- package/package.json +2 -1
- package/lib/config/env.js +0 -294
- package/lib/instrumentation/hapi/hapi.js +0 -207
- package/lib/instrumentation/hapi/shared.js +0 -28
- package/lib/instrumentation/hapi.js +0 -254
|
@@ -5,4 +5,234 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
/* eslint sonarjs/cognitive-complexity: ["error", 68] -- TODO: https://issues.newrelic.com/browse/NEWRELIC-5252 */
|
|
9
|
+
|
|
10
|
+
const record = require('../../metrics/recorders/generic')
|
|
11
|
+
// This object defines all the events that we want to wrap extensions
|
|
12
|
+
// for, as they are the only ones associated with requests.
|
|
13
|
+
const ROUTE_EVENTS = {
|
|
14
|
+
onRequest: true,
|
|
15
|
+
onPreAuth: true,
|
|
16
|
+
onCredentials: true,
|
|
17
|
+
onPostAuth: true,
|
|
18
|
+
onPreHandler: true,
|
|
19
|
+
onPostHandler: true,
|
|
20
|
+
onPreResponse: true,
|
|
21
|
+
|
|
22
|
+
// Server events
|
|
23
|
+
onPreStart: false,
|
|
24
|
+
onPostStart: false,
|
|
25
|
+
onPreStop: false,
|
|
26
|
+
onPostStop: false
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = function initialize(agent, hapi, moduleName, shim) {
|
|
30
|
+
if (!agent || !hapi || !shim) {
|
|
31
|
+
shim &&
|
|
32
|
+
shim.logger.debug(
|
|
33
|
+
'Hapi instrumentation function called with incorrect arguments, not instrumenting.'
|
|
34
|
+
)
|
|
35
|
+
return false
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
shim.setFramework(shim.HAPI)
|
|
39
|
+
|
|
40
|
+
shim.setErrorPredicate(function hapiErrorPredicate(err) {
|
|
41
|
+
return err instanceof Error
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
// At this point, framework and error predicate have both already been set via ./hapi,
|
|
45
|
+
// so we only need to set the response predicate and wrap the server object
|
|
46
|
+
shim.setResponsePredicate(function hapiResponsePredicate(args, result) {
|
|
47
|
+
return !(result instanceof Error) && result !== args[1].continue
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// 'Server' and 'server' both point to the same export,
|
|
51
|
+
// but we can't make any assumption about which will be used.
|
|
52
|
+
// Since we wrap the prototype, the second wrap should exit early.
|
|
53
|
+
shim.wrapReturn(hapi, 'server', serverFactoryWrapper)
|
|
54
|
+
shim.wrapReturn(hapi, 'Server', serverFactoryWrapper)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function serverFactoryWrapper(shim, fn, fnName, server) {
|
|
58
|
+
serverPostConstructor.call(server, shim)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function serverPostConstructor(shim) {
|
|
62
|
+
const proto = Object.getPrototypeOf(this)
|
|
63
|
+
|
|
64
|
+
if (shim.isWrapped(proto.decorate)) {
|
|
65
|
+
shim.logger.trace('Already wrapped Server proto, not wrapping again')
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
shim.wrap(proto, 'decorate', function wrapDecorate(shim, original) {
|
|
70
|
+
return function wrappedDecorate(type) {
|
|
71
|
+
// server.decorate also accepts 'request', 'toolkit', 'server' types,
|
|
72
|
+
// but we're only concerned with 'handler'
|
|
73
|
+
if (type !== 'handler') {
|
|
74
|
+
return original.apply(this, arguments)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Convert arguments to usable array
|
|
78
|
+
const args = shim.argsToArray.apply(shim, arguments)
|
|
79
|
+
|
|
80
|
+
// Wrap the third server.decorate arg, the user-defined handler
|
|
81
|
+
shim.wrap(args, shim.THIRD, function wrapHandler(shim, fn) {
|
|
82
|
+
if (typeof fn !== 'function') {
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (fn.defaults) {
|
|
87
|
+
wrappedHandler.defaults = fn.defaults
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return wrappedHandler
|
|
91
|
+
|
|
92
|
+
function wrappedHandler(route) {
|
|
93
|
+
const ret = fn.apply(this, arguments)
|
|
94
|
+
|
|
95
|
+
return typeof ret === 'function' ? wrapRouteHandler(shim, ret, route && route.path) : ret
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
return original.apply(this, args)
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
shim.wrap(proto, 'route', function wrapRoute(shim, original) {
|
|
104
|
+
return function wrappedRoute() {
|
|
105
|
+
const args = shim.argsToArray.apply(shim, arguments)
|
|
106
|
+
|
|
107
|
+
if (!shim.isObject(args[0])) {
|
|
108
|
+
return original.apply(this, args)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// If route is created via a plugin, pull prefix if it exists
|
|
112
|
+
const prefix =
|
|
113
|
+
(this.realm &&
|
|
114
|
+
this.realm.modifiers &&
|
|
115
|
+
this.realm.modifiers.route &&
|
|
116
|
+
this.realm.modifiers.route.prefix) ||
|
|
117
|
+
''
|
|
118
|
+
|
|
119
|
+
_wrapRoute(shim, args[0])
|
|
120
|
+
|
|
121
|
+
return original.apply(this, args)
|
|
122
|
+
|
|
123
|
+
function _wrapRoute(shim, route) {
|
|
124
|
+
const routePath = prefix + route.path
|
|
125
|
+
if (shim.isArray(route)) {
|
|
126
|
+
for (let i = 0; i < route.length; ++i) {
|
|
127
|
+
_wrapRoute(shim, route[i])
|
|
128
|
+
}
|
|
129
|
+
return
|
|
130
|
+
} else if (route.options) {
|
|
131
|
+
// v17 now prefers `options` property...
|
|
132
|
+
if (route.options.pre) {
|
|
133
|
+
// config objects can also contain multiple OTHER handlers in a `pre` array
|
|
134
|
+
route.options.pre = wrapPreHandlers(shim, route.options.pre, routePath)
|
|
135
|
+
}
|
|
136
|
+
if (route.options.handler) {
|
|
137
|
+
_wrapRouteHandler(shim, route.options, routePath)
|
|
138
|
+
return
|
|
139
|
+
}
|
|
140
|
+
} else if (route.config) {
|
|
141
|
+
// ... but `config` still works
|
|
142
|
+
if (route.config.pre) {
|
|
143
|
+
route.config.pre = wrapPreHandlers(shim, route.config.pre, routePath)
|
|
144
|
+
}
|
|
145
|
+
if (route.config.handler) {
|
|
146
|
+
_wrapRouteHandler(shim, route.config, routePath)
|
|
147
|
+
return
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
_wrapRouteHandler(shim, route, routePath)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function _wrapRouteHandler(shim, container, path) {
|
|
154
|
+
if (typeof container.handler !== 'function') {
|
|
155
|
+
return
|
|
156
|
+
}
|
|
157
|
+
shim.wrap(container, 'handler', function wrapHandler(shim, handler) {
|
|
158
|
+
return wrapRouteHandler(shim, handler, path)
|
|
159
|
+
})
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
shim.wrap(proto, 'ext', function wrapExt(shim, original) {
|
|
165
|
+
return function wrappedExt(event, method) {
|
|
166
|
+
const args = shim.argsToArray.apply(shim, arguments)
|
|
167
|
+
|
|
168
|
+
if (shim.isArray(event)) {
|
|
169
|
+
for (let i = 0; i < event.length; i++) {
|
|
170
|
+
event[i].method = wrapMiddleware(shim, event[i].method, event[i].type)
|
|
171
|
+
}
|
|
172
|
+
} else if (shim.isObject(event)) {
|
|
173
|
+
event.method = wrapMiddleware(shim, event.method, event.type)
|
|
174
|
+
} else if (shim.isString(event)) {
|
|
175
|
+
args[1] = wrapMiddleware(shim, method, event)
|
|
176
|
+
} else {
|
|
177
|
+
shim.logger.debug('Unsupported event type %j', event)
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return original.apply(this, args)
|
|
182
|
+
}
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function wrapPreHandlers(shim, container, path) {
|
|
187
|
+
if (shim.isArray(container)) {
|
|
188
|
+
for (let i = 0; i < container.length; ++i) {
|
|
189
|
+
container[i] = wrapPreHandlers(shim, container[i], path)
|
|
190
|
+
}
|
|
191
|
+
return container
|
|
192
|
+
} else if (shim.isFunction(container)) {
|
|
193
|
+
return wrapPreHandler(shim, container, path)
|
|
194
|
+
} else if (container.method && shim.isFunction(container.method)) {
|
|
195
|
+
return shim.wrap(container, 'method', function wrapHandler(shim, handler) {
|
|
196
|
+
return wrapPreHandler(shim, handler, path)
|
|
197
|
+
})
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function wrapPreHandler(shim, container, path) {
|
|
202
|
+
return shim.record(container, (shim) => {
|
|
203
|
+
return { name: [shim.HAPI, ' pre handler: ', '(', path, ')'].join(''), recorder: record }
|
|
204
|
+
})
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function wrapRouteHandler(shim, handler, path) {
|
|
208
|
+
return shim.recordMiddleware(handler, {
|
|
209
|
+
route: path,
|
|
210
|
+
req: function getReq(shim, fn, fnName, args) {
|
|
211
|
+
const request = args[0]
|
|
212
|
+
if (request && request.raw) {
|
|
213
|
+
return request.raw.req
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
promise: true,
|
|
217
|
+
params: function getParams(shim, fn, fnName, args) {
|
|
218
|
+
const req = args[0]
|
|
219
|
+
return req && req.params
|
|
220
|
+
}
|
|
221
|
+
})
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function wrapMiddleware(shim, middleware, event) {
|
|
225
|
+
if (!ROUTE_EVENTS[event]) {
|
|
226
|
+
return middleware
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return shim.recordMiddleware(middleware, {
|
|
230
|
+
route: event,
|
|
231
|
+
type: event === 'onPreResponse' ? shim.ERRORWARE : shim.MIDDLEWARE,
|
|
232
|
+
promise: true,
|
|
233
|
+
req: function getReq(shim, fn, fnName, args) {
|
|
234
|
+
const req = args[0]
|
|
235
|
+
return req && req.raw && req.raw.req
|
|
236
|
+
}
|
|
237
|
+
})
|
|
238
|
+
}
|
|
File without changes
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
+
/* eslint sonarjs/cognitive-complexity: ["error", 18] -- TODO: https://issues.newrelic.com/browse/NEWRELIC-5252 */
|
|
9
|
+
|
|
8
10
|
const logger = require('../../logger').child({ component: 'async_hooks' })
|
|
9
11
|
const asyncHooks = require('async_hooks')
|
|
10
12
|
|
|
@@ -38,7 +40,7 @@ function initialize(agent, shim) {
|
|
|
38
40
|
|
|
39
41
|
function getPromiseResolveStyleHooks(segmentMap, agent, shim) {
|
|
40
42
|
const hooks = {
|
|
41
|
-
init: function initHook(id, type, triggerId
|
|
43
|
+
init: function initHook(id, type, triggerId) {
|
|
42
44
|
if (type !== 'PROMISE') {
|
|
43
45
|
return
|
|
44
46
|
}
|
|
@@ -55,9 +57,6 @@ function getPromiseResolveStyleHooks(segmentMap, agent, shim) {
|
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
const activeSegment = shim.getActiveSegment() || parentSegment
|
|
58
|
-
if (asyncResource && asyncResource.promise) {
|
|
59
|
-
asyncResource.promise.__NR_id = id
|
|
60
|
-
}
|
|
61
60
|
|
|
62
61
|
segmentMap.set(id, activeSegment)
|
|
63
62
|
},
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
8
|
const asyncHooks = require('./async_hooks')
|
|
9
|
+
const symbols = require('../../symbols')
|
|
9
10
|
|
|
10
11
|
module.exports = initialize
|
|
11
12
|
|
|
@@ -37,16 +38,17 @@ function initialize(agent, nodule, name, shim) {
|
|
|
37
38
|
return function wrappedEmit(ev, error, promise) {
|
|
38
39
|
// Check for unhandledRejections here so we don't change the behavior of
|
|
39
40
|
// the event.
|
|
40
|
-
if (
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
if (
|
|
42
|
+
ev === 'unhandledRejection' &&
|
|
43
|
+
error &&
|
|
44
|
+
!process.domain &&
|
|
45
|
+
process.listenerCount('unhandledRejection') === 0
|
|
46
|
+
) {
|
|
47
|
+
// If there are no unhandledRejection handlers report the error.
|
|
48
|
+
const segment = promise[symbols.context] && promise[symbols.context].getSegment()
|
|
49
|
+
const tx = segment && segment.transaction
|
|
50
|
+
shim.logger.trace('Captured unhandled rejection for transaction %s', tx && tx.id)
|
|
51
|
+
agent.errors.add(tx, error)
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
return original.apply(this, arguments)
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
+
/* eslint sonarjs/cognitive-complexity: ["error", 40] -- TODO: https://issues.newrelic.com/browse/NEWRELIC-5252 */
|
|
9
|
+
|
|
8
10
|
const recordExternal = require('../../metrics/recorders/http_external')
|
|
9
11
|
const cat = require('../../util/cat')
|
|
10
12
|
const urltils = require('../../util/urltils')
|
|
@@ -12,9 +14,9 @@ const logger = require('../../logger').child({ component: 'outbound' })
|
|
|
12
14
|
const shimmer = require('../../shimmer')
|
|
13
15
|
const url = require('url')
|
|
14
16
|
const copy = require('../../util/copy')
|
|
17
|
+
const symbols = require('../../symbols')
|
|
15
18
|
|
|
16
19
|
const NAMES = require('../../metrics/names')
|
|
17
|
-
const SHIM_SYMBOLS = require('../../shim/constants').SYMBOLS
|
|
18
20
|
|
|
19
21
|
const DEFAULT_HOST = 'localhost'
|
|
20
22
|
const DEFAULT_HTTP_PORT = 80
|
|
@@ -25,10 +27,10 @@ const NEWRELIC_SYNTHETICS_HEADER = 'x-newrelic-synthetics'
|
|
|
25
27
|
/**
|
|
26
28
|
* Instruments an outbound HTTP request.
|
|
27
29
|
*
|
|
28
|
-
* @param {
|
|
29
|
-
* @param {object} opts
|
|
30
|
-
* @param {Function} makeRequest
|
|
31
|
-
* @returns {
|
|
30
|
+
* @param {object} agent instantiation of lib/agent.js
|
|
31
|
+
* @param {object} opts HTTP request options
|
|
32
|
+
* @param {Function} makeRequest function for issuing actual HTTP request
|
|
33
|
+
* @returns {object} The instrumented outbound HTTP request.
|
|
32
34
|
*/
|
|
33
35
|
module.exports = function instrumentOutbound(agent, opts, makeRequest) {
|
|
34
36
|
if (typeof opts === 'string') {
|
|
@@ -85,7 +87,7 @@ module.exports = function instrumentOutbound(agent, opts, makeRequest) {
|
|
|
85
87
|
|
|
86
88
|
// TODO: abstract header logic shared with TransactionShim#insertCATRequestHeaders
|
|
87
89
|
if (agent.config.distributed_tracing.enabled) {
|
|
88
|
-
if (opts.headers && opts.headers[
|
|
90
|
+
if (opts.headers && opts.headers[symbols.disableDT]) {
|
|
89
91
|
logger.trace('Distributed tracing disabled by instrumentation.')
|
|
90
92
|
} else {
|
|
91
93
|
transaction.insertDistributedTraceHeaders(outboundHeaders)
|
|
@@ -113,9 +115,7 @@ module.exports = function instrumentOutbound(agent, opts, makeRequest) {
|
|
|
113
115
|
const parsed = urltils.scrubAndParseParameters(request.path)
|
|
114
116
|
const proto = parsed.protocol || opts.protocol || 'http:'
|
|
115
117
|
segment.name += parsed.path
|
|
116
|
-
|
|
117
|
-
value: segment
|
|
118
|
-
})
|
|
118
|
+
request[symbols.segment] = segment
|
|
119
119
|
|
|
120
120
|
if (parsed.parameters) {
|
|
121
121
|
// Scrub and parse returns on object with a null prototype.
|
|
@@ -153,10 +153,10 @@ module.exports = function instrumentOutbound(agent, opts, makeRequest) {
|
|
|
153
153
|
* Notices the given error if there is no listener for the `error` event on the
|
|
154
154
|
* request object.
|
|
155
155
|
*
|
|
156
|
-
* @param {
|
|
157
|
-
* @param {http.ClientRequest
|
|
158
|
-
* @param {Error} error
|
|
159
|
-
* @returns {
|
|
156
|
+
* @param {object} segment TraceSegment instance
|
|
157
|
+
* @param {object} req http.ClientRequest
|
|
158
|
+
* @param {Error} error If provided, unhandled error that occurred during request
|
|
159
|
+
* @returns {boolean} True if the error will be collected by New Relic.
|
|
160
160
|
*/
|
|
161
161
|
function handleError(segment, req, error) {
|
|
162
162
|
if (req.listenerCount('error') > 0) {
|
|
@@ -173,10 +173,10 @@ function handleError(segment, req, error) {
|
|
|
173
173
|
/**
|
|
174
174
|
* Ties the response object to the request segment.
|
|
175
175
|
*
|
|
176
|
-
* @param {
|
|
177
|
-
* @param {string} hostname
|
|
178
|
-
* @param {http.ClientRequest
|
|
179
|
-
* @param {http.IncomingMessage
|
|
176
|
+
* @param {object} segment TraceSegment instance
|
|
177
|
+
* @param {string} hostname host of the HTTP request
|
|
178
|
+
* @param {object} req http.ClientRequest
|
|
179
|
+
* @param {object} res http.IncomingMessage
|
|
180
180
|
*/
|
|
181
181
|
function handleResponse(segment, hostname, req, res) {
|
|
182
182
|
// Add response attributes for spans
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
+
/* eslint sonarjs/cognitive-complexity: ["error", 42] -- TODO: https://issues.newrelic.com/browse/NEWRELIC-5252 */
|
|
9
|
+
|
|
8
10
|
const shimmer = require('../../shimmer')
|
|
9
11
|
const logger = require('../../logger').child({ component: 'http' })
|
|
10
12
|
const recordWeb = require('../../metrics/recorders/http')
|
|
@@ -13,21 +15,20 @@ const cat = require('../../util/cat')
|
|
|
13
15
|
const instrumentOutbound = require('./http-outbound')
|
|
14
16
|
const url = require('url')
|
|
15
17
|
const urltils = require('../../util/urltils')
|
|
16
|
-
const properties = require('../../util/properties')
|
|
17
18
|
const headerAttributes = require('../../header-attributes')
|
|
18
19
|
const headerProcessing = require('../../header-processing')
|
|
19
20
|
|
|
20
21
|
const NAMES = require('../../metrics/names')
|
|
21
22
|
const DESTS = require('../../config/attribute-filter').DESTINATIONS
|
|
22
23
|
|
|
24
|
+
const symbols = require('../../symbols')
|
|
25
|
+
|
|
23
26
|
/*
|
|
24
27
|
*
|
|
25
28
|
* CONSTANTS
|
|
26
29
|
*
|
|
27
30
|
*/
|
|
28
|
-
const NR_CONNECTION_PROP = '__NR__connection'
|
|
29
31
|
const NEWRELIC_SYNTHETICS_HEADER = 'x-newrelic-synthetics'
|
|
30
|
-
const TRANSACTION_INFO_KEY = '__NR_transactionInfo'
|
|
31
32
|
|
|
32
33
|
// For incoming requests this instrumentation functions by wrapping
|
|
33
34
|
// `http.createServer` and `http.Server#addListener`. The former merely sets the
|
|
@@ -55,12 +56,6 @@ function wrapEmitWithTransaction(agent, emit, isHTTPS) {
|
|
|
55
56
|
// Store the transaction information on the request and response.
|
|
56
57
|
const txInfo = storeTxInfo(transaction, request, response)
|
|
57
58
|
|
|
58
|
-
// Hook for web framework instrumentations that don't have easy access to
|
|
59
|
-
// the request entry point.
|
|
60
|
-
if (properties.hasOwn(this, '__NR_onRequestStarted')) {
|
|
61
|
-
this.__NR_onRequestStarted(request, response)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
59
|
if (request) {
|
|
65
60
|
initializeRequest(transaction, request)
|
|
66
61
|
}
|
|
@@ -204,7 +199,6 @@ function storeTxInfo(transaction, request, response) {
|
|
|
204
199
|
logger.debug('Missing request or response object! Not storing transaction info.')
|
|
205
200
|
return
|
|
206
201
|
}
|
|
207
|
-
const hideInternal = transaction.agent.config.transaction_tracer.hide_internals
|
|
208
202
|
|
|
209
203
|
const txInfo = {
|
|
210
204
|
transaction: transaction,
|
|
@@ -212,12 +206,7 @@ function storeTxInfo(transaction, request, response) {
|
|
|
212
206
|
errorHandled: false,
|
|
213
207
|
error: null
|
|
214
208
|
}
|
|
215
|
-
|
|
216
|
-
properties.setInternal(request, TRANSACTION_INFO_KEY, txInfo)
|
|
217
|
-
properties.setInternal(response, TRANSACTION_INFO_KEY, txInfo)
|
|
218
|
-
} else {
|
|
219
|
-
request[TRANSACTION_INFO_KEY] = response[TRANSACTION_INFO_KEY] = txInfo
|
|
220
|
-
}
|
|
209
|
+
request[symbols.transactionInfo] = response[symbols.transactionInfo] = txInfo
|
|
221
210
|
|
|
222
211
|
logger.trace('Stored transaction %s information on request and response', transaction.id)
|
|
223
212
|
|
|
@@ -245,7 +234,7 @@ function wrapResponseEnd(agent, proto) {
|
|
|
245
234
|
}
|
|
246
235
|
|
|
247
236
|
return function wrappedResEnd() {
|
|
248
|
-
const txInfo = this && this[
|
|
237
|
+
const txInfo = this && this[symbols.transactionInfo]
|
|
249
238
|
if (!txInfo) {
|
|
250
239
|
return end.apply(this, arguments)
|
|
251
240
|
}
|
|
@@ -256,10 +245,11 @@ function wrapResponseEnd(agent, proto) {
|
|
|
256
245
|
}
|
|
257
246
|
|
|
258
247
|
// If an error happened, add it to the aggregator.
|
|
259
|
-
if (
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
248
|
+
if (
|
|
249
|
+
txInfo.error &&
|
|
250
|
+
(!txInfo.errorHandled || urltils.isError(agent.config, this.statusCode))
|
|
251
|
+
) {
|
|
252
|
+
agent.errors.add(txInfo.transaction, txInfo.error)
|
|
263
253
|
}
|
|
264
254
|
|
|
265
255
|
// End all the segments leading up to and including this one.
|
|
@@ -393,9 +383,9 @@ function wrapRequest(agent, request) {
|
|
|
393
383
|
const reqArgs = [options, cb]
|
|
394
384
|
|
|
395
385
|
// Don't pollute metrics and calls with NR connections
|
|
396
|
-
const internalOnly = options && options[
|
|
386
|
+
const internalOnly = options && options[symbols.offTheRecord]
|
|
397
387
|
if (internalOnly) {
|
|
398
|
-
delete options[
|
|
388
|
+
delete options[symbols.offTheRecord]
|
|
399
389
|
}
|
|
400
390
|
|
|
401
391
|
// If this is not a request we're recording, exit early.
|
|
@@ -492,8 +482,7 @@ module.exports = function initialize(agent, http, moduleName) {
|
|
|
492
482
|
args[1] = agent.tracer.bindFunction(args[1], segment, true)
|
|
493
483
|
}
|
|
494
484
|
|
|
495
|
-
|
|
496
|
-
return sock
|
|
485
|
+
return agent.tracer.bindFunction(original, segment, true).apply(this, args)
|
|
497
486
|
}
|
|
498
487
|
}
|
|
499
488
|
)
|
|
@@ -507,7 +496,7 @@ module.exports = function initialize(agent, http, moduleName) {
|
|
|
507
496
|
* @param {string} header - The raw X-NewRelic-Synthetics header
|
|
508
497
|
* @param {string} encKey - Encoding key handed down from the server
|
|
509
498
|
* @param {Array.<number>} trustedIds - Array of accounts to trust the header from.
|
|
510
|
-
* @param {
|
|
499
|
+
* @param {object} transaction - Where the synthetics data is attached to.
|
|
511
500
|
*/
|
|
512
501
|
function handleSyntheticsHeader(header, encKey, trustedIds, transaction) {
|
|
513
502
|
const synthData = parseSyntheticsHeader(header, encKey, trustedIds)
|
|
@@ -525,7 +514,7 @@ function handleSyntheticsHeader(header, encKey, trustedIds, transaction) {
|
|
|
525
514
|
* @param {string} header - The raw X-NewRelic-Synthetics header
|
|
526
515
|
* @param {string} encKey - Encoding key handed down from the server
|
|
527
516
|
* @param {Array.<number>} trustedIds - Array of accounts to trust the header from.
|
|
528
|
-
* @
|
|
517
|
+
* @returns {object | null} - On successful parse and verification an object of
|
|
529
518
|
* synthetics data is returned, otherwise null is
|
|
530
519
|
* returned.
|
|
531
520
|
*/
|
|
@@ -5,6 +5,10 @@
|
|
|
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
|
+
const symbols = require('../../symbols')
|
|
11
|
+
|
|
8
12
|
module.exports = initialize
|
|
9
13
|
|
|
10
14
|
function initialize(agent, timers, moduleName, shim) {
|
|
@@ -53,7 +57,7 @@ function initialize(agent, timers, moduleName, shim) {
|
|
|
53
57
|
function wrapClearTimeout(shim, fn) {
|
|
54
58
|
return function wrappedClearTimeout(timer) {
|
|
55
59
|
if (timer && timer._onTimeout) {
|
|
56
|
-
const segment = timer._onTimeout.
|
|
60
|
+
const segment = timer._onTimeout[symbols.segment]
|
|
57
61
|
if (segment && !segment.opaque) {
|
|
58
62
|
segment.ignore = true
|
|
59
63
|
}
|
|
@@ -148,9 +148,7 @@ function wrapMiddleware(shim, middleware, name, route) {
|
|
|
148
148
|
const segmentName = `onRequest/${name}`
|
|
149
149
|
const spec = buildMiddlewareSpecForMiddlewareFunction(shim, segmentName, route)
|
|
150
150
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
return newMiddlewareFunction
|
|
151
|
+
return shim.recordMiddleware(middleware, spec)
|
|
154
152
|
}
|
|
155
153
|
|
|
156
154
|
/**
|
|
@@ -78,8 +78,10 @@ function wrapStart(shim, original) {
|
|
|
78
78
|
segment.addAttribute('grpc.statusCode', code)
|
|
79
79
|
segment.addAttribute('grpc.statusText', details)
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
const agent = shim.agent
|
|
82
|
+
const config = agent.config
|
|
83
|
+
|
|
84
|
+
if (shouldTrackError(code, config)) {
|
|
83
85
|
shim.agent.errors.add(segment.transaction, details)
|
|
84
86
|
}
|
|
85
87
|
|
|
@@ -184,9 +186,10 @@ function wrapRegister(shim, original) {
|
|
|
184
186
|
|
|
185
187
|
function instrumentEventListeners(stream, transaction) {
|
|
186
188
|
const agent = shim.agent
|
|
189
|
+
const config = agent.config
|
|
187
190
|
stream.call.once('callEnd', (statusCode) => {
|
|
188
191
|
transaction.trace.attributes.addAttribute(DESTINATION, 'response.status', statusCode)
|
|
189
|
-
if (statusCode
|
|
192
|
+
if (shouldTrackError(statusCode, config)) {
|
|
190
193
|
const status = constants.Status[statusCode]
|
|
191
194
|
const error = new Error(`gRPC status code ${statusCode}: ${status}`)
|
|
192
195
|
agent.errors.add(transaction, error)
|
|
@@ -202,6 +205,14 @@ function wrapRegister(shim, original) {
|
|
|
202
205
|
}
|
|
203
206
|
}
|
|
204
207
|
|
|
208
|
+
function shouldTrackError(statusCode, config) {
|
|
209
|
+
return (
|
|
210
|
+
statusCode > 0 &&
|
|
211
|
+
config.grpc.record_errors &&
|
|
212
|
+
!config.grpc.ignore_status_codes.includes(statusCode)
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
|
|
205
216
|
module.exports = function instrument(shim) {
|
|
206
217
|
const genericShim = shim.makeSpecializedShim(shim.GENERIC, 'call-stream')
|
|
207
218
|
const callStream = genericShim.require('./build/src/call-stream')
|
|
@@ -21,6 +21,11 @@ function wrapKeys(metacall) {
|
|
|
21
21
|
* Thanks to Hernan Silberman!
|
|
22
22
|
*
|
|
23
23
|
* instrument the memcached driver to intercept calls and keep stats on them.
|
|
24
|
+
*
|
|
25
|
+
* @param agent
|
|
26
|
+
* @param memcached
|
|
27
|
+
* @param moduleName
|
|
28
|
+
* @param shim
|
|
24
29
|
*/
|
|
25
30
|
module.exports = function initialize(agent, memcached, moduleName, shim) {
|
|
26
31
|
const proto = memcached && memcached.prototype
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
|
+
|
|
8
|
+
/* eslint sonarjs/cognitive-complexity: ["error", 18] -- TODO: https://issues.newrelic.com/browse/NEWRELIC-5252 */
|
|
9
|
+
|
|
7
10
|
const { CURSOR_OPS, COLLECTION_OPS, DB_OPS } = require('./constants')
|
|
8
11
|
const common = module.exports
|
|
9
12
|
common.NR_ATTRS = Symbol('NR_ATTRS')
|
|
@@ -11,7 +11,7 @@ const { captureAttributesOnStarted, makeQueryDescFunc } = require('./common')
|
|
|
11
11
|
* parser used to grab the collection and operation
|
|
12
12
|
* from a running query
|
|
13
13
|
*
|
|
14
|
-
* @param {
|
|
14
|
+
* @param {object} operation
|
|
15
15
|
*/
|
|
16
16
|
function queryParser(operation) {
|
|
17
17
|
let collection = this.collectionName || 'unknown'
|
|
@@ -29,7 +29,7 @@ function queryParser(operation) {
|
|
|
29
29
|
* add necessary attributes to segments
|
|
30
30
|
*
|
|
31
31
|
* @param {Shim} shim
|
|
32
|
-
* @param {
|
|
32
|
+
* @param {object} mongodb resolved package
|
|
33
33
|
*/
|
|
34
34
|
module.exports = function instrument(shim, mongodb) {
|
|
35
35
|
shim.setParser(queryParser)
|
|
@@ -65,6 +65,9 @@ module.exports = function instrument(shim, mongodb) {
|
|
|
65
65
|
* Iterate over permutations and properly
|
|
66
66
|
* wrap depending on the `recordDesc` above
|
|
67
67
|
* See: https://github.com/mongodb/node-mongodb-native/blob/v3.0.5/lib/collection.js#L384
|
|
68
|
+
*
|
|
69
|
+
* @param _
|
|
70
|
+
* @param modules
|
|
68
71
|
*/
|
|
69
72
|
function instrumentModules(_, modules) {
|
|
70
73
|
modules.forEach((module) => {
|
|
@@ -80,7 +83,7 @@ module.exports = function instrument(shim, mongodb) {
|
|
|
80
83
|
* if it needs to be wrapped as an operation or query
|
|
81
84
|
*
|
|
82
85
|
* @param {string} objectName name of class getting instrumented
|
|
83
|
-
* @param {
|
|
86
|
+
* @param {object} object reference to the class getting instrumented
|
|
84
87
|
* @param {Define} meta describes the methods and if they are callbacks
|
|
85
88
|
* promises, and return values
|
|
86
89
|
*/
|
|
@@ -25,7 +25,7 @@ module.exports = initialize
|
|
|
25
25
|
* based on version of mongodb
|
|
26
26
|
*
|
|
27
27
|
* @param {Agent} agent
|
|
28
|
-
* @param {
|
|
28
|
+
* @param {object} mongodb resolved package
|
|
29
29
|
* @param {string} moduleName name of module
|
|
30
30
|
* @param {Shim} shim
|
|
31
31
|
*/
|