newrelic 6.12.0 → 6.13.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/CONTRIBUTING.md +3 -3
- package/NEWS.md +38 -2
- package/README.md +4 -4
- package/THIRD_PARTY_NOTICES.md +0 -56
- package/lib/attributes.js +13 -1
- package/lib/collector/serverless.js +38 -13
- package/lib/prioritized-attributes.js +12 -0
- package/lib/transaction/trace/index.js +24 -1
- package/newrelic.js +1 -1
- package/package.json +1 -2
- package/third_party_manifest.json +1 -14
- package/CODE_OF_CONDUCT.md +0 -5
package/CONTRIBUTING.md
CHANGED
|
@@ -20,9 +20,9 @@ licensing restrictions.
|
|
|
20
20
|
|
|
21
21
|
### Code of Conduct
|
|
22
22
|
|
|
23
|
-
Before contributing please read the [code of conduct](
|
|
23
|
+
Before contributing please read the [code of conduct](https://github.com/newrelic/.github/blob/main/CODE_OF_CONDUCT.md)
|
|
24
24
|
|
|
25
|
-
Note that our [code of conduct](
|
|
25
|
+
Note that our [code of conduct](https://github.com/newrelic/.github/blob/main/CODE_OF_CONDUCT.md) applies to all platforms
|
|
26
26
|
and venues related to this project; please follow it in all your interactions
|
|
27
27
|
with the project and its participants.
|
|
28
28
|
|
|
@@ -53,7 +53,7 @@ When contributing, keep in mind that New Relic customers (that's you!) are runni
|
|
|
53
53
|
|
|
54
54
|
Be aware that the instrumentation needs to work with a wide range of versions of the instrumented modules, and that code that looks nonsensical or overcomplicated may be that way for compatibility-related reasons. Read all the comments and check the related tests before deciding whether existing code is incorrect.
|
|
55
55
|
|
|
56
|
-
If you’re planning on contributing a new feature or an otherwise complex contribution, we kindly ask you to start a conversation with the maintainer team by opening up an Github issue first.
|
|
56
|
+
If you’re planning on contributing a new feature or an otherwise complex contribution, we kindly ask you to start a conversation with the maintainer team by opening up an Github issue first.
|
|
57
57
|
|
|
58
58
|
### General Guidelines
|
|
59
59
|
|
package/NEWS.md
CHANGED
|
@@ -1,9 +1,45 @@
|
|
|
1
|
+
## 6.13.2 (2020-10-13):
|
|
2
|
+
|
|
3
|
+
* Removed lodash as a development dependency
|
|
4
|
+
|
|
5
|
+
* Check for named pipe existence before each flush
|
|
6
|
+
|
|
7
|
+
This removes the cached value used in 6.13.1
|
|
8
|
+
|
|
9
|
+
* Update shim documentation
|
|
10
|
+
|
|
11
|
+
Thank you to @ronen-e for the contribution!
|
|
12
|
+
|
|
13
|
+
## 6.13.1 (2020-09-24):
|
|
14
|
+
|
|
15
|
+
* Fixed named-pipe check for lambda invocations to avoid race-condition.
|
|
16
|
+
|
|
17
|
+
Named-pipe existence will now be checked just prior to first write and then cached.
|
|
18
|
+
|
|
19
|
+
* Updated README with community-plus header.
|
|
20
|
+
|
|
21
|
+
* Updated README config copy example.
|
|
22
|
+
|
|
23
|
+
* Added Open Source Policy workflow.
|
|
24
|
+
|
|
25
|
+
* Removed repository CoC in favor of centralized CoC at org root.
|
|
26
|
+
|
|
27
|
+
### 6.13.0 (2020-08-25):
|
|
28
|
+
|
|
29
|
+
* Added ability for the agent to write to a named pipe, instead of stdout, when in serverless mode.
|
|
30
|
+
|
|
31
|
+
### 6.12.1 (2020-08-20):
|
|
32
|
+
|
|
33
|
+
* **Security fix:** Resolves an issue where transaction traces will still capture the request URI when the Node.js agent is configured to exclude the 'request.uri' attribute. This can be problematic for certain customers in environments where sensitive information is included in the URI. See security bulletin [NR20-02](https://docs.newrelic.com/docs/security/new-relic-security/security-bulletins/security-bulletin-nr20-02).
|
|
34
|
+
|
|
35
|
+
The request URI will now be excluded from transaction traces if the 'request.uri' attribute has been set to be excluded at either the top-level 'attributes.exclude' configuration or at the 'transaction_tracer.attributes.exclude' configuration.
|
|
36
|
+
|
|
1
37
|
### 6.12.0 (2020-08-11):
|
|
2
38
|
|
|
3
|
-
* Fixes obfuscation of SQL queries with large data inserts.
|
|
39
|
+
* Fixes obfuscation of SQL queries with large data inserts.
|
|
4
40
|
Special thanks to Tomáš Hanáček (@tomashanacek) for tracking down the issue and providing the fix.
|
|
5
41
|
* On failed instrumentation, prevent multiple requires from re-wrapping shims.
|
|
6
|
-
Special thanks to Ryan Copley (@RyanCopley) for the contribution.
|
|
42
|
+
Special thanks to Ryan Copley (@RyanCopley) for the contribution.
|
|
7
43
|
* Upgrade `async` to `v3.2.0`. Special thanks to Yohan Siguret (@Crow-EH) for the contribution
|
|
8
44
|
* Bumped `@newrelic/native-metrics` to `^5.3.0`.
|
|
9
45
|
* Bumped `@newrelic/aws-sdk` to `^2.0.0`.
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[](https://opensource.newrelic.com/oss-category/#community-plus)
|
|
2
2
|
|
|
3
3
|
# New Relic's Node.js agent [![Server Smoke Tests][3]][4] [![Node Agent CI][5]][6]
|
|
4
4
|
|
|
@@ -20,11 +20,11 @@ To use New Relic's Node.js agent entails these three steps, which are described
|
|
|
20
20
|
|
|
21
21
|
1. To install the agent for performance monitoring, use your favorite npm-based package manager and install the `newrelic` package into your application:
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
`$ npm install newrelic`
|
|
24
24
|
|
|
25
25
|
2. Then, copy the stock configuration file to your program's base folder:
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
`$ cp ./node_modules/newrelic/newrelic.js ./<your destination>`
|
|
28
28
|
|
|
29
29
|
3. Now, add your New Relic license key and application/service name to that file:
|
|
30
30
|
|
|
@@ -172,4 +172,4 @@ The Node.js agent also uses source code from third-party libraries. You can find
|
|
|
172
172
|
[3]: https://github.com/newrelic/node-newrelic/workflows/Server%20Smoke%20Tests/badge.svg
|
|
173
173
|
[4]: https://github.com/newrelic/node-newrelic/actions?query=workflow%3A%22Server+Smoke+Tests%22
|
|
174
174
|
[5]: https://github.com/newrelic/node-newrelic/workflows/Node%20Agent%20CI/badge.svg
|
|
175
|
-
[6]: https://github.com/newrelic/node-newrelic/actions?query=workflow%3A%22Node+Agent+CI%22
|
|
175
|
+
[6]: https://github.com/newrelic/node-newrelic/actions?query=workflow%3A%22Node+Agent+CI%22
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -48,7 +48,6 @@ code, the source code can be found at [https://github.com/newrelic/node-newrelic
|
|
|
48
48
|
* [got](#got)
|
|
49
49
|
* [http-errors](#http-errors)
|
|
50
50
|
* [jsdoc](#jsdoc)
|
|
51
|
-
* [lodash](#lodash)
|
|
52
51
|
* [memcached](#memcached)
|
|
53
52
|
* [minami](#minami)
|
|
54
53
|
* [mongodb](#mongodb)
|
|
@@ -2197,61 +2196,6 @@ https://github.com/jmblog/color-themes-for-google-code-prettify
|
|
|
2197
2196
|
|
|
2198
2197
|
```
|
|
2199
2198
|
|
|
2200
|
-
### lodash
|
|
2201
|
-
|
|
2202
|
-
This product includes source derived from [lodash](https://github.com/lodash/lodash) ([v4.17.15](https://github.com/lodash/lodash/tree/v4.17.15)), distributed under the [MIT License](https://github.com/lodash/lodash/blob/v4.17.15/LICENSE):
|
|
2203
|
-
|
|
2204
|
-
```
|
|
2205
|
-
Copyright OpenJS Foundation and other contributors <https://openjsf.org/>
|
|
2206
|
-
|
|
2207
|
-
Based on Underscore.js, copyright Jeremy Ashkenas,
|
|
2208
|
-
DocumentCloud and Investigative Reporters & Editors <http://underscorejs.org/>
|
|
2209
|
-
|
|
2210
|
-
This software consists of voluntary contributions made by many
|
|
2211
|
-
individuals. For exact contribution history, see the revision history
|
|
2212
|
-
available at https://github.com/lodash/lodash
|
|
2213
|
-
|
|
2214
|
-
The following license applies to all parts of this software except as
|
|
2215
|
-
documented below:
|
|
2216
|
-
|
|
2217
|
-
====
|
|
2218
|
-
|
|
2219
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
|
2220
|
-
a copy of this software and associated documentation files (the
|
|
2221
|
-
"Software"), to deal in the Software without restriction, including
|
|
2222
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
|
2223
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
|
2224
|
-
permit persons to whom the Software is furnished to do so, subject to
|
|
2225
|
-
the following conditions:
|
|
2226
|
-
|
|
2227
|
-
The above copyright notice and this permission notice shall be
|
|
2228
|
-
included in all copies or substantial portions of the Software.
|
|
2229
|
-
|
|
2230
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
2231
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
2232
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
2233
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
2234
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
2235
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
2236
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
2237
|
-
|
|
2238
|
-
====
|
|
2239
|
-
|
|
2240
|
-
Copyright and related rights for sample code are waived via CC0. Sample
|
|
2241
|
-
code is defined as all source code displayed within the prose of the
|
|
2242
|
-
documentation.
|
|
2243
|
-
|
|
2244
|
-
CC0: http://creativecommons.org/publicdomain/zero/1.0/
|
|
2245
|
-
|
|
2246
|
-
====
|
|
2247
|
-
|
|
2248
|
-
Files located in the node_modules and vendor directories are externally
|
|
2249
|
-
maintained libraries used by this software which have their own
|
|
2250
|
-
licenses; we recommend you read them, as their terms may differ from the
|
|
2251
|
-
terms above.
|
|
2252
|
-
|
|
2253
|
-
```
|
|
2254
|
-
|
|
2255
2199
|
### memcached
|
|
2256
2200
|
|
|
2257
2201
|
This product includes source derived from [memcached](https://github.com/3rd-Eden/node-memcached) ([v2.2.2](https://github.com/3rd-Eden/node-memcached/tree/v2.2.2)), distributed under the [MIT License](https://github.com/3rd-Eden/node-memcached/blob/v2.2.2/LICENSE):
|
package/lib/attributes.js
CHANGED
|
@@ -108,7 +108,7 @@ class Attributes {
|
|
|
108
108
|
addAttribute(destinations, key, value, truncateExempt = false) {
|
|
109
109
|
if (this.attributeCount + 1 > this.limit) {
|
|
110
110
|
return logger.debug(
|
|
111
|
-
`Maximum number of custom attributes have been added.
|
|
111
|
+
`Maximum number of custom attributes have been added.
|
|
112
112
|
Dropping attribute ${key} with ${value} type.`
|
|
113
113
|
)
|
|
114
114
|
}
|
|
@@ -151,6 +151,18 @@ class Attributes {
|
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Returns true if a given key is valid for any of the
|
|
157
|
+
* provided destinations.
|
|
158
|
+
*
|
|
159
|
+
* @param {DESTINATIONS} destinations
|
|
160
|
+
* @param {string} key
|
|
161
|
+
*/
|
|
162
|
+
hasValidDestination(destinations, key) {
|
|
163
|
+
const validDestinations = this.filter(destinations, key)
|
|
164
|
+
return !!validDestinations
|
|
165
|
+
}
|
|
154
166
|
}
|
|
155
167
|
|
|
156
168
|
/**
|
|
@@ -14,6 +14,9 @@ const stringify = require('json-stringify-safe')
|
|
|
14
14
|
const PAYLOAD_VERSION = 1
|
|
15
15
|
const PAYLOAD_MARKER = 'NR_LAMBDA_MONITORING'
|
|
16
16
|
|
|
17
|
+
const path = require('path')
|
|
18
|
+
const defaultPipePath = path.resolve('/tmp', 'newrelic-telemetry')
|
|
19
|
+
|
|
17
20
|
class ServerlessCollector {
|
|
18
21
|
/**
|
|
19
22
|
* Constructs a new serverless collector instance with the give agent.
|
|
@@ -24,7 +27,7 @@ class ServerlessCollector {
|
|
|
24
27
|
*
|
|
25
28
|
* @param {Agent} agent - The agent this collector will use
|
|
26
29
|
*/
|
|
27
|
-
constructor(agent) {
|
|
30
|
+
constructor(agent, pipePath) {
|
|
28
31
|
this._agent = agent
|
|
29
32
|
this.enabled = true
|
|
30
33
|
this.metadata = {
|
|
@@ -35,6 +38,7 @@ class ServerlessCollector {
|
|
|
35
38
|
agent_version: agent.version
|
|
36
39
|
}
|
|
37
40
|
this.payload = {}
|
|
41
|
+
this.pipePath = pipePath || process.env.NEWRELIC_PIPE_PATH || defaultPipePath
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
/**
|
|
@@ -243,6 +247,36 @@ class ServerlessCollector {
|
|
|
243
247
|
}
|
|
244
248
|
}
|
|
245
249
|
|
|
250
|
+
/**
|
|
251
|
+
* Writes payload to pipe
|
|
252
|
+
*/
|
|
253
|
+
flushToPipeSync(payload) {
|
|
254
|
+
try {
|
|
255
|
+
fs.writeFileSync(this.pipePath, payload)
|
|
256
|
+
return true
|
|
257
|
+
} catch (e) {
|
|
258
|
+
logger.warn('Error attempting to write to pipe, falling back to stdout', e)
|
|
259
|
+
return false
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
flushToStdOut(serializedPayload, payloadLength, sync = false) {
|
|
264
|
+
if (sync) {
|
|
265
|
+
// Long log lines have been truncated at 65538
|
|
266
|
+
// Guarantees process.stdout will block, so long logs
|
|
267
|
+
// won't be truncated if process.exit() is called early.
|
|
268
|
+
const s = process.stdout
|
|
269
|
+
payloadLength > 65000 &&
|
|
270
|
+
s._handle &&
|
|
271
|
+
s._handle.setBlocking &&
|
|
272
|
+
s._handle.setBlocking(true)
|
|
273
|
+
|
|
274
|
+
fs.writeSync(process.stdout.fd, serializedPayload)
|
|
275
|
+
} else {
|
|
276
|
+
process.stdout.write(serializedPayload)
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
246
280
|
/**
|
|
247
281
|
* Internal method to handle flushing to stdout.
|
|
248
282
|
*
|
|
@@ -258,19 +292,10 @@ class ServerlessCollector {
|
|
|
258
292
|
payload
|
|
259
293
|
]) + '\n'
|
|
260
294
|
|
|
261
|
-
|
|
262
|
-
// Long log lines have been truncated at 65538
|
|
263
|
-
// Guarantees process.stdout will block, so long logs
|
|
264
|
-
// won't be truncated if process.exit() is called early.
|
|
265
|
-
const s = process.stdout
|
|
266
|
-
payload.length > 65000 &&
|
|
267
|
-
s._handle &&
|
|
268
|
-
s._handle.setBlocking &&
|
|
269
|
-
s._handle.setBlocking(true)
|
|
295
|
+
const didUsePipe = fs.existsSync(this.pipePath) && this.flushToPipeSync(serializedPayload)
|
|
270
296
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
process.stdout.write(serializedPayload)
|
|
297
|
+
if (!didUsePipe) {
|
|
298
|
+
this.flushToStdOut(serializedPayload, payload.length, sync)
|
|
274
299
|
}
|
|
275
300
|
}
|
|
276
301
|
}
|
|
@@ -139,6 +139,18 @@ class PrioritizedAttributes {
|
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
+
/**
|
|
143
|
+
* Returns true if a given key is valid for any of the
|
|
144
|
+
* provided destinations.
|
|
145
|
+
*
|
|
146
|
+
* @param {DESTINATIONS} destinations
|
|
147
|
+
* @param {string} key
|
|
148
|
+
*/
|
|
149
|
+
hasValidDestination(destinations, key) {
|
|
150
|
+
const validDestinations = this.filter(destinations, key)
|
|
151
|
+
return !!validDestinations
|
|
152
|
+
}
|
|
153
|
+
|
|
142
154
|
_getDroppableAttributeKey(incomingPriority) {
|
|
143
155
|
// There will never be anything lower priority to drop
|
|
144
156
|
if (incomingPriority === ATTRIBUTE_PRIORITY.LOW) {
|
|
@@ -15,6 +15,8 @@ var {DESTINATIONS} = require('../../config/attribute-filter')
|
|
|
15
15
|
var FROM_MILLIS = 1e-3
|
|
16
16
|
const ATTRIBUTE_SCOPE = 'transaction'
|
|
17
17
|
|
|
18
|
+
const REQUEST_URI_KEY = 'request.uri'
|
|
19
|
+
const UNKNOWN_URI_PLACEHOLDER = '/Unknown'
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
22
|
* A Trace holds the root of the Segment graph and produces the final
|
|
@@ -293,11 +295,13 @@ Trace.prototype._generatePayload = function _generatePayload(data) {
|
|
|
293
295
|
syntheticsResourceId = this.transaction.syntheticsData.resourceId
|
|
294
296
|
}
|
|
295
297
|
|
|
298
|
+
const requestUri = this._getRequestUri()
|
|
299
|
+
|
|
296
300
|
return [
|
|
297
301
|
this.root.timer.start, // start
|
|
298
302
|
this.transaction.getResponseTimeInMillis(), // response time
|
|
299
303
|
this.transaction.getFullName(), // path
|
|
300
|
-
|
|
304
|
+
requestUri, // request.uri
|
|
301
305
|
data, // encodedCompressedData
|
|
302
306
|
this.transaction.id, // guid
|
|
303
307
|
null, // reserved for future use
|
|
@@ -307,6 +311,25 @@ Trace.prototype._generatePayload = function _generatePayload(data) {
|
|
|
307
311
|
]
|
|
308
312
|
}
|
|
309
313
|
|
|
314
|
+
/**
|
|
315
|
+
* Returns the transaction URL if attribute is not exluded globally or
|
|
316
|
+
* for transaction traces. Returns '/Unknown' if included but not known.
|
|
317
|
+
*
|
|
318
|
+
* The URI on a trace is a special attribute. It is included as a positional field,
|
|
319
|
+
* not as an "agent attribute", to avoid having to decompress on the backend.
|
|
320
|
+
* But it still needs to be gaited by the same attribute exclusion/inclusion
|
|
321
|
+
* rules so sensitive information can be removed.
|
|
322
|
+
*/
|
|
323
|
+
Trace.prototype._getRequestUri = function _getRequestUri() {
|
|
324
|
+
const canAddUri = this.attributes.hasValidDestination(DESTINATIONS.TRANS_TRACE, REQUEST_URI_KEY)
|
|
325
|
+
let requestUri = null // must be null if excluded
|
|
326
|
+
if (canAddUri) {
|
|
327
|
+
requestUri = this.transaction.url || UNKNOWN_URI_PLACEHOLDER
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return requestUri
|
|
331
|
+
}
|
|
332
|
+
|
|
310
333
|
/**
|
|
311
334
|
* Serializes the trace into the expected JSON format to be sent.
|
|
312
335
|
*
|
package/newrelic.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "newrelic",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.13.2",
|
|
4
4
|
"author": "New Relic Node.js agent team <nodejs@newrelic.com>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"contributors": [
|
|
@@ -174,7 +174,6 @@
|
|
|
174
174
|
"got": "^8.0.1",
|
|
175
175
|
"http-errors": "^1.7.3",
|
|
176
176
|
"jsdoc": "^3.6.3",
|
|
177
|
-
"lodash": "^4.17.14",
|
|
178
177
|
"memcached": ">=0.2.8",
|
|
179
178
|
"minami": "^1.1.1",
|
|
180
179
|
"mongodb": "^3.3.3",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"lastUpdated": "
|
|
2
|
+
"lastUpdated": "Tue Oct 13 2020 14:24:25 GMT-0700 (Pacific Daylight Time)",
|
|
3
3
|
"projectName": "New Relic Node Agent",
|
|
4
4
|
"projectUrl": "https://github.com/newrelic/node-newrelic",
|
|
5
5
|
"includeDev": true,
|
|
@@ -358,19 +358,6 @@
|
|
|
358
358
|
"publisher": "Michael Mathews",
|
|
359
359
|
"email": "micmath@gmail.com"
|
|
360
360
|
},
|
|
361
|
-
"lodash@4.17.15": {
|
|
362
|
-
"name": "lodash",
|
|
363
|
-
"version": "4.17.15",
|
|
364
|
-
"range": "^4.17.14",
|
|
365
|
-
"licenses": "MIT",
|
|
366
|
-
"repoUrl": "https://github.com/lodash/lodash",
|
|
367
|
-
"versionedRepoUrl": "https://github.com/lodash/lodash/tree/v4.17.15",
|
|
368
|
-
"licenseFile": "node_modules/lodash/LICENSE",
|
|
369
|
-
"licenseUrl": "https://github.com/lodash/lodash/blob/v4.17.15/LICENSE",
|
|
370
|
-
"licenseTextSource": "file",
|
|
371
|
-
"publisher": "John-David Dalton",
|
|
372
|
-
"email": "john.david.dalton@gmail.com"
|
|
373
|
-
},
|
|
374
361
|
"memcached@2.2.2": {
|
|
375
362
|
"name": "memcached",
|
|
376
363
|
"version": "2.2.2",
|
package/CODE_OF_CONDUCT.md
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
### Hello! We're glad you've joined us.
|
|
2
|
-
|
|
3
|
-
We believe participation in our community should be a harassment free experience for everyone.
|
|
4
|
-
|
|
5
|
-
Learn more about our guidelines and principles by reading our [Code of Conduct](https://opensource.newrelic.com/code-of-conduct/) on our Open Source Website.
|