newrelic 6.4.0 → 6.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/.eslintignore +1 -1
- package/{.eslintrc → .eslintrc.js} +2 -1
- package/.travis.yml +5 -6
- package/NEWS.md +105 -1
- package/THIRD_PARTY_NOTICES.md +420 -0
- package/api.js +72 -1
- package/index.js +3 -3
- package/lib/agent.js +22 -8
- package/lib/aggregators/base-aggregator.js +1 -1
- package/lib/attributes.js +15 -6
- package/lib/collector/serverless.js +8 -0
- package/lib/config/default.js +23 -1
- package/lib/config/env.js +7 -1
- package/lib/config/hsm.js +6 -1
- package/lib/config/index.js +36 -8
- package/lib/config/lasp.js +16 -1
- package/lib/errors/error-collector.js +51 -90
- package/lib/errors/helper.js +13 -13
- package/lib/errors/index.js +36 -18
- package/lib/grpc/connection/states.js +9 -0
- package/lib/grpc/connection.js +344 -0
- package/lib/grpc/endpoints/infinite-tracing/v1.proto +29 -0
- package/lib/header-processing.js +75 -0
- package/lib/instrumentation/core/child_process.js +12 -0
- package/lib/instrumentation/core/http-outbound.js +4 -0
- package/lib/instrumentation/core/http.js +98 -145
- package/lib/instrumentation/hapi/hapi-17.js +10 -3
- package/lib/metrics/names.js +12 -1
- package/lib/proxy/grpc.js +15 -0
- package/lib/serverless/aws-lambda.js +2 -0
- package/lib/spans/create-span-event-aggregator.js +112 -0
- package/lib/spans/map-to-streaming-type.js +44 -0
- package/lib/spans/span-event-aggregator.js +5 -0
- package/lib/spans/span-event.js +22 -9
- package/lib/spans/span-streamer.js +109 -0
- package/lib/spans/streaming-span-attributes.js +59 -0
- package/lib/spans/streaming-span-event-aggregator.js +98 -0
- package/lib/spans/streaming-span-event.js +261 -0
- package/lib/transaction/index.js +36 -20
- package/lib/transaction/trace/index.js +13 -10
- package/lib/transaction/trace/segment.js +12 -1
- package/lib/transaction/tracecontext.js +4 -0
- package/package.json +10 -10
- package/stub_api.js +5 -0
package/index.js
CHANGED
|
@@ -43,10 +43,10 @@ function initialize() {
|
|
|
43
43
|
preAgentTime
|
|
44
44
|
)
|
|
45
45
|
|
|
46
|
-
// TODO: Update this check when Node
|
|
47
|
-
if (psemver.satisfies('<
|
|
46
|
+
// TODO: Update this check when Node v8 is deprecated.
|
|
47
|
+
if (psemver.satisfies('<8.0.0')) {
|
|
48
48
|
message = 'New Relic for Node.js requires a version of Node equal to or\n' +
|
|
49
|
-
'greater than
|
|
49
|
+
'greater than 8.0.0. Not starting!'
|
|
50
50
|
|
|
51
51
|
logger.error(message)
|
|
52
52
|
throw new Error(message)
|
package/lib/agent.js
CHANGED
|
@@ -18,12 +18,12 @@ const NAMES = require('./metrics/names')
|
|
|
18
18
|
const QueryTraceAggregator = require('./db/query-trace-aggregator')
|
|
19
19
|
const sampler = require('./sampler')
|
|
20
20
|
const TransactionTraceAggregator = require('./transaction/trace/aggregator')
|
|
21
|
-
const SpanEventAggregator = require('./spans/span-event-aggregator')
|
|
22
21
|
const TransactionEventAggregator = require('./transaction/transaction-event-aggregator')
|
|
23
22
|
const Tracer = require('./transaction/tracer')
|
|
24
23
|
const TxSegmentNormalizer = require('./metrics/normalizer/tx_segment')
|
|
25
24
|
const uninstrumented = require('./uninstrumented')
|
|
26
25
|
const util = require('util')
|
|
26
|
+
const createSpanEventAggregator = require('./spans/create-span-event-aggregator')
|
|
27
27
|
|
|
28
28
|
// Map of valid states to whether or not data collection is valid
|
|
29
29
|
const STATES = {
|
|
@@ -84,13 +84,7 @@ function Agent(config) {
|
|
|
84
84
|
this._beforeMetricDataSend.bind(this)
|
|
85
85
|
)
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
this.spanEventAggregator = new SpanEventAggregator({
|
|
89
|
-
periodMs: config.event_harvest_config.report_period_ms,
|
|
90
|
-
limit: config.event_harvest_config.harvest_limits.span_event_data
|
|
91
|
-
},
|
|
92
|
-
this.collector,
|
|
93
|
-
this.metrics)
|
|
87
|
+
this.spanEventAggregator = createSpanEventAggregator(config, this.collector, this.metrics)
|
|
94
88
|
|
|
95
89
|
this.transactionNameNormalizer = new MetricNormalizer(this.config, 'transaction name')
|
|
96
90
|
// Segment term based tx renaming for MGI mitigation.
|
|
@@ -249,6 +243,10 @@ Agent.prototype.start = function start(callback) {
|
|
|
249
243
|
agent.startAggregators()
|
|
250
244
|
callback(null, config)
|
|
251
245
|
} else {
|
|
246
|
+
// For data collection that streams immediately, dont delay capture/sending until
|
|
247
|
+
// the harvest of everything else has completed.
|
|
248
|
+
agent.startStreaming()
|
|
249
|
+
|
|
252
250
|
// Harvest immediately for quicker data display, but after at least 1
|
|
253
251
|
// second or the collector will throw away the data.
|
|
254
252
|
//
|
|
@@ -409,6 +407,16 @@ Agent.prototype.stopAggregators = function stopAggregators() {
|
|
|
409
407
|
this.customEventAggregator.stop()
|
|
410
408
|
}
|
|
411
409
|
|
|
410
|
+
Agent.prototype.startStreaming = function startStreaming() {
|
|
411
|
+
if (
|
|
412
|
+
this.spanEventAggregator.isStream &&
|
|
413
|
+
this.config.distributed_tracing.enabled &&
|
|
414
|
+
this.config.span_events.enabled
|
|
415
|
+
) {
|
|
416
|
+
this.spanEventAggregator.start()
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
412
420
|
Agent.prototype.startAggregators = function startAggregators() {
|
|
413
421
|
this.metrics.start()
|
|
414
422
|
this.errors.start()
|
|
@@ -798,6 +806,12 @@ Agent.prototype.setLambdaArn = function setLambdaArn(arn) {
|
|
|
798
806
|
}
|
|
799
807
|
}
|
|
800
808
|
|
|
809
|
+
Agent.prototype.setLambdaFunctionVersion = function setLambdaFunctionVersion(function_version) {
|
|
810
|
+
if (this.collector instanceof ServerlessCollector) {
|
|
811
|
+
this.collector.setLambdaFunctionVersion(function_version)
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
801
815
|
/**
|
|
802
816
|
* Get the current transaction (if there is one) from the tracer.
|
|
803
817
|
*
|
|
@@ -88,7 +88,7 @@ class Aggregator extends EventEmitter {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
send() {
|
|
91
|
-
logger.
|
|
91
|
+
logger.debug(`${this.method} Aggregator data send.`)
|
|
92
92
|
this.emit(`starting ${this.method} data send.`)
|
|
93
93
|
|
|
94
94
|
const data = this._getMergeData()
|
package/lib/attributes.js
CHANGED
|
@@ -6,6 +6,8 @@ const isValidType = require('./util/attribute-types')
|
|
|
6
6
|
const byteUtils = require('./util/byte-limit')
|
|
7
7
|
const properties = require('./util/properties')
|
|
8
8
|
|
|
9
|
+
const MAXIMUM_CUSTOM_ATTRIBUTES = 64
|
|
10
|
+
|
|
9
11
|
/**
|
|
10
12
|
* @class
|
|
11
13
|
* @private
|
|
@@ -23,6 +25,7 @@ class Attributes {
|
|
|
23
25
|
this.filter = makeFilter(scope)
|
|
24
26
|
this.limit = limit
|
|
25
27
|
this.attributes = Object.create(null)
|
|
28
|
+
this.attributeCount = 0
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
/**
|
|
@@ -57,7 +60,6 @@ class Attributes {
|
|
|
57
60
|
*/
|
|
58
61
|
get(dest) {
|
|
59
62
|
const attrs = Object.create(null)
|
|
60
|
-
let attrCount = 0
|
|
61
63
|
for (let key in this.attributes) { // eslint-disable-line guard-for-in
|
|
62
64
|
const attr = this.attributes[key]
|
|
63
65
|
if (!(attr.destinations & dest)) {
|
|
@@ -67,10 +69,6 @@ class Attributes {
|
|
|
67
69
|
attrs[key] = typeof attr.value === 'string' && !attr.truncateExempt
|
|
68
70
|
? byteUtils.truncate(attr.value, 255)
|
|
69
71
|
: attr.value
|
|
70
|
-
|
|
71
|
-
if (++attrCount >= this.limit) {
|
|
72
|
-
break
|
|
73
|
-
}
|
|
74
72
|
}
|
|
75
73
|
|
|
76
74
|
return attrs
|
|
@@ -103,6 +101,13 @@ class Attributes {
|
|
|
103
101
|
* @param {boolean} [truncateExempt=false] - Flag marking value exempt from truncation
|
|
104
102
|
*/
|
|
105
103
|
addAttribute(destinations, key, value, truncateExempt = false) {
|
|
104
|
+
if (this.attributeCount + 1 > this.limit) {
|
|
105
|
+
return logger.debug(
|
|
106
|
+
`Maximum number of custom attributes have been added.
|
|
107
|
+
Dropping attribute ${key} with ${value} type.`
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
|
|
106
111
|
if (!isValidType(value)) {
|
|
107
112
|
return logger.debug(
|
|
108
113
|
'Not adding attribute %s with %s value type. This is expected for undefined' +
|
|
@@ -123,6 +128,7 @@ class Attributes {
|
|
|
123
128
|
// Only set the attribute if at least one destination passed
|
|
124
129
|
const validDestinations = this.filter(destinations, key)
|
|
125
130
|
if (validDestinations) {
|
|
131
|
+
this.attributeCount = this.attributeCount + 1
|
|
126
132
|
this._set(validDestinations, key, value, truncateExempt)
|
|
127
133
|
}
|
|
128
134
|
}
|
|
@@ -159,4 +165,7 @@ function makeFilter(scope) {
|
|
|
159
165
|
}
|
|
160
166
|
}
|
|
161
167
|
|
|
162
|
-
module.exports =
|
|
168
|
+
module.exports = {
|
|
169
|
+
Attributes: Attributes,
|
|
170
|
+
MAXIMUM_CUSTOM_ATTRIBUTES: MAXIMUM_CUSTOM_ATTRIBUTES
|
|
171
|
+
}
|
|
@@ -24,6 +24,7 @@ class ServerlessCollector {
|
|
|
24
24
|
this.enabled = true
|
|
25
25
|
this.metadata = {
|
|
26
26
|
arn: null,
|
|
27
|
+
function_version: null,
|
|
27
28
|
execution_environment: process.env.AWS_EXECUTION_ENV,
|
|
28
29
|
protocol_version: 16,
|
|
29
30
|
agent_version: agent.version
|
|
@@ -38,6 +39,13 @@ class ServerlessCollector {
|
|
|
38
39
|
this.metadata.arn = arn
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Sets the function_version to be sent up in the metadata.
|
|
44
|
+
*/
|
|
45
|
+
setLambdaFunctionVersion(function_version) {
|
|
46
|
+
this.metadata.function_version = function_version
|
|
47
|
+
}
|
|
48
|
+
|
|
41
49
|
/**
|
|
42
50
|
* Checks if the collector is currently collecting.
|
|
43
51
|
*
|
package/lib/config/default.js
CHANGED
|
@@ -456,6 +456,8 @@ exports.config = () => ({
|
|
|
456
456
|
* or 'obfuscated' and other criteria (slow_sql.enabled etc) are met
|
|
457
457
|
* for a query. The raw or obfuscated sql will be included in the
|
|
458
458
|
* transaction trace and a slow query sample will be collected.
|
|
459
|
+
*
|
|
460
|
+
* @env NEW_RELIC_RECORD_SQL
|
|
459
461
|
*/
|
|
460
462
|
record_sql: 'off',
|
|
461
463
|
|
|
@@ -882,6 +884,26 @@ exports.config = () => ({
|
|
|
882
884
|
segment_parameters: {enabled: true}
|
|
883
885
|
},
|
|
884
886
|
|
|
887
|
+
/**
|
|
888
|
+
* Controls the use of infinite tracing.
|
|
889
|
+
*/
|
|
890
|
+
infinite_tracing: {
|
|
891
|
+
trace_observer: {
|
|
892
|
+
/**
|
|
893
|
+
* The URI HOST of the observer. Setting this enables infinite tracing.
|
|
894
|
+
*
|
|
895
|
+
* @env NEW_RELIC_INFINITE_TRACING_TRACE_OBSERVER_HOST
|
|
896
|
+
*/
|
|
897
|
+
host: '',
|
|
898
|
+
/**
|
|
899
|
+
* The URI PORT of the observer.
|
|
900
|
+
*
|
|
901
|
+
* @env NEW_RELIC_INFINITE_TRACING_TRACE_OBSERVER_PORT
|
|
902
|
+
*/
|
|
903
|
+
port: '443'
|
|
904
|
+
}
|
|
905
|
+
},
|
|
906
|
+
|
|
885
907
|
/**
|
|
886
908
|
* Specifies whether the agent will be used to monitor serverless functions.
|
|
887
909
|
* For example: AWS Lambda
|
|
@@ -898,5 +920,5 @@ exports.config = () => ({
|
|
|
898
920
|
* loop data.
|
|
899
921
|
*/
|
|
900
922
|
native_metrics: {enabled: true}
|
|
901
|
-
}
|
|
923
|
+
}
|
|
902
924
|
})
|
package/lib/config/env.js
CHANGED
|
@@ -152,7 +152,13 @@ const ENV_MAPPING = {
|
|
|
152
152
|
},
|
|
153
153
|
trusted_account_key: 'NEW_RELIC_TRUSTED_ACCOUNT_KEY',
|
|
154
154
|
primary_application_id: 'NEW_RELIC_PRIMARY_APPLICATION_ID',
|
|
155
|
-
account_id: 'NEW_RELIC_ACCOUNT_ID'
|
|
155
|
+
account_id: 'NEW_RELIC_ACCOUNT_ID',
|
|
156
|
+
infinite_tracing: {
|
|
157
|
+
trace_observer: {
|
|
158
|
+
host: 'NEW_RELIC_INFINITE_TRACING_TRACE_OBSERVER_HOST',
|
|
159
|
+
port: 'NEW_RELIC_INFINITE_TRACING_TRACE_OBSERVER_PORT'
|
|
160
|
+
}
|
|
161
|
+
}
|
|
156
162
|
}
|
|
157
163
|
|
|
158
164
|
// List of environment values which are comma-delimited lists.
|
package/lib/config/hsm.js
CHANGED
|
@@ -51,7 +51,12 @@ const HIGH_SECURITY_SETTINGS = {
|
|
|
51
51
|
const HIGH_SECURITY_KEYS = flatten.keys(HIGH_SECURITY_SETTINGS)
|
|
52
52
|
|
|
53
53
|
// blank out these config values before sending to the collector
|
|
54
|
-
const REDACT_BEFORE_SEND = new Set([
|
|
54
|
+
const REDACT_BEFORE_SEND = new Set([
|
|
55
|
+
'proxy_pass',
|
|
56
|
+
'proxy_user',
|
|
57
|
+
'proxy',
|
|
58
|
+
'certificates' // should be public but in case user mistake and also these are huge
|
|
59
|
+
])
|
|
55
60
|
|
|
56
61
|
// process.domain needs to be stripped befeore sending
|
|
57
62
|
const REMOVE_BEFORE_SEND = new Set(['domain'])
|
package/lib/config/index.js
CHANGED
|
@@ -1152,15 +1152,15 @@ Config.prototype._loggingManuallySet = function _loggingManuallySet(inputConfig)
|
|
|
1152
1152
|
/**
|
|
1153
1153
|
* Returns true if native-metrics has been manually enabled via configuration
|
|
1154
1154
|
* file or enveironment variable
|
|
1155
|
-
*
|
|
1155
|
+
*
|
|
1156
1156
|
* @param {*} inputConfig configuration pass to the Config constructor
|
|
1157
|
-
*
|
|
1157
|
+
*
|
|
1158
1158
|
* @returns {boolean}
|
|
1159
1159
|
*/
|
|
1160
|
-
Config.prototype._nativeMetricsManuallySet =
|
|
1160
|
+
Config.prototype._nativeMetricsManuallySet =
|
|
1161
1161
|
function _nativeMetricsManuallySet(inputConfig) {
|
|
1162
|
-
const inputEnabled = inputConfig
|
|
1163
|
-
&& inputConfig.plugins
|
|
1162
|
+
const inputEnabled = inputConfig
|
|
1163
|
+
&& inputConfig.plugins
|
|
1164
1164
|
&& inputConfig.plugins.native_metrics
|
|
1165
1165
|
&& inputConfig.plugins.native_metrics.enabled
|
|
1166
1166
|
const envEnabled = process.env.NEW_RELIC_NATIVE_METRICS_ENABLED
|
|
@@ -1201,6 +1201,12 @@ Config.prototype._enforceServerless = function _enforceServerless(inputConfig) {
|
|
|
1201
1201
|
logger.info('Cross application tracing is explicitly disabled in serverless_mode.')
|
|
1202
1202
|
}
|
|
1203
1203
|
|
|
1204
|
+
if (this.infinite_tracing.trace_observer.host) {
|
|
1205
|
+
this.infinite_tracing.trace_observer.host = ''
|
|
1206
|
+
this.infinite_tracing.trace_observer.port = ''
|
|
1207
|
+
logger.info('Infinite tracing is explicitly disabled in serverless_mode.')
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1204
1210
|
if (!this._loggingManuallySet(inputConfig)) {
|
|
1205
1211
|
this.logging.enabled = false
|
|
1206
1212
|
|
|
@@ -1211,7 +1217,7 @@ Config.prototype._enforceServerless = function _enforceServerless(inputConfig) {
|
|
|
1211
1217
|
)
|
|
1212
1218
|
}
|
|
1213
1219
|
|
|
1214
|
-
if (this._nativeMetricsManuallySet(inputConfig) &&
|
|
1220
|
+
if (this._nativeMetricsManuallySet(inputConfig) &&
|
|
1215
1221
|
this.plugins.native_metrics.enabled) {
|
|
1216
1222
|
logger.info(
|
|
1217
1223
|
'Enabling the native-metrics module when in serverless mode may greatly ' +
|
|
@@ -1253,6 +1259,7 @@ Config.prototype._enforceServerless = function _enforceServerless(inputConfig) {
|
|
|
1253
1259
|
|
|
1254
1260
|
return
|
|
1255
1261
|
}
|
|
1262
|
+
|
|
1256
1263
|
const DT_KEYS = ['account_id', 'primary_application_id', 'trusted_account_key']
|
|
1257
1264
|
// Don't allow DT config settings to be set if serverless_mode is disabled
|
|
1258
1265
|
DT_KEYS.forEach((key) => {
|
|
@@ -1458,8 +1465,12 @@ Config.prototype.applyLasp = function applyLasp(agent, policies) {
|
|
|
1458
1465
|
}
|
|
1459
1466
|
var valueName = splitConfigName[splitConfigName.length - 1]
|
|
1460
1467
|
var localVal = settingBlock[valueName]
|
|
1468
|
+
|
|
1469
|
+
// Indexes into "allowed values" based on "enabled" setting
|
|
1470
|
+
// to retreive proper mapping.
|
|
1461
1471
|
var policyValues = localMapping.allowedValues
|
|
1462
1472
|
var policyValue = policyValues[policy.enabled ? 1 : 0]
|
|
1473
|
+
|
|
1463
1474
|
// get the most secure setting between local config and the policy
|
|
1464
1475
|
var finalValue = settingBlock[valueName] = config._getMostSecure(
|
|
1465
1476
|
name,
|
|
@@ -1522,6 +1533,20 @@ Config.prototype.validateFlags = function validateFlags() {
|
|
|
1522
1533
|
})
|
|
1523
1534
|
}
|
|
1524
1535
|
|
|
1536
|
+
function redactValue(value) {
|
|
1537
|
+
const REDACT_VALUE = '****'
|
|
1538
|
+
|
|
1539
|
+
let result = null
|
|
1540
|
+
if (Array.isArray(value)) {
|
|
1541
|
+
// Redact each value so we know if was configured and how many values
|
|
1542
|
+
result = value.map(() => REDACT_VALUE)
|
|
1543
|
+
} else {
|
|
1544
|
+
result = REDACT_VALUE
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
return result
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1525
1550
|
/**
|
|
1526
1551
|
* Get a JSONifiable object containing all settings we want to report to the
|
|
1527
1552
|
* collector and store in the environment_values table.
|
|
@@ -1532,9 +1557,10 @@ Config.prototype.publicSettings = function publicSettings() {
|
|
|
1532
1557
|
var settings = Object.create(null)
|
|
1533
1558
|
|
|
1534
1559
|
for (var key in this) {
|
|
1535
|
-
if (this.hasOwnProperty(key)) {
|
|
1560
|
+
if (this.hasOwnProperty(key) && !REMOVE_BEFORE_SEND.has(key)) {
|
|
1536
1561
|
if (HSM.REDACT_BEFORE_SEND.has(key)) {
|
|
1537
|
-
|
|
1562
|
+
const value = this[key]
|
|
1563
|
+
settings[key] = redactValue(value)
|
|
1538
1564
|
} else if (!HSM.REMOVE_BEFORE_SEND.has(key)) {
|
|
1539
1565
|
settings[key] = this[key]
|
|
1540
1566
|
}
|
|
@@ -1695,6 +1721,8 @@ function createInstance(config) {
|
|
|
1695
1721
|
return _configInstance
|
|
1696
1722
|
}
|
|
1697
1723
|
|
|
1724
|
+
const REMOVE_BEFORE_SEND = new Set(['attributeFilter'])
|
|
1725
|
+
|
|
1698
1726
|
/**
|
|
1699
1727
|
* Preserve the legacy initializer, but also allow consumers to manage their
|
|
1700
1728
|
* own configuration if they choose.
|
package/lib/config/lasp.js
CHANGED
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
// TODO: would likely be easier to understand if the allowedValues mapping
|
|
4
|
+
// just took the raw enabled/disabled and translated. This is not a hot path.
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* path: Full nested path for the local configuration item.
|
|
8
|
+
* allowedValues:
|
|
9
|
+
* Array of valid config values to map for incoming enabled/disabled.
|
|
10
|
+
* policy.enabled: false uses index 0, policy.enabled: true uses index 1.
|
|
11
|
+
* filter: Allows for calculating most secure setting to use
|
|
12
|
+
* applyAdditionalSettings: Applies additional settings that are required
|
|
13
|
+
* when the policy is disabled.
|
|
14
|
+
* clearData: Clears the relevant agent collection.
|
|
15
|
+
*/
|
|
3
16
|
const LASP_MAP = {
|
|
4
17
|
// LASP key
|
|
5
18
|
record_sql: {
|
|
6
19
|
// full path to corresponding config key
|
|
7
20
|
path: 'transaction_tracer.record_sql',
|
|
8
21
|
// Mapping from policy enabled status to usable config value
|
|
9
|
-
//
|
|
22
|
+
// policy.enabled: false === off, policy.enabled: true === 'obfuscated'
|
|
10
23
|
allowedValues: ['off', 'obfuscated'],
|
|
11
24
|
// Tracks the precedent of settings controlled by LASP.
|
|
12
25
|
filter: function mostSecureRecordSQL(first, second) {
|
|
@@ -45,6 +58,8 @@ const LASP_MAP = {
|
|
|
45
58
|
// TODO: rename config key, because the names contradict each other's behavior
|
|
46
59
|
allow_raw_exception_messages: {
|
|
47
60
|
path: 'strip_exception_messages.enabled',
|
|
61
|
+
// if raw messages are allowed, then we should not strip them
|
|
62
|
+
// policy.enabled: false === true, policy.enabled: true === false
|
|
48
63
|
allowedValues: [true, false],
|
|
49
64
|
filter: function mostSecureStripException(first, second) {
|
|
50
65
|
return first || second
|
|
@@ -4,6 +4,7 @@ const errorsModule = require('./index')
|
|
|
4
4
|
|
|
5
5
|
const logger = require('../logger').child({component: 'error_tracer'})
|
|
6
6
|
const urltils = require('../util/urltils')
|
|
7
|
+
const Exception = require('../errors').Exception
|
|
7
8
|
const errorHelper = require('./helper')
|
|
8
9
|
const createError = errorsModule.createError
|
|
9
10
|
const createEvent = errorsModule.createEvent
|
|
@@ -129,7 +130,7 @@ class ErrorCollector {
|
|
|
129
130
|
if (transaction.userErrors.length) {
|
|
130
131
|
for (let i = 0; i < transaction.userErrors.length; i++) {
|
|
131
132
|
const exception = transaction.userErrors[i]
|
|
132
|
-
if (this.
|
|
133
|
+
if (this.collect(transaction, exception)) {
|
|
133
134
|
++collectedErrors
|
|
134
135
|
}
|
|
135
136
|
}
|
|
@@ -145,13 +146,13 @@ class ErrorCollector {
|
|
|
145
146
|
if (transaction.exceptions.length) {
|
|
146
147
|
for (let i = 0; i < transaction.exceptions.length; i++) {
|
|
147
148
|
const exception = transaction.exceptions[i]
|
|
148
|
-
if (this.collect(transaction, exception
|
|
149
|
+
if (this.collect(transaction, exception)) {
|
|
149
150
|
++collectedErrors
|
|
150
151
|
// if we could collect it, then check if expected
|
|
151
152
|
if (isExpectedErrorStatusCode ||
|
|
152
153
|
errorHelper.isExpectedException(
|
|
153
154
|
transaction,
|
|
154
|
-
exception
|
|
155
|
+
exception.error,
|
|
155
156
|
this.config,
|
|
156
157
|
urltils
|
|
157
158
|
)
|
|
@@ -178,31 +179,32 @@ class ErrorCollector {
|
|
|
178
179
|
}
|
|
179
180
|
|
|
180
181
|
/**
|
|
181
|
-
* This function collects the error right away when transaction is not supplied.
|
|
182
|
-
*
|
|
182
|
+
* This function collects the error right away when transaction is not supplied. Otherwise it
|
|
183
|
+
* delays collecting the error until the transaction ends.
|
|
183
184
|
*
|
|
184
185
|
* NOTE: this interface is unofficial and may change in future.
|
|
185
186
|
*
|
|
186
|
-
* @param {?Transaction}
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
* @param {Error} exception
|
|
190
|
-
* The error to be traced.
|
|
191
|
-
*
|
|
192
|
-
* @param {object} customAttributes
|
|
193
|
-
* Any custom attributes associated with the request (optional).
|
|
187
|
+
* @param {?Transaction} transaction Transaction associated with the error.
|
|
188
|
+
* @param {Error} error The error to be traced.
|
|
189
|
+
* @param {?object} customAttributes Custom attributes associated with the request (optional).
|
|
194
190
|
*/
|
|
195
|
-
add(transaction,
|
|
196
|
-
if (!
|
|
191
|
+
add(transaction, error, customAttributes) {
|
|
192
|
+
if (!error) {
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (errorHelper.shouldIgnoreError(transaction, error, this.config)) {
|
|
197
|
+
logger.trace('Ignoring error')
|
|
197
198
|
return
|
|
198
199
|
}
|
|
199
200
|
|
|
200
201
|
const timestamp = Date.now()
|
|
202
|
+
const exception = new Exception({error, timestamp, customAttributes})
|
|
201
203
|
|
|
202
204
|
if (transaction) {
|
|
203
|
-
transaction.addException(exception
|
|
205
|
+
transaction.addException(exception)
|
|
204
206
|
} else {
|
|
205
|
-
this.collect(transaction, exception
|
|
207
|
+
this.collect(transaction, exception)
|
|
206
208
|
}
|
|
207
209
|
}
|
|
208
210
|
|
|
@@ -217,95 +219,54 @@ class ErrorCollector {
|
|
|
217
219
|
*
|
|
218
220
|
* NOTE: this interface is unofficial and may change in future.
|
|
219
221
|
*
|
|
220
|
-
* @param {?Transaction}
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
* @param {Error} exception
|
|
224
|
-
* The error to be traced.
|
|
225
|
-
*
|
|
226
|
-
* @param {object} [customAttributes=null]
|
|
227
|
-
* Any custom attributes associated with the request (optional).
|
|
222
|
+
* @param {?Transaction} transaction Transaction associated with the error.
|
|
223
|
+
* @param {Exception} exception The Exception to be traced.
|
|
228
224
|
*/
|
|
229
|
-
addUserError(transaction,
|
|
230
|
-
if (!
|
|
225
|
+
addUserError(transaction, error, customAttributes) {
|
|
226
|
+
if (!error) return
|
|
231
227
|
|
|
232
|
-
|
|
228
|
+
const timestamp = Date.now()
|
|
229
|
+
const exception = new Exception({error, timestamp, customAttributes})
|
|
233
230
|
|
|
234
231
|
if (transaction) {
|
|
235
|
-
transaction.addUserError(exception
|
|
232
|
+
transaction.addUserError(exception)
|
|
236
233
|
} else {
|
|
237
|
-
this.
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* Wrapper for _collect, include logic for whether an error should
|
|
243
|
-
* be ignored or not. Exists to allow userErrors to bypass ignore
|
|
244
|
-
* logic.
|
|
245
|
-
*
|
|
246
|
-
* NOTE: this interface is unofficial and may change in future.
|
|
247
|
-
*
|
|
248
|
-
* @param {?Transaction} transaction
|
|
249
|
-
* Transaction associated with the error.
|
|
250
|
-
*
|
|
251
|
-
* @param {?Error} exception
|
|
252
|
-
* The error to be traced.
|
|
253
|
-
*
|
|
254
|
-
* @param {?object} customAttributes
|
|
255
|
-
* Any custom attributes associated with the request.
|
|
256
|
-
*
|
|
257
|
-
* @param {number} timestamp
|
|
258
|
-
*
|
|
259
|
-
* @return {bool} True if the error was collected.
|
|
260
|
-
*/
|
|
261
|
-
collect(transaction, exception, customAttributes, timestamp) {
|
|
262
|
-
if (errorHelper.shouldIgnoreError(transaction, exception, this.config)) {
|
|
263
|
-
logger.trace("Ignoring error")
|
|
264
|
-
return
|
|
234
|
+
this.collect(transaction, exception)
|
|
265
235
|
}
|
|
266
|
-
return this._collect(transaction, exception, customAttributes, timestamp)
|
|
267
236
|
}
|
|
268
237
|
|
|
269
238
|
/**
|
|
270
239
|
* Collects the error and also creates the error event.
|
|
271
240
|
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
* This function uses an array of seen exceptions to ensure errors don't get
|
|
275
|
-
* double-counted. It can also be used as an unofficial means of marking that
|
|
276
|
-
* user errors shouldn't be traced.
|
|
241
|
+
* This function uses an array of seen exceptions to ensure errors don't get double-counted. It
|
|
242
|
+
* can also be used as an unofficial means of marking that user errors shouldn't be traced.
|
|
277
243
|
*
|
|
278
|
-
* For an error to be traced, at least one of the transaction or the error
|
|
279
|
-
* must be present.
|
|
244
|
+
* For an error to be traced, at least one of the transaction or the error must be present.
|
|
280
245
|
*
|
|
281
246
|
* NOTE: this interface is unofficial and may change in future.
|
|
282
247
|
*
|
|
283
|
-
* @param
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
* @param {?Error} exception
|
|
287
|
-
* The error to be traced.
|
|
288
|
-
*
|
|
289
|
-
* @param {?object} customAttributes
|
|
290
|
-
* Any custom attributes associated with the request.
|
|
291
|
-
*
|
|
292
|
-
* @param {number} timestamp
|
|
293
|
-
*
|
|
294
|
-
* @return {bool} True if the error was collected.
|
|
248
|
+
* @param {?Transaction} transaction Transaction associated with the error.
|
|
249
|
+
* @param {?Exception} exception The Exception object to be traced.
|
|
250
|
+
* @return {bool} True if the error was collected.
|
|
295
251
|
*/
|
|
296
|
-
|
|
297
|
-
if (exception) {
|
|
298
|
-
|
|
252
|
+
collect(transaction, exception) {
|
|
253
|
+
if (!exception) {
|
|
254
|
+
exception = new Exception({})
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (exception.error) {
|
|
258
|
+
if (this._haveSeen(transaction, exception.error)) {
|
|
299
259
|
return false
|
|
300
260
|
}
|
|
301
261
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
262
|
+
const error = exception.error
|
|
263
|
+
if (typeof error !== 'string' && !error.message && !error.stack) {
|
|
264
|
+
logger.trace(error, 'Got error that is not an instance of Error or string.')
|
|
265
|
+
exception.error = null
|
|
305
266
|
}
|
|
306
267
|
}
|
|
307
268
|
|
|
308
|
-
if (!exception && (!transaction || !transaction.statusCode || transaction.error)) {
|
|
269
|
+
if (!exception.error && (!transaction || !transaction.statusCode || transaction.error)) {
|
|
309
270
|
return false
|
|
310
271
|
}
|
|
311
272
|
|
|
@@ -321,13 +282,13 @@ class ErrorCollector {
|
|
|
321
282
|
return false
|
|
322
283
|
}
|
|
323
284
|
|
|
324
|
-
if (exception) {
|
|
325
|
-
logger.trace(exception, 'Got exception to trace:')
|
|
285
|
+
if (exception.error) {
|
|
286
|
+
logger.trace(exception.error, 'Got exception to trace:')
|
|
326
287
|
}
|
|
327
288
|
|
|
328
|
-
const
|
|
289
|
+
const errorTrace = createError(transaction, exception, this.config)
|
|
329
290
|
|
|
330
|
-
const isExpectedError = true ===
|
|
291
|
+
const isExpectedError = true === errorTrace[4].intrinsics['error.expected']
|
|
331
292
|
|
|
332
293
|
if (isExpectedError) {
|
|
333
294
|
this.metrics.getOrCreateMetric(NAMES.ERRORS.EXPECTED).incrementCallCount()
|
|
@@ -343,11 +304,11 @@ class ErrorCollector {
|
|
|
343
304
|
}
|
|
344
305
|
}
|
|
345
306
|
|
|
346
|
-
this.traceAggregator.add(
|
|
307
|
+
this.traceAggregator.add(errorTrace)
|
|
347
308
|
|
|
348
309
|
if (this.config.error_collector.capture_events === true) {
|
|
349
310
|
const priority = transaction && transaction.priority || Math.random()
|
|
350
|
-
const event = createEvent(transaction,
|
|
311
|
+
const event = createEvent(transaction, errorTrace, exception.timestamp, this.config)
|
|
351
312
|
this.eventAggregator.add(event, priority)
|
|
352
313
|
}
|
|
353
314
|
|
package/lib/errors/helper.js
CHANGED
|
@@ -48,7 +48,7 @@ module.exports = {
|
|
|
48
48
|
|
|
49
49
|
extractErrorInformation: function extractErrorInformation(
|
|
50
50
|
transaction,
|
|
51
|
-
|
|
51
|
+
error,
|
|
52
52
|
config,
|
|
53
53
|
urltils
|
|
54
54
|
) {
|
|
@@ -58,21 +58,21 @@ module.exports = {
|
|
|
58
58
|
|
|
59
59
|
// String errors do not provide us with as much information to provide to the
|
|
60
60
|
// user, but it is a common pattern.
|
|
61
|
-
if (typeof
|
|
62
|
-
message =
|
|
61
|
+
if (typeof error === 'string') {
|
|
62
|
+
message = error
|
|
63
63
|
} else if (
|
|
64
|
-
|
|
65
|
-
typeof
|
|
66
|
-
|
|
64
|
+
error !== null &&
|
|
65
|
+
typeof error === 'object' &&
|
|
66
|
+
error.message &&
|
|
67
67
|
!config.high_security &&
|
|
68
68
|
!config.strip_exception_messages.enabled
|
|
69
69
|
) {
|
|
70
|
-
message =
|
|
70
|
+
message = error.message
|
|
71
71
|
|
|
72
|
-
if (
|
|
73
|
-
type =
|
|
74
|
-
} else if (
|
|
75
|
-
type =
|
|
72
|
+
if (error.name) {
|
|
73
|
+
type = error.name
|
|
74
|
+
} else if (error.constructor && error.constructor.name) {
|
|
75
|
+
type = error.constructor.name
|
|
76
76
|
}
|
|
77
77
|
} else if (transaction && transaction.statusCode &&
|
|
78
78
|
urltils.isError(config, transaction.statusCode)) {
|
|
@@ -95,9 +95,9 @@ module.exports = {
|
|
|
95
95
|
}
|
|
96
96
|
},
|
|
97
97
|
|
|
98
|
-
shouldIgnoreError: function shouldIgnoreError(transaction,
|
|
98
|
+
shouldIgnoreError: function shouldIgnoreError(transaction, error, config) {
|
|
99
99
|
// extract _just_ the error information, not transaction stuff
|
|
100
|
-
let errorInfo = this.extractErrorInformation(null,
|
|
100
|
+
let errorInfo = this.extractErrorInformation(null, error, config, null)
|
|
101
101
|
|
|
102
102
|
return this.shouldIgnoreErrorClass(errorInfo, config) ||
|
|
103
103
|
this.shouldIgnoreErrorMessage(errorInfo, config) ||
|