newrelic 7.5.2 → 8.3.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 +4989 -4886
- package/THIRD_PARTY_NOTICES.md +625 -216
- package/api.js +105 -174
- package/bin/test-naming-rules.js +38 -32
- package/bin/tracetractor +0 -1
- package/index.js +12 -18
- package/lib/agent.js +108 -111
- package/lib/aggregators/base-aggregator.js +1 -1
- package/lib/aggregators/event-aggregator.js +6 -6
- package/lib/attributes.js +12 -13
- package/lib/collector/api.js +32 -42
- package/lib/collector/facts.js +67 -65
- package/lib/collector/http-agents.js +30 -27
- package/lib/collector/parse-response.js +1 -2
- package/lib/collector/remote-method.js +43 -36
- package/lib/collector/serverless.js +13 -18
- package/lib/collector/ssl/certificates.js +1056 -1056
- package/lib/config/attribute-filter.js +90 -82
- package/lib/config/default.js +30 -18
- package/lib/config/env.js +17 -12
- package/lib/config/harvest-config-validator.js +1 -1
- package/lib/config/index.js +160 -177
- package/lib/config/merge-server-config.js +7 -5
- package/lib/custom-events/custom-event-aggregator.js +1 -1
- package/lib/db/parse-sql.js +6 -9
- package/lib/db/parsed-statement.js +6 -13
- package/lib/db/query-parsers/sql.js +6 -9
- package/lib/db/query-sample.js +7 -3
- package/lib/db/query-trace-aggregator.js +12 -12
- package/lib/db/utils.js +1 -1
- package/lib/environment.js +173 -138
- package/lib/errors/error-collector.js +18 -31
- package/lib/errors/error-event-aggregator.js +1 -1
- package/lib/errors/error-trace-aggregator.js +2 -3
- package/lib/errors/helper.js +21 -30
- package/lib/errors/index.js +16 -28
- package/lib/feature_flags.js +5 -8
- package/lib/grpc/connection/states.js +6 -6
- package/lib/grpc/connection.js +35 -46
- package/lib/header-attributes.js +49 -53
- package/lib/instrumentation/amqplib.js +8 -17
- package/lib/instrumentation/bluebird.js +61 -20
- package/lib/instrumentation/cassandra-driver.js +2 -2
- package/lib/instrumentation/connect.js +4 -3
- package/lib/instrumentation/core/async_hooks.js +11 -4
- package/lib/instrumentation/core/child_process.js +20 -28
- package/lib/instrumentation/core/crypto.js +1 -7
- package/lib/instrumentation/core/dns.js +3 -7
- package/lib/instrumentation/core/domain.js +2 -8
- package/lib/instrumentation/core/fs.js +22 -37
- package/lib/instrumentation/core/globals.js +3 -7
- package/lib/instrumentation/core/http-outbound.js +15 -40
- package/lib/instrumentation/core/http.js +29 -63
- package/lib/instrumentation/core/inspector.js +6 -10
- package/lib/instrumentation/core/net.js +3 -1
- package/lib/instrumentation/core/timers.js +17 -24
- package/lib/instrumentation/core/zlib.js +2 -10
- package/lib/instrumentation/express.js +4 -2
- package/lib/instrumentation/fastify/spec-builders.js +5 -0
- package/lib/instrumentation/fastify.js +37 -10
- package/lib/instrumentation/hapi/hapi-17.js +9 -10
- package/lib/instrumentation/hapi.js +15 -15
- package/lib/instrumentation/ioredis.js +1 -2
- package/lib/instrumentation/memcached.js +39 -43
- package/lib/instrumentation/mongodb/common.js +218 -0
- package/lib/instrumentation/mongodb/constants.js +87 -0
- package/lib/instrumentation/mongodb/v2-mongo.js +110 -0
- package/lib/instrumentation/mongodb/v3-mongo.js +80 -0
- package/lib/instrumentation/mongodb/v4-mongo.js +90 -0
- package/lib/instrumentation/mongodb.js +20 -312
- package/lib/instrumentation/mysql.js +33 -26
- package/lib/instrumentation/oracle.js +10 -14
- package/lib/instrumentation/pg.js +30 -21
- package/lib/instrumentation/promise.js +20 -17
- package/lib/instrumentation/redis.js +30 -30
- package/lib/instrumentation/when.js +9 -1
- package/lib/instrumentations.js +24 -24
- package/lib/logger.js +1 -1
- package/lib/metrics/index.js +37 -17
- package/lib/metrics/mapper.js +9 -9
- package/lib/metrics/metric-aggregator.js +5 -10
- package/lib/metrics/names.js +8 -7
- package/lib/metrics/normalizer/rule.js +6 -7
- package/lib/metrics/normalizer/tx_segment.js +17 -13
- package/lib/metrics/normalizer.js +30 -33
- package/lib/metrics/recorders/custom.js +3 -1
- package/lib/metrics/recorders/distributed-trace.js +3 -18
- package/lib/metrics/recorders/generic.js +3 -2
- package/lib/metrics/recorders/http.js +4 -6
- package/lib/metrics/recorders/http_external.js +1 -3
- package/lib/metrics/recorders/message-transaction.js +2 -12
- package/lib/metrics/recorders/other.js +2 -12
- package/lib/parse-proc-cpuinfo.js +11 -16
- package/lib/parse-proc-meminfo.js +5 -3
- package/lib/prioritized-attributes.js +12 -17
- package/lib/priority-queue.js +1 -1
- package/lib/proxy/grpc.js +1 -1
- package/lib/reservoir.js +9 -3
- package/lib/sampler.js +12 -13
- package/lib/serverless/api-gateway.js +3 -3
- package/lib/serverless/aws-lambda.js +28 -37
- package/lib/shim/conglomerate-shim.js +4 -4
- package/lib/shim/datastore-shim.js +29 -38
- package/lib/shim/index.js +8 -9
- package/lib/shim/message-shim.js +111 -113
- package/lib/shim/promise-shim.js +18 -13
- package/lib/shim/shim.js +72 -66
- package/lib/shim/specs/index.js +18 -19
- package/lib/shim/transaction-shim.js +26 -36
- package/lib/shim/webframework-shim.js +25 -35
- package/lib/shimmer.js +184 -166
- package/lib/spans/create-span-event-aggregator.js +24 -44
- package/lib/spans/span-context.js +4 -10
- package/lib/spans/span-event-aggregator.js +68 -13
- package/lib/spans/span-event.js +5 -7
- package/lib/spans/span-streamer.js +10 -18
- package/lib/spans/streaming-span-event-aggregator.js +1 -1
- package/lib/spans/streaming-span-event.js +4 -4
- package/lib/stats/apdex.js +5 -11
- package/lib/stats/index.js +12 -17
- package/lib/system-info.js +7 -3
- package/lib/timer.js +30 -16
- package/lib/transaction/dt-payload.js +1 -1
- package/lib/transaction/handle.js +19 -19
- package/lib/transaction/index.js +94 -112
- package/lib/transaction/name-state.js +5 -6
- package/lib/transaction/trace/aggregator.js +78 -73
- package/lib/transaction/trace/exclusive-time-calculator.js +5 -9
- package/lib/transaction/trace/index.js +26 -24
- package/lib/transaction/trace/segment.js +39 -56
- package/lib/transaction/tracecontext.js +37 -45
- package/lib/transaction/tracer/index.js +79 -44
- package/lib/transaction/transaction-event-aggregator.js +29 -31
- package/lib/uninstrumented.js +4 -5
- package/lib/util/attribute-types.js +1 -5
- package/lib/util/byte-limit.js +0 -1
- package/lib/util/cat.js +5 -13
- package/lib/util/codec.js +8 -4
- package/lib/util/deep-equal.js +48 -18
- package/lib/util/flatten.js +5 -2
- package/lib/util/hashes.js +2 -2
- package/lib/util/label-parser.js +7 -13
- package/lib/util/logger.js +31 -13
- package/lib/util/process-version.js +1 -1
- package/lib/util/properties.js +1 -1
- package/lib/util/sql/obfuscate.js +7 -17
- package/lib/util/stream-sink.js +2 -3
- package/lib/util/urltils.js +9 -13
- package/lib/utilization/aws-info.js +2 -3
- package/lib/utilization/azure-info.js +32 -30
- package/lib/utilization/common.js +5 -4
- package/lib/utilization/docker-info.js +4 -6
- package/lib/utilization/gcp-info.js +36 -35
- package/lib/utilization/index.js +1 -1
- package/lib/utilization/kubernetes-info.js +2 -2
- package/lib/utilization/pcf-info.js +4 -4
- package/package.json +32 -18
- package/stub_api.js +8 -6
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
8
|
var genericRecorder = require('../metrics/recorders/generic')
|
|
9
|
-
var logger = require('../logger.js').child({component: 'WebFrameworkShim'})
|
|
9
|
+
var logger = require('../logger.js').child({ component: 'WebFrameworkShim' })
|
|
10
10
|
var metrics = require('../metrics/names')
|
|
11
11
|
var TransactionShim = require('./transaction-shim')
|
|
12
12
|
var Shim = require('./shim')
|
|
@@ -14,7 +14,6 @@ var specs = require('./specs')
|
|
|
14
14
|
var urltils = require('../util/urltils')
|
|
15
15
|
var util = require('util')
|
|
16
16
|
|
|
17
|
-
|
|
18
17
|
/**
|
|
19
18
|
* An enumeration of well-known web frameworks so that new instrumentations can
|
|
20
19
|
* use the same names we already use for first-party instrumentation.
|
|
@@ -37,12 +36,12 @@ var FRAMEWORK_NAMES = {
|
|
|
37
36
|
}
|
|
38
37
|
|
|
39
38
|
var MIDDLEWARE_TYPE_DETAILS = {
|
|
40
|
-
APPLICATION:
|
|
41
|
-
ERRORWARE:
|
|
42
|
-
MIDDLEWARE:
|
|
43
|
-
PARAMWARE:
|
|
44
|
-
ROUTE:
|
|
45
|
-
ROUTER:
|
|
39
|
+
APPLICATION: { name: 'Mounted App: ', path: true, record: false },
|
|
40
|
+
ERRORWARE: { name: '', path: false, record: true },
|
|
41
|
+
MIDDLEWARE: { name: '', path: false, record: true },
|
|
42
|
+
PARAMWARE: { name: '', path: false, record: true },
|
|
43
|
+
ROUTE: { name: 'Route Path: ', path: true, record: false },
|
|
44
|
+
ROUTER: { name: 'Router: ', path: true, record: false }
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
var MIDDLEWARE_TYPE_NAMES = {
|
|
@@ -61,7 +60,6 @@ var MIDDLEWARE_TYPE_NAMES = {
|
|
|
61
60
|
*/
|
|
62
61
|
var TRANSACTION_INFO_KEY = '__NR_transactionInfo'
|
|
63
62
|
|
|
64
|
-
|
|
65
63
|
/**
|
|
66
64
|
* Constructs a shim associated with the given agent instance, specialized for
|
|
67
65
|
* instrumenting web frameworks.
|
|
@@ -89,7 +87,7 @@ var TRANSACTION_INFO_KEY = '__NR_transactionInfo'
|
|
|
89
87
|
*/
|
|
90
88
|
function WebFrameworkShim(agent, moduleName, resolvedName, frameworkId) {
|
|
91
89
|
TransactionShim.call(this, agent, moduleName, resolvedName)
|
|
92
|
-
this._logger = logger.child({module: moduleName})
|
|
90
|
+
this._logger = logger.child({ module: moduleName })
|
|
93
91
|
if (frameworkId) {
|
|
94
92
|
this.setFramework(frameworkId)
|
|
95
93
|
}
|
|
@@ -326,8 +324,8 @@ function setFramework(framework) {
|
|
|
326
324
|
}
|
|
327
325
|
this.agent.environment.setFramework(framework)
|
|
328
326
|
|
|
329
|
-
this._logger = this._logger.child({framework: framework})
|
|
330
|
-
this.logger.trace({metrics: this._metrics}, 'Framework metric names set')
|
|
327
|
+
this._logger = this._logger.child({ framework: framework })
|
|
328
|
+
this.logger.trace({ metrics: this._metrics }, 'Framework metric names set')
|
|
331
329
|
}
|
|
332
330
|
|
|
333
331
|
/**
|
|
@@ -343,12 +341,7 @@ function setTransactionUri(uri) {
|
|
|
343
341
|
return
|
|
344
342
|
}
|
|
345
343
|
|
|
346
|
-
tx.nameState.setName(
|
|
347
|
-
this._metrics.FRAMEWORK,
|
|
348
|
-
tx.verb,
|
|
349
|
-
metrics.ACTION_DELIMITER,
|
|
350
|
-
uri
|
|
351
|
-
)
|
|
344
|
+
tx.nameState.setName(this._metrics.FRAMEWORK, tx.verb, metrics.ACTION_DELIMITER, uri)
|
|
352
345
|
}
|
|
353
346
|
|
|
354
347
|
/**
|
|
@@ -388,10 +381,7 @@ function recordRender(nodule, properties, spec) {
|
|
|
388
381
|
return this.record(nodule, properties, function renderRecorder(shim, fn, name, args) {
|
|
389
382
|
var viewIdx = shim.normalizeIndex(args.length, spec.view)
|
|
390
383
|
if (viewIdx === null) {
|
|
391
|
-
shim.logger.debug(
|
|
392
|
-
'Invalid spec.view (%d vs %d), not recording.',
|
|
393
|
-
spec.view, args.length
|
|
394
|
-
)
|
|
384
|
+
shim.logger.debug('Invalid spec.view (%d vs %d), not recording.', spec.view, args.length)
|
|
395
385
|
return null
|
|
396
386
|
}
|
|
397
387
|
|
|
@@ -441,7 +431,7 @@ function wrapMiddlewareMounter(nodule, properties, spec) {
|
|
|
441
431
|
}
|
|
442
432
|
if (this.isFunction(spec)) {
|
|
443
433
|
// wrapMiddlewareMounter(nodule [, properties], wrapper)
|
|
444
|
-
spec = {wrapper: spec}
|
|
434
|
+
spec = { wrapper: spec }
|
|
445
435
|
}
|
|
446
436
|
|
|
447
437
|
spec = this.setDefaults(spec, {
|
|
@@ -823,9 +813,7 @@ function _recordMiddleware(shim, middleware, spec) {
|
|
|
823
813
|
|
|
824
814
|
return shim.record(
|
|
825
815
|
middleware,
|
|
826
|
-
spec.promise
|
|
827
|
-
? middlewareWithPromiseRecorder
|
|
828
|
-
: middlewareWithCallbackRecorder
|
|
816
|
+
spec.promise ? middlewareWithPromiseRecorder : middlewareWithCallbackRecorder
|
|
829
817
|
)
|
|
830
818
|
|
|
831
819
|
// TODO: let's please break these out
|
|
@@ -839,9 +827,10 @@ function _recordMiddleware(shim, middleware, spec) {
|
|
|
839
827
|
var txInfo = _getTransactionInfo(shim, req)
|
|
840
828
|
if (!txInfo || !txInfo.transaction) {
|
|
841
829
|
shim.logger.debug(
|
|
842
|
-
{txInfo: txInfo},
|
|
830
|
+
{ txInfo: txInfo },
|
|
843
831
|
'Could not get transaction info in %s (%s)',
|
|
844
|
-
route,
|
|
832
|
+
route,
|
|
833
|
+
fnName
|
|
845
834
|
)
|
|
846
835
|
return null
|
|
847
836
|
}
|
|
@@ -850,7 +839,8 @@ function _recordMiddleware(shim, middleware, spec) {
|
|
|
850
839
|
|
|
851
840
|
// Copy over route parameters onto the transaction root.
|
|
852
841
|
var params = shim.agent.config.high_security
|
|
853
|
-
? null
|
|
842
|
+
? null
|
|
843
|
+
: spec.params.call(this, shim, fn, fnName, args, req)
|
|
854
844
|
|
|
855
845
|
// Wrap up `next` and push on our name state if we find it. We only want to
|
|
856
846
|
// push the name state if there is a next so that we can safely remove it
|
|
@@ -929,9 +919,10 @@ function _recordMiddleware(shim, middleware, spec) {
|
|
|
929
919
|
var txInfo = _getTransactionInfo(shim, req)
|
|
930
920
|
if (!txInfo || !txInfo.transaction) {
|
|
931
921
|
shim.logger.debug(
|
|
932
|
-
{txInfo: txInfo},
|
|
922
|
+
{ txInfo: txInfo },
|
|
933
923
|
'Could not get transaction info in %s (%s)',
|
|
934
|
-
route,
|
|
924
|
+
route,
|
|
925
|
+
fnName
|
|
935
926
|
)
|
|
936
927
|
return null
|
|
937
928
|
}
|
|
@@ -940,7 +931,8 @@ function _recordMiddleware(shim, middleware, spec) {
|
|
|
940
931
|
|
|
941
932
|
// Copy over route parameters onto the transaction root.
|
|
942
933
|
var params = shim.agent.config.high_security
|
|
943
|
-
? null
|
|
934
|
+
? null
|
|
935
|
+
: spec.params.call(this, shim, fn, fnName, args, req)
|
|
944
936
|
|
|
945
937
|
// Append this middleware's mount point and possibly construct a recorder.
|
|
946
938
|
if (spec.appendPath) {
|
|
@@ -1171,9 +1163,7 @@ function _isError(shim, err) {
|
|
|
1171
1163
|
* The spec object the values are coming from
|
|
1172
1164
|
*/
|
|
1173
1165
|
function _copyExpectedSpecParameters(destination, source) {
|
|
1174
|
-
var keys = [
|
|
1175
|
-
'matchArity'
|
|
1176
|
-
]
|
|
1166
|
+
var keys = ['matchArity']
|
|
1177
1167
|
|
|
1178
1168
|
for (var i = 0; i < keys.length; ++i) {
|
|
1179
1169
|
var key = keys[i]
|
package/lib/shimmer.js
CHANGED
|
@@ -5,16 +5,16 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
const path = require('path')
|
|
9
|
+
const fs = require('./util/unwrapped-core').fs
|
|
10
|
+
const logger = require('./logger').child({ component: 'shimmer' })
|
|
11
|
+
const INSTRUMENTATIONS = require('./instrumentations')()
|
|
12
|
+
const properties = require('./util/properties')
|
|
13
|
+
const shims = require('./shim')
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
const MODULE_TYPE = shims.constants.MODULE_TYPE
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
const CORE_INSTRUMENTATION = {
|
|
18
18
|
child_process: {
|
|
19
19
|
type: MODULE_TYPE.GENERIC,
|
|
20
20
|
file: 'child_process.js'
|
|
@@ -73,114 +73,12 @@ const FORCE_MODULE_RESOLUTION_WARNING =
|
|
|
73
73
|
* maneuver, but it should be pretty safe if there's a desire to reboot the
|
|
74
74
|
* agent in flight.
|
|
75
75
|
*
|
|
76
|
-
* All of the wrapped methods are tracked in this
|
|
76
|
+
* All of the wrapped methods are tracked in this constiable and used by unwrapAll
|
|
77
77
|
* below.
|
|
78
78
|
*/
|
|
79
|
-
|
|
79
|
+
let instrumented = []
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
if (shimmer.debug) {
|
|
83
|
-
shim.enableDebug()
|
|
84
|
-
instrumented.push(shim)
|
|
85
|
-
instrumented.push({__NR_unwrap: function unwrapNodule() {
|
|
86
|
-
delete nodule.__NR_instrumented_errored
|
|
87
|
-
delete nodule.__NR_instrumented
|
|
88
|
-
delete nodule.__NR_shim
|
|
89
|
-
}})
|
|
90
|
-
nodule.__NR_shim = shim
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* All instrumentation files must export the same interface: a single
|
|
96
|
-
* initialization function that takes the agent and the module to be
|
|
97
|
-
* instrumented.
|
|
98
|
-
*/
|
|
99
|
-
function instrument(agent, nodule, moduleName, resolvedName) {
|
|
100
|
-
var instrumentation = shimmer.registeredInstrumentations[moduleName]
|
|
101
|
-
if (properties.hasOwn(nodule, '__NR_instrumented')
|
|
102
|
-
|| properties.hasOwn(nodule, '__NR_instrumented_errored')) {
|
|
103
|
-
logger.trace(
|
|
104
|
-
'Already instrumented or failed to instrument %s, skipping redundant instrumentation',
|
|
105
|
-
moduleName
|
|
106
|
-
)
|
|
107
|
-
return nodule
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
var shim = shims.createShimFromType(
|
|
112
|
-
instrumentation.type,
|
|
113
|
-
agent,
|
|
114
|
-
moduleName,
|
|
115
|
-
resolvedName
|
|
116
|
-
)
|
|
117
|
-
|
|
118
|
-
applyDebugState(shimmer, shim, nodule)
|
|
119
|
-
|
|
120
|
-
try {
|
|
121
|
-
if (instrumentation.onRequire(shim, nodule, moduleName) !== false) {
|
|
122
|
-
nodule = shim.getExport(nodule)
|
|
123
|
-
nodule.__NR_instrumented = true
|
|
124
|
-
}
|
|
125
|
-
} catch (instrumentationError) {
|
|
126
|
-
nodule.__NR_instrumented_errored = true
|
|
127
|
-
if (instrumentation.onError) {
|
|
128
|
-
try {
|
|
129
|
-
instrumentation.onError(instrumentationError)
|
|
130
|
-
} catch (e) {
|
|
131
|
-
logger.warn(
|
|
132
|
-
e, instrumentationError,
|
|
133
|
-
'Custom instrumentation for %s failed, then the onError handler threw an error',
|
|
134
|
-
moduleName
|
|
135
|
-
)
|
|
136
|
-
}
|
|
137
|
-
} else {
|
|
138
|
-
logger.warn(
|
|
139
|
-
instrumentationError,
|
|
140
|
-
'Custom instrumentation for %s failed. Please report this to the ' +
|
|
141
|
-
'maintainers of the custom instrumentation.',
|
|
142
|
-
moduleName
|
|
143
|
-
)
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return nodule
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function _firstPartyInstrumentation(agent, fileName, shim, nodule, moduleName) {
|
|
151
|
-
var fullPath = path.resolve(fileName)
|
|
152
|
-
if (!fs.existsSync(fileName)) {
|
|
153
|
-
return logger.warn(
|
|
154
|
-
'Tried to load instrumentation from %s, but file does not exist',
|
|
155
|
-
fullPath
|
|
156
|
-
)
|
|
157
|
-
}
|
|
158
|
-
try {
|
|
159
|
-
return require(fileName)(agent, nodule, moduleName, shim)
|
|
160
|
-
} catch (error) {
|
|
161
|
-
logger.warn(
|
|
162
|
-
error,
|
|
163
|
-
'Failed to instrument module %s using %s',
|
|
164
|
-
path.basename(fileName, '.js'),
|
|
165
|
-
fullPath
|
|
166
|
-
)
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function _postLoad(agent, nodule, name, resolvedName) {
|
|
171
|
-
var instrumentation
|
|
172
|
-
instrumentation = shimmer.getInstrumentationNameFromModuleName(name)
|
|
173
|
-
|
|
174
|
-
// Check if this is a known instrumentation and then run it.
|
|
175
|
-
if (shimmer.registeredInstrumentations[instrumentation]) {
|
|
176
|
-
logger.trace('Instrumenting %s.', name)
|
|
177
|
-
return instrument(agent, nodule, instrumentation, resolvedName)
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return nodule
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
var shimmer = module.exports = {
|
|
81
|
+
const shimmer = (module.exports = {
|
|
184
82
|
/**
|
|
185
83
|
* If debug isn't false, the agent will retain references to wrapped methods
|
|
186
84
|
* for the entire lifetime of the agent. Some instrumentation depends on
|
|
@@ -218,17 +116,18 @@ var shimmer = module.exports = {
|
|
|
218
116
|
*/
|
|
219
117
|
wrapMethod: function wrapMethod(nodule, noduleName, methods, wrapper) {
|
|
220
118
|
if (!methods) {
|
|
221
|
-
return logger.warn(
|
|
222
|
-
new Error(),
|
|
223
|
-
"Must include a method name to wrap. Called from:"
|
|
224
|
-
)
|
|
119
|
+
return logger.warn(new Error(), 'Must include a method name to wrap. Called from:')
|
|
225
120
|
}
|
|
226
121
|
|
|
227
|
-
if (!noduleName)
|
|
228
|
-
|
|
122
|
+
if (!noduleName) {
|
|
123
|
+
noduleName = '[unknown]'
|
|
124
|
+
}
|
|
125
|
+
if (!Array.isArray(methods)) {
|
|
126
|
+
methods = [methods]
|
|
127
|
+
}
|
|
229
128
|
|
|
230
|
-
methods.forEach(
|
|
231
|
-
|
|
129
|
+
methods.forEach((method) => {
|
|
130
|
+
const fqmn = noduleName + '.' + method
|
|
232
131
|
|
|
233
132
|
if (!nodule) {
|
|
234
133
|
return logger.debug("Can't wrap %s from nonexistent object.", fqmn)
|
|
@@ -238,24 +137,31 @@ var shimmer = module.exports = {
|
|
|
238
137
|
return logger.debug("Can't wrap %s without a wrapper generator.", fqmn)
|
|
239
138
|
}
|
|
240
139
|
|
|
241
|
-
|
|
140
|
+
const original = nodule[method]
|
|
242
141
|
|
|
243
|
-
if (!original)
|
|
244
|
-
|
|
142
|
+
if (!original) {
|
|
143
|
+
return logger.trace('%s not defined, so not wrapping.', fqmn)
|
|
144
|
+
}
|
|
145
|
+
if (original.__NR_unwrap) {
|
|
146
|
+
return logger.debug('%s already wrapped by agent.', fqmn)
|
|
147
|
+
}
|
|
245
148
|
|
|
246
|
-
|
|
149
|
+
const wrapped = wrapper(original, method)
|
|
247
150
|
Object.keys(original).forEach((key) => {
|
|
248
151
|
wrapped[key] = original[key]
|
|
249
152
|
})
|
|
250
153
|
wrapped.__NR_original = original
|
|
154
|
+
// eslint-disable-next-line camelcase
|
|
251
155
|
wrapped.__NR_unwrap = function __NR_unwrap() {
|
|
252
156
|
nodule[method] = original
|
|
253
|
-
logger.trace(
|
|
157
|
+
logger.trace('Removed instrumentation from %s.', fqmn)
|
|
254
158
|
}
|
|
255
159
|
|
|
256
160
|
nodule[method] = wrapped
|
|
257
|
-
if (shimmer.debug)
|
|
258
|
-
|
|
161
|
+
if (shimmer.debug) {
|
|
162
|
+
instrumented.push(wrapped)
|
|
163
|
+
}
|
|
164
|
+
logger.trace('Instrumented %s.', fqmn)
|
|
259
165
|
})
|
|
260
166
|
},
|
|
261
167
|
|
|
@@ -277,34 +183,40 @@ var shimmer = module.exports = {
|
|
|
277
183
|
*/
|
|
278
184
|
wrapDeprecated: function wrapDeprecated(nodule, noduleName, property, options) {
|
|
279
185
|
if (!property) {
|
|
280
|
-
logger.warn(new Error(),
|
|
186
|
+
logger.warn(new Error(), 'Must include a function name to wrap. Called from:')
|
|
281
187
|
return
|
|
282
188
|
}
|
|
283
189
|
|
|
284
|
-
if (!noduleName)
|
|
190
|
+
if (!noduleName) {
|
|
191
|
+
noduleName = '[unknown]'
|
|
192
|
+
}
|
|
285
193
|
|
|
286
|
-
|
|
194
|
+
const fqmn = noduleName + '.' + property
|
|
287
195
|
if (!nodule) {
|
|
288
196
|
logger.debug("Can't wrap %s from nonexistent object.", fqmn)
|
|
289
197
|
return
|
|
290
198
|
}
|
|
291
199
|
|
|
292
|
-
|
|
200
|
+
const original = nodule[property]
|
|
293
201
|
if (!original) {
|
|
294
|
-
logger.trace(
|
|
202
|
+
logger.trace('%s not defined, so not wrapping.', fqmn)
|
|
295
203
|
return
|
|
296
204
|
}
|
|
297
205
|
|
|
298
206
|
delete nodule[property]
|
|
299
207
|
|
|
300
|
-
|
|
208
|
+
const descriptor = {
|
|
301
209
|
configurable: true,
|
|
302
210
|
enumerable: true
|
|
303
211
|
}
|
|
304
|
-
if (options.get)
|
|
305
|
-
|
|
212
|
+
if (options.get) {
|
|
213
|
+
descriptor.get = options.get
|
|
214
|
+
}
|
|
215
|
+
if (options.set) {
|
|
216
|
+
descriptor.set = options.set
|
|
217
|
+
}
|
|
306
218
|
Object.defineProperty(nodule, property, descriptor)
|
|
307
|
-
logger.trace(
|
|
219
|
+
logger.trace('Instrumented %s.', fqmn)
|
|
308
220
|
|
|
309
221
|
if (shimmer.debug) {
|
|
310
222
|
instrumented.push({
|
|
@@ -319,30 +231,42 @@ var shimmer = module.exports = {
|
|
|
319
231
|
},
|
|
320
232
|
|
|
321
233
|
unwrapMethod: function unwrapMethod(nodule, noduleName, method) {
|
|
322
|
-
if (!noduleName)
|
|
323
|
-
|
|
324
|
-
|
|
234
|
+
if (!noduleName) {
|
|
235
|
+
noduleName = '[unknown]'
|
|
236
|
+
}
|
|
237
|
+
if (!method) {
|
|
238
|
+
return logger.debug(
|
|
239
|
+
'Must include a method name to unwrap. ' + 'Called from: %s',
|
|
240
|
+
new Error().stack
|
|
241
|
+
)
|
|
242
|
+
}
|
|
325
243
|
|
|
326
|
-
|
|
244
|
+
const fqmn = noduleName + '.' + method
|
|
327
245
|
|
|
328
246
|
if (!nodule) {
|
|
329
247
|
return logger.debug("Can't unwrap %s from nonexistent object.", fqmn)
|
|
330
248
|
}
|
|
331
249
|
|
|
332
|
-
|
|
250
|
+
const wrapped = nodule[method]
|
|
333
251
|
|
|
334
252
|
// keep instrumented up to date
|
|
335
|
-
|
|
336
|
-
if (pos !== -1)
|
|
253
|
+
const pos = instrumented.indexOf(wrapped)
|
|
254
|
+
if (pos !== -1) {
|
|
255
|
+
instrumented.splice(pos, 1)
|
|
256
|
+
}
|
|
337
257
|
|
|
338
|
-
if (!wrapped)
|
|
339
|
-
|
|
258
|
+
if (!wrapped) {
|
|
259
|
+
return logger.debug('%s not defined, so not unwrapping.', fqmn)
|
|
260
|
+
}
|
|
261
|
+
if (!wrapped.__NR_unwrap) {
|
|
262
|
+
return logger.debug("%s isn't unwrappable.", fqmn)
|
|
263
|
+
}
|
|
340
264
|
|
|
341
265
|
wrapped.__NR_unwrap()
|
|
342
266
|
},
|
|
343
267
|
|
|
344
268
|
unwrapAll: function unwrapAll() {
|
|
345
|
-
instrumented.forEach(
|
|
269
|
+
instrumented.forEach((wrapper) => {
|
|
346
270
|
wrapper.__NR_unwrap()
|
|
347
271
|
})
|
|
348
272
|
instrumented = []
|
|
@@ -353,9 +277,9 @@ var shimmer = module.exports = {
|
|
|
353
277
|
* have an opportunity to patch them with instrumentation.
|
|
354
278
|
*/
|
|
355
279
|
patchModule: function patchModule(agent) {
|
|
356
|
-
logger.trace(
|
|
357
|
-
|
|
358
|
-
|
|
280
|
+
logger.trace('Wrapping module loader.')
|
|
281
|
+
const Module = require('module')
|
|
282
|
+
const filepathMap = {}
|
|
359
283
|
|
|
360
284
|
shimmer.wrapMethod(Module, 'Module', '_resolveFilename', function wrapRes(resolve) {
|
|
361
285
|
return function wrappedResolveFilename(file) {
|
|
@@ -404,8 +328,8 @@ var shimmer = module.exports = {
|
|
|
404
328
|
},
|
|
405
329
|
|
|
406
330
|
unpatchModule: function unpatchModule() {
|
|
407
|
-
logger.trace(
|
|
408
|
-
|
|
331
|
+
logger.trace('Unwrapping to previous module loader.')
|
|
332
|
+
const Module = require('module')
|
|
409
333
|
|
|
410
334
|
shimmer.unwrapMethod(Module, 'Module', '_resolveFilename')
|
|
411
335
|
shimmer.unwrapMethod(Module, 'Module', '_load')
|
|
@@ -414,8 +338,8 @@ var shimmer = module.exports = {
|
|
|
414
338
|
bootstrapInstrumentation: function bootstrapInstrumentation(agent) {
|
|
415
339
|
// Instrument global.
|
|
416
340
|
const globalShim = new shims.Shim(agent, 'globals', 'globals')
|
|
417
|
-
applyDebugState(
|
|
418
|
-
|
|
341
|
+
applyDebugState(globalShim, global)
|
|
342
|
+
const globalsFilepath = path.join(__dirname, 'instrumentation', 'core', 'globals.js')
|
|
419
343
|
_firstPartyInstrumentation(agent, globalsFilepath, globalShim, global, 'globals')
|
|
420
344
|
|
|
421
345
|
// Instrument each of the core modules.
|
|
@@ -427,27 +351,23 @@ var shimmer = module.exports = {
|
|
|
427
351
|
try {
|
|
428
352
|
uninstrumented = require(mojule)
|
|
429
353
|
} catch (err) {
|
|
430
|
-
logger.trace(
|
|
431
|
-
'Could not load core module %s got error %s',
|
|
432
|
-
mojule,
|
|
433
|
-
err
|
|
434
|
-
)
|
|
354
|
+
logger.trace('Could not load core module %s got error %s', mojule, err)
|
|
435
355
|
}
|
|
436
356
|
|
|
437
357
|
const shim = shims.createShimFromType(core.type, agent, mojule, mojule)
|
|
438
|
-
applyDebugState(
|
|
358
|
+
applyDebugState(shim, core)
|
|
439
359
|
_firstPartyInstrumentation(agent, filePath, shim, uninstrumented, mojule)
|
|
440
360
|
})
|
|
441
361
|
|
|
442
362
|
// Register all the first-party instrumentations.
|
|
443
363
|
Object.keys(INSTRUMENTATIONS).forEach(function forEachInstrumentation(moduleName) {
|
|
444
|
-
|
|
364
|
+
const instrInfo = INSTRUMENTATIONS[moduleName]
|
|
445
365
|
if (instrInfo.module) {
|
|
446
366
|
// Because external instrumentations can change independent of
|
|
447
367
|
// the agent core, we don't want breakages in them to entirely
|
|
448
368
|
// disable the agent.
|
|
449
369
|
try {
|
|
450
|
-
|
|
370
|
+
const hooks = require(instrInfo.module + '/nr-hooks')
|
|
451
371
|
hooks.forEach(shimmer.registerInstrumentation)
|
|
452
372
|
} catch (e) {
|
|
453
373
|
logger.warn('Failed to load instrumentation for ' + instrInfo.module, e)
|
|
@@ -457,7 +377,7 @@ var shimmer = module.exports = {
|
|
|
457
377
|
// TODO: Remove this code when amqplib instrumentation is made external.
|
|
458
378
|
require('./instrumentation/amqplib').selfRegister(shimmer)
|
|
459
379
|
} else {
|
|
460
|
-
|
|
380
|
+
const fileName = path.join(__dirname, 'instrumentation', moduleName + '.js')
|
|
461
381
|
shimmer.registerInstrumentation({
|
|
462
382
|
moduleName: moduleName,
|
|
463
383
|
type: instrInfo.type,
|
|
@@ -469,7 +389,7 @@ var shimmer = module.exports = {
|
|
|
469
389
|
// Even though domain is a core module we add it as a registered
|
|
470
390
|
// instrumentation to be lazy-loaded because we do not want to cause domain
|
|
471
391
|
// usage.
|
|
472
|
-
|
|
392
|
+
const domainPath = path.join(__dirname, 'instrumentation/core/domain.js')
|
|
473
393
|
shimmer.registerInstrumentation({
|
|
474
394
|
moduleName: 'domain',
|
|
475
395
|
type: null,
|
|
@@ -510,12 +430,13 @@ var shimmer = module.exports = {
|
|
|
510
430
|
* the same.
|
|
511
431
|
*/
|
|
512
432
|
getInstrumentationNameFromModuleName(moduleName) {
|
|
513
|
-
|
|
433
|
+
let instrumentation
|
|
514
434
|
// XXX When updating these special cases, also update `uninstrumented`.
|
|
515
435
|
// To allow for instrumenting both 'pg' and 'pg.js'.
|
|
516
436
|
if (moduleName === 'pg.js') {
|
|
517
437
|
instrumentation = 'pg'
|
|
518
|
-
}
|
|
438
|
+
}
|
|
439
|
+
if (moduleName === 'mysql2') {
|
|
519
440
|
// mysql2 (https://github.com/sidorares/node-mysql2) is a drop in replacement for
|
|
520
441
|
// mysql which conforms to the existing mysql API. If we see mysql2, treat it as
|
|
521
442
|
// mysql
|
|
@@ -525,4 +446,101 @@ var shimmer = module.exports = {
|
|
|
525
446
|
}
|
|
526
447
|
return instrumentation
|
|
527
448
|
}
|
|
449
|
+
})
|
|
450
|
+
|
|
451
|
+
function applyDebugState(shim, nodule) {
|
|
452
|
+
if (shimmer.debug) {
|
|
453
|
+
shim.enableDebug()
|
|
454
|
+
instrumented.push(shim)
|
|
455
|
+
instrumented.push({
|
|
456
|
+
__NR_unwrap: function unwrapNodule() {
|
|
457
|
+
delete nodule.__NR_instrumented_errored
|
|
458
|
+
delete nodule.__NR_instrumented
|
|
459
|
+
delete nodule.__NR_shim
|
|
460
|
+
}
|
|
461
|
+
})
|
|
462
|
+
nodule.__NR_shim = shim
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* All instrumentation files must export the same interface: a single
|
|
468
|
+
* initialization function that takes the agent and the module to be
|
|
469
|
+
* instrumented.
|
|
470
|
+
*/
|
|
471
|
+
function instrument(agent, nodule, moduleName, resolvedName) {
|
|
472
|
+
const instrumentation = shimmer.registeredInstrumentations[moduleName]
|
|
473
|
+
if (
|
|
474
|
+
properties.hasOwn(nodule, '__NR_instrumented') ||
|
|
475
|
+
properties.hasOwn(nodule, '__NR_instrumented_errored')
|
|
476
|
+
) {
|
|
477
|
+
logger.trace(
|
|
478
|
+
'Already instrumented or failed to instrument %s, skipping redundant instrumentation',
|
|
479
|
+
moduleName
|
|
480
|
+
)
|
|
481
|
+
return nodule
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
const shim = shims.createShimFromType(instrumentation.type, agent, moduleName, resolvedName)
|
|
485
|
+
|
|
486
|
+
applyDebugState(shim, nodule)
|
|
487
|
+
|
|
488
|
+
try {
|
|
489
|
+
if (instrumentation.onRequire(shim, nodule, moduleName) !== false) {
|
|
490
|
+
nodule = shim.getExport(nodule)
|
|
491
|
+
nodule.__NR_instrumented = true
|
|
492
|
+
}
|
|
493
|
+
} catch (instrumentationError) {
|
|
494
|
+
nodule.__NR_instrumented_errored = true
|
|
495
|
+
if (instrumentation.onError) {
|
|
496
|
+
try {
|
|
497
|
+
instrumentation.onError(instrumentationError)
|
|
498
|
+
} catch (e) {
|
|
499
|
+
logger.warn(
|
|
500
|
+
e,
|
|
501
|
+
instrumentationError,
|
|
502
|
+
'Custom instrumentation for %s failed, then the onError handler threw an error',
|
|
503
|
+
moduleName
|
|
504
|
+
)
|
|
505
|
+
}
|
|
506
|
+
} else {
|
|
507
|
+
logger.warn(
|
|
508
|
+
instrumentationError,
|
|
509
|
+
'Custom instrumentation for %s failed. Please report this to the ' +
|
|
510
|
+
'maintainers of the custom instrumentation.',
|
|
511
|
+
moduleName
|
|
512
|
+
)
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
return nodule
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
function _firstPartyInstrumentation(agent, fileName, shim, nodule, moduleName) {
|
|
520
|
+
const fullPath = path.resolve(fileName)
|
|
521
|
+
if (!fs.existsSync(fileName)) {
|
|
522
|
+
return logger.warn('Tried to load instrumentation from %s, but file does not exist', fullPath)
|
|
523
|
+
}
|
|
524
|
+
try {
|
|
525
|
+
return require(fileName)(agent, nodule, moduleName, shim)
|
|
526
|
+
} catch (error) {
|
|
527
|
+
logger.warn(
|
|
528
|
+
error,
|
|
529
|
+
'Failed to instrument module %s using %s',
|
|
530
|
+
path.basename(fileName, '.js'),
|
|
531
|
+
fullPath
|
|
532
|
+
)
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function _postLoad(agent, nodule, name, resolvedName) {
|
|
537
|
+
const instrumentation = shimmer.getInstrumentationNameFromModuleName(name)
|
|
538
|
+
|
|
539
|
+
// Check if this is a known instrumentation and then run it.
|
|
540
|
+
if (shimmer.registeredInstrumentations[instrumentation]) {
|
|
541
|
+
logger.trace('Instrumenting %s.', name)
|
|
542
|
+
return instrument(agent, nodule, instrumentation, resolvedName)
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
return nodule
|
|
528
546
|
}
|