newrelic 13.19.2 → 14.0.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 +115 -0
- package/THIRD_PARTY_NOTICES.md +82 -345
- package/api.js +85 -0
- package/lib/agent.js +12 -9
- package/lib/attributes.js +1 -2
- package/lib/collector/api.js +2 -20
- package/lib/collector/http-agents.js +4 -1
- package/lib/collector/remote-method.js +3 -1
- package/lib/config/default.js +43 -21
- package/lib/config/index.js +20 -190
- package/lib/context-manager/async-local-context-manager.js +3 -9
- package/lib/db/statement-matcher.js +1 -1
- package/lib/errors/index.js +0 -2
- package/lib/instrumentation/@prisma/client.js +12 -2
- package/lib/instrumentation/core/domain.js +2 -13
- package/lib/instrumentation/core/globals.js +0 -1
- package/lib/instrumentation/core/http-outbound.js +14 -31
- package/lib/instrumentation/core/http.js +17 -70
- package/lib/instrumentation/core/http2.js +2 -11
- package/lib/instrumentation/koa/nr-hooks.js +0 -12
- package/lib/instrumentations.js +0 -4
- package/lib/llm-events/ai-agent.js +28 -0
- package/lib/llm-events/google-genai/chat-completion-message.js +6 -3
- package/lib/message-broker-description.js +29 -12
- package/lib/metrics/names.js +14 -8
- package/lib/metrics/recorders/apollo-resolver.js +40 -0
- package/lib/metrics/recorders/http.js +0 -2
- package/lib/metrics/recorders/http_external.js +1 -25
- package/lib/shim/message-shim/index.js +4 -4
- package/lib/shim/shim.js +2 -40
- package/lib/shim/transaction-shim.js +10 -130
- package/lib/subscriber-configs.js +5 -0
- package/lib/subscribers/amqplib/consume.js +1 -1
- package/lib/subscribers/apollo-server/config.js +52 -0
- package/lib/subscribers/apollo-server/constants.js +49 -0
- package/lib/subscribers/apollo-server/request.js +355 -0
- package/lib/subscribers/apollo-server/resolve.js +242 -0
- package/lib/subscribers/aws-sdk/config.js +41 -3
- package/lib/subscribers/aws-sdk/core-send.js +16 -0
- package/lib/subscribers/aws-sdk/middleware/bedrock/index.js +3 -4
- package/lib/subscribers/aws-sdk/middleware/dynamodb/index.js +2 -3
- package/lib/subscribers/aws-sdk/middleware/nr-specific/attributes.js +2 -2
- package/lib/subscribers/aws-sdk/middleware/nr-specific/headers.js +3 -3
- package/lib/subscribers/aws-sdk/middleware/sns/index.js +3 -4
- package/lib/subscribers/aws-sdk/middleware/sqs/index.js +11 -15
- package/lib/subscribers/aws-sdk/utils/attach-headers.js +1 -1
- package/lib/subscribers/azure-functions/azure-handler-base.js +138 -0
- package/lib/subscribers/azure-functions/background-handler.js +29 -0
- package/lib/subscribers/azure-functions/config.js +44 -0
- package/lib/subscribers/azure-functions/http-handler.js +58 -0
- package/lib/subscribers/azure-functions/index.js +74 -0
- package/lib/subscribers/azure-functions/logger.js +72 -0
- package/lib/subscribers/base.js +8 -29
- package/lib/subscribers/bluebird/config.js +1 -1
- package/lib/subscribers/bluebird/instrumentation.js +3 -7
- package/lib/subscribers/cassandra-driver/config.js +5 -5
- package/lib/subscribers/connect/config.js +42 -0
- package/lib/subscribers/connect/use.js +31 -0
- package/lib/subscribers/dc-base.js +45 -4
- package/lib/subscribers/fastify/config.js +2 -2
- package/lib/subscribers/fastify/index.js +1 -1
- package/lib/subscribers/google-adk/agent-run-async.js +118 -0
- package/lib/subscribers/google-adk/config.js +59 -0
- package/lib/subscribers/google-adk/tool-run-async.js +87 -0
- package/lib/subscribers/grpcjs/client.js +3 -12
- package/lib/subscribers/grpcjs/server.js +2 -2
- package/lib/subscribers/kafkajs/client-constructor.js +349 -0
- package/lib/subscribers/kafkajs/config.js +25 -0
- package/lib/subscribers/kafkajs/utils/record-data-metrics.js +48 -0
- package/lib/subscribers/kafkajs/utils/record-linking-metrics.js +30 -0
- package/lib/{instrumentation/kafkajs → subscribers/kafkajs/utils}/record-method-metric.js +3 -2
- package/lib/subscribers/langgraph/graph-stream.js +2 -1
- package/lib/subscribers/message-consumer-tools.js +161 -0
- package/lib/subscribers/message-consumer.js +43 -61
- package/lib/subscribers/message-producer.js +2 -3
- package/lib/subscribers/middleware-wrapper.js +7 -7
- package/lib/subscribers/mysql/config.js +1 -33
- package/lib/subscribers/mysql/connection-query.js +72 -3
- package/lib/subscribers/mysql/pool-get-connection.js +0 -1
- package/lib/subscribers/mysql2/config.js +14 -56
- package/lib/subscribers/mysql2/connection-execute.js +2 -2
- package/lib/subscribers/mysql2/pool-get-connection.js +0 -2
- package/lib/subscribers/nestjs/config.js +1 -1
- package/lib/subscribers/undici/index.js +6 -31
- package/lib/symbols.js +1 -0
- package/lib/transaction/index.js +16 -82
- package/lib/transaction/trace/index.js +148 -67
- package/lib/transaction/trace/segment-tree.js +7 -15
- package/lib/transaction/trace/segment.js +24 -28
- package/lib/transaction/tracer/index.js +71 -29
- package/lib/util/attributes.js +1 -70
- package/lib/util/hashes.js +0 -30
- package/lib/util/logger.js +1 -1
- package/package.json +19 -25
- package/lib/config/lasp.js +0 -106
- package/lib/instrumentation/@azure/functions.js +0 -323
- package/lib/instrumentation/connect.js +0 -83
- package/lib/instrumentation/fastify/spec-builders.js +0 -103
- package/lib/instrumentation/fastify.js +0 -100
- package/lib/instrumentation/kafkajs/consumer.js +0 -145
- package/lib/instrumentation/kafkajs/index.js +0 -34
- package/lib/instrumentation/kafkajs/producer.js +0 -83
- package/lib/instrumentation/kafkajs/record-linking-metrics.js +0 -17
- package/lib/instrumentation/kafkajs.js +0 -7
- package/lib/instrumentation/koa/route-instrumentation.js +0 -31
- package/lib/subscribers/mysql/pool-namespace-query.js +0 -19
- package/lib/subscribers/mysql/pool-query.js +0 -41
- package/lib/subscribers/mysql2/pool-namespace-query.js +0 -19
- package/lib/subscribers/mysql2/pool-query.js +0 -19
- package/lib/transaction/trace/exclusive-time-calculator.js +0 -143
- package/lib/util/cat.js +0 -305
package/api.js
CHANGED
|
@@ -1977,4 +1977,89 @@ API.prototype.withLlmCustomAttributes = function withLlmCustomAttributes(context
|
|
|
1977
1977
|
return transaction._llmContextManager.run(fullContext, callback)
|
|
1978
1978
|
}
|
|
1979
1979
|
|
|
1980
|
+
/**
|
|
1981
|
+
* Function for adding a custom callback to generate custom attributes on apollo server operation segments.
|
|
1982
|
+
*
|
|
1983
|
+
* Provided functions must be synchronous and return an object of custom attribute key/values.
|
|
1984
|
+
* The arguments provided to callback are: `requestContext`, which is the apollo server `requestContext`.
|
|
1985
|
+
*
|
|
1986
|
+
*
|
|
1987
|
+
* @param {Function} callback - callback function to generate custom attributes on apollo operation segments
|
|
1988
|
+
* @example
|
|
1989
|
+
* function customOperationAttributes(requestContext) {
|
|
1990
|
+
* return {
|
|
1991
|
+
* clientName: requestContext.request.http.headers.get('graphql-client-name')
|
|
1992
|
+
* }
|
|
1993
|
+
* }
|
|
1994
|
+
*
|
|
1995
|
+
* newrelic.setApolloOperationAttributesCallback(customOperationAttributes)
|
|
1996
|
+
*/
|
|
1997
|
+
API.prototype.setApolloOperationAttributesCallback = function setApolloOperationAttributesCallback(callback) {
|
|
1998
|
+
const self = this
|
|
1999
|
+
const metric = this.agent.metrics.getOrCreateMetric(
|
|
2000
|
+
NAMES.SUPPORTABILITY.API + '/setApolloOperationAttributesCallback'
|
|
2001
|
+
)
|
|
2002
|
+
metric.incrementCallCount()
|
|
2003
|
+
|
|
2004
|
+
if (!this.shim.isFunction(callback) || this.shim.isAsyncFunction(callback)) {
|
|
2005
|
+
logger.warn(
|
|
2006
|
+
'Apollo operation attributes callback must be a synchronous function, custom operation attributes will not be added.'
|
|
2007
|
+
)
|
|
2008
|
+
return
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
this.agent.customCallbacks.apollo.operationCallback = function wrappedOperationAttributesCb(requestContext) {
|
|
2012
|
+
const result = callback(requestContext)
|
|
2013
|
+
self.addCustomAttributes(result)
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
/**
|
|
2018
|
+
* Function for adding a custom callback to generate custom attributes on apollo server resolver segments.
|
|
2019
|
+
*
|
|
2020
|
+
* Provided functions must be synchronous and return an object of custom attribute key/values.
|
|
2021
|
+
* The arguments provided to callback are:
|
|
2022
|
+
*
|
|
2023
|
+
* ```
|
|
2024
|
+
* {
|
|
2025
|
+
* source: object,
|
|
2026
|
+
* args: array,
|
|
2027
|
+
* contextValue: object,
|
|
2028
|
+
* info: object
|
|
2029
|
+
* }
|
|
2030
|
+
* ```
|
|
2031
|
+
*
|
|
2032
|
+
* @param {Function} callback - callback function to generate custom attributes on apollo operation segments
|
|
2033
|
+
* @example
|
|
2034
|
+
* function customResolverAttributes({ source, args, contextValue, info }}) {
|
|
2035
|
+
* return {
|
|
2036
|
+
* allArgs: Object.keys(args).join(','),
|
|
2037
|
+
* returnType: info.returnType.name,
|
|
2038
|
+
* sourceBranch: source?.branch
|
|
2039
|
+
* stage: contextValue.event.requestContext.stage
|
|
2040
|
+
* }
|
|
2041
|
+
* }
|
|
2042
|
+
*
|
|
2043
|
+
* newrelic.setApolloResolverAttributesCallback(customResolverAttributes)
|
|
2044
|
+
*/
|
|
2045
|
+
API.prototype.setApolloResolverAttributesCallback = function setApolloResolverAttributesCallback(callback) {
|
|
2046
|
+
const self = this
|
|
2047
|
+
const metric = this.agent.metrics.getOrCreateMetric(
|
|
2048
|
+
NAMES.SUPPORTABILITY.API + '/setApolloResolverAttributesCallback'
|
|
2049
|
+
)
|
|
2050
|
+
metric.incrementCallCount()
|
|
2051
|
+
|
|
2052
|
+
if (!this.shim.isFunction(callback) || this.shim.isAsyncFunction(callback)) {
|
|
2053
|
+
logger.warn(
|
|
2054
|
+
'Apollo resolver attributes callback must be a synchronous function, custom resolver attributes will not be added.'
|
|
2055
|
+
)
|
|
2056
|
+
return
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
this.agent.customCallbacks.apollo.resolverCallback = function wrappedResolverAttributesCb(args) {
|
|
2060
|
+
const result = callback(args)
|
|
2061
|
+
self.addCustomAttributes(result)
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
|
|
1980
2065
|
module.exports = API
|
package/lib/agent.js
CHANGED
|
@@ -31,8 +31,6 @@ const createSpanEventAggregator = require('./spans/create-span-event-aggregator'
|
|
|
31
31
|
const {
|
|
32
32
|
maybeAddDatabaseAttributes,
|
|
33
33
|
maybeAddExternalAttributes,
|
|
34
|
-
addRequiredCATAttributes,
|
|
35
|
-
maybeAddExtraCATAttributes,
|
|
36
34
|
maybeAddParentAttributes,
|
|
37
35
|
maybeAddQueueAttributes
|
|
38
36
|
} = require('./util/attributes')
|
|
@@ -321,6 +319,18 @@ function Agent(config) {
|
|
|
321
319
|
this._listenForConfigChanges()
|
|
322
320
|
|
|
323
321
|
this.initCounters()
|
|
322
|
+
// Set up data structure to store user defined callbacks for various features
|
|
323
|
+
this.customCallbacks = {
|
|
324
|
+
apollo: {
|
|
325
|
+
// defined with `api.setApolloOperationAttributesCallback`
|
|
326
|
+
// it is called to add custom attributes to the operation segments
|
|
327
|
+
operationCallback: null,
|
|
328
|
+
// defined with `api.setApolloResolverAttributesCallback`
|
|
329
|
+
// it is called to add custom attributes to the resolver segments
|
|
330
|
+
resolverCallback: null
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
// TODO: move to `this.customCallbacks`
|
|
324
334
|
this.llm = {}
|
|
325
335
|
|
|
326
336
|
// Finally, add listeners for the agent's own events.
|
|
@@ -751,13 +761,6 @@ function _addIntrinsicAttrsFromTransaction(transaction) {
|
|
|
751
761
|
if (this.config.distributed_tracing.enabled) {
|
|
752
762
|
transaction.addDistributedTraceIntrinsics(intrinsicAttributes)
|
|
753
763
|
maybeAddParentAttributes(transaction, intrinsicAttributes)
|
|
754
|
-
} else if (
|
|
755
|
-
this.config.cross_application_tracer.enabled &&
|
|
756
|
-
!transaction.invalidIncomingExternalTransaction &&
|
|
757
|
-
(transaction.referringTransactionGuid || transaction.includesOutboundRequests())
|
|
758
|
-
) {
|
|
759
|
-
addRequiredCATAttributes(transaction, intrinsicAttributes, this.config)
|
|
760
|
-
maybeAddExtraCATAttributes(transaction, intrinsicAttributes, this.config)
|
|
761
764
|
}
|
|
762
765
|
|
|
763
766
|
return intrinsicAttributes
|
package/lib/attributes.js
CHANGED
package/lib/collector/api.js
CHANGED
|
@@ -296,10 +296,6 @@ CollectorAPI.prototype._login = function _login(callback) {
|
|
|
296
296
|
const agent = this._agent
|
|
297
297
|
|
|
298
298
|
const preconnectData = { high_security: agent.config.high_security }
|
|
299
|
-
if (agent.config.security_policies_token) {
|
|
300
|
-
preconnectData.security_policies_token = agent.config.security_policies_token
|
|
301
|
-
}
|
|
302
|
-
|
|
303
299
|
const payload = [preconnectData]
|
|
304
300
|
|
|
305
301
|
this._methods.preconnect.invoke(payload, this._onPreConnect.bind(this, callback))
|
|
@@ -312,7 +308,6 @@ CollectorAPI.prototype._login = function _login(callback) {
|
|
|
312
308
|
* @returns {void}
|
|
313
309
|
*/
|
|
314
310
|
CollectorAPI.prototype._onPreConnect = function _onPreConnect(callback, error, response) {
|
|
315
|
-
const agent = this._agent
|
|
316
311
|
if (error || !SUCCESS.has(response.status)) {
|
|
317
312
|
callback(error, response)
|
|
318
313
|
return
|
|
@@ -320,16 +315,7 @@ CollectorAPI.prototype._onPreConnect = function _onPreConnect(callback, error, r
|
|
|
320
315
|
|
|
321
316
|
const res = response.payload || Object.create(null)
|
|
322
317
|
this._handlePreConnectResponse(res)
|
|
323
|
-
|
|
324
|
-
const policies = res.security_policies || Object.create(null)
|
|
325
|
-
|
|
326
|
-
const laspResponse = agent.config.applyLasp(agent, policies)
|
|
327
|
-
if (laspResponse.shouldShutdownRun()) {
|
|
328
|
-
callback(null, laspResponse)
|
|
329
|
-
return
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
this._getFacts(laspResponse.payload, callback)
|
|
318
|
+
this._getFacts(callback)
|
|
333
319
|
}
|
|
334
320
|
|
|
335
321
|
/**
|
|
@@ -372,15 +358,11 @@ CollectorAPI.prototype._handlePreConnectResponse = function _handlePreConnectRes
|
|
|
372
358
|
}
|
|
373
359
|
}
|
|
374
360
|
|
|
375
|
-
CollectorAPI.prototype._getFacts = function _getFacts(
|
|
361
|
+
CollectorAPI.prototype._getFacts = function _getFacts(callback) {
|
|
376
362
|
const agent = this._agent
|
|
377
363
|
const self = this
|
|
378
364
|
|
|
379
365
|
facts(agent, function getEnvDict(environmentDict) {
|
|
380
|
-
if (lasp) {
|
|
381
|
-
environmentDict.security_policies = lasp
|
|
382
|
-
}
|
|
383
|
-
|
|
384
366
|
// The collector really likes arrays.
|
|
385
367
|
// In fact, it kind of insists on them.
|
|
386
368
|
const environment = [environmentDict]
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
const { HttpsProxyAgent } = require('https-proxy-agent')
|
|
9
8
|
const logger = require('../logger').child({ component: 'http-agent' })
|
|
10
9
|
const https = require('https')
|
|
11
10
|
|
|
@@ -64,6 +63,10 @@ exports.proxyAgent = function proxyAgent(config) {
|
|
|
64
63
|
}
|
|
65
64
|
|
|
66
65
|
logger.info(`using proxy: ${proxyUrl}`)
|
|
66
|
+
// lazy-load `https-proxy-agent` as it is ESM
|
|
67
|
+
// if required at top it would not allow us to instrument
|
|
68
|
+
// the core `node:http` correctly.
|
|
69
|
+
const { HttpsProxyAgent } = require('https-proxy-agent')
|
|
67
70
|
agentProxyWithKeepAlive = new HttpsProxyAgent(proxyUrl, proxyOpts)
|
|
68
71
|
return agentProxyWithKeepAlive
|
|
69
72
|
}
|
|
@@ -354,7 +354,9 @@ RemoteMethod.prototype._path = function _path({ redactLicenseKey } = {}) {
|
|
|
354
354
|
const query = {
|
|
355
355
|
marshal_format: 'json',
|
|
356
356
|
protocol_version: this._protocolVersion,
|
|
357
|
-
license_key: redactLicenseKey
|
|
357
|
+
license_key: redactLicenseKey
|
|
358
|
+
? this._config.redacted_license_key
|
|
359
|
+
: this._config.license_key,
|
|
358
360
|
method: this.name
|
|
359
361
|
}
|
|
360
362
|
|
package/lib/config/default.js
CHANGED
|
@@ -43,12 +43,6 @@ defaultConfig.definition = () => {
|
|
|
43
43
|
* The user's license key. Must be set by per-app configuration file.
|
|
44
44
|
*/
|
|
45
45
|
license_key: '',
|
|
46
|
-
/**
|
|
47
|
-
*
|
|
48
|
-
* Enables/Disables security policies. Paste your security policies
|
|
49
|
-
* token from the New Relic Admin below.
|
|
50
|
-
*/
|
|
51
|
-
security_policies_token: '',
|
|
52
46
|
/**
|
|
53
47
|
* Hostname for the New Relic collector proxy.
|
|
54
48
|
*
|
|
@@ -1140,7 +1134,7 @@ defaultConfig.definition = () => {
|
|
|
1140
1134
|
*/
|
|
1141
1135
|
exclude_newrelic_header: {
|
|
1142
1136
|
formatter: boolean,
|
|
1143
|
-
default:
|
|
1137
|
+
default: true
|
|
1144
1138
|
},
|
|
1145
1139
|
|
|
1146
1140
|
sampler: {
|
|
@@ -1175,20 +1169,6 @@ defaultConfig.definition = () => {
|
|
|
1175
1169
|
}
|
|
1176
1170
|
},
|
|
1177
1171
|
|
|
1178
|
-
/**
|
|
1179
|
-
* Controls the use of cross-application tracing.
|
|
1180
|
-
*
|
|
1181
|
-
* @property {boolean} [enabled=false]
|
|
1182
|
-
* Enables tracing transactions across multiple applications. Default is `false`.
|
|
1183
|
-
* This feature has been deprecated in favor of Distributed Tracing (DT).
|
|
1184
|
-
* To fully enable this feature, you must also disable DT in your configuration.
|
|
1185
|
-
*/
|
|
1186
|
-
cross_application_tracer: {
|
|
1187
|
-
enabled: {
|
|
1188
|
-
formatter: boolean,
|
|
1189
|
-
default: false
|
|
1190
|
-
}
|
|
1191
|
-
},
|
|
1192
1172
|
/**
|
|
1193
1173
|
* Controls behavior of message broker tracing.
|
|
1194
1174
|
*
|
|
@@ -1782,6 +1762,48 @@ defaultConfig.definition = () => {
|
|
|
1782
1762
|
formatter: int
|
|
1783
1763
|
}
|
|
1784
1764
|
}
|
|
1765
|
+
},
|
|
1766
|
+
|
|
1767
|
+
/**
|
|
1768
|
+
* Stanza for customizing behavior for apollo server instrumentation
|
|
1769
|
+
*/
|
|
1770
|
+
apollo_server: {
|
|
1771
|
+
/**
|
|
1772
|
+
* Enable capture of timing of fields resolved with the GraphQLScalarType return type. This may be desired when performing time intensive calculations to return a scalar value. This is not recommended for queries that return a large number of pre-calculated scalar fields.
|
|
1773
|
+
* NOTE: query/mutation resolvers will always be captured even if returning a scalar type.
|
|
1774
|
+
*/
|
|
1775
|
+
scalars: {
|
|
1776
|
+
formatter: boolean,
|
|
1777
|
+
default: false
|
|
1778
|
+
},
|
|
1779
|
+
/**
|
|
1780
|
+
* Enable capture of timings for an [IntrospectionQuery](https://www.graphql-js.org/api-v16/utilities/#introspectionquery)
|
|
1781
|
+
*/
|
|
1782
|
+
introspection_queries: {
|
|
1783
|
+
formatter: boolean,
|
|
1784
|
+
default: false
|
|
1785
|
+
},
|
|
1786
|
+
/**
|
|
1787
|
+
* Enable capture of timings for a [Service Definition query](https://www.apollographql.com/docs/federation/federation-spec/#fetch-service-capabilities) received from an Apollo Federated Gateway Server.
|
|
1788
|
+
*/
|
|
1789
|
+
service_definition_queries: {
|
|
1790
|
+
formatter: boolean,
|
|
1791
|
+
default: false
|
|
1792
|
+
},
|
|
1793
|
+
/**
|
|
1794
|
+
* Enable capture of timings for a [Health Check query](https://www.apollographql.com/docs/federation/api/apollo-gateway/#servicehealthcheck) received from an Apollo Federated Gateway Server.
|
|
1795
|
+
*/
|
|
1796
|
+
health_check_queries: {
|
|
1797
|
+
formatter: boolean,
|
|
1798
|
+
default: false
|
|
1799
|
+
},
|
|
1800
|
+
/**
|
|
1801
|
+
* Enable capture of metrics for every field and resolver argument seen for an Apollo query. This is intended to be used to check for any unused fields in your graphql schema.
|
|
1802
|
+
*/
|
|
1803
|
+
field_metrics: {
|
|
1804
|
+
formatter: boolean,
|
|
1805
|
+
default: false
|
|
1806
|
+
}
|
|
1785
1807
|
}
|
|
1786
1808
|
}
|
|
1787
1809
|
}
|
package/lib/config/index.js
CHANGED
|
@@ -6,14 +6,12 @@
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
8
|
const AttributeFilter = require('./attribute-filter')
|
|
9
|
-
const CollectorResponse = require('../collector/response')
|
|
10
9
|
const copy = require('../util/copy')
|
|
11
10
|
const { config: defaultConfig, definition, setNestedKey } = require('./default')
|
|
12
11
|
const EventEmitter = require('events').EventEmitter
|
|
13
12
|
const featureFlag = require('../feature_flags')
|
|
14
13
|
const flatten = require('../util/flatten')
|
|
15
14
|
const fs = require('../util/unwrapped-core').fs
|
|
16
|
-
const hashes = require('../util/hashes')
|
|
17
15
|
const os = require('os')
|
|
18
16
|
const parseKey = require('../collector/key-parser').parseKey
|
|
19
17
|
const path = require('path')
|
|
@@ -35,7 +33,6 @@ const DEFAULT_MAX_PAYLOAD_SIZE_IN_BYTES = 1_000_000
|
|
|
35
33
|
const BASE_CONFIG_PATH = require.resolve('../../newrelic')
|
|
36
34
|
const HAS_ARBITRARY_KEYS = new Set(['ignore_messages', 'expected_messages', 'labels'])
|
|
37
35
|
|
|
38
|
-
const LASP_MAP = require('./lasp').LASP_MAP
|
|
39
36
|
const HSM = require('./hsm')
|
|
40
37
|
const REMOVE_BEFORE_SEND = new Set(['attributeFilter'])
|
|
41
38
|
const SSL_WARNING = 'SSL config key can no longer be disabled, not updating.'
|
|
@@ -118,9 +115,7 @@ function Config(config) {
|
|
|
118
115
|
this.account_id = null
|
|
119
116
|
this.application_id = null
|
|
120
117
|
this.web_transactions_apdex = Object.create(null)
|
|
121
|
-
this.cross_process_id = null
|
|
122
118
|
this.encoding_key = null
|
|
123
|
-
this.obfuscatedId = null
|
|
124
119
|
this.primary_application_id = null
|
|
125
120
|
this.trusted_account_ids = null
|
|
126
121
|
this.trusted_account_key = null
|
|
@@ -185,14 +180,6 @@ function Config(config) {
|
|
|
185
180
|
|
|
186
181
|
// 8. apply high security overrides
|
|
187
182
|
if (this.high_security) {
|
|
188
|
-
if (this.security_policies_token) {
|
|
189
|
-
throw new Error(
|
|
190
|
-
'Security Policies and High Security Mode cannot both be present ' +
|
|
191
|
-
'in the agent configuration. If Security Policies have been set ' +
|
|
192
|
-
'for your account, please ensure the security_policies_token is ' +
|
|
193
|
-
'set but high_security is disabled (default).'
|
|
194
|
-
)
|
|
195
|
-
}
|
|
196
183
|
this._applyHighSecurity()
|
|
197
184
|
}
|
|
198
185
|
|
|
@@ -284,22 +271,9 @@ Config.prototype.onConnect = function onConnect(json, recursion) {
|
|
|
284
271
|
this._fromServer(json, key)
|
|
285
272
|
}
|
|
286
273
|
|
|
287
|
-
this._warnDeprecations()
|
|
288
|
-
|
|
289
274
|
this.emit('change', this)
|
|
290
275
|
}
|
|
291
276
|
|
|
292
|
-
Config.prototype._getMostSecure = function getMostSecure(key, currentVal, newVal) {
|
|
293
|
-
const filter = LASP_MAP[key] && LASP_MAP[key].filter
|
|
294
|
-
if (!this.security_policies_token || !filter) {
|
|
295
|
-
// If we aren't applying something vetted by security policies we
|
|
296
|
-
// just return the new value.
|
|
297
|
-
return newVal
|
|
298
|
-
}
|
|
299
|
-
// Return the most secure if we have a filter to apply
|
|
300
|
-
return filter(currentVal, newVal)
|
|
301
|
-
}
|
|
302
|
-
|
|
303
277
|
/**
|
|
304
278
|
* Helper that checks if value from server is false
|
|
305
279
|
* then updates the corresponding configuration enabled flag.
|
|
@@ -389,12 +363,8 @@ Config.prototype._fromServer = function _fromServer(params, key) {
|
|
|
389
363
|
break
|
|
390
364
|
|
|
391
365
|
// always accept these settings
|
|
392
|
-
case 'cross_process_id':
|
|
393
366
|
case 'encoding_key':
|
|
394
367
|
this._alwaysUpdateIfChanged(params, key)
|
|
395
|
-
if (this.cross_process_id && this.encoding_key) {
|
|
396
|
-
this.obfuscatedId = hashes.obfuscateNameUsingKey(this.cross_process_id, this.encoding_key)
|
|
397
|
-
}
|
|
398
368
|
break
|
|
399
369
|
|
|
400
370
|
// always accept these settings
|
|
@@ -476,12 +446,6 @@ Config.prototype._fromServer = function _fromServer(params, key) {
|
|
|
476
446
|
break
|
|
477
447
|
|
|
478
448
|
//
|
|
479
|
-
// Cross Application Tracer
|
|
480
|
-
//
|
|
481
|
-
case 'cross_application_tracer.enabled':
|
|
482
|
-
this._updateNestedIfChanged(params, this.cross_application_tracer, key, 'enabled')
|
|
483
|
-
break
|
|
484
|
-
//
|
|
485
449
|
// Error Collector
|
|
486
450
|
//
|
|
487
451
|
case 'error_collector.enabled':
|
|
@@ -1335,16 +1299,6 @@ Config.prototype._serverlessAppName = function _serverlessAppName() {
|
|
|
1335
1299
|
}
|
|
1336
1300
|
}
|
|
1337
1301
|
|
|
1338
|
-
/**
|
|
1339
|
-
* Disables CAT in serverless mode
|
|
1340
|
-
*/
|
|
1341
|
-
Config.prototype._serverlessCAT = function _serverlessCAT() {
|
|
1342
|
-
if (this.cross_application_tracer.enabled) {
|
|
1343
|
-
this.cross_application_tracer.enabled = false
|
|
1344
|
-
logger.info('Cross application tracing is explicitly disabled in serverless_mode.')
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
|
|
1348
1302
|
Config.prototype._serverlessInfiniteTracing = function _serverlessInfiniteTracing() {
|
|
1349
1303
|
if (this.infinite_tracing.trace_observer.host) {
|
|
1350
1304
|
this.infinite_tracing.trace_observer.host = ''
|
|
@@ -1401,7 +1355,6 @@ Config.prototype._preventServerlessDT = function _preventServerlessDT() {
|
|
|
1401
1355
|
|
|
1402
1356
|
/**
|
|
1403
1357
|
* Enforces config rules specific to running in serverless_mode:
|
|
1404
|
-
* - disables cross_application_tracer.enabled if set
|
|
1405
1358
|
* - defaults logging to disabled
|
|
1406
1359
|
* - verifies data specific to running DT is defined either in config file of env vars
|
|
1407
1360
|
*
|
|
@@ -1410,7 +1363,6 @@ Config.prototype._preventServerlessDT = function _preventServerlessDT() {
|
|
|
1410
1363
|
Config.prototype._enforceServerless = function _enforceServerless(inputConfig) {
|
|
1411
1364
|
if (this.serverless_mode.enabled) {
|
|
1412
1365
|
this._serverlessAppName()
|
|
1413
|
-
this._serverlessCAT()
|
|
1414
1366
|
this._serverlessInfiniteTracing()
|
|
1415
1367
|
this._serverlessLogging(inputConfig)
|
|
1416
1368
|
this._serverlessNativeMetrics(inputConfig)
|
|
@@ -1470,6 +1422,8 @@ Config.prototype._canonicalize = function _canonicalize() {
|
|
|
1470
1422
|
if (this.license_key) {
|
|
1471
1423
|
this.license_key = this.license_key.trim()
|
|
1472
1424
|
}
|
|
1425
|
+
|
|
1426
|
+
this.redacted_license_key = redactLicenseKey(this.license_key)
|
|
1473
1427
|
}
|
|
1474
1428
|
|
|
1475
1429
|
/**
|
|
@@ -1573,135 +1527,6 @@ Config.prototype._applyHighSecurity = function _applyHighSecurity() {
|
|
|
1573
1527
|
}
|
|
1574
1528
|
}
|
|
1575
1529
|
|
|
1576
|
-
/**
|
|
1577
|
-
* Sends a response to collector for LASP application
|
|
1578
|
-
*
|
|
1579
|
-
* @param {Array} keys keys from a LASP policy
|
|
1580
|
-
* @returns {CollectorResponse} creates CollectorResponse with either preserve or shutdown
|
|
1581
|
-
*/
|
|
1582
|
-
function _laspResponse(keys) {
|
|
1583
|
-
if (keys.length) {
|
|
1584
|
-
logger.error('The agent received one or more unexpected security policies and will shut down.')
|
|
1585
|
-
return CollectorResponse.fatal(null)
|
|
1586
|
-
}
|
|
1587
|
-
return CollectorResponse.success(null)
|
|
1588
|
-
}
|
|
1589
|
-
|
|
1590
|
-
/**
|
|
1591
|
-
* Applies the server side LASP policies to a local configuration object
|
|
1592
|
-
*
|
|
1593
|
-
* @param {Agent} agent Agent instance
|
|
1594
|
-
* @param {object} policies server side LASP policy
|
|
1595
|
-
* @returns {object} { missingRequired, finalPolicies } list of missing required fields and finalized LASP policy
|
|
1596
|
-
*/
|
|
1597
|
-
Config.prototype._buildLaspPolicy = function _buildLaspPolicy(agent, policies) {
|
|
1598
|
-
const config = this
|
|
1599
|
-
const keys = Object.keys(policies)
|
|
1600
|
-
const missingRequired = []
|
|
1601
|
-
|
|
1602
|
-
const finalPolicies = keys.reduce(function applyPolicy(obj, name) {
|
|
1603
|
-
const policy = policies[name]
|
|
1604
|
-
const localMapping = LASP_MAP[name]
|
|
1605
|
-
|
|
1606
|
-
if (!localMapping) {
|
|
1607
|
-
if (!policy.required) {
|
|
1608
|
-
// policy is not implemented in agent -- don't send to connect
|
|
1609
|
-
return obj
|
|
1610
|
-
}
|
|
1611
|
-
// policy is required but does not exist in agent -- fail
|
|
1612
|
-
missingRequired.push(name)
|
|
1613
|
-
} else {
|
|
1614
|
-
const splitConfigName = localMapping.path.split('.')
|
|
1615
|
-
let settingBlock = config[splitConfigName[0]]
|
|
1616
|
-
// pull out the configuration subsection that the option lives in
|
|
1617
|
-
for (let i = 1; i < splitConfigName.length - 1; ++i) {
|
|
1618
|
-
settingBlock = settingBlock[splitConfigName[i]]
|
|
1619
|
-
}
|
|
1620
|
-
const valueName = splitConfigName[splitConfigName.length - 1]
|
|
1621
|
-
const localVal = settingBlock[valueName]
|
|
1622
|
-
|
|
1623
|
-
// Indexes into "allowed values" based on "enabled" setting
|
|
1624
|
-
// to retrieve proper mapping.
|
|
1625
|
-
const policyValues = localMapping.allowedValues
|
|
1626
|
-
const policyValue = policyValues[policy.enabled ? 1 : 0]
|
|
1627
|
-
|
|
1628
|
-
// get the most secure setting between local config and the policy
|
|
1629
|
-
const finalValue = (settingBlock[valueName] = config._getMostSecure(
|
|
1630
|
-
name,
|
|
1631
|
-
localVal,
|
|
1632
|
-
policyValue
|
|
1633
|
-
))
|
|
1634
|
-
policy.enabled = policyValues.indexOf(finalValue) === 1
|
|
1635
|
-
obj[name] = policy
|
|
1636
|
-
|
|
1637
|
-
if (!policy.enabled && localMapping.applyAdditionalSettings) {
|
|
1638
|
-
localMapping.applyAdditionalSettings(config)
|
|
1639
|
-
}
|
|
1640
|
-
|
|
1641
|
-
if (finalValue !== localVal) {
|
|
1642
|
-
// finalValue is more secure than original local val,
|
|
1643
|
-
// so drop corresponding data
|
|
1644
|
-
localMapping.clearData(agent)
|
|
1645
|
-
}
|
|
1646
|
-
}
|
|
1647
|
-
|
|
1648
|
-
return obj
|
|
1649
|
-
}, Object.create(null))
|
|
1650
|
-
|
|
1651
|
-
return { missingRequired, finalPolicies }
|
|
1652
|
-
}
|
|
1653
|
-
|
|
1654
|
-
/**
|
|
1655
|
-
* Checks policies received from preconnect against those expected
|
|
1656
|
-
* by the agent, if LASP-enabled. Responds with an error to shut down
|
|
1657
|
-
* the agent if necessary.
|
|
1658
|
-
*
|
|
1659
|
-
* @param {Agent} agent Agent instance
|
|
1660
|
-
* @param {object} policies lasp policy
|
|
1661
|
-
* @returns {CollectorResponse} The result of the processing, with the known
|
|
1662
|
-
* policies as the response payload.
|
|
1663
|
-
*/
|
|
1664
|
-
Config.prototype.applyLasp = function applyLasp(agent, policies) {
|
|
1665
|
-
const keys = Object.keys(policies)
|
|
1666
|
-
|
|
1667
|
-
if (!this.security_policies_token) {
|
|
1668
|
-
return _laspResponse(keys)
|
|
1669
|
-
}
|
|
1670
|
-
|
|
1671
|
-
const { finalPolicies, missingRequired } = this._buildLaspPolicy(agent, policies)
|
|
1672
|
-
|
|
1673
|
-
const missingLASP = []
|
|
1674
|
-
for (const name of Object.keys(LASP_MAP)) {
|
|
1675
|
-
if (!policies[name]) {
|
|
1676
|
-
// agent is expecting a policy that was not sent from server -- fail
|
|
1677
|
-
missingLASP.push(name)
|
|
1678
|
-
}
|
|
1679
|
-
}
|
|
1680
|
-
|
|
1681
|
-
let fatalMessage = null
|
|
1682
|
-
if (missingLASP.length) {
|
|
1683
|
-
fatalMessage =
|
|
1684
|
-
'The agent did not receive one or more security policies that it ' +
|
|
1685
|
-
'expected and will shut down: ' +
|
|
1686
|
-
missingLASP.join(', ') +
|
|
1687
|
-
'.'
|
|
1688
|
-
} else if (missingRequired.length) {
|
|
1689
|
-
fatalMessage =
|
|
1690
|
-
'The agent received one or more required security policies that it ' +
|
|
1691
|
-
'does not recognize and will shut down: ' +
|
|
1692
|
-
missingRequired.join(', ') +
|
|
1693
|
-
'. Please check if a newer agent version supports these policies ' +
|
|
1694
|
-
'or contact support.'
|
|
1695
|
-
}
|
|
1696
|
-
|
|
1697
|
-
if (fatalMessage) {
|
|
1698
|
-
logger.error(fatalMessage)
|
|
1699
|
-
return CollectorResponse.fatal(null)
|
|
1700
|
-
}
|
|
1701
|
-
|
|
1702
|
-
return CollectorResponse.success(finalPolicies)
|
|
1703
|
-
}
|
|
1704
|
-
|
|
1705
1530
|
Config.prototype.validateFlags = function validateFlags() {
|
|
1706
1531
|
for (const key of Object.keys(this.feature_flag)) {
|
|
1707
1532
|
if (featureFlag.released.indexOf(key) > -1) {
|
|
@@ -1727,6 +1552,24 @@ function redactValue(value) {
|
|
|
1727
1552
|
return result
|
|
1728
1553
|
}
|
|
1729
1554
|
|
|
1555
|
+
/**
|
|
1556
|
+
* Redact a license key, preserving its original length.
|
|
1557
|
+
* The first 10 characters remain visible; the rest are replaced with '*'.
|
|
1558
|
+
* Keys of 10 or fewer characters are fully redacted.
|
|
1559
|
+
*
|
|
1560
|
+
* @param {string} key the license key to redact
|
|
1561
|
+
* @returns {string} the redacted key
|
|
1562
|
+
*/
|
|
1563
|
+
function redactLicenseKey(key) {
|
|
1564
|
+
if (!key) {
|
|
1565
|
+
return ''
|
|
1566
|
+
}
|
|
1567
|
+
if (key.length <= 10) {
|
|
1568
|
+
return '*'.repeat(key.length)
|
|
1569
|
+
}
|
|
1570
|
+
return key.substring(0, 10) + '*'.repeat(key.length - 10)
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1730
1573
|
/**
|
|
1731
1574
|
* Get a JSONifiable object containing all settings we want to report to the
|
|
1732
1575
|
* collector and store in the environment_values table.
|
|
@@ -1774,19 +1617,6 @@ Config.prototype.getAggregatorConfig = function getAggregatorConfig(method) {
|
|
|
1774
1617
|
}
|
|
1775
1618
|
}
|
|
1776
1619
|
|
|
1777
|
-
Config.prototype._warnDeprecations = function _warnDeprecations() {
|
|
1778
|
-
// DT overrides CAT so only warn when CAT is actually used.
|
|
1779
|
-
if (this.cross_application_tracer.enabled && !this.distributed_tracing.enabled) {
|
|
1780
|
-
const deprecationWarning = [
|
|
1781
|
-
'[Deprecation Warning]: Cross Application Tracing (CAT) has been deprecated and will be ',
|
|
1782
|
-
'removed in a future major release. CAT has been replaced by Distributed Tracing (DT). ',
|
|
1783
|
-
'Enable DT by setting distributed_tracing: { enabled: true }.'
|
|
1784
|
-
].join('')
|
|
1785
|
-
|
|
1786
|
-
logger.infoOnce('Deprecation:CAT', deprecationWarning)
|
|
1787
|
-
}
|
|
1788
|
-
}
|
|
1789
|
-
|
|
1790
1620
|
/**
|
|
1791
1621
|
* Create a configuration, either from a configuration file or the node
|
|
1792
1622
|
* process's environment.
|
|
@@ -35,7 +35,7 @@ class AsyncLocalContextManager {
|
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* Set a new active context. Not bound to function execution.
|
|
38
|
-
*
|
|
38
|
+
* **Note**: Should only be used in tests
|
|
39
39
|
*
|
|
40
40
|
* @param {object} newContext The context to set as active.
|
|
41
41
|
*/
|
|
@@ -53,14 +53,8 @@ class AsyncLocalContextManager {
|
|
|
53
53
|
* @param {Array<*>} [args] Optional arguments object or args array to invoke the callback with.
|
|
54
54
|
* @returns {*} Returns the value returned by the callback function.
|
|
55
55
|
*/
|
|
56
|
-
runInContext(context, callback, cbThis, args) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (args) {
|
|
60
|
-
return this._asyncLocalStorage.run(context, toInvoke, ...args)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return this._asyncLocalStorage.run(context, toInvoke)
|
|
56
|
+
runInContext(context, callback, cbThis, args = []) {
|
|
57
|
+
return this._asyncLocalStorage.run(context, Reflect.apply, callback, cbThis, args)
|
|
64
58
|
}
|
|
65
59
|
}
|
|
66
60
|
|
|
@@ -28,7 +28,7 @@ StatementMatcher.prototype.getParsedStatement = function getParsedStatement(sql)
|
|
|
28
28
|
// If the cleaner can match this collection, pull out the cleaned up names
|
|
29
29
|
// from there. The spec doesn't want the database names in the collection
|
|
30
30
|
// name, but for legacy reasons we keep it.
|
|
31
|
-
// TODO: Either update the spec
|
|
31
|
+
// TODO: Either update the spec to accept database name in the
|
|
32
32
|
// collection name or remove it here.
|
|
33
33
|
const cleanerMatch = CLEANER.exec(collection)
|
|
34
34
|
if (cleanerMatch && cleanerMatch[4]) {
|
package/lib/errors/index.js
CHANGED
|
@@ -293,8 +293,6 @@ function _getErrorEventIntrinsicAttrs(transaction, errorClass, message, expected
|
|
|
293
293
|
|
|
294
294
|
if (transaction.agent.config.distributed_tracing.enabled) {
|
|
295
295
|
transaction.addDistributedTraceIntrinsics(attributes)
|
|
296
|
-
} else {
|
|
297
|
-
attributes['nr.referringTransactionGuid'] = transaction.referringTransactionGuid
|
|
298
296
|
}
|
|
299
297
|
|
|
300
298
|
attributes['nr.transactionGuid'] = transaction.id
|