newrelic 9.2.0 → 9.3.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 +10 -0
- package/README.md +41 -0
- package/THIRD_PARTY_NOTICES.md +23 -0
- package/lib/instrumentation/bunyan.js +110 -0
- package/lib/instrumentations.js +1 -0
- package/lib/metrics/names.js +2 -0
- package/package.json +5 -4
package/NEWS.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
### v9.3.0 (2022-10-17)
|
|
2
|
+
|
|
3
|
+
* Added instrumentation to bunyan to support application logging use cases: forwarding, local decorating, and metrics.
|
|
4
|
+
|
|
5
|
+
Big thanks to @brianphillips for his contribution 🚀
|
|
6
|
+
|
|
7
|
+
* Added c8 to track code coverage.
|
|
8
|
+
|
|
9
|
+
* Added documentation about custom instrumentation in ES module applications
|
|
10
|
+
|
|
1
11
|
### v9.2.0 (2022-10-06)
|
|
2
12
|
|
|
3
13
|
* Added ability to instrument ES Modules with the New Relic ESM Loader.
|
package/README.md
CHANGED
|
@@ -84,6 +84,47 @@ $ node --experimental-loader newrelic/esm-loader.mjs your-program.js
|
|
|
84
84
|
|
|
85
85
|
**Note**: Unlike the CommonJS methods listed above, there are no alternatives to running the agent without the `--experimental-loader` flag.
|
|
86
86
|
|
|
87
|
+
### Custom Instrumentation
|
|
88
|
+
|
|
89
|
+
The agent supports adding your own custom instrumentation to ES module applications. In order to load custom instrumentation in an ES module app, you'll need to update your `newrelic.cjs` file to include the following:
|
|
90
|
+
|
|
91
|
+
```js
|
|
92
|
+
/* File: newrelic.cjs */
|
|
93
|
+
'use strict'
|
|
94
|
+
/**
|
|
95
|
+
* New Relic agent configuration.
|
|
96
|
+
*
|
|
97
|
+
* See lib/config/default.js in the agent distribution for a more complete
|
|
98
|
+
* description of configuration variables and their potential values.
|
|
99
|
+
*/
|
|
100
|
+
exports.config = {
|
|
101
|
+
app_name: ['Your application or service name'],
|
|
102
|
+
license_key: 'your new relic license key',
|
|
103
|
+
api: {
|
|
104
|
+
esm: {
|
|
105
|
+
custom_instrumentation_entrypoint: '/path/to/my/instrumentation.js'
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/* ... rest of configuration .. */
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
If you do not use a configuration file, then use the environment variable `NEW_RELIC_API_ESM_CUSTOM_INSTRUMENTATION_ENTRYPOINT` instead.
|
|
113
|
+
|
|
114
|
+
By updating the configuration, the agent's ES module loader will ensure that your custom instrumentation is added at module load. This is required in ES module applications due to the immutability of module export bindings: we are unable to apply our instrumentation after loading is complete.
|
|
115
|
+
|
|
116
|
+
We support the following custom instrumentation API methods in ES module apps:
|
|
117
|
+
|
|
118
|
+
* `newrelic.instrument`
|
|
119
|
+
* `newrelic.instrumentConglomerate`
|
|
120
|
+
* `newrelic.instrumentDatastore`
|
|
121
|
+
* `newrelic.instrumentMessages`
|
|
122
|
+
* `newrelic.instrumentWebframework`
|
|
123
|
+
|
|
124
|
+
Note that we _do not_ support `newrelic.instrumentLoadedModule`, for the same issue of immutability mentioned above.
|
|
125
|
+
|
|
126
|
+
If you want to see an example of how to write custom instrumentation in an ES module app, check out our [examples](https://github.com/newrelic/newrelic-node-examples/tree/main/esm-app) repo for a working demo.
|
|
127
|
+
|
|
87
128
|
## Getting Started
|
|
88
129
|
|
|
89
130
|
For more information on getting started, [check the Node.js docs](https://docs.newrelic.com/docs/agents/nodejs-agent/getting-started/introduction-new-relic-nodejs).
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -37,6 +37,7 @@ code, the source code can be found at [https://github.com/newrelic/node-newrelic
|
|
|
37
37
|
* [@slack/bolt](#slackbolt)
|
|
38
38
|
* [ajv](#ajv)
|
|
39
39
|
* [async](#async)
|
|
40
|
+
* [c8](#c8)
|
|
40
41
|
* [chai](#chai)
|
|
41
42
|
* [commander](#commander)
|
|
42
43
|
* [eslint-config-prettier](#eslint-config-prettier)
|
|
@@ -2091,6 +2092,28 @@ THE SOFTWARE.
|
|
|
2091
2092
|
|
|
2092
2093
|
```
|
|
2093
2094
|
|
|
2095
|
+
### c8
|
|
2096
|
+
|
|
2097
|
+
This product includes source derived from [c8](https://github.com/bcoe/c8) ([v7.12.0](https://github.com/bcoe/c8/tree/v7.12.0)), distributed under the [ISC License](https://github.com/bcoe/c8/blob/v7.12.0/LICENSE.txt):
|
|
2098
|
+
|
|
2099
|
+
```
|
|
2100
|
+
Copyright (c) 2017, Contributors
|
|
2101
|
+
|
|
2102
|
+
Permission to use, copy, modify, and/or distribute this software
|
|
2103
|
+
for any purpose with or without fee is hereby granted, provided
|
|
2104
|
+
that the above copyright notice and this permission notice
|
|
2105
|
+
appear in all copies.
|
|
2106
|
+
|
|
2107
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
2108
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
|
2109
|
+
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE
|
|
2110
|
+
LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
|
|
2111
|
+
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
|
2112
|
+
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
|
2113
|
+
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
2114
|
+
|
|
2115
|
+
```
|
|
2116
|
+
|
|
2094
2117
|
### chai
|
|
2095
2118
|
|
|
2096
2119
|
This product includes source derived from [chai](https://github.com/chaijs/chai) ([v4.3.6](https://github.com/chaijs/chai/tree/v4.3.6)), distributed under the [MIT License](https://github.com/chaijs/chai/blob/v4.3.6/LICENSE):
|
|
@@ -0,0 +1,110 @@
|
|
|
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 {
|
|
9
|
+
isApplicationLoggingEnabled,
|
|
10
|
+
isLogForwardingEnabled,
|
|
11
|
+
isLocalDecoratingEnabled,
|
|
12
|
+
isMetricsEnabled,
|
|
13
|
+
createModuleUsageMetric,
|
|
14
|
+
incrementLoggingLinesMetrics
|
|
15
|
+
} = require('../util/application-logging')
|
|
16
|
+
|
|
17
|
+
const MAX_LENGTH = 1021
|
|
18
|
+
const OUTPUT_LENGTH = 1024
|
|
19
|
+
const truncate = (str) => {
|
|
20
|
+
if (str && str.length > OUTPUT_LENGTH) {
|
|
21
|
+
return str.substring(0, MAX_LENGTH) + '...'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return str
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const logger = require('../logger').child({ component: 'bunyan' })
|
|
28
|
+
|
|
29
|
+
function augmentLogData(originalLog, agent, nameFromLevel) {
|
|
30
|
+
// shallow copy, since we're modifying things
|
|
31
|
+
const newLog = Object.assign({}, originalLog)
|
|
32
|
+
newLog.timestamp = Date.now()
|
|
33
|
+
newLog.level = nameFromLevel[originalLog.level]
|
|
34
|
+
|
|
35
|
+
// put log message into a consistent spot and ensure it's not too long
|
|
36
|
+
newLog.message = truncate(newLog.msg)
|
|
37
|
+
|
|
38
|
+
// tidy up the error output to help with max length restrictions
|
|
39
|
+
if (newLog.err) {
|
|
40
|
+
newLog['error.message'] = truncate(newLog.err.message)
|
|
41
|
+
newLog['error.stack'] = truncate(newLog.err.stack)
|
|
42
|
+
newLog['error.class'] =
|
|
43
|
+
newLog.err.name === 'Error' ? newLog.err.constructor.name : newLog.err.name
|
|
44
|
+
// clear out the old error message
|
|
45
|
+
delete newLog.err
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Add the metadata to the object being logged
|
|
49
|
+
const metadata = agent.getLinkingMetadata(true)
|
|
50
|
+
Object.keys(metadata).forEach((m) => {
|
|
51
|
+
newLog[m] = metadata[m]
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
return newLog
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function createLoggerWrapper(shim, fn, fnName, bunyanLogger, nameFromLevel) {
|
|
58
|
+
const agent = shim.agent
|
|
59
|
+
|
|
60
|
+
createModuleUsageMetric('bunyan', agent.metrics)
|
|
61
|
+
|
|
62
|
+
// forward logs via the agent logs aggregator
|
|
63
|
+
bunyanLogger.addStream({
|
|
64
|
+
name: 'NRLogForwarder',
|
|
65
|
+
type: 'raw',
|
|
66
|
+
level: bunyanLogger.level(),
|
|
67
|
+
stream: {
|
|
68
|
+
write: function nrLogWrite(logLine) {
|
|
69
|
+
agent.logs.add(augmentLogData(logLine, agent, nameFromLevel))
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
// no return here means the original return value is preserved
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
module.exports = function instrument(agent, bunyan, _, shim) {
|
|
77
|
+
const config = agent.config
|
|
78
|
+
|
|
79
|
+
if (!isApplicationLoggingEnabled(config)) {
|
|
80
|
+
logger.debug('Application logging not enabled. Not instrumenting bunyan.')
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const logForwardingEnabled = isLogForwardingEnabled(config, agent)
|
|
85
|
+
const localDecoratingEnabled = isLocalDecoratingEnabled(config)
|
|
86
|
+
const metricsEnabled = isMetricsEnabled(config)
|
|
87
|
+
|
|
88
|
+
if (logForwardingEnabled) {
|
|
89
|
+
shim.wrapReturn(bunyan, 'createLogger', createLoggerWrapper, [bunyan.nameFromLevel])
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (metricsEnabled || localDecoratingEnabled) {
|
|
93
|
+
shim.wrap(bunyan.prototype, '_emit', function wrapEmit(_shim, emit) {
|
|
94
|
+
return function wrappedEmit() {
|
|
95
|
+
const args = shim.argsToArray.apply(shim, arguments)
|
|
96
|
+
const rec = args[0]
|
|
97
|
+
|
|
98
|
+
if (metricsEnabled) {
|
|
99
|
+
incrementLoggingLinesMetrics(bunyan.nameFromLevel[rec.level], agent.metrics)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (localDecoratingEnabled) {
|
|
103
|
+
rec.message = truncate(rec.msg) + agent.getNRLinkingMetadata()
|
|
104
|
+
}
|
|
105
|
+
args[0] = rec
|
|
106
|
+
return emit.apply(this, args)
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
}
|
package/lib/instrumentations.js
CHANGED
|
@@ -15,6 +15,7 @@ module.exports = function instrumentations() {
|
|
|
15
15
|
'cassandra-driver': { type: MODULE_TYPE.DATASTORE },
|
|
16
16
|
'connect': { type: MODULE_TYPE.WEB_FRAMEWORK },
|
|
17
17
|
'bluebird': { type: MODULE_TYPE.PROMISE },
|
|
18
|
+
'bunyan': { type: MODULE_TYPE.GENERIC },
|
|
18
19
|
'director': { type: MODULE_TYPE.WEB_FRAMEWORK },
|
|
19
20
|
'express': { type: MODULE_TYPE.WEB_FRAMEWORK },
|
|
20
21
|
'fastify': { type: MODULE_TYPE.WEB_FRAMEWORK },
|
package/lib/metrics/names.js
CHANGED
|
@@ -277,11 +277,13 @@ const LOGGING = {
|
|
|
277
277
|
INFO: `${LOGGING_LINES_PREFIX}/INFO`,
|
|
278
278
|
WARN: `${LOGGING_LINES_PREFIX}/WARN`,
|
|
279
279
|
ERROR: `${LOGGING_LINES_PREFIX}/ERROR`,
|
|
280
|
+
FATAL: `${LOGGING_LINES_PREFIX}/FATAL`,
|
|
280
281
|
DEBUG: `${LOGGING_LINES_PREFIX}/DEBUG`,
|
|
281
282
|
TRACE: `${LOGGING_LINES_PREFIX}/TRACE`,
|
|
282
283
|
UNKNOWN: `${LOGGING_LINES_PREFIX}/UNKNOWN`
|
|
283
284
|
},
|
|
284
285
|
LIBS: {
|
|
286
|
+
BUNYAN: `${SUPPORTABILITY.LOGGING}/${NODEJS.PREFIX}bunyan/enabled`,
|
|
285
287
|
PINO: `${SUPPORTABILITY.LOGGING}/${NODEJS.PREFIX}pino/enabled`,
|
|
286
288
|
WINSTON: `${SUPPORTABILITY.LOGGING}/${NODEJS.PREFIX}winston/enabled`
|
|
287
289
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "newrelic",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.3.0",
|
|
4
4
|
"author": "New Relic Node.js agent team <nodejs@newrelic.com>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"contributors": [
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
"bench": "node ./bin/run-bench.js",
|
|
147
147
|
"docker-env": "./bin/docker-env-vars.sh",
|
|
148
148
|
"docs": "npm ci && jsdoc -c ./jsdoc-conf.json --private -r .",
|
|
149
|
-
"integration": "npm run prepare-test && npm run sub-install && time tap test/integration/**/**/*.tap.js --timeout=180 --no-coverage --reporter classic",
|
|
149
|
+
"integration": "npm run prepare-test && npm run sub-install && time c8 -o ./coverage/integration tap test/integration/**/**/*.tap.js --timeout=180 --no-coverage --reporter classic",
|
|
150
150
|
"prepare-test": "npm run ssl && npm run docker-env",
|
|
151
151
|
"lint": "eslint ./*.{js,mjs} lib test bin examples",
|
|
152
152
|
"lint:fix": "eslint --fix, ./*.{js,mjs} lib test bin examples",
|
|
@@ -158,8 +158,8 @@
|
|
|
158
158
|
"sub-install": "node test/bin/install_sub_deps",
|
|
159
159
|
"test": "npm run integration && npm run unit && npm run unit:esm",
|
|
160
160
|
"third-party-updates": "oss third-party manifest --includeOptDeps && oss third-party notices --includeOptDeps && git add THIRD_PARTY_NOTICES.md third_party_manifest.json",
|
|
161
|
-
"unit": "rm -f newrelic_agent.log && time tap --test-regex='(\\/|^test\\/unit\\/.*\\.test\\.js)$' --timeout=180 --no-coverage --reporter classic",
|
|
162
|
-
"unit:esm": "rm -f newrelic_agent.log && time tap --test-regex='(\\/|^test\\/unit\\/.*\\.test\\.mjs)$' --timeout=180 --no-coverage --reporter classic --node-arg=--experimental-loader=testdouble",
|
|
161
|
+
"unit": "rm -f newrelic_agent.log && time c8 -o ./coverage/unit tap --test-regex='(\\/|^test\\/unit\\/.*\\.test\\.js)$' --timeout=180 --no-coverage --reporter classic",
|
|
162
|
+
"unit:esm": "rm -f newrelic_agent.log && time c8 -o ./coverage/esm-unit --include *.mjs --include **/*.mjs --exclude false tap --test-regex='(\\/|^test\\/unit\\/.*\\.test\\.mjs)$' --timeout=180 --no-coverage --reporter classic --node-arg=--experimental-loader=testdouble",
|
|
163
163
|
"update-cross-agent-tests": "./bin/update-cats.sh",
|
|
164
164
|
"versioned-tests": "./bin/run-versioned-tests.sh",
|
|
165
165
|
"update-changelog-version": "node ./bin/update-changelog-version",
|
|
@@ -199,6 +199,7 @@
|
|
|
199
199
|
"@slack/bolt": "^3.7.0",
|
|
200
200
|
"ajv": "^6.12.6",
|
|
201
201
|
"async": "^3.2.4",
|
|
202
|
+
"c8": "^7.12.0",
|
|
202
203
|
"chai": "^4.1.2",
|
|
203
204
|
"commander": "^7.0.0",
|
|
204
205
|
"eslint": "^8.24.0",
|