newrelic 8.10.0 → 8.11.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 +65 -20
- package/THIRD_PARTY_NOTICES.md +2 -2
- package/api.js +1 -26
- package/lib/agent.js +132 -0
- package/lib/aggregators/log-aggregator.js +57 -0
- package/lib/collector/api.js +71 -2
- package/lib/collector/facts.js +41 -1
- package/lib/collector/serverless.js +23 -3
- package/lib/config/default.js +50 -10
- package/lib/config/env.js +20 -2
- package/lib/config/hsm.js +5 -0
- package/lib/config/index.js +2 -1
- package/lib/instrumentation/@node-redis/client.js +61 -0
- package/lib/instrumentation/@redis/client.js +7 -0
- package/lib/instrumentation/core/child_process.js +1 -1
- package/lib/instrumentation/winston.js +187 -0
- package/lib/instrumentations.js +4 -1
- package/lib/metrics/names.js +29 -2
- package/lib/transaction/index.js +16 -11
- package/lib/transaction/logs.js +46 -0
- package/lib/util/application-logging.js +97 -0
- package/newrelic.js +8 -16
- package/package.json +2 -2
|
@@ -22,10 +22,10 @@ class ServerlessCollector {
|
|
|
22
22
|
/**
|
|
23
23
|
* Constructs a new serverless collector instance with the give agent.
|
|
24
24
|
*
|
|
25
|
-
* @
|
|
25
|
+
* @class
|
|
26
|
+
* @param pipePath
|
|
26
27
|
* @classdesc
|
|
27
28
|
* A helper class for wrapping modules with segments
|
|
28
|
-
*
|
|
29
29
|
* @param {Agent} agent - The agent this collector will use
|
|
30
30
|
*/
|
|
31
31
|
constructor(agent, pipePath) {
|
|
@@ -44,6 +44,8 @@ class ServerlessCollector {
|
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
46
|
* Sets the ARN to be sent up in the metadata.
|
|
47
|
+
*
|
|
48
|
+
* @param arn
|
|
47
49
|
*/
|
|
48
50
|
setLambdaArn(arn) {
|
|
49
51
|
this.metadata.arn = arn
|
|
@@ -51,6 +53,8 @@ class ServerlessCollector {
|
|
|
51
53
|
|
|
52
54
|
/**
|
|
53
55
|
* Sets the function_version to be sent up in the metadata.
|
|
56
|
+
*
|
|
57
|
+
* @param function_version
|
|
54
58
|
*/
|
|
55
59
|
setLambdaFunctionVersion(function_version) {
|
|
56
60
|
this.metadata.function_version = function_version
|
|
@@ -79,6 +83,8 @@ class ServerlessCollector {
|
|
|
79
83
|
|
|
80
84
|
/**
|
|
81
85
|
* There is nothing to actually restart for serverless, so we do nothing.
|
|
86
|
+
*
|
|
87
|
+
* @param cb
|
|
82
88
|
*/
|
|
83
89
|
restart(cb) {
|
|
84
90
|
setImmediate(cb, null, CollectorResponse.success(null))
|
|
@@ -193,6 +199,19 @@ class ServerlessCollector {
|
|
|
193
199
|
cb(null, { retainData: false })
|
|
194
200
|
}
|
|
195
201
|
|
|
202
|
+
/**
|
|
203
|
+
* Records log event data to be serialized.
|
|
204
|
+
*
|
|
205
|
+
* @param {Array} payload The log event data payload to serialize.
|
|
206
|
+
* @param {Function} cb The callback to invoke when finished.
|
|
207
|
+
*/
|
|
208
|
+
log_event_data(payload, cb) {
|
|
209
|
+
if (this.enabled) {
|
|
210
|
+
this.payload.log_event_data = payload
|
|
211
|
+
}
|
|
212
|
+
cb(null, { retainData: false })
|
|
213
|
+
}
|
|
214
|
+
|
|
196
215
|
/**
|
|
197
216
|
* Constructs, serializes, and prints the final consolidated payload to stdout.
|
|
198
217
|
*
|
|
@@ -250,6 +269,8 @@ class ServerlessCollector {
|
|
|
250
269
|
|
|
251
270
|
/**
|
|
252
271
|
* Writes payload to pipe
|
|
272
|
+
*
|
|
273
|
+
* @param payload
|
|
253
274
|
*/
|
|
254
275
|
flushToPipeSync(payload) {
|
|
255
276
|
try {
|
|
@@ -279,7 +300,6 @@ class ServerlessCollector {
|
|
|
279
300
|
* Internal method to handle flushing to stdout.
|
|
280
301
|
*
|
|
281
302
|
* @private
|
|
282
|
-
*
|
|
283
303
|
* @param {string} payload The payload to flush.
|
|
284
304
|
* @param {boolean} sync Whether to write to stdout synchronously.
|
|
285
305
|
*/
|
package/lib/config/default.js
CHANGED
|
@@ -305,7 +305,6 @@ exports.config = () => ({
|
|
|
305
305
|
* grows too large the New Relic servers may reject it.
|
|
306
306
|
*
|
|
307
307
|
* @env NEW_RELIC_ERROR_COLLECTOR_MAX_EVENT_SAMPLES_STORED
|
|
308
|
-
*
|
|
309
308
|
*/
|
|
310
309
|
max_event_samples_stored: 100,
|
|
311
310
|
|
|
@@ -689,7 +688,6 @@ exports.config = () => ({
|
|
|
689
688
|
* grows too large the New Relic servers may reject it.
|
|
690
689
|
*
|
|
691
690
|
* @env NEW_RELIC_CUSTOM_INSIGHTS_EVENTS_MAX_SAMPLES_STORED
|
|
692
|
-
*
|
|
693
691
|
*/
|
|
694
692
|
max_samples_stored: 1000
|
|
695
693
|
},
|
|
@@ -720,9 +718,9 @@ exports.config = () => ({
|
|
|
720
718
|
* disabled.
|
|
721
719
|
*
|
|
722
720
|
* Attributes of high security mode (when enabled):
|
|
723
|
-
*
|
|
724
|
-
*
|
|
725
|
-
*
|
|
721
|
+
* requires SSL
|
|
722
|
+
* does not allow capturing of http params
|
|
723
|
+
* does not allow custom params
|
|
726
724
|
*
|
|
727
725
|
* To read more see: https://docs.newrelic.com/docs/subscriptions/high-security
|
|
728
726
|
*/
|
|
@@ -761,11 +759,10 @@ exports.config = () => ({
|
|
|
761
759
|
/**
|
|
762
760
|
* Controls behavior of datastore instance metrics.
|
|
763
761
|
*
|
|
764
|
-
* @property {
|
|
762
|
+
* @property {boolean} [instance_reporting.enabled=true]
|
|
765
763
|
* Enables reporting the host and port/path/id of database servers. Default
|
|
766
764
|
* is `true`.
|
|
767
|
-
*
|
|
768
|
-
* @property {Boolean} [database_name_reporting.enabled=true]
|
|
765
|
+
* @property {boolean} [database_name_reporting.enabled=true]
|
|
769
766
|
* Enables reporting of database/schema names. Default is `true`.
|
|
770
767
|
*/
|
|
771
768
|
datastore_tracer: {
|
|
@@ -873,7 +870,7 @@ exports.config = () => ({
|
|
|
873
870
|
/**
|
|
874
871
|
* Controls the use of cross-application tracing.
|
|
875
872
|
*
|
|
876
|
-
* @property {
|
|
873
|
+
* @property {boolean} [enabled=false]
|
|
877
874
|
* Enables tracing transactions across multiple applications. Default is `false`.
|
|
878
875
|
* This feature has been deprecated in favor of Distributed Tracing (DT).
|
|
879
876
|
* To fully enable this feature, you must also disable DT in your configuration.
|
|
@@ -883,7 +880,7 @@ exports.config = () => ({
|
|
|
883
880
|
/**
|
|
884
881
|
* Controls behavior of message broker tracing.
|
|
885
882
|
*
|
|
886
|
-
* @property {
|
|
883
|
+
* @property {boolean} [segment_parameters.enabled=true]
|
|
887
884
|
* Enables reporting parameters on message broker segments.
|
|
888
885
|
*/
|
|
889
886
|
message_tracer: {
|
|
@@ -934,5 +931,48 @@ exports.config = () => ({
|
|
|
934
931
|
* loop data.
|
|
935
932
|
*/
|
|
936
933
|
native_metrics: { enabled: true }
|
|
934
|
+
},
|
|
935
|
+
|
|
936
|
+
/**
|
|
937
|
+
*
|
|
938
|
+
* Controls the behavior of Logs in Context within agent
|
|
939
|
+
*/
|
|
940
|
+
application_logging: {
|
|
941
|
+
/**
|
|
942
|
+
* Toggles the ability for all application logging features to be enabled.
|
|
943
|
+
*
|
|
944
|
+
* @env NEW_RELIC_APPLICATION_LOGGING_ENABLED
|
|
945
|
+
*/
|
|
946
|
+
enabled: true,
|
|
947
|
+
forwarding: {
|
|
948
|
+
/**
|
|
949
|
+
* Toggles whether the agent gathers log records for sending to New Relic.
|
|
950
|
+
*
|
|
951
|
+
* @env NEW_RELIC_APPLICATION_LOGGING_FORWARDING_ENABLED
|
|
952
|
+
*/
|
|
953
|
+
enabled: false,
|
|
954
|
+
/**
|
|
955
|
+
* Number of log records to send per minute to New Relic.
|
|
956
|
+
*
|
|
957
|
+
* @env NEW_RELIC_APPLICATION_LOGGING_FORWARDING_MAX_SAMPLES_STORED
|
|
958
|
+
*/
|
|
959
|
+
max_samples_stored: 10000
|
|
960
|
+
},
|
|
961
|
+
metrics: {
|
|
962
|
+
/**
|
|
963
|
+
* Toggles whether the agent gathers logging metrics.
|
|
964
|
+
*
|
|
965
|
+
* @env NEW_RELIC_APPLICATION_LOGGING_METRICS_ENABLED
|
|
966
|
+
*/
|
|
967
|
+
enabled: true
|
|
968
|
+
},
|
|
969
|
+
local_decorating: {
|
|
970
|
+
/**
|
|
971
|
+
* Toggles whether the agent performs log decoration on standard log output.
|
|
972
|
+
*
|
|
973
|
+
* @env NEW_RELIC_APPLICATION_LOGGING_LOCAL_DECORATING_ENABLED
|
|
974
|
+
*/
|
|
975
|
+
enabled: false
|
|
976
|
+
}
|
|
937
977
|
}
|
|
938
978
|
})
|
package/lib/config/env.js
CHANGED
|
@@ -167,6 +167,19 @@ const ENV_MAPPING = {
|
|
|
167
167
|
span_events: {
|
|
168
168
|
queue_size: 'NEW_RELIC_INFINITE_TRACING_SPAN_EVENTS_QUEUE_SIZE'
|
|
169
169
|
}
|
|
170
|
+
},
|
|
171
|
+
application_logging: {
|
|
172
|
+
enabled: 'NEW_RELIC_APPLICATION_LOGGING_ENABLED',
|
|
173
|
+
forwarding: {
|
|
174
|
+
enabled: 'NEW_RELIC_APPLICATION_LOGGING_FORWARDING_ENABLED',
|
|
175
|
+
max_samples_stored: 'NEW_RELIC_APPLICATION_LOGGING_FORWARDING_MAX_SAMPLES_STORED'
|
|
176
|
+
},
|
|
177
|
+
metrics: {
|
|
178
|
+
enabled: 'NEW_RELIC_APPLICATION_LOGGING_METRICS_ENABLED'
|
|
179
|
+
},
|
|
180
|
+
local_decorating: {
|
|
181
|
+
enabled: 'NEW_RELIC_APPLICATION_LOGGING_LOCAL_DECORATING_ENABLED'
|
|
182
|
+
}
|
|
170
183
|
}
|
|
171
184
|
}
|
|
172
185
|
|
|
@@ -242,7 +255,11 @@ const BOOLEAN_VARS = new Set([
|
|
|
242
255
|
'NEW_RELIC_UTILIZATION_DETECT_GCP',
|
|
243
256
|
'NEW_RELIC_UTILIZATION_DETECT_KUBERNETES',
|
|
244
257
|
'NEW_RELIC_SERVERLESS_MODE_ENABLED',
|
|
245
|
-
'NEW_RELIC_NATIVE_METRICS_ENABLED'
|
|
258
|
+
'NEW_RELIC_NATIVE_METRICS_ENABLED',
|
|
259
|
+
'NEW_RELIC_APPLICATION_LOGGING_ENABLED',
|
|
260
|
+
'NEW_RELIC_APPLICATION_LOGGING_FORWARDING_ENABLED',
|
|
261
|
+
'NEW_RELIC_APPLICATION_LOGGING_METRICS_ENABLED',
|
|
262
|
+
'NEW_RELIC_APPLICATION_LOGGING_LOCAL_DECORATING_ENABLED'
|
|
246
263
|
])
|
|
247
264
|
|
|
248
265
|
const FLOAT_VARS = new Set(['NEW_RELIC_APDEX_T', 'NEW_RELIC_TRACER_THRESHOLD'])
|
|
@@ -254,7 +271,8 @@ const INT_VARS = new Set([
|
|
|
254
271
|
'NEW_RELIC_SPAN_EVENTS_MAX_SAMPLES_STORED',
|
|
255
272
|
'NEW_RELIC_CUSTOM_INSIGHTS_EVENTS_MAX_SAMPLES_STORED',
|
|
256
273
|
'NEW_RELIC_TRANSACTION_EVENTS_MAX_SAMPLES_STORED',
|
|
257
|
-
'NEW_RELIC_ERROR_COLLECTOR_MAX_EVENT_SAMPLES_STORED'
|
|
274
|
+
'NEW_RELIC_ERROR_COLLECTOR_MAX_EVENT_SAMPLES_STORED',
|
|
275
|
+
'NEW_RELIC_APPLICATION_LOGGING_FORWARDING_MAX_SAMPLES_STORED'
|
|
258
276
|
])
|
|
259
277
|
|
|
260
278
|
exports.ENV_MAPPING = ENV_MAPPING
|
package/lib/config/hsm.js
CHANGED
package/lib/config/index.js
CHANGED
|
@@ -182,7 +182,8 @@ function Config(config) {
|
|
|
182
182
|
analytic_event_data: this.transaction_events.max_samples_stored,
|
|
183
183
|
custom_event_data: this.custom_insights_events.max_samples_stored,
|
|
184
184
|
error_event_data: this.error_collector.max_event_samples_stored,
|
|
185
|
-
span_event_data: this.span_events.max_samples_stored
|
|
185
|
+
span_event_data: this.span_events.max_samples_stored,
|
|
186
|
+
log_event_data: this.application_logging.forwarding.max_samples_stored
|
|
186
187
|
}
|
|
187
188
|
}
|
|
188
189
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2021 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
const CLIENT_COMMANDS = ['select', 'quit', 'SELECT', 'QUIT']
|
|
8
|
+
|
|
9
|
+
module.exports = function initialize(agent, redis, moduleName, shim) {
|
|
10
|
+
shim.setDatastore(shim.REDIS)
|
|
11
|
+
const COMMANDS = Object.keys(shim.require('dist/lib/client/commands.js').default)
|
|
12
|
+
const CMDS_TO_INSTRUMENT = [...COMMANDS, ...CLIENT_COMMANDS]
|
|
13
|
+
shim.wrap(redis, 'createClient', function wrapCreateClient(shim, original) {
|
|
14
|
+
return function wrappedCreateClient() {
|
|
15
|
+
const client = original.apply(this, arguments)
|
|
16
|
+
const clientOptions = getRedisParams(client.options)
|
|
17
|
+
CMDS_TO_INSTRUMENT.forEach((cmd) => {
|
|
18
|
+
shim.recordOperation(client, cmd, function wrapCommand(shim, fn, fnName, args) {
|
|
19
|
+
const [key, value] = args
|
|
20
|
+
const parameters = Object.assign({}, clientOptions)
|
|
21
|
+
// If selecting a database, subsequent commands
|
|
22
|
+
// will be using said database, update the clientOptions
|
|
23
|
+
// but not the current parameters(feature parity with v3)
|
|
24
|
+
if (cmd.toLowerCase() === 'select') {
|
|
25
|
+
clientOptions.database_name = key
|
|
26
|
+
}
|
|
27
|
+
if (agent.config.attributes.enabled) {
|
|
28
|
+
if (key) {
|
|
29
|
+
parameters.key = JSON.stringify(key)
|
|
30
|
+
}
|
|
31
|
+
if (value) {
|
|
32
|
+
parameters.value = JSON.stringify(value)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
name: (cmd && cmd.toLowerCase()) || 'other',
|
|
38
|
+
parameters,
|
|
39
|
+
promise: true
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
return client
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Extracts the datastore parameters from the client options
|
|
50
|
+
*
|
|
51
|
+
* @param {object} opts client.options
|
|
52
|
+
* @returns {object} params
|
|
53
|
+
*/
|
|
54
|
+
function getRedisParams(opts) {
|
|
55
|
+
return {
|
|
56
|
+
host: (opts.socket && opts.socket.host) || 'localhost',
|
|
57
|
+
port_path_or_id: (opts.socket && opts.socket.path) || opts.socket.port || '6379',
|
|
58
|
+
database_name: opts.database || 0
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -9,7 +9,7 @@ module.exports = initialize
|
|
|
9
9
|
|
|
10
10
|
function initialize(agent, childProcess, moduleName, shim) {
|
|
11
11
|
if (!childProcess) {
|
|
12
|
-
shim.
|
|
12
|
+
shim.logger.debug('Could not find child_process, not instrumenting')
|
|
13
13
|
return false
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
const Stream = require('stream')
|
|
9
|
+
const {
|
|
10
|
+
isApplicationLoggingEnabled,
|
|
11
|
+
isLogForwardingEnabled,
|
|
12
|
+
isLocalDecoratingEnabled,
|
|
13
|
+
isMetricsEnabled,
|
|
14
|
+
createModuleUsageMetric,
|
|
15
|
+
incrementLoggingLinesMetrics,
|
|
16
|
+
truncate
|
|
17
|
+
} = require('../util/application-logging')
|
|
18
|
+
const logger = require('../logger').child({ component: 'winston' })
|
|
19
|
+
|
|
20
|
+
module.exports = function instrument(agent, winston, _, shim) {
|
|
21
|
+
const config = agent.config
|
|
22
|
+
|
|
23
|
+
if (!isApplicationLoggingEnabled(config)) {
|
|
24
|
+
logger.debug('Application logging not enabled. Not instrumenting winston.')
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
shim.wrap(winston, 'createLogger', function wrapCreate(shim, createLogger) {
|
|
29
|
+
return function createWrappedLogger() {
|
|
30
|
+
const args = shim.argsToArray.apply(shim, arguments)
|
|
31
|
+
const opts = args[0]
|
|
32
|
+
if (!shim.isObject(opts) || isStream(opts)) {
|
|
33
|
+
return createLogger.apply(this, args)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
registerFormatter({ opts, config, agent, winston })
|
|
37
|
+
|
|
38
|
+
return createLogger.apply(this, args)
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* There is no right way to do this. But since we are automagical
|
|
45
|
+
* it is hard to predict how a customer uses winston. We will iterate over the formatters specified on the logger and add last if forwarder or first if local decorating.
|
|
46
|
+
* This is because we want all the customizations of previous formatters before adding log log to log aggregator. But in the case of local decorating we want to do this first so any formatter that is transforming data will have the changes.
|
|
47
|
+
*
|
|
48
|
+
* Note: The logic explained above does not apply if a customer specifies multiple formats for a given transport.
|
|
49
|
+
* We cannot instrument the formats on the transport because if a customer has multiple transports we would be duplicating logs when forwaring.
|
|
50
|
+
*
|
|
51
|
+
* @param {object} params object passed to function
|
|
52
|
+
* @param {object} params.opts options from winston.createLogger
|
|
53
|
+
* @param {object} params.config agent config
|
|
54
|
+
* @param {object} params.agent NR agent
|
|
55
|
+
* @param {object} params.winston exported winston package
|
|
56
|
+
*/
|
|
57
|
+
function registerFormatter({ opts, config, agent, winston }) {
|
|
58
|
+
const instrumentedFormatter = nrWinstonFormatter(agent, winston)
|
|
59
|
+
|
|
60
|
+
if ('format' in opts) {
|
|
61
|
+
const formatters = [opts.format]
|
|
62
|
+
|
|
63
|
+
if (isLogForwardingEnabled(config, agent)) {
|
|
64
|
+
formatters.push(instrumentedFormatter())
|
|
65
|
+
} else {
|
|
66
|
+
formatters.unshift(instrumentedFormatter())
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
opts.format = winston.format.combine(...formatters)
|
|
70
|
+
} else {
|
|
71
|
+
opts.format = instrumentedFormatter()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* This formatter is being used to facilitate
|
|
77
|
+
* the application logging use cases.
|
|
78
|
+
* It is worth noting that the features below are mutually
|
|
79
|
+
* exclusive.
|
|
80
|
+
*
|
|
81
|
+
* The application logging use cases are local log decorating
|
|
82
|
+
* and log forwarding.
|
|
83
|
+
*
|
|
84
|
+
* Local log decorating appends `NR-LINKING` piped metadata to
|
|
85
|
+
* the message key in log line. You must configure a log forwarder to get
|
|
86
|
+
* this data to NR1.
|
|
87
|
+
*
|
|
88
|
+
* Log forwarding includes the linking metadata as keys on logging
|
|
89
|
+
* object as well as adds the log line to the agent log aggregator.
|
|
90
|
+
*
|
|
91
|
+
* @param {object} agent NR agent
|
|
92
|
+
* @param {object} winston exported winston package
|
|
93
|
+
* @returns {object} log line with NR context or NR-LINKING metadata on message
|
|
94
|
+
*/
|
|
95
|
+
function nrWinstonFormatter(agent, winston) {
|
|
96
|
+
const config = agent.config
|
|
97
|
+
const metrics = agent.metrics
|
|
98
|
+
createModuleUsageMetric('winston', metrics)
|
|
99
|
+
|
|
100
|
+
return winston.format((logLine) => {
|
|
101
|
+
if (isMetricsEnabled(config)) {
|
|
102
|
+
incrementLoggingLinesMetrics(logLine.level, metrics)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (isLogForwardingEnabled(config, agent)) {
|
|
106
|
+
const metadata = agent.getLinkingMetadata()
|
|
107
|
+
reformatLogLine(logLine, metadata, agent)
|
|
108
|
+
agent.logs.add(logLine)
|
|
109
|
+
} else if (isLocalDecoratingEnabled(config)) {
|
|
110
|
+
logLine.message += agent.getNRLinkingMetadata()
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return logLine
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Reformats a log line by reformatting errors, timestamp and adding
|
|
119
|
+
* new relic linking metadata(context)
|
|
120
|
+
*
|
|
121
|
+
* @param {object} logLine log line
|
|
122
|
+
* @param {object} metadata linking metadata
|
|
123
|
+
* @param {object} agent NR agent
|
|
124
|
+
*/
|
|
125
|
+
function reformatLogLine(logLine, metadata, agent) {
|
|
126
|
+
if (logLine.exception === true) {
|
|
127
|
+
reformatError(logLine)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
reformatTimestamp(logLine, agent)
|
|
131
|
+
|
|
132
|
+
// Add the metadata to the logLine object being logged
|
|
133
|
+
Object.assign(logLine, metadata)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Decorates the log line with truncated error.message, error.class, and error.stack and removes
|
|
138
|
+
* trace and stack
|
|
139
|
+
*
|
|
140
|
+
* @param {object} logLine a log line
|
|
141
|
+
*/
|
|
142
|
+
function reformatError(logLine) {
|
|
143
|
+
// Due to Winston internals sometimes the error on the logLine object is a string or an
|
|
144
|
+
// empty object, and so the message property is all we have
|
|
145
|
+
const errorMessage = logLine.error.message || logLine.message || ''
|
|
146
|
+
|
|
147
|
+
logLine['error.message'] = truncate(errorMessage)
|
|
148
|
+
logLine['error.class'] =
|
|
149
|
+
logLine.error.name === 'Error' ? logLine.error.constructor.name : logLine.error.name
|
|
150
|
+
logLine['error.stack'] = truncate(logLine.error.stack)
|
|
151
|
+
logLine.message = truncate(logLine.message)
|
|
152
|
+
|
|
153
|
+
// Removes additional capture of stack to reduce overall payload/log-line size.
|
|
154
|
+
// The server has a maximum of ~4k characters per line allowed.
|
|
155
|
+
delete logLine.trace
|
|
156
|
+
delete logLine.stack
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Turns timestamp into unix timestamp. If timestamp existed it will move original
|
|
161
|
+
* to `original_timestamp` key
|
|
162
|
+
*
|
|
163
|
+
* @param {object} logLine a log line
|
|
164
|
+
*/
|
|
165
|
+
function reformatTimestamp(logLine) {
|
|
166
|
+
if (logLine.timestamp) {
|
|
167
|
+
logger.traceOnce(
|
|
168
|
+
'Overwriting `timestamp` key; assigning original value to `original_timestamp`.'
|
|
169
|
+
)
|
|
170
|
+
logLine.original_timestamp = logLine.timestamp
|
|
171
|
+
}
|
|
172
|
+
logLine.timestamp = Date.now()
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* winston allows you to compose a logger
|
|
177
|
+
* from an instantiated logger. Through a series
|
|
178
|
+
* of inherited classes, this logger instance is a Stream.
|
|
179
|
+
* Check what gets passed into `winston.createLogger` to avoid
|
|
180
|
+
* instrumenting an already instrumented instance of a logger.
|
|
181
|
+
*
|
|
182
|
+
* @param {*} obj obj to check if a stream
|
|
183
|
+
* @returns {boolean} is object is a stream or not
|
|
184
|
+
*/
|
|
185
|
+
function isStream(obj) {
|
|
186
|
+
return obj instanceof Stream
|
|
187
|
+
}
|
package/lib/instrumentations.js
CHANGED
|
@@ -29,11 +29,14 @@ module.exports = function instrumentations() {
|
|
|
29
29
|
'pg': { type: MODULE_TYPE.DATASTORE },
|
|
30
30
|
'q': { type: null },
|
|
31
31
|
'redis': { type: MODULE_TYPE.DATASTORE },
|
|
32
|
+
'@node-redis/client': { type: MODULE_TYPE.DATASTORE },
|
|
33
|
+
'@redis/client': { type: MODULE_TYPE.DATASTORE },
|
|
32
34
|
'restify': { type: MODULE_TYPE.WEB_FRAMEWORK },
|
|
33
35
|
'superagent': { module: '@newrelic/superagent' },
|
|
34
36
|
'undici': { type: MODULE_TYPE.TRANSACTION },
|
|
35
37
|
'oracle': { type: null },
|
|
36
38
|
'vision': { type: MODULE_TYPE.WEB_FRAMEWORK },
|
|
37
|
-
'when': { type: null }
|
|
39
|
+
'when': { type: null },
|
|
40
|
+
'winston': { type: MODULE_TYPE.GENERIC }
|
|
38
41
|
}
|
|
39
42
|
}
|
package/lib/metrics/names.js
CHANGED
|
@@ -19,11 +19,13 @@ const SUPPORTABILITY = {
|
|
|
19
19
|
TRANSACTION_API: 'Supportability/API/Transaction',
|
|
20
20
|
UTILIZATION: 'Supportability/utilization',
|
|
21
21
|
DEPENDENCIES: 'Supportability/InstalledDependencies',
|
|
22
|
+
NODEJS_DEPENDENCIES: 'Supportability/InstalledDependencies/Nodejs',
|
|
22
23
|
NODEJS: 'Supportability/Nodejs',
|
|
23
24
|
REGISTRATION: 'Supportability/Registration',
|
|
24
25
|
EVENT_HARVEST: 'Supportability/EventHarvest',
|
|
25
26
|
INFINITE_TRACING: 'Supportability/InfiniteTracing',
|
|
26
|
-
FEATURES: 'Supportability/Features'
|
|
27
|
+
FEATURES: 'Supportability/Features',
|
|
28
|
+
LOGGING: 'Supportability/Logging'
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
const ERRORS = {
|
|
@@ -197,7 +199,8 @@ const EVENT_HARVEST = {
|
|
|
197
199
|
ANALYTIC: SUPPORTABILITY.EVENT_HARVEST + '/AnalyticEventData/HarvestLimit',
|
|
198
200
|
CUSTOM: SUPPORTABILITY.EVENT_HARVEST + '/CustomEventData/HarvestLimit',
|
|
199
201
|
ERROR: SUPPORTABILITY.EVENT_HARVEST + '/ErrorEventData/HarvestLimit',
|
|
200
|
-
SPAN: SUPPORTABILITY.EVENT_HARVEST + '/SpanEventData/HarvestLimit'
|
|
202
|
+
SPAN: SUPPORTABILITY.EVENT_HARVEST + '/SpanEventData/HarvestLimit',
|
|
203
|
+
LOG: SUPPORTABILITY.EVENT_HARVEST + '/LogEventData/HarvestLimit'
|
|
201
204
|
}
|
|
202
205
|
}
|
|
203
206
|
|
|
@@ -259,6 +262,29 @@ const FEATURES = {
|
|
|
259
262
|
}
|
|
260
263
|
}
|
|
261
264
|
|
|
265
|
+
const LOGGING_LINES_PREFIX = 'Logging/lines'
|
|
266
|
+
const LOGGING_FORWARDING_PREFIX = `${SUPPORTABILITY.LOGGING}/Forwarding`
|
|
267
|
+
const LOGGING = {
|
|
268
|
+
LINES: LOGGING_LINES_PREFIX,
|
|
269
|
+
LEVELS: {
|
|
270
|
+
INFO: `${LOGGING_LINES_PREFIX}/INFO`,
|
|
271
|
+
WARN: `${LOGGING_LINES_PREFIX}/WARN`,
|
|
272
|
+
ERROR: `${LOGGING_LINES_PREFIX}/ERROR`,
|
|
273
|
+
DEBUG: `${LOGGING_LINES_PREFIX}/DEBUG`,
|
|
274
|
+
TRACE: `${LOGGING_LINES_PREFIX}/TRACE`
|
|
275
|
+
},
|
|
276
|
+
LIBS: {
|
|
277
|
+
PINO: `${SUPPORTABILITY.LOGGING}/${NODEJS.PREFIX}pino/enabled`,
|
|
278
|
+
WINSTON: `${SUPPORTABILITY.LOGGING}/${NODEJS.PREFIX}winston/enabled`
|
|
279
|
+
},
|
|
280
|
+
DROPPED: `Logging/Forwarding/Dropped`,
|
|
281
|
+
SEEN: `${LOGGING_FORWARDING_PREFIX}/Seen`,
|
|
282
|
+
SENT: `${LOGGING_FORWARDING_PREFIX}/Sent`,
|
|
283
|
+
FORWARDING: `${LOGGING_FORWARDING_PREFIX}/${NODEJS.PREFIX}`,
|
|
284
|
+
METRICS: `${SUPPORTABILITY.LOGGING}/Metrics/${NODEJS.PREFIX}`,
|
|
285
|
+
LOCAL_DECORATING: `${SUPPORTABILITY.LOGGING}/LocalDecorating/${NODEJS.PREFIX}`
|
|
286
|
+
}
|
|
287
|
+
|
|
262
288
|
module.exports = {
|
|
263
289
|
ACTION_DELIMITER: '/',
|
|
264
290
|
ALL: ALL,
|
|
@@ -284,6 +310,7 @@ module.exports = {
|
|
|
284
310
|
HTTP: 'HttpDispatcher',
|
|
285
311
|
INFINITE_TRACING: INFINITE_TRACING,
|
|
286
312
|
LOOP: LOOP,
|
|
313
|
+
LOGGING,
|
|
287
314
|
MEMCACHE: MEMCACHE,
|
|
288
315
|
MEMORY: MEMORY,
|
|
289
316
|
MESSAGE_TRANSACTION: MESSAGE_TRANSACTION,
|