newrelic 8.3.0 → 8.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NEWS.md +76 -0
- package/README.md +7 -6
- package/THIRD_PARTY_NOTICES.md +95 -35
- package/api.js +74 -68
- package/bin/test-naming-rules.js +22 -22
- package/lib/agent.js +4 -4
- package/lib/attributes.js +2 -2
- package/lib/collector/api.js +12 -12
- package/lib/collector/facts.js +1 -1
- package/lib/collector/http-agents.js +12 -11
- package/lib/collector/key-parser.js +1 -1
- package/lib/collector/remote-method.js +27 -26
- package/lib/config/attribute-filter.js +23 -23
- package/lib/config/default.js +12 -10
- package/lib/config/hsm.js +1 -1
- package/lib/config/index.js +82 -66
- package/lib/config/lasp.js +3 -3
- package/lib/config/merge-server-config.js +1 -1
- package/lib/db/parse-sql.js +8 -8
- package/lib/db/parsed-statement.js +9 -8
- package/lib/db/query-parsers/sql.js +7 -7
- package/lib/db/query-sample.js +9 -9
- package/lib/db/query-trace-aggregator.js +4 -4
- package/lib/db/statement-matcher.js +5 -5
- package/lib/db/utils.js +1 -1
- package/lib/environment.js +43 -43
- package/lib/errors/error-collector.js +2 -2
- package/lib/errors/error-trace-aggregator.js +1 -1
- package/lib/errors/helper.js +3 -3
- package/lib/errors/index.js +17 -17
- package/lib/feature_flags.js +7 -5
- package/lib/header-attributes.js +6 -6
- package/lib/header-processing.js +1 -1
- package/lib/instrumentation/amqplib.js +26 -26
- package/lib/instrumentation/bluebird.js +3 -3
- package/lib/instrumentation/cassandra-driver.js +7 -3
- package/lib/instrumentation/connect.js +4 -4
- package/lib/instrumentation/core/async_hooks.js +6 -6
- package/lib/instrumentation/core/domain.js +2 -2
- package/lib/instrumentation/core/globals.js +1 -1
- package/lib/instrumentation/core/http-outbound.js +15 -84
- package/lib/instrumentation/core/http.js +34 -67
- package/lib/instrumentation/core/inspector.js +2 -2
- package/lib/instrumentation/core/timers.js +7 -7
- package/lib/instrumentation/core/zlib.js +2 -2
- package/lib/instrumentation/director.js +4 -4
- package/lib/instrumentation/express.js +8 -8
- package/lib/instrumentation/fastify/spec-builders.js +57 -47
- package/lib/instrumentation/fastify.js +85 -24
- package/lib/instrumentation/generic-pool.js +1 -1
- package/lib/instrumentation/hapi/hapi-17.js +11 -11
- package/lib/instrumentation/hapi/shared.js +1 -1
- package/lib/instrumentation/hapi.js +22 -22
- package/lib/instrumentation/ioredis.js +7 -7
- package/lib/instrumentation/memcached.js +7 -7
- package/lib/instrumentation/mongodb/common.js +16 -5
- package/lib/instrumentation/mysql.js +19 -19
- package/lib/instrumentation/oracle.js +15 -15
- package/lib/instrumentation/pg.js +4 -4
- package/lib/instrumentation/promise.js +46 -46
- package/lib/instrumentation/q.js +2 -2
- package/lib/instrumentation/redis.js +11 -11
- package/lib/instrumentation/restify.js +1 -1
- package/lib/instrumentation/undici.js +242 -0
- package/lib/instrumentation/vision.js +4 -4
- package/lib/instrumentation/when.js +3 -3
- package/lib/instrumentations.js +2 -1
- package/lib/logger.js +5 -5
- package/lib/metrics/index.js +15 -15
- package/lib/metrics/mapper.js +7 -7
- package/lib/metrics/normalizer/rule.js +9 -9
- package/lib/metrics/normalizer/tx_segment.js +17 -17
- package/lib/metrics/normalizer.js +22 -22
- package/lib/metrics/recorders/custom.js +5 -5
- package/lib/metrics/recorders/generic.js +3 -3
- package/lib/metrics/recorders/http.js +7 -7
- package/lib/metrics/recorders/http_external.js +7 -7
- package/lib/metrics/recorders/message-transaction.js +5 -6
- package/lib/metrics/recorders/other.js +5 -5
- package/lib/parse-proc-cpuinfo.js +25 -19
- package/lib/parse-proc-meminfo.js +8 -2
- package/lib/prioritized-attributes.js +2 -2
- package/lib/priority-queue.js +10 -10
- package/lib/reservoir.js +3 -3
- package/lib/sampler.js +26 -26
- package/lib/serverless/aws-lambda.js +8 -2
- package/lib/shim/datastore-shim.js +35 -32
- package/lib/shim/index.js +2 -2
- package/lib/shim/message-shim.js +47 -47
- package/lib/shim/promise-shim.js +1 -1
- package/lib/shim/shim.js +61 -61
- package/lib/shim/specs/index.js +3 -3
- package/lib/shim/transaction-shim.js +44 -192
- package/lib/shim/webframework-shim.js +52 -52
- package/lib/spans/span-event.js +1 -1
- package/lib/spans/streaming-span-attributes.js +1 -1
- package/lib/stats/apdex.js +2 -2
- package/lib/stats/index.js +2 -2
- package/lib/system-info.js +23 -23
- package/lib/timer.js +5 -5
- package/lib/transaction/dt-payload.js +1 -1
- package/lib/transaction/index.js +40 -40
- package/lib/transaction/name-state.js +14 -14
- package/lib/transaction/trace/exclusive-time-calculator.js +6 -6
- package/lib/transaction/trace/index.js +14 -14
- package/lib/transaction/trace/segment.js +18 -18
- package/lib/transaction/tracecontext.js +1 -1
- package/lib/transaction/tracer/index.js +53 -49
- package/lib/uninstrumented.js +7 -7
- package/lib/util/arity.js +2 -2
- package/lib/util/byte-limit.js +4 -4
- package/lib/util/cat.js +269 -24
- package/lib/util/codec.js +2 -2
- package/lib/util/copy.js +2 -2
- package/lib/util/deep-equal.js +10 -10
- package/lib/util/flatten.js +4 -4
- package/lib/util/hashes.js +14 -14
- package/lib/util/label-parser.js +17 -17
- package/lib/util/logger.js +24 -24
- package/lib/util/process-version.js +2 -2
- package/lib/util/properties.js +4 -4
- package/lib/util/sql/obfuscate.js +15 -15
- package/lib/util/stream-sink.js +3 -3
- package/lib/util/unwrapped-core.js +2 -2
- package/lib/util/urltils.js +16 -16
- package/lib/utilization/aws-info.js +7 -7
- package/lib/utilization/azure-info.js +6 -6
- package/lib/utilization/common.js +13 -13
- package/lib/utilization/docker-info.js +11 -11
- package/lib/utilization/gcp-info.js +4 -4
- package/lib/utilization/index.js +5 -5
- package/lib/utilization/pcf-info.js +9 -9
- package/package.json +13 -6
- package/stub_api.js +8 -8
package/lib/config/index.js
CHANGED
|
@@ -61,7 +61,7 @@ function isTruthular(setting) {
|
|
|
61
61
|
return false
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
const normalized = setting.toString().toLowerCase()
|
|
65
65
|
switch (normalized) {
|
|
66
66
|
case 'false':
|
|
67
67
|
case 'f':
|
|
@@ -245,11 +245,13 @@ Config.prototype.onConnect = function onConnect(json, recursion) {
|
|
|
245
245
|
this._fromServer(json, key)
|
|
246
246
|
}, this)
|
|
247
247
|
|
|
248
|
+
this._warnDeprecations()
|
|
249
|
+
|
|
248
250
|
this.emit('change', this)
|
|
249
251
|
}
|
|
250
252
|
|
|
251
253
|
Config.prototype._getMostSecure = function getMostSecure(key, currentVal, newVal) {
|
|
252
|
-
|
|
254
|
+
const filter = LASP_MAP[key] && LASP_MAP[key].filter
|
|
253
255
|
if (!this.security_policies_token || !filter) {
|
|
254
256
|
// If we aren't applying something vetted by security policies we
|
|
255
257
|
// just return the new value.
|
|
@@ -584,7 +586,7 @@ Config.prototype._fromServer = function _fromServer(params, key) {
|
|
|
584
586
|
* @param {string} key Value we're looking to set.
|
|
585
587
|
*/
|
|
586
588
|
Config.prototype._alwaysUpdateIfChanged = function _alwaysUpdateIfChanged(json, key) {
|
|
587
|
-
|
|
589
|
+
const value = json[key]
|
|
588
590
|
if (value != null && this[key] !== value) {
|
|
589
591
|
if (Array.isArray(value) && Array.isArray(this[key])) {
|
|
590
592
|
value.forEach(function pushIfNew(element) {
|
|
@@ -628,7 +630,7 @@ Config.prototype._updateIfChanged = function _updateIfChanged(json, key) {
|
|
|
628
630
|
*/
|
|
629
631
|
Config.prototype._validateThenUpdateStatusCodes = _validateThenUpdateStatusCodes
|
|
630
632
|
function _validateThenUpdateStatusCodes(remote, local, remoteKey, localKey) {
|
|
631
|
-
|
|
633
|
+
const valueToTest = remote[remoteKey]
|
|
632
634
|
if (!Array.isArray(valueToTest)) {
|
|
633
635
|
logger.warn(
|
|
634
636
|
'Saw SSC (ignore|expect)_status_codes that is not an array, will not merge: %s',
|
|
@@ -672,7 +674,7 @@ function _validateThenUpdateStatusCodes(remote, local, remoteKey, localKey) {
|
|
|
672
674
|
Config.prototype._validateThenUpdateErrorClasses = _validateThenUpdateErrorClasses
|
|
673
675
|
|
|
674
676
|
function _validateThenUpdateErrorClasses(remote, local, remoteKey, localKey) {
|
|
675
|
-
|
|
677
|
+
const valueToTest = remote[remoteKey]
|
|
676
678
|
if (!Array.isArray(valueToTest)) {
|
|
677
679
|
logger.warn(
|
|
678
680
|
'Saw SSC (ignore|expect)_classes that is not an array, will not merge: %s',
|
|
@@ -683,7 +685,7 @@ function _validateThenUpdateErrorClasses(remote, local, remoteKey, localKey) {
|
|
|
683
685
|
|
|
684
686
|
let valid = true
|
|
685
687
|
Object.keys(valueToTest).forEach(function validateArray(key) {
|
|
686
|
-
|
|
688
|
+
const thingToTest = valueToTest[key]
|
|
687
689
|
if ('string' !== typeof thingToTest) {
|
|
688
690
|
logger.warn(
|
|
689
691
|
'Saw SSC (ignore|expect)_class that is not a string, will not merge: %s',
|
|
@@ -716,7 +718,7 @@ function _validateThenUpdateErrorClasses(remote, local, remoteKey, localKey) {
|
|
|
716
718
|
Config.prototype._validateThenUpdateErrorMessages = _validateThenUpdateErrorMessages
|
|
717
719
|
|
|
718
720
|
function _validateThenUpdateErrorMessages(remote, local, remoteKey, localKey) {
|
|
719
|
-
|
|
721
|
+
const valueToTest = remote[remoteKey]
|
|
720
722
|
if (Array.isArray(valueToTest)) {
|
|
721
723
|
logger.warn('Saw SSC (ignore|expect)_message that is an Array, will not merge: %s', valueToTest)
|
|
722
724
|
return
|
|
@@ -742,7 +744,7 @@ function _validateThenUpdateErrorMessages(remote, local, remoteKey, localKey) {
|
|
|
742
744
|
|
|
743
745
|
let valid = true
|
|
744
746
|
Object.keys(valueToTest).forEach(function validateArray(key) {
|
|
745
|
-
|
|
747
|
+
const arrayToTest = valueToTest[key]
|
|
746
748
|
if (!Array.isArray(arrayToTest)) {
|
|
747
749
|
logger.warn('Saw SSC message array that is not an array, will not merge: %s', arrayToTest)
|
|
748
750
|
valid = false
|
|
@@ -793,7 +795,7 @@ function _updateNestedIfChangedRaw(remote, local, remoteKey, localKey) {
|
|
|
793
795
|
* @param {string} key Value we're looking to set.
|
|
794
796
|
*/
|
|
795
797
|
Config.prototype._emitIfSet = function _emitIfSet(json, key) {
|
|
796
|
-
|
|
798
|
+
const value = json[key]
|
|
797
799
|
if (value != null) {
|
|
798
800
|
this.emit(key, value)
|
|
799
801
|
}
|
|
@@ -807,7 +809,7 @@ Config.prototype._emitIfSet = function _emitIfSet(json, key) {
|
|
|
807
809
|
* @param {string} key Value the agent won't set.
|
|
808
810
|
*/
|
|
809
811
|
Config.prototype.logDisabled = function logDisabled(json, key) {
|
|
810
|
-
|
|
812
|
+
const value = json[key]
|
|
811
813
|
if (value != null) {
|
|
812
814
|
logger.debug(
|
|
813
815
|
'Server-side configuration of %s is currently disabled by local configuration. ' +
|
|
@@ -826,7 +828,7 @@ Config.prototype.logDisabled = function logDisabled(json, key) {
|
|
|
826
828
|
* @param {string} key Value the agent doesn't set.
|
|
827
829
|
*/
|
|
828
830
|
Config.prototype.logUnsupported = function logUnsupported(json, key) {
|
|
829
|
-
|
|
831
|
+
const value = json[key]
|
|
830
832
|
if (value !== null && value !== undefined) {
|
|
831
833
|
logger.debug(
|
|
832
834
|
'Server-side configuration of %s is currently not supported by the ' +
|
|
@@ -845,7 +847,7 @@ Config.prototype.logUnsupported = function logUnsupported(json, key) {
|
|
|
845
847
|
* @param {string} key Value the agent knows nothing about.
|
|
846
848
|
*/
|
|
847
849
|
Config.prototype.logUnknown = function logUnknown(json, key) {
|
|
848
|
-
|
|
850
|
+
const value = json[key]
|
|
849
851
|
logger.debug('New Relic sent unknown configuration parameter %s with value %s.', key, value)
|
|
850
852
|
}
|
|
851
853
|
|
|
@@ -872,7 +874,7 @@ Config.prototype.clearDisplayHostCache = function clearDisplayHostCache() {
|
|
|
872
874
|
}
|
|
873
875
|
|
|
874
876
|
function getDisplayHost() {
|
|
875
|
-
|
|
877
|
+
let _displayHost
|
|
876
878
|
this.getDisplayHost = function getCachedDisplayHost() {
|
|
877
879
|
return _displayHost
|
|
878
880
|
}
|
|
@@ -880,8 +882,8 @@ function getDisplayHost() {
|
|
|
880
882
|
_displayHost = this.getHostnameSafe()
|
|
881
883
|
return _displayHost
|
|
882
884
|
}
|
|
883
|
-
|
|
884
|
-
|
|
885
|
+
const stringBuffer = Buffer.from(this.process_host.display_name, 'utf8')
|
|
886
|
+
const numBytes = stringBuffer.length
|
|
885
887
|
|
|
886
888
|
if (numBytes > 255) {
|
|
887
889
|
logger.warn('Custom host display name must be less than 255 bytes')
|
|
@@ -910,18 +912,18 @@ Config.prototype.clearHostnameCache = function clearHostnameCache() {
|
|
|
910
912
|
}
|
|
911
913
|
|
|
912
914
|
Config.prototype.getIPAddresses = function getIPAddresses() {
|
|
913
|
-
|
|
914
|
-
|
|
915
|
+
const addresses = Object.create(null)
|
|
916
|
+
const interfaces = os.networkInterfaces()
|
|
915
917
|
|
|
916
|
-
for (
|
|
918
|
+
for (const interfaceKey in interfaces) {
|
|
917
919
|
if (interfaceKey.match(/^lo/)) {
|
|
918
920
|
continue
|
|
919
921
|
}
|
|
920
922
|
|
|
921
|
-
|
|
922
|
-
for (
|
|
923
|
-
|
|
924
|
-
|
|
923
|
+
const interfaceDescriptions = interfaces[interfaceKey]
|
|
924
|
+
for (let i = 0; i < interfaceDescriptions.length; i++) {
|
|
925
|
+
const description = interfaceDescriptions[i]
|
|
926
|
+
const family = description.family.toLowerCase()
|
|
925
927
|
addresses[family] = description.address
|
|
926
928
|
}
|
|
927
929
|
}
|
|
@@ -929,7 +931,7 @@ Config.prototype.getIPAddresses = function getIPAddresses() {
|
|
|
929
931
|
}
|
|
930
932
|
|
|
931
933
|
function getHostnameSafe() {
|
|
932
|
-
|
|
934
|
+
let _hostname
|
|
933
935
|
this.getHostnameSafe = function getCachedHostname() {
|
|
934
936
|
return _hostname
|
|
935
937
|
}
|
|
@@ -937,7 +939,7 @@ function getHostnameSafe() {
|
|
|
937
939
|
_hostname = os.hostname()
|
|
938
940
|
return _hostname
|
|
939
941
|
} catch (e) {
|
|
940
|
-
|
|
942
|
+
const addresses = this.getIPAddresses()
|
|
941
943
|
|
|
942
944
|
if (this.process_host.ipv_preference === '6' && addresses.ipv6) {
|
|
943
945
|
_hostname = addresses.ipv6
|
|
@@ -960,7 +962,7 @@ function getHostnameSafe() {
|
|
|
960
962
|
* Ensure that the apps names are always returned as a list.
|
|
961
963
|
*/
|
|
962
964
|
Config.prototype.applications = function applications() {
|
|
963
|
-
|
|
965
|
+
const apps = this.app_name
|
|
964
966
|
|
|
965
967
|
if (Array.isArray(apps) && apps.length > 0) {
|
|
966
968
|
return apps
|
|
@@ -998,8 +1000,9 @@ Config.prototype._fromPassed = function _fromPassed(external, internal, arbitrar
|
|
|
998
1000
|
return
|
|
999
1001
|
}
|
|
1000
1002
|
|
|
1003
|
+
let node = null
|
|
1001
1004
|
try {
|
|
1002
|
-
|
|
1005
|
+
node = external[key]
|
|
1003
1006
|
} catch (err) {
|
|
1004
1007
|
logger.warn('Error thrown on access of user config for key: %s', key)
|
|
1005
1008
|
return
|
|
@@ -1007,7 +1010,7 @@ Config.prototype._fromPassed = function _fromPassed(external, internal, arbitrar
|
|
|
1007
1010
|
|
|
1008
1011
|
if (typeof node === 'object' && !Array.isArray(node)) {
|
|
1009
1012
|
// is top level and can have arbitrary keys
|
|
1010
|
-
|
|
1013
|
+
const allowArbitrary = internal === this || HAS_ARBITRARY_KEYS.has(key)
|
|
1011
1014
|
this._fromPassed(node, internal[key], allowArbitrary)
|
|
1012
1015
|
} else {
|
|
1013
1016
|
internal[key] = node
|
|
@@ -1024,14 +1027,14 @@ Config.prototype._fromPassed = function _fromPassed(external, internal, arbitrar
|
|
|
1024
1027
|
* of configuration.
|
|
1025
1028
|
*/
|
|
1026
1029
|
Config.prototype._fromSpecial = function _fromSpecial() {
|
|
1027
|
-
|
|
1030
|
+
const name = this.app_name
|
|
1028
1031
|
if (
|
|
1029
1032
|
name === null ||
|
|
1030
1033
|
name === undefined ||
|
|
1031
1034
|
name === '' ||
|
|
1032
1035
|
(Array.isArray(name) && name.length === 0)
|
|
1033
1036
|
) {
|
|
1034
|
-
|
|
1037
|
+
const azureName = process.env[AZURE_APP_NAME]
|
|
1035
1038
|
if (azureName) {
|
|
1036
1039
|
this.app_name = azureName.split(',')
|
|
1037
1040
|
}
|
|
@@ -1077,14 +1080,14 @@ Config.prototype._fromEnvironment = function _fromEnvironment(metadata, data) {
|
|
|
1077
1080
|
return
|
|
1078
1081
|
}
|
|
1079
1082
|
|
|
1080
|
-
|
|
1083
|
+
const node = metadata[value]
|
|
1081
1084
|
if (typeof node === 'string') {
|
|
1082
|
-
|
|
1085
|
+
const setting = process.env[node]
|
|
1083
1086
|
if (setting) {
|
|
1084
1087
|
logger.debug(`${node} environment variable set.`)
|
|
1085
1088
|
|
|
1086
1089
|
if (ENV.LIST_VARS.has(node)) {
|
|
1087
|
-
|
|
1090
|
+
const split = ENV.LIST_VARS_CUSTOM_DELIMITERS[node] || /,/
|
|
1088
1091
|
data[value] = setting.split(split).map(function trimVal(k) {
|
|
1089
1092
|
return k.trim()
|
|
1090
1093
|
})
|
|
@@ -1273,7 +1276,7 @@ Config.prototype._enforceServerless = function _enforceServerless(inputConfig) {
|
|
|
1273
1276
|
* based on special properties of configuration values should go here as well.
|
|
1274
1277
|
*/
|
|
1275
1278
|
Config.prototype._canonicalize = function _canonicalize() {
|
|
1276
|
-
|
|
1279
|
+
const statusCodes = this.error_collector && this.error_collector.ignore_status_codes
|
|
1277
1280
|
if (statusCodes) {
|
|
1278
1281
|
this.error_collector.ignore_status_codes = _parseCodes(statusCodes)
|
|
1279
1282
|
}
|
|
@@ -1283,17 +1286,17 @@ Config.prototype._canonicalize = function _canonicalize() {
|
|
|
1283
1286
|
this.error_collector.expected_status_codes = _parseCodes(expectedCodes)
|
|
1284
1287
|
}
|
|
1285
1288
|
|
|
1286
|
-
|
|
1289
|
+
const logAliases = {
|
|
1287
1290
|
verbose: 'trace',
|
|
1288
1291
|
debugging: 'debug',
|
|
1289
1292
|
warning: 'warn',
|
|
1290
1293
|
err: 'error'
|
|
1291
1294
|
}
|
|
1292
|
-
|
|
1295
|
+
const level = this.logging.level
|
|
1293
1296
|
this.logging.level = logAliases[level] || level
|
|
1294
1297
|
|
|
1295
1298
|
if (this.host === '') {
|
|
1296
|
-
|
|
1299
|
+
const region = parseKey(this.license_key)
|
|
1297
1300
|
if (region) {
|
|
1298
1301
|
this.host = 'collector.' + region + '.nr-data.net'
|
|
1299
1302
|
} else {
|
|
@@ -1318,7 +1321,7 @@ Config.prototype._canonicalize = function _canonicalize() {
|
|
|
1318
1321
|
function _parseCodes(codes) {
|
|
1319
1322
|
// range does not support negative values
|
|
1320
1323
|
function parseRange(range, parsed) {
|
|
1321
|
-
|
|
1324
|
+
const split = range.split('-')
|
|
1322
1325
|
if (split.length !== 2) {
|
|
1323
1326
|
logger.warn('Failed to parse range %s', range)
|
|
1324
1327
|
return parsed
|
|
@@ -1327,8 +1330,8 @@ function _parseCodes(codes) {
|
|
|
1327
1330
|
// catch negative code. ex. -7
|
|
1328
1331
|
return parsed.push(parseInt(range, 10))
|
|
1329
1332
|
}
|
|
1330
|
-
|
|
1331
|
-
|
|
1333
|
+
const lower = parseInt(split[0], 10)
|
|
1334
|
+
const upper = parseInt(split[1], 10)
|
|
1332
1335
|
if (Number.isNaN(lower) || Number.isNaN(upper)) {
|
|
1333
1336
|
logger.warn('Range must contain two numbers %s', range)
|
|
1334
1337
|
return parsed
|
|
@@ -1339,21 +1342,21 @@ function _parseCodes(codes) {
|
|
|
1339
1342
|
logger.warn('Range must be between 0 and 1000 %s', range)
|
|
1340
1343
|
} else {
|
|
1341
1344
|
// success
|
|
1342
|
-
for (
|
|
1345
|
+
for (let i = lower; i <= upper; i++) {
|
|
1343
1346
|
parsed.push(i)
|
|
1344
1347
|
}
|
|
1345
1348
|
}
|
|
1346
1349
|
return parsed
|
|
1347
1350
|
}
|
|
1348
1351
|
|
|
1349
|
-
|
|
1350
|
-
for (
|
|
1351
|
-
|
|
1352
|
-
|
|
1352
|
+
const parsedCodes = []
|
|
1353
|
+
for (let i = 0; i < codes.length; i++) {
|
|
1354
|
+
const code = codes[i]
|
|
1355
|
+
|
|
1353
1356
|
if (typeof code === 'string' && code.indexOf('-') !== -1) {
|
|
1354
1357
|
parseRange(code, parsedCodes)
|
|
1355
1358
|
} else {
|
|
1356
|
-
parsedCode = parseInt(code, 10)
|
|
1359
|
+
const parsedCode = parseInt(code, 10)
|
|
1357
1360
|
if (!Number.isNaN(parsedCode)) {
|
|
1358
1361
|
parsedCodes.push(parsedCode)
|
|
1359
1362
|
} else {
|
|
@@ -1369,7 +1372,7 @@ function _parseCodes(codes) {
|
|
|
1369
1372
|
* them to be correct.
|
|
1370
1373
|
*/
|
|
1371
1374
|
Config.prototype._applyHighSecurity = function _applyHighSecurity() {
|
|
1372
|
-
|
|
1375
|
+
const config = this
|
|
1373
1376
|
checkNode('', this, HSM.HIGH_SECURITY_SETTINGS)
|
|
1374
1377
|
// as a one off, we add a global exclude rule to the list to keep from
|
|
1375
1378
|
// clobbering user defined rules
|
|
@@ -1381,7 +1384,7 @@ Config.prototype._applyHighSecurity = function _applyHighSecurity() {
|
|
|
1381
1384
|
}
|
|
1382
1385
|
|
|
1383
1386
|
function checkKey(base, target, settings, key) {
|
|
1384
|
-
|
|
1387
|
+
const hsValue = settings[key]
|
|
1385
1388
|
|
|
1386
1389
|
if (hsValue && typeof hsValue === 'object' && !(hsValue instanceof Array)) {
|
|
1387
1390
|
if (typeof target[key] !== 'object') {
|
|
@@ -1412,8 +1415,8 @@ Config.prototype._applyHighSecurity = function _applyHighSecurity() {
|
|
|
1412
1415
|
* policies as the response payload.
|
|
1413
1416
|
*/
|
|
1414
1417
|
Config.prototype.applyLasp = function applyLasp(agent, policies) {
|
|
1415
|
-
|
|
1416
|
-
|
|
1418
|
+
const config = this
|
|
1419
|
+
const keys = Object.keys(policies)
|
|
1417
1420
|
|
|
1418
1421
|
if (!config.security_policies_token) {
|
|
1419
1422
|
if (keys.length) {
|
|
@@ -1425,12 +1428,12 @@ Config.prototype.applyLasp = function applyLasp(agent, policies) {
|
|
|
1425
1428
|
return CollectorResponse.success(null)
|
|
1426
1429
|
}
|
|
1427
1430
|
|
|
1428
|
-
|
|
1429
|
-
|
|
1431
|
+
const missingLASP = []
|
|
1432
|
+
const missingRequired = []
|
|
1430
1433
|
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
+
const finalPolicies = keys.reduce(function applyPolicy(obj, name) {
|
|
1435
|
+
const policy = policies[name]
|
|
1436
|
+
const localMapping = LASP_MAP[name]
|
|
1434
1437
|
|
|
1435
1438
|
if (!localMapping) {
|
|
1436
1439
|
if (!policy.required) {
|
|
@@ -1440,22 +1443,22 @@ Config.prototype.applyLasp = function applyLasp(agent, policies) {
|
|
|
1440
1443
|
// policy is required but does not exist in agent -- fail
|
|
1441
1444
|
missingRequired.push(name)
|
|
1442
1445
|
} else {
|
|
1443
|
-
|
|
1444
|
-
|
|
1446
|
+
const splitConfigName = localMapping.path.split('.')
|
|
1447
|
+
let settingBlock = config[splitConfigName[0]]
|
|
1445
1448
|
// pull out the configuration subsection that the option lives in
|
|
1446
|
-
for (
|
|
1449
|
+
for (let i = 1; i < splitConfigName.length - 1; ++i) {
|
|
1447
1450
|
settingBlock = settingBlock[splitConfigName[i]]
|
|
1448
1451
|
}
|
|
1449
|
-
|
|
1450
|
-
|
|
1452
|
+
const valueName = splitConfigName[splitConfigName.length - 1]
|
|
1453
|
+
const localVal = settingBlock[valueName]
|
|
1451
1454
|
|
|
1452
1455
|
// Indexes into "allowed values" based on "enabled" setting
|
|
1453
1456
|
// to retrieve proper mapping.
|
|
1454
|
-
|
|
1455
|
-
|
|
1457
|
+
const policyValues = localMapping.allowedValues
|
|
1458
|
+
const policyValue = policyValues[policy.enabled ? 1 : 0]
|
|
1456
1459
|
|
|
1457
1460
|
// get the most secure setting between local config and the policy
|
|
1458
|
-
|
|
1461
|
+
const finalValue = (settingBlock[valueName] = config._getMostSecure(
|
|
1459
1462
|
name,
|
|
1460
1463
|
localVal,
|
|
1461
1464
|
policyValue
|
|
@@ -1540,9 +1543,9 @@ function redactValue(value) {
|
|
|
1540
1543
|
* @return Object containing simple key-value pairs of settings
|
|
1541
1544
|
*/
|
|
1542
1545
|
Config.prototype.publicSettings = function publicSettings() {
|
|
1543
|
-
|
|
1546
|
+
let settings = Object.create(null)
|
|
1544
1547
|
|
|
1545
|
-
for (
|
|
1548
|
+
for (const key in this) {
|
|
1546
1549
|
if (this.hasOwnProperty(key) && !REMOVE_BEFORE_SEND.has(key)) {
|
|
1547
1550
|
if (HSM.REDACT_BEFORE_SEND.has(key)) {
|
|
1548
1551
|
const value = this[key]
|
|
@@ -1580,6 +1583,19 @@ Config.prototype.getAggregatorConfig = function getAggregatorConfig(method) {
|
|
|
1580
1583
|
}
|
|
1581
1584
|
}
|
|
1582
1585
|
|
|
1586
|
+
Config.prototype._warnDeprecations = function _warnDeprecations() {
|
|
1587
|
+
// DT overrides CAT so only warn when CAT is actually used.
|
|
1588
|
+
if (this.cross_application_tracer.enabled && !this.distributed_tracing.enabled) {
|
|
1589
|
+
const deprecationWarning = [
|
|
1590
|
+
'[Deprecation Warning]: Cross Application Tracing (CAT) has been deprecated and will be ',
|
|
1591
|
+
'removed in a future major release. CAT has been replaced by Distributed Tracing (DT). ',
|
|
1592
|
+
'Enable DT by setting distributed_tracing: { enabled: true }.'
|
|
1593
|
+
].join('')
|
|
1594
|
+
|
|
1595
|
+
logger.infoOnce('Deprecation:CAT', deprecationWarning)
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1583
1599
|
/**
|
|
1584
1600
|
* Create a configuration, either from a configuration file or the node
|
|
1585
1601
|
* process's environment.
|
|
@@ -1620,7 +1636,7 @@ function initialize(config) {
|
|
|
1620
1636
|
return createNewConfigObject(config)
|
|
1621
1637
|
}
|
|
1622
1638
|
|
|
1623
|
-
|
|
1639
|
+
const filepath = _findConfigFile()
|
|
1624
1640
|
if (!filepath) {
|
|
1625
1641
|
logger.info(
|
|
1626
1642
|
[
|
|
@@ -1636,7 +1652,7 @@ function initialize(config) {
|
|
|
1636
1652
|
return createNewConfigObject(config)
|
|
1637
1653
|
}
|
|
1638
1654
|
|
|
1639
|
-
|
|
1655
|
+
let userConf
|
|
1640
1656
|
try {
|
|
1641
1657
|
userConf = require(filepath).config
|
|
1642
1658
|
} catch (error) {
|
package/lib/config/lasp.js
CHANGED
|
@@ -29,9 +29,9 @@ const LASP_MAP = {
|
|
|
29
29
|
// Tracks the precedent of settings controlled by LASP.
|
|
30
30
|
filter: function mostSecureRecordSQL(first, second) {
|
|
31
31
|
// Ordered from least to most secure
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
const recordSQLSettings = ['obfuscated', 'off']
|
|
33
|
+
const firstIdx = recordSQLSettings.indexOf(first)
|
|
34
|
+
const secondIdx = recordSQLSettings.indexOf(second)
|
|
35
35
|
if (firstIdx < 0 && secondIdx < 0) {
|
|
36
36
|
// Return the most secure possible
|
|
37
37
|
return recordSQLSettings[recordSQLSettings.length - 1]
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
class MergeServerConfig {
|
|
9
9
|
// eslint-disable-next-line max-params
|
|
10
10
|
updateNestedIfChanged(config, remote, local, remoteKey, localKey, logger) {
|
|
11
|
-
|
|
11
|
+
const value = remote[remoteKey]
|
|
12
12
|
|
|
13
13
|
// if the value hasn't changed, skip this work.
|
|
14
14
|
// currently, this will always treat objects as
|
package/lib/db/parse-sql.js
CHANGED
|
@@ -8,18 +8,18 @@
|
|
|
8
8
|
// TODO: remove in favor of /lib/db/query-parsers/sql.js
|
|
9
9
|
// This module is currently used only in the Oracle instrumentation
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
const logger = require('../logger').child({ component: 'parse_sql' })
|
|
12
|
+
const StatementMatcher = require('./statement-matcher')
|
|
13
|
+
const ParsedStatement = require('./parsed-statement')
|
|
14
|
+
const stringify = require('json-stringify-safe')
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
const OPERATIONS = [
|
|
17
17
|
new StatementMatcher('select', /^\s*select[\S\s]*from[\s\[]+([^\]\s,)(;]*).*/gi),
|
|
18
18
|
new StatementMatcher('update', /^\s*update\s+([^\s,;]*).*/gi),
|
|
19
19
|
new StatementMatcher('insert', /^\s*insert(?:\s+ignore)?\s+into\s+([^\s(,;]*).*/gi),
|
|
20
20
|
new StatementMatcher('delete', /^\s*delete\s+from\s+([^\s,(;]*).*/gi)
|
|
21
21
|
]
|
|
22
|
-
|
|
22
|
+
const COMMENT_PATTERN = /\/\\*.*?\\*\//
|
|
23
23
|
|
|
24
24
|
// This must be called synchronously after the initial db call for backtraces to
|
|
25
25
|
// work correctly
|
|
@@ -44,9 +44,9 @@ module.exports = function parseSql(type, sql) {
|
|
|
44
44
|
|
|
45
45
|
sql = sql.replace(COMMENT_PATTERN, '').trim()
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
let parsedStatement
|
|
48
48
|
|
|
49
|
-
for (
|
|
49
|
+
for (let i = 0, l = OPERATIONS.length; i < l; i++) {
|
|
50
50
|
parsedStatement = OPERATIONS[i].getParsedStatement(sql)
|
|
51
51
|
if (parsedStatement) {
|
|
52
52
|
return new ParsedStatement(
|
|
@@ -22,12 +22,12 @@ function ParsedStatement(type, operation, collection, raw) {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
ParsedStatement.prototype.recordMetrics = function recordMetrics(segment, scope) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
const duration = segment.getDurationInMillis()
|
|
26
|
+
const exclusive = segment.getExclusiveDurationInMillis()
|
|
27
|
+
const transaction = segment.transaction
|
|
28
|
+
const type = transaction.isWeb() ? DB.WEB : DB.OTHER
|
|
29
|
+
const thisTypeSlash = this.type + '/'
|
|
30
|
+
const operation = DB.OPERATION + '/' + thisTypeSlash + this.operation
|
|
31
31
|
|
|
32
32
|
// Note, an operation metric should _always_ be created even if the action was
|
|
33
33
|
// a statement. This is part of the spec.
|
|
@@ -43,8 +43,9 @@ ParsedStatement.prototype.recordMetrics = function recordMetrics(segment, scope)
|
|
|
43
43
|
// as the scoped metric for transaction breakdowns. Otherwise, skip the
|
|
44
44
|
// 'statement' metric and use the 'operation' metric as the scoped metric for
|
|
45
45
|
// transaction breakdowns.
|
|
46
|
+
let collection
|
|
46
47
|
if (this.collection) {
|
|
47
|
-
|
|
48
|
+
collection = DB.STATEMENT + '/' + thisTypeSlash + this.collection + '/' + this.operation
|
|
48
49
|
transaction.measure(collection, null, duration, exclusive)
|
|
49
50
|
if (scope) {
|
|
50
51
|
transaction.measure(collection, scope, duration, exclusive)
|
|
@@ -61,7 +62,7 @@ ParsedStatement.prototype.recordMetrics = function recordMetrics(segment, scope)
|
|
|
61
62
|
// Datastore instance metrics.
|
|
62
63
|
const attributes = segment.attributes.get(DESTINATIONS.TRANS_SEGMENT)
|
|
63
64
|
if (attributes.host && attributes.port_path_or_id) {
|
|
64
|
-
|
|
65
|
+
const instanceName =
|
|
65
66
|
DB.INSTANCE + '/' + thisTypeSlash + attributes.host + '/' + attributes.port_path_or_id
|
|
66
67
|
transaction.measure(instanceName, null, duration, exclusive)
|
|
67
68
|
}
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
const logger = require('../../logger').child({ component: 'sql_query_parser' })
|
|
9
|
+
const StatementMatcher = require('../statement-matcher')
|
|
10
|
+
const stringify = require('json-stringify-safe')
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
const OPERATIONS = [
|
|
13
13
|
new StatementMatcher(
|
|
14
14
|
'select',
|
|
15
15
|
/^[^\S]*?select\b[\s\S]+?\bfrom[\s\n\r\[\(]+([^\]\s\n\r,)(;]*)/gim
|
|
@@ -21,7 +21,7 @@ var OPERATIONS = [
|
|
|
21
21
|
),
|
|
22
22
|
new StatementMatcher('delete', /^[^\S]*?delete[^\S]+?from[^\S]+([^\s\n\r,(;]+)/gim)
|
|
23
23
|
]
|
|
24
|
-
|
|
24
|
+
const COMMENT_PATTERN = /\/\\*.*?\\*\//g
|
|
25
25
|
|
|
26
26
|
// This must be called synchronously after the initial db call for backtraces to
|
|
27
27
|
// work correctly
|
|
@@ -50,9 +50,9 @@ module.exports = function parseSql(sql) {
|
|
|
50
50
|
|
|
51
51
|
sql = sql.replace(COMMENT_PATTERN, '').trim()
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
let parsedStatement
|
|
54
54
|
|
|
55
|
-
for (
|
|
55
|
+
for (let i = 0, l = OPERATIONS.length; i < l; i++) {
|
|
56
56
|
parsedStatement = OPERATIONS[i].getParsedStatement(sql)
|
|
57
57
|
if (parsedStatement) {
|
|
58
58
|
break
|
package/lib/db/query-sample.js
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
const codec = require('../util/codec')
|
|
9
|
+
const Stats = require('../stats')
|
|
10
|
+
const util = require('util')
|
|
11
11
|
|
|
12
12
|
function QuerySample(tracer, slowQuery) {
|
|
13
13
|
Stats.call(this)
|
|
@@ -34,11 +34,11 @@ QuerySample.prototype.merge = function merge(sample) {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
QuerySample.prototype.prepareJSON = function prepareJSON(done) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
const transaction = this.trace.segment.transaction
|
|
38
|
+
const sample = this
|
|
39
|
+
const trace = sample.trace
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
const params = sample.getParams()
|
|
42
42
|
|
|
43
43
|
if (!this.tracer.config.simple_compression) {
|
|
44
44
|
codec.encode(params, respond)
|
|
@@ -81,8 +81,8 @@ function _getJSON(sample, trace, transaction, data) {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
QuerySample.prototype.getParams = function getParams() {
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
const segmentAttrs = this.trace.segment.getAttributes()
|
|
85
|
+
const params = {
|
|
86
86
|
backtrace: this.trace.trace
|
|
87
87
|
}
|
|
88
88
|
|
|
@@ -28,7 +28,7 @@ class QueryTraceAggregator extends Aggregator {
|
|
|
28
28
|
|
|
29
29
|
removeShortest() {
|
|
30
30
|
let shortest = null
|
|
31
|
-
for (
|
|
31
|
+
for (const sample of this.samples.values()) {
|
|
32
32
|
const trace = sample.trace
|
|
33
33
|
if (!shortest || shortest.duration > trace.duration) {
|
|
34
34
|
shortest = trace
|
|
@@ -39,8 +39,8 @@ class QueryTraceAggregator extends Aggregator {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
_merge(samples) {
|
|
42
|
-
for (
|
|
43
|
-
|
|
42
|
+
for (const sample of samples.values()) {
|
|
43
|
+
const ownSample = this.samples.get(sample.trace.normalized)
|
|
44
44
|
if (ownSample) {
|
|
45
45
|
ownSample.merge(sample)
|
|
46
46
|
} else {
|
|
@@ -55,7 +55,7 @@ class QueryTraceAggregator extends Aggregator {
|
|
|
55
55
|
// If DT is enabled and the segment is part of a sampled transaction
|
|
56
56
|
// (i.e. we are creating a span event for this segment), then we need
|
|
57
57
|
// to collect the sql trace.
|
|
58
|
-
|
|
58
|
+
let slowQuery
|
|
59
59
|
switch (ttConfig.record_sql) {
|
|
60
60
|
case 'raw':
|
|
61
61
|
slowQuery = new SlowQuery(segment, type, query, trace)
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
8
|
// ( ` database` . ` table ` )
|
|
9
|
-
|
|
9
|
+
const CLEANER = /^\(?(?:([`'"]?)(.*?)\1\.)?([`'"]?)(.*?)\3\)?$/
|
|
10
10
|
|
|
11
11
|
function StatementMatcher(operation, operationPattern) {
|
|
12
12
|
this.operation = operation
|
|
@@ -20,16 +20,16 @@ StatementMatcher.prototype.getParsedStatement = function getParsedStatement(sql)
|
|
|
20
20
|
CLEANER.lastIndex = 0
|
|
21
21
|
|
|
22
22
|
if (this.matcher.test(sql)) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
const queryMatch = this.operationPattern.exec(sql)
|
|
24
|
+
let collection = queryMatch ? queryMatch[1] : 'unknown'
|
|
25
|
+
let database = null
|
|
26
26
|
|
|
27
27
|
// If the cleaner can match this collection, pull out the cleaned up names
|
|
28
28
|
// from there. The spec doesn't want the database names in the collection
|
|
29
29
|
// name, but for legacy reasons we keep it.
|
|
30
30
|
// TODO: Either update the spec (and CATs) to accept database name in the
|
|
31
31
|
// collection name or remove it here.
|
|
32
|
-
|
|
32
|
+
const cleanerMatch = CLEANER.exec(collection)
|
|
33
33
|
if (cleanerMatch && cleanerMatch[4]) {
|
|
34
34
|
collection = cleanerMatch[4]
|
|
35
35
|
if (cleanerMatch[2]) {
|