newrelic 8.8.0 → 8.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NEWS.md +65 -0
- package/README.md +3 -0
- package/THIRD_PARTY_NOTICES.md +4 -4
- package/lib/config/default.js +2 -0
- package/lib/config/env.js +2 -0
- package/lib/config/index.js +10 -2
- package/lib/instrumentation/mongodb/common.js +39 -2
- package/lib/instrumentation/mongodb/v3-mongo.js +4 -0
- package/lib/instrumentation/{mysql.js → mysql/mysql.js} +21 -14
- package/lib/instrumentation/mysql/nr-hooks.js +25 -0
- package/lib/instrumentations.js +1 -1
- package/lib/logger.js +10 -9
- package/lib/sampler.js +2 -21
- package/lib/serverless/aws-lambda.js +2 -3
- package/lib/shim/shim.js +5 -17
- package/lib/util/logger.js +36 -1
- package/lib/utilization/aws-info.js +1 -1
- package/package.json +4 -4
package/NEWS.md
CHANGED
|
@@ -1,3 +1,68 @@
|
|
|
1
|
+
### v8.10.0 (2022-04-18)
|
|
2
|
+
|
|
3
|
+
* Added instrumentation for `mysql2/promise`.
|
|
4
|
+
* This previously only existed in our standalone `@newrelic/mysql`, but now gives feature partiy between the two.
|
|
5
|
+
|
|
6
|
+
* Removed unused native CPU metric sampler. This logic was no longer getting touched if running Node.js > 6.1.0.
|
|
7
|
+
|
|
8
|
+
* Fixed promise interceptor from re-throwing errors.
|
|
9
|
+
|
|
10
|
+
* Added transaction naming documentation ported from a discussion forum post: https://discuss.newrelic.com/t/relic-solution-the-philosophy-of-naming-your-node-agent-transactions/.
|
|
11
|
+
|
|
12
|
+
* Added `promises.tap.js` to mysql2 versioned tests.
|
|
13
|
+
|
|
14
|
+
* Updated @newrelic/test-utilities to latest.
|
|
15
|
+
* Removed unused test file in restify versioned tests.
|
|
16
|
+
* Added `--strict` flag to versioned test runner to properly fail CI runs when test files are not included.
|
|
17
|
+
|
|
18
|
+
### v8.9.1 (2022-03-22)
|
|
19
|
+
|
|
20
|
+
* Fixed `shim.wrapReturn` to call `Reflect.construct` in construct Proxy trap. Also including `newTarget` to work with inherited classes.
|
|
21
|
+
|
|
22
|
+
* Added link to New Relic Node.js Examples repository.
|
|
23
|
+
|
|
24
|
+
* Excluded installing dependencies in `versioned-external` folders when running integration tests.
|
|
25
|
+
|
|
26
|
+
### v8.9.0 (2022-03-15)
|
|
27
|
+
|
|
28
|
+
* Added support for `initializeUnorderedBulkOp`, and `initializeOrderedBulkOp` in mongodb v3 instrumentation.
|
|
29
|
+
|
|
30
|
+
Thanks to Denis Lantsman (@dlants) for the contribution.
|
|
31
|
+
|
|
32
|
+
* Updated logger to delay logging until configuration is parsed. The logger will now queue all log entries that occur before the agent can parse the configuration.
|
|
33
|
+
|
|
34
|
+
Thanks to Cody Landry (@codylandry) for the contribution.
|
|
35
|
+
|
|
36
|
+
* Added `NEW_RELIC_ALLOW_ALL_HEADERS` as a boolean environment variable, same behavior as existing `allow_all_headers`.
|
|
37
|
+
|
|
38
|
+
* Updated the AWS IMDBS v2 endpoint to use `latest` to align with the internal agent specification.
|
|
39
|
+
|
|
40
|
+
* Bumped `@newrelic/koa` to ^6.1.1.
|
|
41
|
+
|
|
42
|
+
* Added Next.js to External Modules list in README.
|
|
43
|
+
|
|
44
|
+
* Updated mysql and mysql2 versioned tests to run against their own databases on the MySQL instance.
|
|
45
|
+
|
|
46
|
+
* Removed upper-bound testing from restify versioned tests so future major versions will be covered.
|
|
47
|
+
|
|
48
|
+
* Removed upper-bound testing from mysql2 versioned tests to cover existing and future major versions.
|
|
49
|
+
|
|
50
|
+
Continues to skip version 1.6.2 which had a bug that broke tests which was resolved in 1.6.3.
|
|
51
|
+
|
|
52
|
+
* Updated @hapi/hapi Node 16 versioned test runs to run against @hapi/hapi >=20.1.2 so future major releases will be ran.
|
|
53
|
+
|
|
54
|
+
* Fixed sparse checkout of non-default branch for external versioned tests.
|
|
55
|
+
|
|
56
|
+
* Added external versioned tests for the Apollo Server plugin instrumentation.
|
|
57
|
+
|
|
58
|
+
* Added nock delay to test timeouts in utilization integration tests.
|
|
59
|
+
|
|
60
|
+
* Added newrelic-node-nextjs to external versioned tests to be run on every PR.
|
|
61
|
+
|
|
62
|
+
* Updated external version test running to support more test scenarios.
|
|
63
|
+
* Adds `test/versioned-external` to lint ignore to avoid issues for scripts in tests that auto run linting tools (next/react).
|
|
64
|
+
* Adds `index.js` and `nr-hooks.js` to files automatically checked-out for test runs.
|
|
65
|
+
|
|
1
66
|
### v8.8.0 (2022-02-23)
|
|
2
67
|
|
|
3
68
|
* Updated AWS metadata capture to utilize IMDSv2.
|
package/README.md
CHANGED
|
@@ -70,6 +70,7 @@ There are several modules that can be installed and configured to accompany the
|
|
|
70
70
|
* [@newrelic/winston-enricher](https://github.com/newrelic/newrelic-node-log-extensions/tree/main/packages/winston-log-enricher): Provides distributed trace and span information output as JSON-formatted log messages in Winston. This is most commonly used with the New Relic Logs product.
|
|
71
71
|
* [@newrelic/pino-enricher](https://github.com/newrelic/newrelic-node-log-extensions/tree/main/packages/pino-log-enricher): Provides distributed trace and span information output as JSON-formatted log messages in Pino. This is most commonly used with the New Relic Logs product.
|
|
72
72
|
* [@newrelic/mysql](https://github.com/newrelic/node-newrelic-mysql)(**Experimental**): Standalone instrumentation for [mysql2](https://github.com/sidorares/node-mysql2#readme) and [mysql2/promise](https://github.com/sidorares/node-mysql2/blob/master/documentation/Promise-Wrapper.md) as well as the same instrumentation for [mysql](https://github.com/mysqljs/mysql#readme) within the Node.js agent.
|
|
73
|
+
* [@newrelic/next](https://github.com/newrelic/newrelic-node-nextjs): Provides instrumentation for the [Next.js](https://github.com/vercel/next.js/) npm package.
|
|
73
74
|
|
|
74
75
|
There are several modules included within the Node.js agent to add more instrumentation for 3rd party modules:
|
|
75
76
|
|
|
@@ -144,6 +145,8 @@ Here are some resources for learning more about the agent:
|
|
|
144
145
|
|
|
145
146
|
- [The changelog](https://github.com/newrelic/node-newrelic/blob/main/NEWS.md)
|
|
146
147
|
|
|
148
|
+
- [Example applications](https://github.com/newrelic/newrelic-node-examples) - Working examples of New Relic features in Node.js.
|
|
149
|
+
|
|
147
150
|
## Support
|
|
148
151
|
|
|
149
152
|
Should you need assistance with New Relic products, you are in good hands with several support channels.
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -712,7 +712,7 @@ This product includes source derived from [@newrelic/aws-sdk](https://github.com
|
|
|
712
712
|
|
|
713
713
|
### @newrelic/koa
|
|
714
714
|
|
|
715
|
-
This product includes source derived from [@newrelic/koa](https://github.com/newrelic/node-newrelic-koa) ([v6.1.
|
|
715
|
+
This product includes source derived from [@newrelic/koa](https://github.com/newrelic/node-newrelic-koa) ([v6.1.1](https://github.com/newrelic/node-newrelic-koa/tree/v6.1.1)), distributed under the [Apache-2.0 License](https://github.com/newrelic/node-newrelic-koa/blob/v6.1.1/LICENSE):
|
|
716
716
|
|
|
717
717
|
```
|
|
718
718
|
Apache License
|
|
@@ -1770,7 +1770,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|
|
1770
1770
|
|
|
1771
1771
|
### @newrelic/test-utilities
|
|
1772
1772
|
|
|
1773
|
-
This product includes source derived from [@newrelic/test-utilities](https://github.com/newrelic/node-test-utilities) ([v6.
|
|
1773
|
+
This product includes source derived from [@newrelic/test-utilities](https://github.com/newrelic/node-test-utilities) ([v6.5.2](https://github.com/newrelic/node-test-utilities/tree/v6.5.2)), distributed under the [Apache-2.0 License](https://github.com/newrelic/node-test-utilities/blob/v6.5.2/LICENSE):
|
|
1774
1774
|
|
|
1775
1775
|
```
|
|
1776
1776
|
Apache License
|
|
@@ -2456,7 +2456,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|
|
2456
2456
|
|
|
2457
2457
|
### glob
|
|
2458
2458
|
|
|
2459
|
-
This product includes source derived from [glob](https://github.com/isaacs/node-glob) ([v7.
|
|
2459
|
+
This product includes source derived from [glob](https://github.com/isaacs/node-glob) ([v7.2.0](https://github.com/isaacs/node-glob/tree/v7.2.0)), distributed under the [ISC License](https://github.com/isaacs/node-glob/blob/v7.2.0/LICENSE):
|
|
2460
2460
|
|
|
2461
2461
|
```
|
|
2462
2462
|
The ISC License
|
|
@@ -3377,7 +3377,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
3377
3377
|
|
|
3378
3378
|
### @newrelic/native-metrics
|
|
3379
3379
|
|
|
3380
|
-
This product includes source derived from [@newrelic/native-metrics](https://github.com/newrelic/node-native-metrics) ([
|
|
3380
|
+
This product includes source derived from [@newrelic/native-metrics](https://github.com/newrelic/node-native-metrics) ([v8.0.0](https://github.com/newrelic/node-native-metrics/tree/v8.0.0)), distributed under the [Apache-2.0 License](https://github.com/newrelic/node-native-metrics/blob/v8.0.0/LICENSE):
|
|
3381
3381
|
|
|
3382
3382
|
```
|
|
3383
3383
|
Apache License
|
package/lib/config/default.js
CHANGED
|
@@ -134,6 +134,8 @@ exports.config = () => ({
|
|
|
134
134
|
* When true, all request headers except for those listed in attributes.exclude
|
|
135
135
|
* will be captured for all traces, unless otherwise specified in a destination's
|
|
136
136
|
* attributes include/exclude lists.
|
|
137
|
+
*
|
|
138
|
+
* @env NEW_RELIC_ALLOW_ALL_HEADERS
|
|
137
139
|
*/
|
|
138
140
|
allow_all_headers: false,
|
|
139
141
|
|
package/lib/config/env.js
CHANGED
|
@@ -21,6 +21,7 @@ const ENV_MAPPING = {
|
|
|
21
21
|
proxy_user: 'NEW_RELIC_PROXY_USER',
|
|
22
22
|
proxy_pass: 'NEW_RELIC_PROXY_PASS',
|
|
23
23
|
agent_enabled: 'NEW_RELIC_ENABLED',
|
|
24
|
+
allow_all_headers: 'NEW_RELIC_ALLOW_ALL_HEADERS',
|
|
24
25
|
attributes: {
|
|
25
26
|
enabled: 'NEW_RELIC_ATTRIBUTES_ENABLED',
|
|
26
27
|
exclude: 'NEW_RELIC_ATTRIBUTES_EXCLUDE',
|
|
@@ -206,6 +207,7 @@ const OBJECT_LIST_VARS = new Set(['NEW_RELIC_NAMING_RULES'])
|
|
|
206
207
|
// fancy--just use 'true' and 'false', everybody.
|
|
207
208
|
const BOOLEAN_VARS = new Set([
|
|
208
209
|
'NEW_RELIC_ENABLED',
|
|
210
|
+
'NEW_RELIC_ALLOW_ALL_HEADERS',
|
|
209
211
|
'NEW_RELIC_ATTRIBUTES_ENABLED',
|
|
210
212
|
'NEW_RELIC_ERROR_COLLECTOR_ENABLED',
|
|
211
213
|
'NEW_RELIC_ERROR_COLLECTOR_ATTRIBUTES_ENABLED',
|
package/lib/config/index.js
CHANGED
|
@@ -1623,7 +1623,8 @@ function initialize(config) {
|
|
|
1623
1623
|
/**
|
|
1624
1624
|
* When the logger is required here, it bootstraps itself and then
|
|
1625
1625
|
* injects itself into this module's closure via setLogger on the
|
|
1626
|
-
* instance of the logger it creates.
|
|
1626
|
+
* instance of the logger it creates. Logs are queued until config
|
|
1627
|
+
* has been loaded to apply logging settings to bootstrapping logs
|
|
1627
1628
|
*/
|
|
1628
1629
|
logger = require('../logger')
|
|
1629
1630
|
|
|
@@ -1712,7 +1713,14 @@ function getOrCreateInstance() {
|
|
|
1712
1713
|
|
|
1713
1714
|
// Config construction has potential to throw due to invalid settings.
|
|
1714
1715
|
// This allows the agent to return a stub api without crashing the process.
|
|
1715
|
-
_configInstance = Object.assign(defaultConfig(), {
|
|
1716
|
+
_configInstance = Object.assign(defaultConfig(), {
|
|
1717
|
+
agent_enabled: false,
|
|
1718
|
+
logging: {
|
|
1719
|
+
enabled: true,
|
|
1720
|
+
filepath: 'stdout'
|
|
1721
|
+
}
|
|
1722
|
+
})
|
|
1723
|
+
|
|
1716
1724
|
_configInstance.setLogger = Config.prototype.setLogger
|
|
1717
1725
|
}
|
|
1718
1726
|
}
|
|
@@ -43,6 +43,23 @@ common.instrumentCollection = function instrumentCollection(shim, Collection) {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Instruments the execute method on
|
|
48
|
+
* the BulkOperationBase class
|
|
49
|
+
*
|
|
50
|
+
* @param {Shim} shim
|
|
51
|
+
* @param {BulkOperationModule} bulk operation module, typically from mongodb/lib/bulk/common
|
|
52
|
+
* @param BulkOperationModule
|
|
53
|
+
*/
|
|
54
|
+
common.instrumentBulkOperation = function instrumentBulkOperation(shim, BulkOperationModule) {
|
|
55
|
+
const BulkOperationBase = BulkOperationModule && BulkOperationModule.BulkOperationBase
|
|
56
|
+
|
|
57
|
+
if (BulkOperationBase && BulkOperationBase.prototype) {
|
|
58
|
+
const proto = BulkOperationBase.prototype
|
|
59
|
+
shim.recordBatchQuery(proto, 'execute', common.makeBulkDescFunc(shim, 'execute'))
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
46
63
|
/**
|
|
47
64
|
* Instruments all methods from constants.DB_OPS on
|
|
48
65
|
* the Db class.
|
|
@@ -84,6 +101,25 @@ common.makeQueryDescFunc = function makeQueryDescFunc(shim, methodName) {
|
|
|
84
101
|
}
|
|
85
102
|
}
|
|
86
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Sets up the desc for all instrumented bulk operations
|
|
106
|
+
*
|
|
107
|
+
* @param {Shim} shim
|
|
108
|
+
* @param {string} methodName
|
|
109
|
+
*/
|
|
110
|
+
common.makeBulkDescFunc = function makeBulkDescFunc(shim) {
|
|
111
|
+
return function bulkDescFunc() {
|
|
112
|
+
const parameters = getInstanceAttributeParameters(shim, this)
|
|
113
|
+
return {
|
|
114
|
+
query: this.isOrdered ? 'orderedBulk' : 'unorderedBulk',
|
|
115
|
+
parameters,
|
|
116
|
+
promise: true,
|
|
117
|
+
callback: shim.LAST,
|
|
118
|
+
opaque: true
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
87
123
|
/**
|
|
88
124
|
* Sets up a listener for `started` on instrumenter(mongo APM). This applies to
|
|
89
125
|
* mongo <4. The listener adds the following attributes to the active segment:
|
|
@@ -161,9 +197,10 @@ function setHostPort(shim, connStr, db, client) {
|
|
|
161
197
|
* @param obj
|
|
162
198
|
*/
|
|
163
199
|
function getInstanceAttributeParameters(shim, obj) {
|
|
164
|
-
if (obj.s && obj.s.
|
|
200
|
+
if (obj.s && obj.s.topology) {
|
|
165
201
|
shim.logger.trace('Adding datastore instance attributes from obj.s.db + obj.s.topology')
|
|
166
|
-
const databaseName =
|
|
202
|
+
const databaseName =
|
|
203
|
+
(obj.s.db && obj.s.db.databaseName) || (obj.s.namespace && obj.s.namespace.db) || null
|
|
167
204
|
const topology = obj.s.topology
|
|
168
205
|
if (topology.s && topology.s.options) {
|
|
169
206
|
return doCapture(topology.s.options, databaseName)
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
const {
|
|
9
9
|
captureAttributesOnStarted,
|
|
10
|
+
instrumentBulkOperation,
|
|
10
11
|
instrumentCollection,
|
|
11
12
|
instrumentCursor,
|
|
12
13
|
instrumentDb,
|
|
@@ -27,6 +28,8 @@ function queryParser(operation) {
|
|
|
27
28
|
collection = this.operation.target
|
|
28
29
|
} else if (this.ns) {
|
|
29
30
|
collection = this.ns.split(/\./)[1] || collection
|
|
31
|
+
} else if (this.s && this.s.collection && this.s.collection.collectionName) {
|
|
32
|
+
collection = this.s.collection.collectionName
|
|
30
33
|
}
|
|
31
34
|
return { operation, collection }
|
|
32
35
|
}
|
|
@@ -68,6 +71,7 @@ module.exports = function instrument(shim, mongodb) {
|
|
|
68
71
|
instrumentCursor(shim, mongodb.Cursor)
|
|
69
72
|
instrumentCursor(shim, shim.require('./lib/aggregation_cursor'))
|
|
70
73
|
instrumentCursor(shim, shim.require('./lib/command_cursor'))
|
|
74
|
+
instrumentBulkOperation(shim, shim.require('./lib/bulk/common'))
|
|
71
75
|
instrumentCollection(shim, mongodb.Collection)
|
|
72
76
|
instrumentDb(shim, mongodb.Db)
|
|
73
77
|
|
|
@@ -5,17 +5,17 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
const dbutils = require('
|
|
9
|
-
const properties = require('
|
|
8
|
+
const dbutils = require('../../db/utils')
|
|
9
|
+
const properties = require('../../util/properties')
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
exports.callbackInitialize = function callbackInitialize(shim, mysql) {
|
|
12
12
|
shim.setDatastore(shim.MYSQL)
|
|
13
13
|
shim.__wrappedPoolConnection = false
|
|
14
14
|
|
|
15
15
|
shim.wrapReturn(mysql, 'createConnection', wrapCreateConnection)
|
|
16
16
|
function wrapCreateConnection(shim, fn, fnName, connection) {
|
|
17
17
|
shim.logger.debug('Wrapping Connection#query')
|
|
18
|
-
if (
|
|
18
|
+
if (wrapQueryable(shim, connection, false)) {
|
|
19
19
|
const connProto = Object.getPrototypeOf(connection)
|
|
20
20
|
shim.setInternalProperty(connProto, '__NR_storeDatabase', true)
|
|
21
21
|
shim.unwrap(mysql, 'createConnection')
|
|
@@ -25,7 +25,7 @@ module.exports = function initialize(agent, mysql, moduleName, shim) {
|
|
|
25
25
|
shim.wrapReturn(mysql, 'createPool', wrapCreatePool)
|
|
26
26
|
function wrapCreatePool(shim, fn, fnName, pool) {
|
|
27
27
|
shim.logger.debug('Wrapping Pool#query and Pool#getConnection')
|
|
28
|
-
if (
|
|
28
|
+
if (wrapQueryable(shim, pool, true) && wrapGetConnection(shim, pool)) {
|
|
29
29
|
shim.unwrap(mysql, 'createPool')
|
|
30
30
|
}
|
|
31
31
|
}
|
|
@@ -48,6 +48,13 @@ module.exports = function initialize(agent, mysql, moduleName, shim) {
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
exports.promiseInitialize = function promiseInitialize(shim) {
|
|
52
|
+
const callbackAPI = shim.require('./index')
|
|
53
|
+
if (callbackAPI && !shim.isWrapped(callbackAPI.createConnection)) {
|
|
54
|
+
exports.callbackInitialize(shim, callbackAPI)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
51
58
|
function wrapGetConnection(shim, connectable) {
|
|
52
59
|
if (!connectable || !connectable.getConnection || shim.isWrapped(connectable.getConnection)) {
|
|
53
60
|
shim.logger.trace(
|
|
@@ -91,7 +98,7 @@ function wrapGetConnectionCallback(shim, cb) {
|
|
|
91
98
|
return function wrappedGetConnectionCallback(err, conn) {
|
|
92
99
|
try {
|
|
93
100
|
shim.logger.debug('Wrapping PoolConnection#query')
|
|
94
|
-
if (!err &&
|
|
101
|
+
if (!err && wrapQueryable(shim, conn, false)) {
|
|
95
102
|
// Leave getConnection wrapped in order to maintain TX state, but we can
|
|
96
103
|
// simplify the wrapping of its callback in future calls.
|
|
97
104
|
shim.__wrappedPoolConnection = true
|
|
@@ -106,20 +113,20 @@ function wrapGetConnectionCallback(shim, cb) {
|
|
|
106
113
|
}
|
|
107
114
|
}
|
|
108
115
|
|
|
109
|
-
function
|
|
110
|
-
if (!
|
|
116
|
+
function wrapQueryable(shim, queryable, isPoolQuery) {
|
|
117
|
+
if (!queryable || !queryable.query || shim.isWrapped(queryable.query)) {
|
|
111
118
|
shim.logger.debug(
|
|
112
119
|
{
|
|
113
|
-
|
|
114
|
-
query: !!(
|
|
115
|
-
isWrapped: !!(
|
|
120
|
+
queryable: !!queryable,
|
|
121
|
+
query: !!(queryable && queryable.query),
|
|
122
|
+
isWrapped: !!(queryable && shim.isWrapped(queryable.query))
|
|
116
123
|
},
|
|
117
|
-
'Not
|
|
124
|
+
'Not wrapping queryable'
|
|
118
125
|
)
|
|
119
126
|
return false
|
|
120
127
|
}
|
|
121
128
|
|
|
122
|
-
const proto = Object.getPrototypeOf(
|
|
129
|
+
const proto = Object.getPrototypeOf(queryable)
|
|
123
130
|
|
|
124
131
|
let describe
|
|
125
132
|
if (isPoolQuery) {
|
|
@@ -131,7 +138,7 @@ function wrapQueriable(shim, queriable, isPoolQuery) {
|
|
|
131
138
|
|
|
132
139
|
shim.recordQuery(proto, 'query', describe)
|
|
133
140
|
|
|
134
|
-
if (
|
|
141
|
+
if (queryable.execute) {
|
|
135
142
|
shim.recordQuery(proto, 'execute', describe)
|
|
136
143
|
}
|
|
137
144
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
const instrumentation = require('./mysql')
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* We only need to register the instrumentation once for both mysql and mysql2
|
|
11
|
+
* because there is some 🪄 in shimmer
|
|
12
|
+
* See: https://github.com/newrelic/node-newrelic/blob/main/lib/shimmer.js#L459
|
|
13
|
+
*/
|
|
14
|
+
module.exports = [
|
|
15
|
+
{
|
|
16
|
+
type: 'datastore',
|
|
17
|
+
moduleName: 'mysql',
|
|
18
|
+
onRequire: instrumentation.callbackInitialize
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
type: 'datastore',
|
|
22
|
+
moduleName: 'mysql2/promise',
|
|
23
|
+
onRequire: instrumentation.promiseInitialize
|
|
24
|
+
}
|
|
25
|
+
]
|
package/lib/instrumentations.js
CHANGED
|
@@ -25,7 +25,7 @@ module.exports = function instrumentations() {
|
|
|
25
25
|
'koa': { module: '@newrelic/koa' },
|
|
26
26
|
'memcached': { type: MODULE_TYPE.DATASTORE },
|
|
27
27
|
'mongodb': { type: MODULE_TYPE.DATASTORE },
|
|
28
|
-
'mysql': {
|
|
28
|
+
'mysql': { module: './instrumentation/mysql' },
|
|
29
29
|
'pg': { type: MODULE_TYPE.DATASTORE },
|
|
30
30
|
'q': { type: null },
|
|
31
31
|
'redis': { type: MODULE_TYPE.DATASTORE },
|
package/lib/logger.js
CHANGED
|
@@ -9,12 +9,16 @@ const Logger = require('./util/logger')
|
|
|
9
9
|
const fs = require('./util/unwrapped-core').fs
|
|
10
10
|
|
|
11
11
|
// create bootstrapping logger
|
|
12
|
-
|
|
12
|
+
const logger = new Logger({
|
|
13
13
|
name: 'newrelic_bootstrap',
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
level: 'info',
|
|
15
|
+
|
|
16
|
+
// logger is configured below. Logs are queued until configured
|
|
17
|
+
configured: false
|
|
16
18
|
})
|
|
17
19
|
|
|
20
|
+
module.exports = logger
|
|
21
|
+
|
|
18
22
|
/**
|
|
19
23
|
* Don't load config until this point, because it requires this
|
|
20
24
|
* module, and if it gets loaded too early, module.exports will have no
|
|
@@ -28,8 +32,8 @@ if (config) {
|
|
|
28
32
|
enabled: config.logging.enabled
|
|
29
33
|
}
|
|
30
34
|
|
|
31
|
-
//
|
|
32
|
-
|
|
35
|
+
// configure logger
|
|
36
|
+
logger.configure(options)
|
|
33
37
|
|
|
34
38
|
if (config.logging.enabled) {
|
|
35
39
|
let stream
|
|
@@ -52,9 +56,6 @@ if (config) {
|
|
|
52
56
|
/* eslint-enable no-console */
|
|
53
57
|
})
|
|
54
58
|
}
|
|
55
|
-
|
|
59
|
+
logger.pipe(stream)
|
|
56
60
|
}
|
|
57
|
-
|
|
58
|
-
// now tell the config module to switch to the real logger
|
|
59
|
-
config.setLogger(module.exports)
|
|
60
61
|
}
|
package/lib/sampler.js
CHANGED
|
@@ -109,17 +109,6 @@ function sampleCpu(agent) {
|
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
function sampleCpuNative(agent, nativeMetrics) {
|
|
113
|
-
const recordCPU = generateCPUMetricRecorder(agent)
|
|
114
|
-
nativeMetrics.on('usage', function collectResourceUsage(usage) {
|
|
115
|
-
recordCPU(usage.diff.ru_utime / MILLIS, usage.diff.ru_stime / MILLIS)
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
return function cpuSampler() {
|
|
119
|
-
// NOOP?
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
112
|
function sampleLoop(agent, nativeMetrics) {
|
|
124
113
|
return function loopSampler() {
|
|
125
114
|
// Convert from microseconds to seconds
|
|
@@ -195,16 +184,8 @@ module.exports = {
|
|
|
195
184
|
}
|
|
196
185
|
}
|
|
197
186
|
|
|
198
|
-
// Add CPU sampling using the built-in data
|
|
199
|
-
|
|
200
|
-
if (process.cpuUsage) {
|
|
201
|
-
// introduced in 6.1.0
|
|
202
|
-
samplers.push(new Sampler(sampleCpu(agent), SAMPLE_INTERVAL))
|
|
203
|
-
} else if (this.nativeMetrics && this.nativeMetrics.usageEnabled) {
|
|
204
|
-
samplers.push(new Sampler(sampleCpuNative(agent, this.nativeMetrics), SAMPLE_INTERVAL))
|
|
205
|
-
} else {
|
|
206
|
-
logger.debug('Not adding CPU metric sampler.')
|
|
207
|
-
}
|
|
187
|
+
// Add CPU sampling using the built-in data (introduced in 6.1.0)
|
|
188
|
+
samplers.push(new Sampler(sampleCpu(agent), SAMPLE_INTERVAL))
|
|
208
189
|
|
|
209
190
|
this.state = 'running'
|
|
210
191
|
},
|
|
@@ -199,20 +199,19 @@ class AwsLambda {
|
|
|
199
199
|
// we need to store the error in uncaughtException
|
|
200
200
|
// otherwise the transaction will end before they are captured
|
|
201
201
|
function lambdaInterceptPromise(prom, resultProcessor, cb) {
|
|
202
|
-
|
|
202
|
+
prom.then(
|
|
203
203
|
function onThen(arg) {
|
|
204
204
|
if (resultProcessor) {
|
|
205
205
|
resultProcessor(arg)
|
|
206
206
|
}
|
|
207
207
|
cb()
|
|
208
|
-
return arg
|
|
209
208
|
},
|
|
210
209
|
function onCatch(err) {
|
|
211
210
|
uncaughtException = err
|
|
212
211
|
cb()
|
|
213
|
-
throw err // This is not our error, just rethrowing the promise rejection.
|
|
214
212
|
}
|
|
215
213
|
)
|
|
214
|
+
return prom
|
|
216
215
|
}
|
|
217
216
|
|
|
218
217
|
function wrapCallbackAndCaptureError(transaction, txnEnder, cb, processResult) {
|
package/lib/shim/shim.js
CHANGED
|
@@ -639,10 +639,9 @@ function wrapReturn(nodule, properties, spec, args) {
|
|
|
639
639
|
}
|
|
640
640
|
return true
|
|
641
641
|
},
|
|
642
|
-
construct: function constructTrap(
|
|
643
|
-
// Call the underlying function
|
|
644
|
-
|
|
645
|
-
let ret = new Target(...proxyArgs)
|
|
642
|
+
construct: function constructTrap(target, proxyArgs, newTarget) {
|
|
643
|
+
// Call the underlying function via Reflect.
|
|
644
|
+
let ret = Reflect.construct(target, proxyArgs, newTarget)
|
|
646
645
|
|
|
647
646
|
// Assemble the arguments to hand to the spec.
|
|
648
647
|
const _args = [shim, fn, fnName, ret]
|
|
@@ -1747,19 +1746,8 @@ function shimRequire(filePath) {
|
|
|
1747
1746
|
* @returns {Promise} A new promise to replace the original one.
|
|
1748
1747
|
*/
|
|
1749
1748
|
function interceptPromise(prom, cb) {
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
}
|
|
1753
|
-
return prom.then(
|
|
1754
|
-
function onThen(arg) {
|
|
1755
|
-
cb()
|
|
1756
|
-
return arg
|
|
1757
|
-
},
|
|
1758
|
-
function onCatch(err) {
|
|
1759
|
-
cb()
|
|
1760
|
-
throw err // This is not our error, just rethrowing the promise rejection.
|
|
1761
|
-
}
|
|
1762
|
-
)
|
|
1749
|
+
prom.then(cb, cb)
|
|
1750
|
+
return prom
|
|
1763
1751
|
}
|
|
1764
1752
|
|
|
1765
1753
|
/**
|
package/lib/util/logger.js
CHANGED
|
@@ -39,7 +39,8 @@ function Logger(options, extra) {
|
|
|
39
39
|
const passedInLevel = this.coerce(options.level)
|
|
40
40
|
this.options = {
|
|
41
41
|
_level: passedInLevel,
|
|
42
|
-
enabled: options.enabled === undefined ? true : options.enabled
|
|
42
|
+
enabled: options.enabled === undefined ? true : options.enabled,
|
|
43
|
+
configured: options.configured === undefined ? true : !!options.configured
|
|
43
44
|
}
|
|
44
45
|
this._nestedLog = false
|
|
45
46
|
this.name = options.name
|
|
@@ -47,12 +48,30 @@ function Logger(options, extra) {
|
|
|
47
48
|
this.extra = extra || Object.create(null)
|
|
48
49
|
this.buffer = ''
|
|
49
50
|
this.reading = false
|
|
51
|
+
this.logQueue = []
|
|
50
52
|
if (options.stream) {
|
|
51
53
|
this.pipe(options.stream)
|
|
52
54
|
}
|
|
53
55
|
}
|
|
54
56
|
Logger.MAX_LOG_BUFFER = MAX_LOG_BUFFER
|
|
55
57
|
|
|
58
|
+
Logger.prototype.configure = function configure(options) {
|
|
59
|
+
if (options.name !== undefined) {
|
|
60
|
+
this.name = options.name
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (options.enabled !== undefined) {
|
|
64
|
+
this.options.enabled = options.enabled
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (options.level !== undefined) {
|
|
68
|
+
this.options._level = this.coerce(options.level)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
this.options.configured = true
|
|
72
|
+
this._flushQueuedLogs()
|
|
73
|
+
}
|
|
74
|
+
|
|
56
75
|
Logger.prototype.coerce = function coerce(value) {
|
|
57
76
|
if (!isNaN(parseInt(value, 10)) && isFinite(value)) {
|
|
58
77
|
// value is numeric
|
|
@@ -74,6 +93,11 @@ Object.keys(LEVELS).forEach(function buildLevel(_level) {
|
|
|
74
93
|
const level = Logger.prototype.coerce(LEVELS[_level])
|
|
75
94
|
|
|
76
95
|
function log(extra) {
|
|
96
|
+
if (!this.options.configured) {
|
|
97
|
+
this.logQueue.unshift({ level: _level, args: arguments })
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
|
|
77
101
|
if (!this.options.enabled) {
|
|
78
102
|
return false
|
|
79
103
|
}
|
|
@@ -149,6 +173,13 @@ Object.keys(LEVELS).forEach(function buildLevel(_level) {
|
|
|
149
173
|
}
|
|
150
174
|
})
|
|
151
175
|
|
|
176
|
+
Logger.prototype._flushQueuedLogs = function _flushQueuedLogs() {
|
|
177
|
+
while (this.logQueue.length) {
|
|
178
|
+
const { level, args } = this.logQueue.shift()
|
|
179
|
+
this[level].apply(this, args)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
152
183
|
Object.assign(Logger.prototype, loggingFunctions)
|
|
153
184
|
|
|
154
185
|
Logger.prototype.child = function child(extra) {
|
|
@@ -196,6 +227,10 @@ Logger.prototype._read = function _read() {
|
|
|
196
227
|
* already converted the objects to strings.
|
|
197
228
|
* Returns a boolean representing the status of the write
|
|
198
229
|
* (success/failure)
|
|
230
|
+
*
|
|
231
|
+
* @param level
|
|
232
|
+
* @param args
|
|
233
|
+
* @param extra
|
|
199
234
|
*/
|
|
200
235
|
Logger.prototype.write = function write(level, args, extra) {
|
|
201
236
|
if (this._nestedLog) {
|
|
@@ -42,7 +42,7 @@ function fetchAWSInfo(agent, callback) {
|
|
|
42
42
|
headers: { 'X-aws-ec2-metadata-token': authToken },
|
|
43
43
|
host: INSTANCE_HOST,
|
|
44
44
|
method: 'GET',
|
|
45
|
-
path: '/
|
|
45
|
+
path: '/latest/dynamic/instance-identity/document',
|
|
46
46
|
timeout: 500
|
|
47
47
|
}
|
|
48
48
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "newrelic",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.10.0",
|
|
4
4
|
"author": "New Relic Node.js agent team <nodejs@newrelic.com>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"contributors": [
|
|
@@ -162,7 +162,7 @@
|
|
|
162
162
|
"@grpc/grpc-js": "^1.5.5",
|
|
163
163
|
"@grpc/proto-loader": "^0.6.9",
|
|
164
164
|
"@newrelic/aws-sdk": "^4.1.1",
|
|
165
|
-
"@newrelic/koa": "^6.1.
|
|
165
|
+
"@newrelic/koa": "^6.1.1",
|
|
166
166
|
"@newrelic/superagent": "^5.1.0",
|
|
167
167
|
"@tyriar/fibonacci-heap": "^2.0.7",
|
|
168
168
|
"async": "^3.2.3",
|
|
@@ -173,13 +173,13 @@
|
|
|
173
173
|
"semver": "^5.3.0"
|
|
174
174
|
},
|
|
175
175
|
"optionalDependencies": {
|
|
176
|
-
"@newrelic/native-metrics": "^
|
|
176
|
+
"@newrelic/native-metrics": "^8.0.0"
|
|
177
177
|
},
|
|
178
178
|
"devDependencies": {
|
|
179
179
|
"@newrelic/eslint-config": "^0.0.3",
|
|
180
180
|
"@newrelic/newrelic-oss-cli": "^0.1.2",
|
|
181
181
|
"@newrelic/proxy": "^2.0.0",
|
|
182
|
-
"@newrelic/test-utilities": "^6.
|
|
182
|
+
"@newrelic/test-utilities": "^6.5.2",
|
|
183
183
|
"@octokit/rest": "^18.0.15",
|
|
184
184
|
"@slack/bolt": "^3.7.0",
|
|
185
185
|
"ajv": "^6.12.6",
|