newrelic 8.5.2 → 8.6.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 +12 -0
- package/api.js +121 -135
- package/lib/agent.js +11 -2
- package/lib/context-manager/create-context-manager.js +32 -0
- package/lib/context-manager/diagnostics/legacy-diagnostic-context-manager.js +36 -0
- package/lib/context-manager/legacy-context-manager.js +66 -0
- package/lib/instrumentation/promise.js +28 -41
- package/lib/shim/message-shim.js +45 -90
- package/lib/shim/shim.js +139 -324
- package/lib/shim/transaction-shim.js +9 -39
- package/lib/shimmer.js +110 -10
- package/lib/transaction/tracer/index.js +24 -22
- package/package.json +2 -1
package/NEWS.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
### v8.6.0 (2021-11-17)
|
|
2
|
+
|
|
3
|
+
* Added `onResolved` instrumentation hook to apply instrumentation prior to module load.
|
|
4
|
+
|
|
5
|
+
This hook fires after the module filepath has been resolved just prior to the module being loaded by the CommonJS module loader.
|
|
6
|
+
|
|
7
|
+
* Fixed issue where `recordConsume` was not binding consumer if it was a promise
|
|
8
|
+
|
|
9
|
+
* Pinned mongo versioned tests to `<4.2.0` until we can address https://github.com/newrelic/node-newrelic/issues/982
|
|
10
|
+
|
|
11
|
+
* Introduced a context management API to be used in place of manually calling tracer.segment get/set.
|
|
12
|
+
|
|
1
13
|
### v8.5.2 (2021-11-09)
|
|
2
14
|
|
|
3
15
|
* Fixed issue where unhandled promise rejections were not getting logged as errors in a lambda execution
|
package/api.js
CHANGED
|
@@ -55,7 +55,8 @@ const CUSTOM_EVENT_TYPE_REGEX = /^[a-zA-Z0-9:_ ]+$/
|
|
|
55
55
|
* You do not need to directly instantiate this class, as an instance of this is
|
|
56
56
|
* the return from `require('newrelic')`.
|
|
57
57
|
*
|
|
58
|
-
* @
|
|
58
|
+
* @param agent
|
|
59
|
+
* @class
|
|
59
60
|
*/
|
|
60
61
|
function API(agent) {
|
|
61
62
|
this.agent = agent
|
|
@@ -139,6 +140,7 @@ API.prototype.getTransaction = function getTransaction() {
|
|
|
139
140
|
* utilization.full_hostname. If utilization.full_hostname is null or empty,
|
|
140
141
|
* this will be the hostname specified in the connect request as host.
|
|
141
142
|
*
|
|
143
|
+
* @param omitSupportability
|
|
142
144
|
* @returns {LinkingMetadata} The linking object with the data above
|
|
143
145
|
*/
|
|
144
146
|
API.prototype.getLinkingMetadata = function getLinkingMetadata(omitSupportability) {
|
|
@@ -186,7 +188,6 @@ API.prototype.getLinkingMetadata = function getLinkingMetadata(omitSupportabilit
|
|
|
186
188
|
*
|
|
187
189
|
* @param {string} name The string you would like to report to New Relic
|
|
188
190
|
* as the dispatcher.
|
|
189
|
-
*
|
|
190
191
|
* @param {string} [version] The dispatcher version you would like to
|
|
191
192
|
* report to New Relic
|
|
192
193
|
*/
|
|
@@ -414,7 +415,6 @@ API.prototype.addCustomSpanAttribute = function addCustomSpanAttribute(key, valu
|
|
|
414
415
|
*
|
|
415
416
|
* @param {Error} error
|
|
416
417
|
* The error to be traced.
|
|
417
|
-
*
|
|
418
418
|
* @param {object} [customAttributes]
|
|
419
419
|
* Optional. Any custom attributes to be displayed in the New Relic UI.
|
|
420
420
|
*/
|
|
@@ -526,7 +526,7 @@ API.prototype.addIgnoringRule = function addIgnoringRule(pattern) {
|
|
|
526
526
|
* Do *not* reuse the headers between users, or even between requests.
|
|
527
527
|
*
|
|
528
528
|
* @param {string} [options.nonce] - Nonce to inject into `<script>` header.
|
|
529
|
-
*
|
|
529
|
+
* @param options
|
|
530
530
|
* @returns {string} The `<script>` header to be injected.
|
|
531
531
|
*/
|
|
532
532
|
API.prototype.getBrowserTimingHeader = function getBrowserTimingHeader(options) {
|
|
@@ -545,7 +545,7 @@ API.prototype.getBrowserTimingHeader = function getBrowserTimingHeader(options)
|
|
|
545
545
|
*
|
|
546
546
|
* @param {number} num - Error code from `RUM_ISSUES`.
|
|
547
547
|
* @param {bool} [quite=false] - Be quiet about this failure.
|
|
548
|
-
*
|
|
548
|
+
* @param quiet
|
|
549
549
|
* @see RUM_ISSUES
|
|
550
550
|
*/
|
|
551
551
|
function _gracefail(num, quiet) {
|
|
@@ -687,9 +687,9 @@ API.prototype.getBrowserTimingHeader = function getBrowserTimingHeader(options)
|
|
|
687
687
|
|
|
688
688
|
/**
|
|
689
689
|
* @callback startSegmentCallback
|
|
690
|
-
* @param {
|
|
690
|
+
* @param {Function} cb
|
|
691
691
|
* The function to time with the created segment.
|
|
692
|
-
* @
|
|
692
|
+
* @returns {Promise=} Returns a promise if cb returns a promise.
|
|
693
693
|
*/
|
|
694
694
|
|
|
695
695
|
/**
|
|
@@ -701,23 +701,18 @@ API.prototype.getBrowserTimingHeader = function getBrowserTimingHeader(options)
|
|
|
701
701
|
* // The returned promise here will signify the end of the segment.
|
|
702
702
|
* return myAsyncTask().then(myNextTask)
|
|
703
703
|
* })
|
|
704
|
-
*
|
|
705
704
|
* @param {string} name
|
|
706
705
|
* The name to give the new segment. This will also be the name of the metric.
|
|
707
|
-
*
|
|
708
706
|
* @param {bool} record
|
|
709
707
|
* Indicates if the segment should be recorded as a metric. Metrics will show
|
|
710
708
|
* up on the transaction breakdown table and server breakdown graph. Segments
|
|
711
709
|
* just show up in transaction traces.
|
|
712
|
-
*
|
|
713
710
|
* @param {startSegmentCallback} handler
|
|
714
711
|
* The function to track as a segment.
|
|
715
|
-
*
|
|
716
|
-
* @param {function} [callback]
|
|
712
|
+
* @param {Function} [callback]
|
|
717
713
|
* An optional callback for the handler. This will indicate the end of the
|
|
718
714
|
* timing if provided.
|
|
719
|
-
*
|
|
720
|
-
* @return {*} Returns the result of calling `handler`.
|
|
715
|
+
* @returns {*} Returns the result of calling `handler`.
|
|
721
716
|
*/
|
|
722
717
|
API.prototype.startSegment = function startSegment(name, record, handler, callback) {
|
|
723
718
|
this.agent.metrics
|
|
@@ -775,11 +770,9 @@ API.prototype.startSegment = function startSegment(name, record, handler, callba
|
|
|
775
770
|
* transaction.end()
|
|
776
771
|
* }, 100)
|
|
777
772
|
* })
|
|
778
|
-
*
|
|
779
773
|
* @param {string} url
|
|
780
774
|
* The URL of the transaction. It is used to name and group related transactions in APM,
|
|
781
775
|
* so it should be a generic name and not iclude any variable parameters.
|
|
782
|
-
*
|
|
783
776
|
* @param {Function} handle
|
|
784
777
|
* Function that represents the transaction work.
|
|
785
778
|
*/
|
|
@@ -862,20 +855,16 @@ API.prototype.startBackgroundTransaction = startBackgroundTransaction
|
|
|
862
855
|
* transaction.end()
|
|
863
856
|
* }, 100)
|
|
864
857
|
* })
|
|
865
|
-
*
|
|
866
858
|
* @param {string} name
|
|
867
859
|
* The name of the transaction. It is used to name and group related
|
|
868
860
|
* transactions in APM, so it should be a generic name and not iclude any
|
|
869
861
|
* variable parameters.
|
|
870
|
-
*
|
|
871
862
|
* @param {string} [group]
|
|
872
863
|
* Optional, used for grouping background transactions in APM. For more
|
|
873
864
|
* information see:
|
|
874
865
|
* https://docs.newrelic.com/docs/apm/applications-menu/monitoring/transactions-page#txn-type-dropdown
|
|
875
|
-
*
|
|
876
866
|
* @param {Function} handle
|
|
877
867
|
* Function that represents the background work.
|
|
878
|
-
*
|
|
879
868
|
* @memberOf API#
|
|
880
869
|
*/
|
|
881
870
|
function startBackgroundTransaction(name, group, handle) {
|
|
@@ -972,9 +961,9 @@ API.prototype.endTransaction = function endTransaction() {
|
|
|
972
961
|
* Record a custom metric, usually associated with a particular duration.
|
|
973
962
|
* The `name` must be a string following standard metric naming rules. The `value` will
|
|
974
963
|
* usually be a number, but it can also be an object.
|
|
975
|
-
*
|
|
964
|
+
* When `value` is a numeric value, it should represent the magnitude of a measurement
|
|
976
965
|
* associated with an event; for example, the duration for a particular method call.
|
|
977
|
-
*
|
|
966
|
+
* When `value` is an object, it must contain count, total, min, max, and sumOfSquares
|
|
978
967
|
* keys, all with number values. This form is useful to aggregate metrics on your own
|
|
979
968
|
* and report them periodically; for example, from a setInterval. These values will
|
|
980
969
|
* be aggregated with any previously collected values for the same metric. The names
|
|
@@ -1151,18 +1140,15 @@ API.prototype.recordCustomEvent = function recordCustomEvent(eventType, attribut
|
|
|
1151
1140
|
* - `newrelic.instrument(moduleName, onRequire [,onError])`
|
|
1152
1141
|
* - `newrelic.instrument(options)`
|
|
1153
1142
|
*
|
|
1154
|
-
* @param {object} options
|
|
1155
|
-
*
|
|
1156
|
-
*
|
|
1157
|
-
* @param {
|
|
1158
|
-
*
|
|
1159
|
-
*
|
|
1160
|
-
* @param {function} options.onRequire
|
|
1161
|
-
* The function to call when the module is required
|
|
1162
|
-
*
|
|
1163
|
-
* @param {function} [options.onError]
|
|
1164
|
-
* If provided, should `onRequire` throw an error, the error will be passed to
|
|
1143
|
+
* @param {object} options The options for this custom instrumentation.
|
|
1144
|
+
* @param {string} options.moduleName The module name given to require to load the module
|
|
1145
|
+
* @param {Function} options.onResolved The function to call prior to module load after the filepath has been resolved
|
|
1146
|
+
* @param {Function} options.onRequire The function to call when the module has been loaded
|
|
1147
|
+
* @param {Function} [options.onError] If provided, should `onRequire` throw an error, the error will be passed to
|
|
1165
1148
|
* this function.
|
|
1149
|
+
* @param moduleName
|
|
1150
|
+
* @param onRequire
|
|
1151
|
+
* @param onError
|
|
1166
1152
|
*/
|
|
1167
1153
|
API.prototype.instrument = function instrument(moduleName, onRequire, onError) {
|
|
1168
1154
|
const metric = this.agent.metrics.getOrCreateMetric(NAMES.SUPPORTABILITY.API + '/instrument')
|
|
@@ -1187,18 +1173,15 @@ API.prototype.instrument = function instrument(moduleName, onRequire, onError) {
|
|
|
1187
1173
|
* - `newrelic.instrumentConglomerate(moduleName, onRequire [, onError])`
|
|
1188
1174
|
* - `newrelic.isntrumentConglomerate(options)`
|
|
1189
1175
|
*
|
|
1190
|
-
* @param {object} options
|
|
1191
|
-
*
|
|
1192
|
-
*
|
|
1193
|
-
* @param {
|
|
1194
|
-
*
|
|
1195
|
-
*
|
|
1196
|
-
* @param {function} options.onRequire
|
|
1197
|
-
* The function to call when the module is required
|
|
1198
|
-
*
|
|
1199
|
-
* @param {function} [options.onError]
|
|
1200
|
-
* If provided, should `onRequire` throw an error, the error will be passed to
|
|
1176
|
+
* @param {object} options The options for this custom instrumentation.
|
|
1177
|
+
* @param {string} options.moduleName The module name given to require to load the module
|
|
1178
|
+
* @param {Function} options.onResolved The function to call prior to module load after the filepath has been resolved
|
|
1179
|
+
* @param {Function} options.onRequire The function to call when the module has been loaded
|
|
1180
|
+
* @param {Function} [options.onError] If provided, should `onRequire` throw an error, the error will be passed to
|
|
1201
1181
|
* this function.
|
|
1182
|
+
* @param moduleName
|
|
1183
|
+
* @param onRequire
|
|
1184
|
+
* @param onError
|
|
1202
1185
|
*/
|
|
1203
1186
|
API.prototype.instrumentConglomerate = function instrumentConglomerate(
|
|
1204
1187
|
moduleName,
|
|
@@ -1224,18 +1207,15 @@ API.prototype.instrumentConglomerate = function instrumentConglomerate(
|
|
|
1224
1207
|
* - `newrelic.instrumentDatastore(moduleName, onRequire [,onError])`
|
|
1225
1208
|
* - `newrelic.instrumentDatastore(options)`
|
|
1226
1209
|
*
|
|
1227
|
-
* @param {object} options
|
|
1228
|
-
*
|
|
1229
|
-
*
|
|
1230
|
-
* @param {
|
|
1231
|
-
*
|
|
1232
|
-
*
|
|
1233
|
-
* @param {function} options.onRequire
|
|
1234
|
-
* The function to call when the module is required
|
|
1235
|
-
*
|
|
1236
|
-
* @param {function} [options.onError]
|
|
1237
|
-
* If provided, should `onRequire` throw an error, the error will be passed to
|
|
1210
|
+
* @param {object} options The options for this custom instrumentation.
|
|
1211
|
+
* @param {string} options.moduleName The module name given to require to load the module
|
|
1212
|
+
* @param {Function} options.onResolved The function to call prior to module load after the filepath has been resolved
|
|
1213
|
+
* @param {Function} options.onRequire The function to call when the module has been loaded
|
|
1214
|
+
* @param {Function} [options.onError] If provided, should `onRequire` throw an error, the error will be passed to
|
|
1238
1215
|
* this function.
|
|
1216
|
+
* @param moduleName
|
|
1217
|
+
* @param onRequire
|
|
1218
|
+
* @param onError
|
|
1239
1219
|
*/
|
|
1240
1220
|
API.prototype.instrumentDatastore = function instrumentDatastore(moduleName, onRequire, onError) {
|
|
1241
1221
|
const metric = this.agent.metrics.getOrCreateMetric(
|
|
@@ -1256,77 +1236,21 @@ API.prototype.instrumentDatastore = function instrumentDatastore(moduleName, onR
|
|
|
1256
1236
|
shimmer.registerInstrumentation(opts)
|
|
1257
1237
|
}
|
|
1258
1238
|
|
|
1259
|
-
/**
|
|
1260
|
-
* Applies an instrumentation to an already loaded module.
|
|
1261
|
-
*
|
|
1262
|
-
* // oh no, express was loaded before newrelic
|
|
1263
|
-
* const express = require('express')
|
|
1264
|
-
* const newrelic = require('newrelic')
|
|
1265
|
-
*
|
|
1266
|
-
* // phew, we can use instrumentLoadedModule to make
|
|
1267
|
-
* // sure express is still instrumented
|
|
1268
|
-
* newrelic.instrumentLoadedModule('express', express)
|
|
1269
|
-
*
|
|
1270
|
-
* @param {string} moduleName
|
|
1271
|
-
* The module's name/identifier. Will be normalized
|
|
1272
|
-
* into an instrumentation key.
|
|
1273
|
-
*
|
|
1274
|
-
* @param {object} module
|
|
1275
|
-
* The actual module object or function we're instrumenting
|
|
1276
|
-
*/
|
|
1277
|
-
API.prototype.instrumentLoadedModule = function instrumentLoadedModule(moduleName, module) {
|
|
1278
|
-
const metric = this.agent.metrics.getOrCreateMetric(
|
|
1279
|
-
NAMES.SUPPORTABILITY.API + '/instrumentLoadedModule'
|
|
1280
|
-
)
|
|
1281
|
-
metric.incrementCallCount()
|
|
1282
|
-
try {
|
|
1283
|
-
const instrumentationName = shimmer.getInstrumentationNameFromModuleName(moduleName)
|
|
1284
|
-
if (!shimmer.registeredInstrumentations[instrumentationName]) {
|
|
1285
|
-
logger.warn("No instrumentation registered for '%s'.", instrumentationName)
|
|
1286
|
-
return false
|
|
1287
|
-
}
|
|
1288
|
-
|
|
1289
|
-
const instrumentation = shimmer.registeredInstrumentations[instrumentationName]
|
|
1290
|
-
if (!instrumentation.onRequire) {
|
|
1291
|
-
logger.warn("No onRequire function registered for '%s'.", instrumentationName)
|
|
1292
|
-
return false
|
|
1293
|
-
}
|
|
1294
|
-
|
|
1295
|
-
const resolvedName = require.resolve(moduleName)
|
|
1296
|
-
|
|
1297
|
-
const shim = shims.createShimFromType(
|
|
1298
|
-
instrumentation.type,
|
|
1299
|
-
this.agent,
|
|
1300
|
-
moduleName,
|
|
1301
|
-
resolvedName
|
|
1302
|
-
)
|
|
1303
|
-
|
|
1304
|
-
instrumentation.onRequire(shim, module, moduleName)
|
|
1305
|
-
|
|
1306
|
-
return true
|
|
1307
|
-
} catch (error) {
|
|
1308
|
-
logger.error('instrumentLoadedModule encountered an error, module not instrumentend: %s', error)
|
|
1309
|
-
}
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
1239
|
/**
|
|
1313
1240
|
* Registers an instrumentation function.
|
|
1314
1241
|
*
|
|
1315
1242
|
* - `newrelic.instrumentWebframework(moduleName, onRequire [,onError])`
|
|
1316
1243
|
* - `newrelic.instrumentWebframework(options)`
|
|
1317
1244
|
*
|
|
1318
|
-
* @param {object} options
|
|
1319
|
-
*
|
|
1320
|
-
*
|
|
1321
|
-
* @param {
|
|
1322
|
-
*
|
|
1323
|
-
*
|
|
1324
|
-
* @param {function} options.onRequire
|
|
1325
|
-
* The function to call when the module is required
|
|
1326
|
-
*
|
|
1327
|
-
* @param {function} [options.onError]
|
|
1328
|
-
* If provided, should `onRequire` throw an error, the error will be passed to
|
|
1245
|
+
* @param {object} options The options for this custom instrumentation.
|
|
1246
|
+
* @param {string} options.moduleName The module name given to require to load the module
|
|
1247
|
+
* @param {Function} options.onResolved The function to call prior to module load after the filepath has been resolved
|
|
1248
|
+
* @param {Function} options.onRequire The function to call when the module has been loaded
|
|
1249
|
+
* @param {Function} [options.onError] If provided, should `onRequire` throw an error, the error will be passed to
|
|
1329
1250
|
* this function.
|
|
1251
|
+
* @param moduleName
|
|
1252
|
+
* @param onRequire
|
|
1253
|
+
* @param onError
|
|
1330
1254
|
*/
|
|
1331
1255
|
API.prototype.instrumentWebframework = function instrumentWebframework(
|
|
1332
1256
|
moduleName,
|
|
@@ -1357,18 +1281,15 @@ API.prototype.instrumentWebframework = function instrumentWebframework(
|
|
|
1357
1281
|
* - `newrelic.instrumentMessages(moduleName, onRequire [,onError])`
|
|
1358
1282
|
* - `newrelic.instrumentMessages(options)`
|
|
1359
1283
|
*
|
|
1360
|
-
* @param {object} options
|
|
1361
|
-
*
|
|
1362
|
-
*
|
|
1363
|
-
* @param {
|
|
1364
|
-
*
|
|
1365
|
-
*
|
|
1366
|
-
* @param {function} options.onRequire
|
|
1367
|
-
* The function to call when the module is required
|
|
1368
|
-
*
|
|
1369
|
-
* @param {function} [options.onError]
|
|
1370
|
-
* If provided, should `onRequire` throw an error, the error will be passed to
|
|
1284
|
+
* @param {object} options The options for this custom instrumentation.
|
|
1285
|
+
* @param {string} options.moduleName The module name given to require to load the module
|
|
1286
|
+
* @param {Function} options.onResolved The function to call prior to module load after the filepath has been resolved
|
|
1287
|
+
* @param {Function} options.onRequire The function to call when the module has been loaded
|
|
1288
|
+
* @param {Function} [options.onError] If provided, should `onRequire` throw an error, the error will be passed to
|
|
1371
1289
|
* this function.
|
|
1290
|
+
* @param moduleName
|
|
1291
|
+
* @param onRequire
|
|
1292
|
+
* @param onError
|
|
1372
1293
|
*/
|
|
1373
1294
|
API.prototype.instrumentMessages = function instrumentMessages(moduleName, onRequire, onError) {
|
|
1374
1295
|
const metric = this.agent.metrics.getOrCreateMetric(
|
|
@@ -1389,6 +1310,58 @@ API.prototype.instrumentMessages = function instrumentMessages(moduleName, onReq
|
|
|
1389
1310
|
shimmer.registerInstrumentation(opts)
|
|
1390
1311
|
}
|
|
1391
1312
|
|
|
1313
|
+
/**
|
|
1314
|
+
* Applies an instrumentation to an already loaded module.
|
|
1315
|
+
*
|
|
1316
|
+
* // oh no, express was loaded before newrelic
|
|
1317
|
+
* const express = require('express')
|
|
1318
|
+
* const newrelic = require('newrelic')
|
|
1319
|
+
*
|
|
1320
|
+
* // phew, we can use instrumentLoadedModule to make
|
|
1321
|
+
* // sure express is still instrumented
|
|
1322
|
+
* newrelic.instrumentLoadedModule('express', express)
|
|
1323
|
+
*
|
|
1324
|
+
* @param {string} moduleName
|
|
1325
|
+
* The module's name/identifier. Will be normalized
|
|
1326
|
+
* into an instrumentation key.
|
|
1327
|
+
* @param {object} module
|
|
1328
|
+
* The actual module object or function we're instrumenting
|
|
1329
|
+
*/
|
|
1330
|
+
API.prototype.instrumentLoadedModule = function instrumentLoadedModule(moduleName, module) {
|
|
1331
|
+
const metric = this.agent.metrics.getOrCreateMetric(
|
|
1332
|
+
NAMES.SUPPORTABILITY.API + '/instrumentLoadedModule'
|
|
1333
|
+
)
|
|
1334
|
+
metric.incrementCallCount()
|
|
1335
|
+
try {
|
|
1336
|
+
const instrumentationName = shimmer.getInstrumentationNameFromModuleName(moduleName)
|
|
1337
|
+
if (!shimmer.registeredInstrumentations[instrumentationName]) {
|
|
1338
|
+
logger.warn("No instrumentation registered for '%s'.", instrumentationName)
|
|
1339
|
+
return false
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
const instrumentation = shimmer.registeredInstrumentations[instrumentationName]
|
|
1343
|
+
if (!instrumentation.onRequire) {
|
|
1344
|
+
logger.warn("No onRequire function registered for '%s'.", instrumentationName)
|
|
1345
|
+
return false
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
const resolvedName = require.resolve(moduleName)
|
|
1349
|
+
|
|
1350
|
+
const shim = shims.createShimFromType(
|
|
1351
|
+
instrumentation.type,
|
|
1352
|
+
this.agent,
|
|
1353
|
+
moduleName,
|
|
1354
|
+
resolvedName
|
|
1355
|
+
)
|
|
1356
|
+
|
|
1357
|
+
instrumentation.onRequire(shim, module, moduleName)
|
|
1358
|
+
|
|
1359
|
+
return true
|
|
1360
|
+
} catch (error) {
|
|
1361
|
+
logger.error('instrumentLoadedModule encountered an error, module not instrumented: %s', error)
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1392
1365
|
/**
|
|
1393
1366
|
* Returns the current trace and span id.
|
|
1394
1367
|
*
|
|
@@ -1424,19 +1397,16 @@ API.prototype.getTraceMetadata = function getTraceMetadata() {
|
|
|
1424
1397
|
*
|
|
1425
1398
|
* @param {object} [options]
|
|
1426
1399
|
* Object with shut down options.
|
|
1427
|
-
*
|
|
1428
1400
|
* @param {boolean} [options.collectPendingData=false]
|
|
1429
1401
|
* If true, the agent will send any pending data to the collector before
|
|
1430
1402
|
* shutting down.
|
|
1431
|
-
*
|
|
1432
1403
|
* @param {number} [options.timeout=0]
|
|
1433
1404
|
* Time in milliseconds to wait before shutting down.
|
|
1434
|
-
*
|
|
1435
1405
|
* @param {boolean} [options.waitForIdle=false]
|
|
1436
1406
|
* If true, the agent will not shut down until there are no active transactions.
|
|
1437
|
-
*
|
|
1438
|
-
* @param {function} [callback]
|
|
1407
|
+
* @param {Function} [callback]
|
|
1439
1408
|
* Callback function that runs when agent stops.
|
|
1409
|
+
* @param cb
|
|
1440
1410
|
*/
|
|
1441
1411
|
API.prototype.shutdown = function shutdown(options, cb) {
|
|
1442
1412
|
this.agent.metrics.getOrCreateMetric(`${NAMES.SUPPORTABILITY.API}/shutdown`).incrementCallCount()
|
|
@@ -1458,6 +1428,11 @@ API.prototype.shutdown = function shutdown(options, cb) {
|
|
|
1458
1428
|
_doShutdown(this, options, callback)
|
|
1459
1429
|
}
|
|
1460
1430
|
|
|
1431
|
+
/**
|
|
1432
|
+
* @param api
|
|
1433
|
+
* @param options
|
|
1434
|
+
* @param callback
|
|
1435
|
+
*/
|
|
1461
1436
|
function _doShutdown(api, options, callback) {
|
|
1462
1437
|
const agent = api.agent
|
|
1463
1438
|
|
|
@@ -1473,6 +1448,9 @@ function _doShutdown(api, options, callback) {
|
|
|
1473
1448
|
return
|
|
1474
1449
|
}
|
|
1475
1450
|
|
|
1451
|
+
/**
|
|
1452
|
+
* @param error
|
|
1453
|
+
*/
|
|
1476
1454
|
function afterHarvest(error) {
|
|
1477
1455
|
if (error) {
|
|
1478
1456
|
logger.error(error, 'An error occurred while running last harvest before shutdown.')
|
|
@@ -1506,6 +1484,10 @@ function _doShutdown(api, options, callback) {
|
|
|
1506
1484
|
}
|
|
1507
1485
|
}
|
|
1508
1486
|
|
|
1487
|
+
/**
|
|
1488
|
+
* @param object
|
|
1489
|
+
* @param maxLength
|
|
1490
|
+
*/
|
|
1509
1491
|
function _checkKeyLength(object, maxLength) {
|
|
1510
1492
|
const keys = Object.keys(object)
|
|
1511
1493
|
let badKey = false
|
|
@@ -1534,6 +1516,10 @@ API.prototype.setLambdaHandler = function setLambdaHandler(handler) {
|
|
|
1534
1516
|
return this.awsLambda.patchLambdaHandler(handler)
|
|
1535
1517
|
}
|
|
1536
1518
|
|
|
1519
|
+
/**
|
|
1520
|
+
* @param attributes
|
|
1521
|
+
* @param name
|
|
1522
|
+
*/
|
|
1537
1523
|
function _filterAttributes(attributes, name) {
|
|
1538
1524
|
const filteredAttributes = Object.create(null)
|
|
1539
1525
|
Object.keys(attributes).forEach((attributeKey) => {
|
package/lib/agent.js
CHANGED
|
@@ -29,6 +29,7 @@ const TxSegmentNormalizer = require('./metrics/normalizer/tx_segment')
|
|
|
29
29
|
const uninstrumented = require('./uninstrumented')
|
|
30
30
|
const util = require('util')
|
|
31
31
|
const createSpanEventAggregator = require('./spans/create-span-event-aggregator')
|
|
32
|
+
const createContextManager = require('./context-manager/create-context-manager')
|
|
32
33
|
|
|
33
34
|
// Map of valid states to whether or not data collection is valid
|
|
34
35
|
const STATES = {
|
|
@@ -53,6 +54,8 @@ const DEFAULT_HARVEST_INTERVAL_MS = 60000
|
|
|
53
54
|
* This constructor can throw if, for some reason, the configuration isn't
|
|
54
55
|
* available. Don't try to recover here, because without configuration the
|
|
55
56
|
* agent can't be brought up to a useful state.
|
|
57
|
+
*
|
|
58
|
+
* @param config
|
|
56
59
|
*/
|
|
57
60
|
function Agent(config) {
|
|
58
61
|
EventEmitter.call(this)
|
|
@@ -136,8 +139,9 @@ function Agent(config) {
|
|
|
136
139
|
|
|
137
140
|
this.errors = new ErrorCollector(config, errorTraceAggregator, errorEventAggregator, this.metrics)
|
|
138
141
|
|
|
142
|
+
this._contextManager = createContextManager(this.config)
|
|
139
143
|
// Transaction tracing.
|
|
140
|
-
this.tracer = new Tracer(this)
|
|
144
|
+
this.tracer = new Tracer(this, this._contextManager)
|
|
141
145
|
this.traces = new TransactionTraceAggregator(
|
|
142
146
|
{
|
|
143
147
|
periodMs: DEFAULT_HARVEST_INTERVAL_MS,
|
|
@@ -185,7 +189,6 @@ util.inherits(Agent, EventEmitter)
|
|
|
185
189
|
* the configuration.
|
|
186
190
|
*
|
|
187
191
|
* @config {boolean} agent_enabled Whether to start up the agent.
|
|
188
|
-
*
|
|
189
192
|
* @param {Function} callback Continuation and error handler.
|
|
190
193
|
*/
|
|
191
194
|
Agent.prototype.start = function start(callback) {
|
|
@@ -248,6 +251,7 @@ Agent.prototype.start = function start(callback) {
|
|
|
248
251
|
|
|
249
252
|
/**
|
|
250
253
|
* Forces all aggregators to send the data collected.
|
|
254
|
+
*
|
|
251
255
|
* @param {Function} callback The callback to invoke when all data types have been sent.
|
|
252
256
|
*/
|
|
253
257
|
Agent.prototype.forceHarvestAll = function forceHarvestAll(callback) {
|
|
@@ -416,6 +420,9 @@ Agent.prototype.startAggregators = function startAggregators() {
|
|
|
416
420
|
/**
|
|
417
421
|
* Completes any final setup upon full connection to New Relic
|
|
418
422
|
* servers and sets the agent state to 'started'.
|
|
423
|
+
*
|
|
424
|
+
* @param shouldImmediatelyHarvest
|
|
425
|
+
* @param callback
|
|
419
426
|
*/
|
|
420
427
|
Agent.prototype.onConnect = function onConnect(shouldImmediatelyHarvest, callback) {
|
|
421
428
|
this._reconfigureAggregators(this.config)
|
|
@@ -485,6 +492,8 @@ Agent.prototype._serverlessModeStart = function _serverlessModeStart(callback) {
|
|
|
485
492
|
* FIXME: make it possible to dispose of the agent, as well as do a
|
|
486
493
|
* "hard" restart. This requires working with shimmer to strip the
|
|
487
494
|
* current instrumentation and patch to the module loader.
|
|
495
|
+
*
|
|
496
|
+
* @param callback
|
|
488
497
|
*/
|
|
489
498
|
Agent.prototype.stop = function stop(callback) {
|
|
490
499
|
if (!callback) {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2021 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
const logger = require('../logger')
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Factory function to create context manager implementations used by the
|
|
12
|
+
* ContextManager class.
|
|
13
|
+
*
|
|
14
|
+
* @param {object} config New Relic config instance.
|
|
15
|
+
* @returns {*} The appropriate underlying context manager implementation based on
|
|
16
|
+
* the current configuration.
|
|
17
|
+
*/
|
|
18
|
+
function createContextManager(config) {
|
|
19
|
+
if (config.logging.diagnostics) {
|
|
20
|
+
logger.info('Using LegacyDiagnosticContextManager')
|
|
21
|
+
|
|
22
|
+
const LegacyDiagnosticContextManager = require('./diagnostics/legacy-diagnostic-context-manager')
|
|
23
|
+
return new LegacyDiagnosticContextManager(config)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
logger.info('Using LegacyContextManager')
|
|
27
|
+
|
|
28
|
+
const LegacyContextManager = require('./legacy-context-manager')
|
|
29
|
+
return new LegacyContextManager(config)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = createContextManager
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2021 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
const LegacyContextManager = require('../legacy-context-manager')
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Overrides setContext to add diagnostic logging around setting and removing
|
|
12
|
+
* from context. Currently just supports the segment.probe().
|
|
13
|
+
*
|
|
14
|
+
* Exists in own class to keep default context management as minimal/efficient as possible
|
|
15
|
+
* given we wrap pretty much every functions execution.
|
|
16
|
+
*/
|
|
17
|
+
class LegacyDiagnosticContextManager extends LegacyContextManager {
|
|
18
|
+
setContext(newContext) {
|
|
19
|
+
this._logDiagnostic(this._context, 'Removed from context')
|
|
20
|
+
|
|
21
|
+
this._context = newContext
|
|
22
|
+
|
|
23
|
+
this._logDiagnostic(newContext, 'Set in context')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
_logDiagnostic(context, message) {
|
|
27
|
+
// This is to currently support diagnostic logging of segments which gets attached to
|
|
28
|
+
// transactions with a stack trace. All of this is output at once at the end of a transaction
|
|
29
|
+
// when enabled for clear tracing.
|
|
30
|
+
if (context && context.probe) {
|
|
31
|
+
context.probe(message)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = LegacyDiagnosticContextManager
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2021 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Class for managing state in the agent.
|
|
10
|
+
* Keeps track of a single context instance.
|
|
11
|
+
*
|
|
12
|
+
* Given current usage with every instrumented function, the functions in this
|
|
13
|
+
* class should do as little work as possible to avoid unnecessary overhead.
|
|
14
|
+
*
|
|
15
|
+
* @class
|
|
16
|
+
*/
|
|
17
|
+
class LegacyContextManager {
|
|
18
|
+
/**
|
|
19
|
+
* @param {object} config New Relic config instance
|
|
20
|
+
*/
|
|
21
|
+
constructor(config) {
|
|
22
|
+
this._config = config
|
|
23
|
+
this._context = null
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get the currently active context.
|
|
28
|
+
*
|
|
29
|
+
* @returns {object} The current active context.
|
|
30
|
+
*/
|
|
31
|
+
getContext() {
|
|
32
|
+
return this._context
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Set a new active context. Not bound to function execution.
|
|
37
|
+
*
|
|
38
|
+
* @param {object} newContext The context to set as active.
|
|
39
|
+
*/
|
|
40
|
+
setContext(newContext) {
|
|
41
|
+
this._context = newContext
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Run a function with the passed in context as the active context.
|
|
46
|
+
* Restores the previously active context upon completion.
|
|
47
|
+
*
|
|
48
|
+
* @param {object} context The context to set as active during callback execution.
|
|
49
|
+
* @param {Function} callback The function to execute in context.
|
|
50
|
+
* @param {Function} [cbThis] Optional `this` to apply to the callback.
|
|
51
|
+
* @param {Array<*>} [args] Optional arguments object or args array to invoke the callback with.
|
|
52
|
+
* @returns {*} Returns the value returned by the callback function.
|
|
53
|
+
*/
|
|
54
|
+
runInContext(context, callback, cbThis, args) {
|
|
55
|
+
const oldContext = this.getContext()
|
|
56
|
+
this.setContext(context)
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
return callback.apply(cbThis, args)
|
|
60
|
+
} finally {
|
|
61
|
+
this.setContext(oldContext)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = LegacyContextManager
|