newrelic 8.6.0 → 8.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 +41 -0
- package/api.js +4 -23
- package/lib/config/index.js +11 -8
- package/lib/metrics/names.js +5 -1
- package/lib/shimmer.js +62 -2
- package/lib/transaction/tracer/index.js +1 -10
- package/package.json +5 -4
package/NEWS.md
CHANGED
|
@@ -1,3 +1,44 @@
|
|
|
1
|
+
### v8.7.0 (2022-01-04)
|
|
2
|
+
|
|
3
|
+
* Updated `onResolved` instrumentation hook to only be called the first time we see a specific module filepath resolved.
|
|
4
|
+
|
|
5
|
+
* Removed `tracer.segment` in place of direct usage of context manager.
|
|
6
|
+
|
|
7
|
+
* Fixed an issue where multiple calls to `instrumentLoadedModule` resulted in re-instrumenting the same module.
|
|
8
|
+
|
|
9
|
+
* Fixed issue where `instrumentLoadedModule` would return `true` even if the instrumentation handler indicated it did not apply instrumentation.
|
|
10
|
+
|
|
11
|
+
* Added support metrics for tracking when instrumentation was applied per module.
|
|
12
|
+
|
|
13
|
+
* `Supportability/Features/Instrumentation/OnResolved/<module-name>`
|
|
14
|
+
* `Supportability/Features/Instrumentation/OnResolved/<module-name>/Version/<major version>`
|
|
15
|
+
* `Supportability/Features/Instrumentation/OnRequire/<module-name>`
|
|
16
|
+
* `Supportability/Features/Instrumentation/OnRequire/<module-name>/Version/<major version>`
|
|
17
|
+
|
|
18
|
+
* Fixed issue where expected status code ranges would not be parsed until ignored status codes were also defined.
|
|
19
|
+
|
|
20
|
+
* Added an input `changelog_file` to pass in name of changelog. This defaults to `NEWS.md` but some repos use `CHANGELOG.md`
|
|
21
|
+
|
|
22
|
+
* Abstracted `bin/prepare-release.js` to work against other repositories.
|
|
23
|
+
|
|
24
|
+
* Added reusable prepare-release workflow that can be referenced in all other newrelic Node.js repositories.
|
|
25
|
+
|
|
26
|
+
* Updated pending PRs workflow to check all repos the team owns.
|
|
27
|
+
|
|
28
|
+
* Changed the event type from `pull_request` to `pull_request_target` to allow for auto assign of PRs to the Node.js Engineering Board
|
|
29
|
+
|
|
30
|
+
* Fixed add to board workflow to properly pass repository secrets into reusable board workflow.
|
|
31
|
+
|
|
32
|
+
* Changes token used to post issues to org level project board
|
|
33
|
+
|
|
34
|
+
* Runs versioned tests for external modules against tests defined in the external repository instead of tests published in npm modules.
|
|
35
|
+
|
|
36
|
+
* Added a reusable workflow to automatically add issues to the Node.js Engineering Board when created.
|
|
37
|
+
|
|
38
|
+
* Added CI job to update system configurations with new agent version on release.
|
|
39
|
+
|
|
40
|
+
* Moved `methods.js` under bluebird versioned test folder.
|
|
41
|
+
|
|
1
42
|
### v8.6.0 (2021-11-17)
|
|
2
43
|
|
|
3
44
|
* Added `onResolved` instrumentation hook to apply instrumentation prior to module load.
|
package/api.js
CHANGED
|
@@ -14,7 +14,6 @@ const hashes = require('./lib/util/hashes')
|
|
|
14
14
|
const properties = require('./lib/util/properties')
|
|
15
15
|
const stringify = require('json-stringify-safe')
|
|
16
16
|
const shimmer = require('./lib/shimmer')
|
|
17
|
-
const shims = require('./lib/shim')
|
|
18
17
|
const isValidType = require('./lib/util/attribute-types')
|
|
19
18
|
const TransactionShim = require('./lib/shim/transaction-shim')
|
|
20
19
|
const TransactionHandle = require('./lib/transaction/handle')
|
|
@@ -1332,34 +1331,16 @@ API.prototype.instrumentLoadedModule = function instrumentLoadedModule(moduleNam
|
|
|
1332
1331
|
NAMES.SUPPORTABILITY.API + '/instrumentLoadedModule'
|
|
1333
1332
|
)
|
|
1334
1333
|
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
1334
|
|
|
1335
|
+
try {
|
|
1348
1336
|
const resolvedName = require.resolve(moduleName)
|
|
1349
1337
|
|
|
1350
|
-
|
|
1351
|
-
instrumentation.type,
|
|
1352
|
-
this.agent,
|
|
1353
|
-
moduleName,
|
|
1354
|
-
resolvedName
|
|
1355
|
-
)
|
|
1356
|
-
|
|
1357
|
-
instrumentation.onRequire(shim, module, moduleName)
|
|
1358
|
-
|
|
1359
|
-
return true
|
|
1338
|
+
return shimmer.instrumentPostLoad(this.agent, module, moduleName, resolvedName)
|
|
1360
1339
|
} catch (error) {
|
|
1361
1340
|
logger.error('instrumentLoadedModule encountered an error, module not instrumented: %s', error)
|
|
1362
1341
|
}
|
|
1342
|
+
|
|
1343
|
+
return false
|
|
1363
1344
|
}
|
|
1364
1345
|
|
|
1365
1346
|
/**
|
package/lib/config/index.js
CHANGED
|
@@ -229,6 +229,7 @@ Config.prototype.mergeServerConfig = mergeServerConfig
|
|
|
229
229
|
* recognized, unsupported, and unknown parameters.
|
|
230
230
|
*
|
|
231
231
|
* @param {object} json The config blob sent by New Relic.
|
|
232
|
+
* @param recursion
|
|
232
233
|
*/
|
|
233
234
|
Config.prototype.onConnect = function onConnect(json, recursion) {
|
|
234
235
|
json = json || Object.create(null)
|
|
@@ -865,7 +866,7 @@ Config.prototype.checkAsyncHookStatus = function checkAsyncHookStatus() {
|
|
|
865
866
|
* I wanted to cache the DisplayHost, but if I attached the variable to the config object,
|
|
866
867
|
* it sends the extra variable to New Relic, which is not desired.
|
|
867
868
|
*
|
|
868
|
-
* @
|
|
869
|
+
* @returns {string} display host name
|
|
869
870
|
*/
|
|
870
871
|
Config.prototype.getDisplayHost = getDisplayHost
|
|
871
872
|
|
|
@@ -903,7 +904,7 @@ function getDisplayHost() {
|
|
|
903
904
|
* I wanted to cache the Hostname, but if I attached the variable to the config object,
|
|
904
905
|
* it sends the extra variable to New Relic, which is not desired.
|
|
905
906
|
*
|
|
906
|
-
* @
|
|
907
|
+
* @returns {string} host name
|
|
907
908
|
*/
|
|
908
909
|
Config.prototype.getHostnameSafe = getHostnameSafe
|
|
909
910
|
|
|
@@ -980,6 +981,7 @@ Config.prototype.applications = function applications() {
|
|
|
980
981
|
*
|
|
981
982
|
* @param {object} external The configuration being loaded.
|
|
982
983
|
* @param {object} internal Whichever chunk of the config being overridden.
|
|
984
|
+
* @param arbitrary
|
|
983
985
|
*/
|
|
984
986
|
Config.prototype._fromPassed = function _fromPassed(external, internal, arbitrary) {
|
|
985
987
|
if (!external) {
|
|
@@ -1065,6 +1067,8 @@ Config.prototype._featureFlagsFromEnv = function _featureFlagsFromEnv() {
|
|
|
1065
1067
|
* need to set this yourself.
|
|
1066
1068
|
* @param object data The current level of the configuration object. Should
|
|
1067
1069
|
* never need to set this yourself.
|
|
1070
|
+
* @param metadata
|
|
1071
|
+
* @param data
|
|
1068
1072
|
*/
|
|
1069
1073
|
Config.prototype._fromEnvironment = function _fromEnvironment(metadata, data) {
|
|
1070
1074
|
if (!metadata) {
|
|
@@ -1122,7 +1126,6 @@ Config.prototype._fromEnvironment = function _fromEnvironment(metadata, data) {
|
|
|
1122
1126
|
* environment variable.
|
|
1123
1127
|
*
|
|
1124
1128
|
* @param {*} inputConfig configuration passed to the Config constructor
|
|
1125
|
-
*
|
|
1126
1129
|
* @returns {boolean}
|
|
1127
1130
|
*/
|
|
1128
1131
|
Config.prototype._loggingManuallySet = function _loggingManuallySet(inputConfig) {
|
|
@@ -1137,7 +1140,6 @@ Config.prototype._loggingManuallySet = function _loggingManuallySet(inputConfig)
|
|
|
1137
1140
|
* file or enveironment variable
|
|
1138
1141
|
*
|
|
1139
1142
|
* @param {*} inputConfig configuration pass to the Config constructor
|
|
1140
|
-
*
|
|
1141
1143
|
* @returns {boolean}
|
|
1142
1144
|
*/
|
|
1143
1145
|
Config.prototype._nativeMetricsManuallySet = function _nativeMetricsManuallySet(inputConfig) {
|
|
@@ -1156,7 +1158,6 @@ Config.prototype._nativeMetricsManuallySet = function _nativeMetricsManuallySet(
|
|
|
1156
1158
|
* environment variable.
|
|
1157
1159
|
*
|
|
1158
1160
|
* @param {*} inputConfig configuration passed to the Config constructor
|
|
1159
|
-
*
|
|
1160
1161
|
* @returns {boolean}
|
|
1161
1162
|
*/
|
|
1162
1163
|
Config.prototype._DTManuallySet = function _DTManuallySet(inputConfig) {
|
|
@@ -1173,6 +1174,7 @@ Config.prototype._DTManuallySet = function _DTManuallySet(inputConfig) {
|
|
|
1173
1174
|
* - disables cross_application_tracer.enabled if set
|
|
1174
1175
|
* - defaults logging to disabled
|
|
1175
1176
|
* - verifies data specific to running DT is defined either in config file of env vars
|
|
1177
|
+
*
|
|
1176
1178
|
* @param {*} inputConfig configuration passed to the Config constructor
|
|
1177
1179
|
*/
|
|
1178
1180
|
Config.prototype._enforceServerless = function _enforceServerless(inputConfig) {
|
|
@@ -1282,7 +1284,7 @@ Config.prototype._canonicalize = function _canonicalize() {
|
|
|
1282
1284
|
}
|
|
1283
1285
|
|
|
1284
1286
|
const expectedCodes = this.error_collector && this.error_collector.expected_status_codes
|
|
1285
|
-
if (
|
|
1287
|
+
if (expectedCodes) {
|
|
1286
1288
|
this.error_collector.expected_status_codes = _parseCodes(expectedCodes)
|
|
1287
1289
|
}
|
|
1288
1290
|
|
|
@@ -1410,7 +1412,6 @@ Config.prototype._applyHighSecurity = function _applyHighSecurity() {
|
|
|
1410
1412
|
*
|
|
1411
1413
|
* @param {Agent} agent
|
|
1412
1414
|
* @param {object} policies
|
|
1413
|
-
*
|
|
1414
1415
|
* @returns {CollectorResponse} The result of the processing, with the known
|
|
1415
1416
|
* policies as the response payload.
|
|
1416
1417
|
*/
|
|
@@ -1540,7 +1541,7 @@ function redactValue(value) {
|
|
|
1540
1541
|
* Get a JSONifiable object containing all settings we want to report to the
|
|
1541
1542
|
* collector and store in the environment_values table.
|
|
1542
1543
|
*
|
|
1543
|
-
* @
|
|
1544
|
+
* @returns Object containing simple key-value pairs of settings
|
|
1544
1545
|
*/
|
|
1545
1546
|
Config.prototype.publicSettings = function publicSettings() {
|
|
1546
1547
|
let settings = Object.create(null)
|
|
@@ -1683,6 +1684,8 @@ function initialize(config) {
|
|
|
1683
1684
|
|
|
1684
1685
|
/**
|
|
1685
1686
|
* This helper function creates an empty configuration object
|
|
1687
|
+
*
|
|
1688
|
+
* @param config
|
|
1686
1689
|
*/
|
|
1687
1690
|
function createNewConfigObject(config) {
|
|
1688
1691
|
config = new Config(Object.create(null))
|
package/lib/metrics/names.js
CHANGED
|
@@ -252,7 +252,11 @@ const INFINITE_TRACING = {
|
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
const FEATURES = {
|
|
255
|
-
CERTIFICATES: SUPPORTABILITY.FEATURES + '/Certificates'
|
|
255
|
+
CERTIFICATES: SUPPORTABILITY.FEATURES + '/Certificates',
|
|
256
|
+
INSTRUMENTATION: {
|
|
257
|
+
ON_RESOLVED: SUPPORTABILITY.FEATURES + '/Instrumentation/OnResolved',
|
|
258
|
+
ON_REQUIRE: SUPPORTABILITY.FEATURES + '/Instrumentation/OnRequire'
|
|
259
|
+
}
|
|
256
260
|
}
|
|
257
261
|
|
|
258
262
|
module.exports = {
|
package/lib/shimmer.js
CHANGED
|
@@ -6,12 +6,15 @@
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
8
|
const path = require('path')
|
|
9
|
+
const semver = require('semver')
|
|
9
10
|
const fs = require('./util/unwrapped-core').fs
|
|
10
11
|
const logger = require('./logger').child({ component: 'shimmer' })
|
|
11
12
|
const INSTRUMENTATIONS = require('./instrumentations')()
|
|
12
13
|
const properties = require('./util/properties')
|
|
13
14
|
const shims = require('./shim')
|
|
14
15
|
|
|
16
|
+
const NAMES = require('./metrics/names')
|
|
17
|
+
|
|
15
18
|
const MODULE_TYPE = shims.constants.MODULE_TYPE
|
|
16
19
|
|
|
17
20
|
const CORE_INSTRUMENTATION = {
|
|
@@ -286,9 +289,13 @@ const shimmer = (module.exports = {
|
|
|
286
289
|
// This is triggered by the load call, so record the path that has been seen so
|
|
287
290
|
// we can examine it after the load call has returned.
|
|
288
291
|
const resolvedFilepath = resolve.apply(this, arguments)
|
|
289
|
-
filepathMap[file] = resolvedFilepath
|
|
290
292
|
|
|
291
|
-
|
|
293
|
+
// Only fire the first time we see a specific module resolved
|
|
294
|
+
if (filepathMap[file] !== resolvedFilepath) {
|
|
295
|
+
filepathMap[file] = resolvedFilepath
|
|
296
|
+
|
|
297
|
+
_onResolveFileName(agent, file, resolvedFilepath)
|
|
298
|
+
}
|
|
292
299
|
|
|
293
300
|
return resolvedFilepath
|
|
294
301
|
}
|
|
@@ -458,6 +465,14 @@ const shimmer = (module.exports = {
|
|
|
458
465
|
instrumentation = moduleName
|
|
459
466
|
}
|
|
460
467
|
return instrumentation
|
|
468
|
+
},
|
|
469
|
+
|
|
470
|
+
instrumentPostLoad(agent, module, moduleName, resolvedName) {
|
|
471
|
+
const result = _postLoad(agent, module, moduleName, resolvedName)
|
|
472
|
+
// This is to not break the public API
|
|
473
|
+
// previously it would just call instrumentation
|
|
474
|
+
// and not check the result
|
|
475
|
+
return !!result.__NR_instrumented
|
|
461
476
|
}
|
|
462
477
|
})
|
|
463
478
|
|
|
@@ -502,6 +517,7 @@ function instrumentPostLoad(agent, nodule, moduleName, resolvedName) {
|
|
|
502
517
|
const shim = shims.createShimFromType(instrumentation.type, agent, moduleName, resolvedName)
|
|
503
518
|
|
|
504
519
|
applyDebugState(shim, nodule)
|
|
520
|
+
trackInstrumentationUsage(agent, shim, moduleName, NAMES.FEATURES.INSTRUMENTATION.ON_REQUIRE)
|
|
505
521
|
|
|
506
522
|
try {
|
|
507
523
|
if (instrumentation.onRequire(shim, nodule, moduleName) !== false) {
|
|
@@ -597,6 +613,8 @@ function _instrumentOnResolved(agent, moduleName, resolvedFilepath) {
|
|
|
597
613
|
|
|
598
614
|
const shim = shims.createShimFromType(instrumentation.type, agent, moduleName, resolvedFilepath)
|
|
599
615
|
|
|
616
|
+
trackInstrumentationUsage(agent, shim, moduleName, NAMES.FEATURES.INSTRUMENTATION.ON_RESOLVED)
|
|
617
|
+
|
|
600
618
|
try {
|
|
601
619
|
instrumentation.onResolved(shim, moduleName, resolvedFilepath)
|
|
602
620
|
} catch (instrumentationError) {
|
|
@@ -644,3 +662,45 @@ function hasValidRegisterOptions(opts) {
|
|
|
644
662
|
|
|
645
663
|
return true
|
|
646
664
|
}
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* Adds metrics to indicate instrumentation was used for a particular module and
|
|
668
|
+
* what major version the module was at, if possible.
|
|
669
|
+
*
|
|
670
|
+
* @param {*} agent The agent instance.
|
|
671
|
+
* @param {*} shim The instance of the shim used to instrument the module.
|
|
672
|
+
* @param {string} moduleName The name of the required module.
|
|
673
|
+
* @param {string} metricPrefix Support metric prefix to prepend to the metrics. Will indicate onRequire or onResolved
|
|
674
|
+
* from NAMES.FEATURES.INSTRUMENTATION.
|
|
675
|
+
*/
|
|
676
|
+
function trackInstrumentationUsage(agent, shim, moduleName, metricPrefix) {
|
|
677
|
+
try {
|
|
678
|
+
const version = tryGetVersion(shim)
|
|
679
|
+
const instrumentationMetricName = `${metricPrefix}/${moduleName}`
|
|
680
|
+
|
|
681
|
+
agent.metrics.getOrCreateMetric(instrumentationMetricName).incrementCallCount()
|
|
682
|
+
|
|
683
|
+
if (version) {
|
|
684
|
+
const majorVersion = semver.major(version)
|
|
685
|
+
const versionMetricName = `${instrumentationMetricName}/Version/${majorVersion}`
|
|
686
|
+
|
|
687
|
+
agent.metrics.getOrCreateMetric(versionMetricName).incrementCallCount()
|
|
688
|
+
}
|
|
689
|
+
} catch (error) {
|
|
690
|
+
logger.debug('Unable to track instrumentation usage for: ', moduleName, error)
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
function tryGetVersion(shim) {
|
|
695
|
+
// Global module (i.e. domain) or finding root failed
|
|
696
|
+
if (shim._moduleRoot === '.') {
|
|
697
|
+
return
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
const packageInfo = shim.require('./package.json')
|
|
701
|
+
if (!packageInfo) {
|
|
702
|
+
return
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
return packageInfo.version
|
|
706
|
+
}
|
|
@@ -45,16 +45,6 @@ Tracer.prototype.wrapFunctionFirst = wrapFunctionFirst
|
|
|
45
45
|
Tracer.prototype.wrapSyncFunction = wrapSyncFunction
|
|
46
46
|
Tracer.prototype.wrapCallback = wrapCallback
|
|
47
47
|
|
|
48
|
-
Object.defineProperty(Tracer.prototype, 'segment', {
|
|
49
|
-
get: function segmentGetter() {
|
|
50
|
-
return this._contextManager.getContext()
|
|
51
|
-
},
|
|
52
|
-
set: function segmentSetter(segment) {
|
|
53
|
-
this._contextManager.setContext(segment)
|
|
54
|
-
return segment
|
|
55
|
-
}
|
|
56
|
-
})
|
|
57
|
-
|
|
58
48
|
function getTransaction() {
|
|
59
49
|
const currentSegment = this._contextManager.getContext()
|
|
60
50
|
if (currentSegment && currentSegment.transaction && currentSegment.transaction.isActive()) {
|
|
@@ -69,6 +59,7 @@ function getSegment() {
|
|
|
69
59
|
return this._contextManager.getContext()
|
|
70
60
|
}
|
|
71
61
|
|
|
62
|
+
// TODO: Remove/replace external uses to tracer.getSpanContext()
|
|
72
63
|
function getSpanContext() {
|
|
73
64
|
const currentSegment = this.getSegment()
|
|
74
65
|
return currentSegment && currentSegment.getSpanContext()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "newrelic",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.7.0",
|
|
4
4
|
"author": "New Relic Node.js agent team <nodejs@newrelic.com>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"contributors": [
|
|
@@ -148,10 +148,11 @@
|
|
|
148
148
|
"update-cross-agent-tests": "./bin/update-cats.sh",
|
|
149
149
|
"versioned-tests": "./bin/run-versioned-tests.sh",
|
|
150
150
|
"update-changelog-version": "node ./bin/update-changelog-version",
|
|
151
|
+
"checkout-external-versioned": "node ./test/versioned-external/checkout-external-tests.js",
|
|
151
152
|
"versioned": "npm run versioned:npm7",
|
|
152
|
-
"versioned:major": "npm run prepare-test && VERSIONED_MODE=--major NPM7=1 time ./bin/run-versioned-tests.sh",
|
|
153
|
-
"versioned:npm6": "npm run prepare-test && time ./bin/run-versioned-tests.sh",
|
|
154
|
-
"versioned:npm7": "npm run prepare-test && NPM7=1 time ./bin/run-versioned-tests.sh",
|
|
153
|
+
"versioned:major": "npm run checkout-external-versioned && npm run prepare-test && VERSIONED_MODE=--major NPM7=1 time ./bin/run-versioned-tests.sh",
|
|
154
|
+
"versioned:npm6": "npm run checkout-external-versioned && npm run prepare-test && time ./bin/run-versioned-tests.sh",
|
|
155
|
+
"versioned:npm7": "npm run checkout-external-versioned && npm run prepare-test && NPM7=1 time ./bin/run-versioned-tests.sh",
|
|
155
156
|
"prepare": "husky install"
|
|
156
157
|
},
|
|
157
158
|
"bin": {
|