newrelic 12.8.2 → 12.10.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 +45 -0
- package/THIRD_PARTY_NOTICES.md +47 -243
- package/api.js +14 -13
- package/bin/test-naming-rules.js +2 -3
- package/index.js +0 -4
- package/lib/agent.js +2 -1
- package/lib/aggregators/base-aggregator.js +2 -2
- package/lib/aggregators/trace-aggregator.js +1 -5
- package/lib/attributes.js +5 -5
- package/lib/collector/api.js +1 -3
- package/lib/collector/facts.js +2 -2
- package/lib/collector/http-agents.js +2 -2
- package/lib/collector/remote-method.js +4 -4
- package/lib/config/attribute-filter.js +1 -1
- package/lib/config/default.js +2 -2
- package/lib/config/harvest-config-validator.js +2 -2
- package/lib/config/index.js +12 -12
- package/lib/config/merge-server-config.js +1 -2
- package/lib/custom-events/custom-event-aggregator.js +0 -1
- package/lib/db/query-parsers/sql.js +2 -0
- package/lib/db/slow-query.js +1 -0
- package/lib/db/statement-matcher.js +3 -2
- package/lib/db/utils.js +4 -0
- package/lib/environment.js +2 -2
- package/lib/errors/error-collector.js +2 -2
- package/lib/errors/error-event-aggregator.js +1 -0
- package/lib/errors/helper.js +4 -4
- package/lib/errors/index.js +5 -6
- package/lib/grpc/connection.js +1 -1
- package/lib/header-attributes.js +21 -20
- package/lib/instrumentation/@elastic/elasticsearch.js +2 -2
- package/lib/instrumentation/@opensearch-project/opensearch.js +161 -0
- package/lib/instrumentation/@prisma/client.js +4 -3
- package/lib/instrumentation/amqplib/utils.js +1 -1
- package/lib/instrumentation/aws-sdk/v3/common.js +4 -7
- package/lib/instrumentation/aws-sdk/v3/lambda.js +56 -0
- package/lib/instrumentation/aws-sdk/v3/smithy-client.js +2 -0
- package/lib/instrumentation/bluebird.js +1 -0
- package/lib/instrumentation/connect.js +1 -1
- package/lib/instrumentation/core/http-outbound.js +1 -2
- package/lib/instrumentation/core/http.js +2 -2
- package/lib/instrumentation/core/timers.js +0 -1
- package/lib/instrumentation/express.js +1 -1
- package/lib/instrumentation/kafkajs/consumer.js +1 -1
- package/lib/instrumentation/mysql/mysql.js +2 -2
- package/lib/instrumentation/openai.js +1 -2
- package/lib/instrumentation/undici.js +2 -1
- package/lib/instrumentation/when/contextualizer.js +2 -1
- package/lib/instrumentation/when/index.js +3 -1
- package/lib/instrumentations.js +27 -26
- package/lib/llm-events/aws-bedrock/bedrock-response.js +0 -2
- package/lib/llm-events/aws-bedrock/chat-completion-summary.js +1 -0
- package/lib/llm-events/aws-bedrock/embedding.js +1 -0
- package/lib/llm-events/aws-bedrock/event.js +1 -1
- package/lib/llm-events/aws-bedrock/stream-handler.js +6 -6
- package/lib/llm-events/event.js +1 -0
- package/lib/llm-events/langchain/chat-completion-summary.js +2 -2
- package/lib/llm-events/langchain/event.js +1 -0
- package/lib/llm-events/langchain/vector-search.js +2 -2
- package/lib/logger.js +0 -2
- package/lib/metrics/index.js +0 -1
- package/lib/metrics/mapper.js +2 -2
- package/lib/metrics/names.js +1 -1
- package/lib/metrics/normalizer/rule.js +2 -1
- package/lib/metrics/normalizer/tx_segment.js +4 -2
- package/lib/metrics/normalizer.js +5 -5
- package/lib/prioritized-attributes.js +3 -2
- package/lib/priority-queue.js +1 -1
- package/lib/reservoir.js +1 -1
- package/lib/sampler.js +5 -5
- package/lib/serverless/api-gateway.js +13 -79
- package/lib/serverless/aws-lambda.js +5 -3
- package/lib/shim/conglomerate-shim.js +5 -0
- package/lib/shim/datastore-shim.js +2 -1
- package/lib/shim/message-shim/consume.js +2 -1
- package/lib/shim/message-shim/index.js +1 -1
- package/lib/shim/message-shim/subscribe-consume.js +10 -12
- package/lib/shim/promise-shim.js +8 -8
- package/lib/shim/shim.js +10 -12
- package/lib/shim/webframework-shim/index.js +1 -1
- package/lib/shim/webframework-shim/middleware.js +1 -1
- package/lib/shimmer.js +2 -3
- package/lib/spans/base-span-streamer.js +1 -1
- package/lib/spans/map-to-streaming-type.js +0 -3
- package/lib/spans/span-event-aggregator.js +1 -1
- package/lib/spans/span-streamer.js +0 -4
- package/lib/spans/streaming-span-event-aggregator.js +1 -3
- package/lib/system-info.js +1 -2
- package/lib/timer.js +0 -1
- package/lib/transaction/index.js +9 -6
- package/lib/transaction/name-state.js +6 -5
- package/lib/transaction/trace/exclusive-time-calculator.js +1 -1
- package/lib/transaction/trace/segment.js +0 -1
- package/lib/transaction/tracecontext.js +3 -3
- package/lib/util/cat.js +3 -3
- package/lib/util/copy.js +1 -1
- package/lib/util/deep-equal.js +1 -1
- package/lib/util/hashes.js +2 -0
- package/lib/util/label-parser.js +1 -0
- package/lib/util/logger.js +2 -4
- package/lib/util/sql/obfuscate.js +7 -4
- package/lib/util/urltils.js +3 -3
- package/lib/utilization/aws-info.js +1 -0
- package/lib/utilization/azure-info.js +1 -0
- package/lib/utilization/docker-info.js +4 -4
- package/lib/utilization/index.js +1 -1
- package/package.json +10 -12
- package/stub_api.js +1 -2
package/lib/attributes.js
CHANGED
|
@@ -22,7 +22,7 @@ class Attributes {
|
|
|
22
22
|
* @param {string} scope
|
|
23
23
|
* The scope of the attributes this will collect. Must be `transaction` or
|
|
24
24
|
* `segment`.
|
|
25
|
-
* @param {number} [limit
|
|
25
|
+
* @param {number} [limit]
|
|
26
26
|
* The maximum number of attributes to retrieve for each destination.
|
|
27
27
|
*/
|
|
28
28
|
constructor(scope, limit = Infinity) {
|
|
@@ -64,9 +64,9 @@ class Attributes {
|
|
|
64
64
|
*/
|
|
65
65
|
get(dest) {
|
|
66
66
|
const attrs = Object.create(null)
|
|
67
|
-
// eslint-disable-next-line guard-for-in
|
|
68
67
|
for (const key in this.attributes) {
|
|
69
68
|
const attr = this.attributes[key]
|
|
69
|
+
// eslint-disable-next-line sonarjs/bitwise-operators
|
|
70
70
|
if (!(attr.destinations & dest)) {
|
|
71
71
|
continue
|
|
72
72
|
}
|
|
@@ -104,7 +104,7 @@ class Attributes {
|
|
|
104
104
|
* @param {DESTINATIONS} destinations - The default destinations for this key.
|
|
105
105
|
* @param {string} key - The attribute name.
|
|
106
106
|
* @param {string} value - The attribute value.
|
|
107
|
-
* @param {boolean} [truncateExempt
|
|
107
|
+
* @param {boolean} [truncateExempt] - Flag marking value exempt from truncation
|
|
108
108
|
*/
|
|
109
109
|
addAttribute(destinations, key, value, truncateExempt = false) {
|
|
110
110
|
if (this.attributeCount + 1 > this.limit) {
|
|
@@ -180,6 +180,6 @@ function makeFilter(scope) {
|
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
module.exports = {
|
|
183
|
-
Attributes
|
|
184
|
-
MAXIMUM_CUSTOM_ATTRIBUTES
|
|
183
|
+
Attributes,
|
|
184
|
+
MAXIMUM_CUSTOM_ATTRIBUTES
|
|
185
185
|
}
|
package/lib/collector/api.js
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
const http = require('http')
|
|
9
8
|
const CollectorResponse = require('./response')
|
|
10
9
|
const facts = require('./facts')
|
|
11
10
|
const logger = require('../logger').child({ component: 'collector_api' })
|
|
@@ -341,7 +340,7 @@ CollectorAPI.prototype._handlePreConnectResponse = function _handlePreConnectRes
|
|
|
341
340
|
|
|
342
341
|
const [host, port] = parts
|
|
343
342
|
const newEndpoint = {
|
|
344
|
-
host
|
|
343
|
+
host,
|
|
345
344
|
port: port || DEFAULT_PORT
|
|
346
345
|
}
|
|
347
346
|
|
|
@@ -614,7 +613,6 @@ CollectorAPI.prototype._handleResponseCode = _handleResponseCode
|
|
|
614
613
|
function _handleResponseCode(response, endpoint, cb) {
|
|
615
614
|
const code = response.status
|
|
616
615
|
|
|
617
|
-
/* eslint-disable padded-blocks */
|
|
618
616
|
if (SUCCESS.has(code)) {
|
|
619
617
|
// The request was a success!
|
|
620
618
|
setImmediate(cb, null, CollectorResponse.success(response.payload))
|
package/lib/collector/facts.js
CHANGED
|
@@ -37,7 +37,7 @@ async function facts(agent, callback, { logger = defaultLogger } = {}) {
|
|
|
37
37
|
metadata_version: 5,
|
|
38
38
|
logical_processors: systemInfo.logicalProcessors || null,
|
|
39
39
|
total_ram_mib: systemInfo.memory || null,
|
|
40
|
-
hostname
|
|
40
|
+
hostname
|
|
41
41
|
},
|
|
42
42
|
pid: process.pid,
|
|
43
43
|
host: hostname,
|
|
@@ -45,7 +45,7 @@ async function facts(agent, callback, { logger = defaultLogger } = {}) {
|
|
|
45
45
|
language: 'nodejs',
|
|
46
46
|
app_name: agent.config.applications(),
|
|
47
47
|
agent_version: agent.version,
|
|
48
|
-
environment
|
|
48
|
+
environment,
|
|
49
49
|
settings: agent.config.publicSettings(),
|
|
50
50
|
high_security: agent.config.high_security,
|
|
51
51
|
labels: agent.config.parsedLabels,
|
|
@@ -27,7 +27,7 @@ exports.keepAliveAgent = function keepAliveAgent(config) {
|
|
|
27
27
|
// always return the same agent instance, which
|
|
28
28
|
// ensures all requests share the same http
|
|
29
29
|
// connection
|
|
30
|
-
if (
|
|
30
|
+
if (agentKeepAlive !== null) {
|
|
31
31
|
return agentKeepAlive
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -48,7 +48,7 @@ exports.keepAliveAgent = function keepAliveAgent(config) {
|
|
|
48
48
|
* @param config
|
|
49
49
|
*/
|
|
50
50
|
exports.proxyAgent = function proxyAgent(config) {
|
|
51
|
-
if (
|
|
51
|
+
if (agentProxyWithKeepAlive !== null) {
|
|
52
52
|
return agentProxyWithKeepAlive
|
|
53
53
|
}
|
|
54
54
|
const proxyUrl = proxyOptions(config)
|
|
@@ -92,7 +92,7 @@ RemoteMethod.prototype._reportDataUsage = function reportDataUsage(sent, receive
|
|
|
92
92
|
* you're doing it wrong.
|
|
93
93
|
*
|
|
94
94
|
* @param {object} payload Serializable payload.
|
|
95
|
-
* @param {object} [nrHeaders
|
|
95
|
+
* @param {object} [nrHeaders] NR request headers from connect response.
|
|
96
96
|
* @param {Function} callback What to do next. Gets passed any error.
|
|
97
97
|
*/
|
|
98
98
|
RemoteMethod.prototype.invoke = function invoke(payload, nrHeaders, callback) {
|
|
@@ -359,7 +359,7 @@ RemoteMethod.prototype._path = function _path({ redactLicenseKey } = {}) {
|
|
|
359
359
|
|
|
360
360
|
return url.format({
|
|
361
361
|
pathname: RAW_METHOD_PATH,
|
|
362
|
-
query
|
|
362
|
+
query
|
|
363
363
|
})
|
|
364
364
|
}
|
|
365
365
|
|
|
@@ -374,9 +374,9 @@ RemoteMethod.prototype._headers = function _headers(options) {
|
|
|
374
374
|
|
|
375
375
|
const headers = {
|
|
376
376
|
// select the virtual host on the server end
|
|
377
|
-
|
|
377
|
+
Host: this.endpoint.host,
|
|
378
378
|
'User-Agent': agent,
|
|
379
|
-
|
|
379
|
+
Connection: 'Keep-Alive',
|
|
380
380
|
'Content-Length': byteLength(options.body),
|
|
381
381
|
'Content-Type': 'application/json'
|
|
382
382
|
}
|
|
@@ -347,7 +347,7 @@ function _convertRulesToRegex(rules) {
|
|
|
347
347
|
// 'fizz.bang' => ['fizz', 'bang']
|
|
348
348
|
// '*' => ['\\*']
|
|
349
349
|
return rule
|
|
350
|
-
.replace(/([.*+?|\\^$()
|
|
350
|
+
.replace(/([.*+?|\\^$()[\]])/g, function cleaner(m) {
|
|
351
351
|
return '\\' + m
|
|
352
352
|
})
|
|
353
353
|
.split('.')
|
package/lib/config/default.js
CHANGED
|
@@ -33,7 +33,7 @@ defaultConfig.definition = () => ({
|
|
|
33
33
|
*/
|
|
34
34
|
app_name: {
|
|
35
35
|
formatter(val) {
|
|
36
|
-
return val.split(
|
|
36
|
+
return val.split(/[;,]/).map((k) => k.trim())
|
|
37
37
|
},
|
|
38
38
|
default: []
|
|
39
39
|
},
|
|
@@ -1589,7 +1589,7 @@ function buildConfig(definition, config, paths = [], objectKeys = 1) {
|
|
|
1589
1589
|
if (type === 'string') {
|
|
1590
1590
|
assignConfigValue({ config: conf, key, value, paths })
|
|
1591
1591
|
} else if (type === 'object') {
|
|
1592
|
-
if (
|
|
1592
|
+
if (Object.prototype.hasOwnProperty.call(value, 'default')) {
|
|
1593
1593
|
assignConfigValue({ config: conf, key, value: value.default, paths })
|
|
1594
1594
|
} else {
|
|
1595
1595
|
// add the current leaf node key to the paths and recurse through function again
|
package/lib/config/index.js
CHANGED
|
@@ -45,7 +45,9 @@ let logger = null // Lazy-loaded in `initialize`.
|
|
|
45
45
|
let _configInstance = null
|
|
46
46
|
|
|
47
47
|
const getConfigFileNames = () =>
|
|
48
|
-
[process.env.NEW_RELIC_CONFIG_FILENAME, 'newrelic.js', 'newrelic.cjs'].filter(
|
|
48
|
+
[process.env.NEW_RELIC_CONFIG_FILENAME, 'newrelic.js', 'newrelic.cjs', 'newrelic.mjs'].filter(
|
|
49
|
+
Boolean
|
|
50
|
+
)
|
|
49
51
|
|
|
50
52
|
const getConfigFileLocations = () =>
|
|
51
53
|
[
|
|
@@ -591,7 +593,7 @@ Config.prototype._fromServer = function _fromServer(params, key) {
|
|
|
591
593
|
case 'rum.load_episodes_file':
|
|
592
594
|
// Ensure the most secure setting is applied to the settings below
|
|
593
595
|
// when enabling them.
|
|
594
|
-
case 'attributes.include_enabled':
|
|
596
|
+
case 'attributes.include_enabled': // eslint-disable-line no-fallthrough
|
|
595
597
|
case 'strip_exception_messages.enabled':
|
|
596
598
|
case 'transaction_tracer.record_sql':
|
|
597
599
|
this.logUnsupported(params, key)
|
|
@@ -693,7 +695,7 @@ function _validateThenUpdateStatusCodes(remote, local, remoteKey, localKey) {
|
|
|
693
695
|
|
|
694
696
|
let valid = true
|
|
695
697
|
valueToTest.forEach(function validateArray(thingToTest) {
|
|
696
|
-
if (!('string'
|
|
698
|
+
if (!(typeof thingToTest === 'string' || typeof thingToTest === 'number')) {
|
|
697
699
|
logger.warn(
|
|
698
700
|
'Saw SSC (ignore|expect)_status_code that is not a number or string,' +
|
|
699
701
|
'will not merge: %s',
|
|
@@ -738,7 +740,7 @@ function _validateThenUpdateErrorClasses(remote, local, remoteKey, localKey) {
|
|
|
738
740
|
let valid = true
|
|
739
741
|
Object.keys(valueToTest).forEach(function validateArray(key) {
|
|
740
742
|
const thingToTest = valueToTest[key]
|
|
741
|
-
if ('string'
|
|
743
|
+
if (typeof thingToTest !== 'string') {
|
|
742
744
|
logger.warn(
|
|
743
745
|
'Saw SSC (ignore|expect)_class that is not a string, will not merge: %s',
|
|
744
746
|
thingToTest
|
|
@@ -781,7 +783,7 @@ function _validateThenUpdateErrorMessages(remote, local, remoteKey, localKey) {
|
|
|
781
783
|
return
|
|
782
784
|
}
|
|
783
785
|
|
|
784
|
-
if ('object'
|
|
786
|
+
if (typeof valueToTest !== 'object') {
|
|
785
787
|
logger.warn(
|
|
786
788
|
'Saw SSC (ignore|expect)_message that is primitive/scaler, will not merge: %s',
|
|
787
789
|
valueToTest
|
|
@@ -984,7 +986,7 @@ function getHostnameSafe() {
|
|
|
984
986
|
_hostname = os.hostname()
|
|
985
987
|
}
|
|
986
988
|
return _hostname
|
|
987
|
-
} catch
|
|
989
|
+
} catch {
|
|
988
990
|
const addresses = this.getIPAddresses()
|
|
989
991
|
|
|
990
992
|
if (this.process_host.ipv_preference === '6' && addresses.ipv6) {
|
|
@@ -1052,7 +1054,7 @@ Config.prototype._fromPassed = function _fromPassed(external, internal, arbitrar
|
|
|
1052
1054
|
let node = null
|
|
1053
1055
|
try {
|
|
1054
1056
|
node = external[key]
|
|
1055
|
-
} catch
|
|
1057
|
+
} catch {
|
|
1056
1058
|
logger.warn('Error thrown on access of user config for key: %s', key)
|
|
1057
1059
|
return
|
|
1058
1060
|
}
|
|
@@ -1158,7 +1160,7 @@ Config.prototype._fromEnvironment = function _fromEnvironment(
|
|
|
1158
1160
|
const envVar = deriveEnvVar(key, paths)
|
|
1159
1161
|
setFromEnv({ config, key, envVar, paths })
|
|
1160
1162
|
} else if (type === 'object') {
|
|
1161
|
-
if (
|
|
1163
|
+
if (Object.prototype.hasOwnProperty.call(value, 'env')) {
|
|
1162
1164
|
setFromEnv({
|
|
1163
1165
|
config,
|
|
1164
1166
|
key,
|
|
@@ -1166,7 +1168,7 @@ Config.prototype._fromEnvironment = function _fromEnvironment(
|
|
|
1166
1168
|
paths,
|
|
1167
1169
|
formatter: value.formatter
|
|
1168
1170
|
})
|
|
1169
|
-
} else if (
|
|
1171
|
+
} else if (Object.prototype.hasOwnProperty.call(value, 'default')) {
|
|
1170
1172
|
const envVar = deriveEnvVar(key, paths)
|
|
1171
1173
|
setFromEnv({ config, key, envVar, formatter: value.formatter, paths })
|
|
1172
1174
|
} else {
|
|
@@ -1657,7 +1659,7 @@ Config.prototype.publicSettings = function publicSettings() {
|
|
|
1657
1659
|
let settings = Object.create(null)
|
|
1658
1660
|
|
|
1659
1661
|
for (const key in this) {
|
|
1660
|
-
if (
|
|
1662
|
+
if (Object.prototype.hasOwnProperty.call(this, key) && !REMOVE_BEFORE_SEND.has(key)) {
|
|
1661
1663
|
if (HSM.REDACT_BEFORE_SEND.has(key)) {
|
|
1662
1664
|
const value = this[key]
|
|
1663
1665
|
settings[key] = redactValue(value)
|
|
@@ -1823,10 +1825,8 @@ function getOrCreateInstance() {
|
|
|
1823
1825
|
try {
|
|
1824
1826
|
_configInstance = initialize()
|
|
1825
1827
|
} catch (err) {
|
|
1826
|
-
/* eslint-disable no-console */
|
|
1827
1828
|
console.error('New Relic for Node.js is disabled due to an error:')
|
|
1828
1829
|
console.error(err.stack)
|
|
1829
|
-
/* eslint-enable no-console */
|
|
1830
1830
|
|
|
1831
1831
|
// Config construction has potential to throw due to invalid settings.
|
|
1832
1832
|
// This allows the agent to return a stub api without crashing the process.
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
const { isSimpleObject } = require('../util/objects')
|
|
9
9
|
|
|
10
10
|
class MergeServerConfig {
|
|
11
|
-
// eslint-disable-next-line max-params
|
|
12
11
|
updateNestedIfChanged(config, remote, local, remoteKey, localKey, logger) {
|
|
13
12
|
const value = remote[remoteKey]
|
|
14
13
|
|
|
@@ -46,7 +45,7 @@ class MergeServerConfig {
|
|
|
46
45
|
if (Array.isArray(local[localKey][element]) && Array.isArray(value[element])) {
|
|
47
46
|
// if both key-values are arrays, push the remote value onto the local array
|
|
48
47
|
value[element].forEach((elementValue) => {
|
|
49
|
-
if (
|
|
48
|
+
if (local[localKey][element].indexOf(elementValue) === -1) {
|
|
50
49
|
local[localKey][element].push(elementValue)
|
|
51
50
|
}
|
|
52
51
|
})
|
|
@@ -9,6 +9,7 @@ const logger = require('../../logger').child({ component: 'sql_query_parser' })
|
|
|
9
9
|
const StatementMatcher = require('../statement-matcher')
|
|
10
10
|
const stringify = require('json-stringify-safe')
|
|
11
11
|
|
|
12
|
+
/* eslint-disable no-useless-escape, sonarjs/slow-regex, sonarjs/duplicates-in-character-class */
|
|
12
13
|
const OPERATIONS = [
|
|
13
14
|
new StatementMatcher(
|
|
14
15
|
'select',
|
|
@@ -22,6 +23,7 @@ const OPERATIONS = [
|
|
|
22
23
|
new StatementMatcher('delete', /^[^\S]*?delete[^\S]+?from[^\S]+([^\s\n\r,(;]+)/gim)
|
|
23
24
|
]
|
|
24
25
|
const COMMENT_PATTERN = /\/\\*.*?\\*\//g
|
|
26
|
+
/* eslint-enable no-useless-escape, sonarjs/slow-regex, sonarjs/duplicates-in-character-class */
|
|
25
27
|
|
|
26
28
|
// This must be called synchronously after the initial db call for backtraces to
|
|
27
29
|
// work correctly
|
package/lib/db/slow-query.js
CHANGED
|
@@ -23,6 +23,7 @@ function SlowQuery(segment, type, query, trace) {
|
|
|
23
23
|
|
|
24
24
|
function normalizedHash(value) {
|
|
25
25
|
// We leverage the last 15 hex digits which will fit in a signed long
|
|
26
|
+
// eslint-disable-next-line sonarjs/hashing
|
|
26
27
|
return parseInt(crypto.createHash('sha1').update(value).digest('hex').slice(-15), 16)
|
|
27
28
|
}
|
|
28
29
|
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
8
|
// ( ` database` . ` table ` )
|
|
9
|
+
// eslint-disable-next-line sonarjs/slow-regex
|
|
9
10
|
const CLEANER = /^\(?(?:([`'"]?)(.*?)\1\.)?([`'"]?)(.*?)\3\)?$/
|
|
10
11
|
|
|
11
12
|
function StatementMatcher(operation, operationPattern) {
|
|
@@ -42,8 +43,8 @@ StatementMatcher.prototype.getParsedStatement = function getParsedStatement(sql)
|
|
|
42
43
|
// be used for datastore attributes.
|
|
43
44
|
return {
|
|
44
45
|
operation: this.operation,
|
|
45
|
-
database
|
|
46
|
-
collection
|
|
46
|
+
database,
|
|
47
|
+
collection,
|
|
47
48
|
query: sql
|
|
48
49
|
}
|
|
49
50
|
}
|
package/lib/db/utils.js
CHANGED
|
@@ -10,6 +10,10 @@ module.exports.extractDatabaseChangeFromUse = extractDatabaseChangeFromUse
|
|
|
10
10
|
function extractDatabaseChangeFromUse(sql) {
|
|
11
11
|
// The character ranges for this were pulled from
|
|
12
12
|
// http://dev.mysql.com/doc/refman/5.7/en/identifiers.html
|
|
13
|
+
|
|
14
|
+
// Suppressing a warning on this regex because it is not obvious what this
|
|
15
|
+
// regex does, and we don't want to break anything.
|
|
16
|
+
// eslint-disable-next-line sonarjs/slow-regex, sonarjs/duplicates-in-character-class
|
|
13
17
|
const match = /^\s*use[^\w`]+([\w$_\u0080-\uFFFF]+|`[^`]+`)[\s;]*$/i.exec(sql)
|
|
14
18
|
return (match && match[1]) || null
|
|
15
19
|
}
|
package/lib/environment.js
CHANGED
|
@@ -67,7 +67,7 @@ function clearSetting(name) {
|
|
|
67
67
|
* the provided root.
|
|
68
68
|
*
|
|
69
69
|
* @param {string} root - Path to start listing packages from.
|
|
70
|
-
* @param {Array} [packages
|
|
70
|
+
* @param {Array} [packages] - Array to append found packages to.
|
|
71
71
|
*/
|
|
72
72
|
async function listPackages(root, packages = []) {
|
|
73
73
|
_log('Listing packages in %s', root)
|
|
@@ -496,7 +496,7 @@ async function getJSON() {
|
|
|
496
496
|
_log('Getting environment JSON')
|
|
497
497
|
try {
|
|
498
498
|
await refresh()
|
|
499
|
-
} catch
|
|
499
|
+
} catch {
|
|
500
500
|
// swallow error
|
|
501
501
|
}
|
|
502
502
|
|
|
@@ -10,7 +10,6 @@ const errorsModule = require('./index')
|
|
|
10
10
|
const logger = require('../logger').child({ component: 'error_tracer' })
|
|
11
11
|
const urltils = require('../util/urltils')
|
|
12
12
|
const Exception = require('../errors').Exception
|
|
13
|
-
const Transaction = require('../transaction')
|
|
14
13
|
const errorHelper = require('./helper')
|
|
15
14
|
const createError = errorsModule.createError
|
|
16
15
|
const createEvent = errorsModule.createEvent
|
|
@@ -312,6 +311,7 @@ class ErrorCollector {
|
|
|
312
311
|
}
|
|
313
312
|
|
|
314
313
|
if (this.config.error_collector.capture_events === true) {
|
|
314
|
+
// eslint-disable-next-line sonarjs/pseudo-random
|
|
315
315
|
const priority = (transaction && transaction.priority) || Math.random()
|
|
316
316
|
const event = createEvent(transaction, errorTrace, exception.timestamp, this.config)
|
|
317
317
|
this.eventAggregator.add(event, priority)
|
|
@@ -360,7 +360,7 @@ class ErrorCollector {
|
|
|
360
360
|
* @param {Transaction} transaction the transaction associated with the trace
|
|
361
361
|
*/
|
|
362
362
|
_maybeRecordErrorMetrics(errorTrace, transaction) {
|
|
363
|
-
const isExpectedError =
|
|
363
|
+
const isExpectedError = errorTrace[4].intrinsics['error.expected'] === true
|
|
364
364
|
|
|
365
365
|
if (isExpectedError) {
|
|
366
366
|
this.metrics.getOrCreateMetric(NAMES.ERRORS.EXPECTED).incrementCallCount()
|
package/lib/errors/helper.js
CHANGED
|
@@ -90,9 +90,9 @@ module.exports = {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
return {
|
|
93
|
-
name
|
|
94
|
-
message
|
|
95
|
-
type
|
|
93
|
+
name,
|
|
94
|
+
message,
|
|
95
|
+
type
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
|
|
@@ -119,7 +119,7 @@ module.exports = {
|
|
|
119
119
|
return false
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
return
|
|
122
|
+
return config.error_collector.ignore_classes.indexOf(errorInfo.type) !== -1
|
|
123
123
|
},
|
|
124
124
|
|
|
125
125
|
shouldIgnoreErrorMessage: function shouldIgnoreErrorMessage(errorInfo, config) {
|
package/lib/errors/index.js
CHANGED
|
@@ -16,7 +16,6 @@ const {
|
|
|
16
16
|
maybeAddDatabaseAttributes
|
|
17
17
|
} = require('../util/attributes')
|
|
18
18
|
const synthetics = require('../synthetics')
|
|
19
|
-
const Transaction = require('../transaction')
|
|
20
19
|
const ERROR_EXPECTED_PATH = 'error.expected'
|
|
21
20
|
|
|
22
21
|
class Exception {
|
|
@@ -121,8 +120,8 @@ function isValidErrorGroupOutput(output) {
|
|
|
121
120
|
function maybeAddAgentAttributes(attributes, exception) {
|
|
122
121
|
if (exception.errorGroupCallback) {
|
|
123
122
|
const callbackInput = {
|
|
124
|
-
|
|
125
|
-
|
|
123
|
+
error: exception.error,
|
|
124
|
+
customAttributes: Object.assign({}, attributes.userAttributes),
|
|
126
125
|
'request.uri': attributes.agentAttributes['request.uri'],
|
|
127
126
|
'http.statusCode': attributes.agentAttributes['http.statusCode'],
|
|
128
127
|
'http.method': attributes.agentAttributes['request.method'],
|
|
@@ -153,6 +152,7 @@ function maybeAddUserAttributes(userAttributes, exception, config) {
|
|
|
153
152
|
for (const key in customAttributes) {
|
|
154
153
|
if (props.hasOwn(customAttributes, key)) {
|
|
155
154
|
const dest = config.attributeFilter.filterTransaction(DESTINATIONS.ERROR_EVENT, key)
|
|
155
|
+
// eslint-disable-next-line sonarjs/bitwise-operators
|
|
156
156
|
if (dest & DESTINATIONS.ERROR_EVENT) {
|
|
157
157
|
userAttributes[key] = customAttributes[key]
|
|
158
158
|
}
|
|
@@ -208,7 +208,6 @@ function createEvent(transaction, error, timestamp, config) {
|
|
|
208
208
|
return [intrinsicAttributes, userAttributes, agentAttributes]
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
// eslint-disable-next-line max-params
|
|
212
211
|
function _getErrorEventIntrinsicAttrs(transaction, errorClass, message, expected, timestamp, conf) {
|
|
213
212
|
// the server expects seconds instead of milliseconds
|
|
214
213
|
if (timestamp) {
|
|
@@ -216,10 +215,10 @@ function _getErrorEventIntrinsicAttrs(transaction, errorClass, message, expected
|
|
|
216
215
|
}
|
|
217
216
|
|
|
218
217
|
const attributes = {
|
|
219
|
-
|
|
218
|
+
type: 'TransactionError',
|
|
220
219
|
'error.class': errorClass,
|
|
221
220
|
'error.message': conf.high_security ? '' : message,
|
|
222
|
-
|
|
221
|
+
timestamp,
|
|
223
222
|
'error.expected': expected
|
|
224
223
|
}
|
|
225
224
|
|
package/lib/grpc/connection.js
CHANGED
|
@@ -43,7 +43,7 @@ class GrpcConnection extends EventEmitter {
|
|
|
43
43
|
*
|
|
44
44
|
* @param {object} infiniteTracingConfig config item config.infinite_tracing
|
|
45
45
|
* @param {MetricAggregator} metrics metric aggregator, for supportability metrics
|
|
46
|
-
* @param {number} [reconnectDelayMs
|
|
46
|
+
* @param {number} [reconnectDelayMs] number of milliseconds to wait before reconnecting
|
|
47
47
|
* for error states that require a reconnect delay.
|
|
48
48
|
*/
|
|
49
49
|
constructor(infiniteTracingConfig, metrics, reconnectDelayMs = DEFAULT_RECONNECT_DELAY_MS) {
|
package/lib/header-attributes.js
CHANGED
|
@@ -17,42 +17,42 @@ const COLLECTED_REQUEST_HEADERS = [
|
|
|
17
17
|
]
|
|
18
18
|
|
|
19
19
|
const HEADER_ATTR_NAMES = {
|
|
20
|
-
|
|
20
|
+
accept: 'accept',
|
|
21
21
|
'accept-charset': 'acceptCharset',
|
|
22
22
|
'accept-encoding': 'acceptEncoding',
|
|
23
23
|
'access-control-allow-headers': 'accessControlAllowHeaders',
|
|
24
24
|
'access-control-allow-methods': 'accessControlAllowMethods',
|
|
25
25
|
'access-control-allow-origin': 'accessControlAllowOrigin',
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
age: 'age',
|
|
27
|
+
allow: 'allow',
|
|
28
|
+
authorization: 'authorization',
|
|
29
29
|
'cache-control': 'cacheControl',
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
connection: 'connection',
|
|
31
|
+
cookie: 'cookie',
|
|
32
32
|
'content-encoding': 'contentEncoding',
|
|
33
33
|
'content-length': 'contentLength',
|
|
34
34
|
'content-type': 'contentType',
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
date: 'date',
|
|
36
|
+
etag: 'eTag',
|
|
37
|
+
expect: 'expect',
|
|
38
|
+
expires: 'expires',
|
|
39
|
+
forwarded: 'forwarded',
|
|
40
|
+
host: 'host',
|
|
41
41
|
'if-match': 'ifMatch',
|
|
42
42
|
'if-modified-since': 'ifModifiedSince',
|
|
43
43
|
'last-modified': 'lastModified',
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
location: 'location',
|
|
45
|
+
newrelic: 'newrelic',
|
|
46
|
+
origin: 'origin',
|
|
47
47
|
'proxy-authorization': 'proxyAuthorization',
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
referer: 'referer',
|
|
49
|
+
refresh: 'refresh',
|
|
50
|
+
server: 'server',
|
|
51
51
|
'set-cookie': 'setCookie',
|
|
52
52
|
'transfer-encoding': 'transferEncoding',
|
|
53
53
|
'user-agent': 'userAgent',
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
upgrade: 'upgrade',
|
|
55
|
+
vary: 'vary',
|
|
56
56
|
'x-correlation-id': 'xCorrelationId',
|
|
57
57
|
'x-csrf-token': 'xCsrfToken',
|
|
58
58
|
'x-forwarded-for': 'xForwardedFor',
|
|
@@ -95,6 +95,7 @@ function _headerToCamelCase(header) {
|
|
|
95
95
|
const newHeader = header.charAt(0).toLowerCase() + header.slice(1)
|
|
96
96
|
|
|
97
97
|
// Converts headers in the form 'header-name' to be in the form 'headerName'
|
|
98
|
+
// eslint-disable-next-line sonarjs/slow-regex
|
|
98
99
|
return newHeader.replace(/[\W_]+(\w)/g, function capitalize(m, $1) {
|
|
99
100
|
return $1.toUpperCase()
|
|
100
101
|
})
|
|
@@ -108,7 +108,7 @@ function parsePath(pathString, method) {
|
|
|
108
108
|
const path = pathString.split('/')
|
|
109
109
|
if (method === 'PUT' && path.length === 2) {
|
|
110
110
|
collection = path?.[1] || defaultCollection
|
|
111
|
-
operation =
|
|
111
|
+
operation = 'index.create'
|
|
112
112
|
return { collection, operation }
|
|
113
113
|
}
|
|
114
114
|
path.forEach((segment, idx) => {
|
|
@@ -116,7 +116,7 @@ function parsePath(pathString, method) {
|
|
|
116
116
|
let opname
|
|
117
117
|
if (segment === '_search') {
|
|
118
118
|
collection = path?.[prev] || defaultCollection
|
|
119
|
-
operation =
|
|
119
|
+
operation = 'search'
|
|
120
120
|
} else if (segment[0] === '_') {
|
|
121
121
|
opname = segment.substring(1)
|
|
122
122
|
collection = path?.[prev] || defaultCollection
|