newrelic 9.11.0 → 9.12.1

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 CHANGED
@@ -1,18 +1,34 @@
1
- ### v9.11.0 (2023-03-08)
2
- * Added instrumentation for Prisma(`@prisma/client`).
3
- * Miniumum supported version of `@prisma/client` is 4.0.0.
4
- * Captures spans for queries.
1
+ ### v9.12.1 (2023-03-15)
2
+
3
+ * Added ability to mark errors as expected when using `newrelic.noticeError`, by adding an optional boolean:
4
+ * `newrelic.noticeError(error, {customAttributes}, true|false)` when there are custom error attributes.
5
+ * `newrelic.noticeError(error, true|false)` if there are no custom error attributes.
6
+ * `expected` errors do not affect error metrics or Apdex.
7
+
8
+ * Added ability to disable distributed tracing for aws-sdk >= 3.290.0.
9
+
10
+ * Updated README header image to latest OSS office required images
11
+
12
+ * updated @grpc/grpc-js from 1.8.8 to 1.8.9
13
+
14
+ ### v9.12.0 (2023-03-13)
15
+ * Release pipeline did not complete.
16
+
17
+ ### v9.11.0 (2023-03-08)
18
+ * Added instrumentation for Prisma(`@prisma/client`).
19
+ * Miniumum supported version of `@prisma/client` is 4.0.0.
20
+ * Captures spans for queries.
5
21
  * It names them based on the model and action.(i.e. Datastore/statement/Prisma/user/create)
6
- * For statements and queries using the `$queryRaw`, `$executeRaw`, `$queryRawUnsafe`, and `$executeRawUnsafe` the names will be aligned with the raw SQL.(i.e. Datastore/statement/Prisma/User/select)
22
+ * For statements and queries using the `$queryRaw`, `$executeRaw`, `$queryRawUnsafe`, and `$executeRawUnsafe` the names will be aligned with the raw SQL.(i.e. Datastore/statement/Prisma/User/select)
7
23
  * Captures database metrics for all statements and queries.
8
- * Captures SQL Traces.
24
+ * Captures SQL Traces.
9
25
  * Provides connection between application and database server via service maps.
10
-
11
- Huge shoutout to @osmanmrtacar for the original contribution 🙏🏻
12
-
13
- * Updated `@grpc/protoloader` from 0.7.4 to 0.7.5.
14
- * Updated `@grpc/grpc-js` from 1.8.7 to 1.8.8.
15
-
26
+
27
+ Huge shoutout to @osmanmrtacar for the original contribution 🙏🏻
28
+
29
+ * Updated `@grpc/protoloader` from 0.7.4 to 0.7.5.
30
+ * Updated `@grpc/grpc-js` from 1.8.7 to 1.8.8.
31
+
16
32
  ### v9.10.2 (2023-02-21)
17
33
 
18
34
  * Replaced `request.aborted` with `response.close` in HTTP instrumentation.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![Community Plus header](https://github.com/newrelic/opensource-website/raw/main/src/images/categories/Community_Plus.png)](https://opensource.newrelic.com/oss-category/#community-plus)
1
+ <a href="https://opensource.newrelic.com/oss-category/#community-plus"><picture><source media="(prefers-color-scheme: dark)" srcset="https://github.com/newrelic/opensource-website/raw/main/src/images/categories/dark/Community_Plus.png"><source media="(prefers-color-scheme: light)" srcset="https://github.com/newrelic/opensource-website/raw/main/src/images/categories/Community_Plus.png"><img alt="New Relic Open Source community plus project banner." src="https://github.com/newrelic/opensource-website/raw/main/src/images/categories/Community_Plus.png"></picture></a>
2
2
 
3
3
  # New Relic's Node.js agent
4
4
  [![npm status badge][1]][2] [![Server Smoke Tests][3]][4] [![Node Agent CI][5]][6] [![codecov][7]][8]
package/api.js CHANGED
@@ -403,7 +403,8 @@ API.prototype.addCustomSpanAttribute = function addCustomSpanAttribute(key, valu
403
403
  * } catch (err) {
404
404
  * newrelic.noticeError(
405
405
  * err,
406
- * {extraInformation: "error already handled in the application"}
406
+ * {extraInformation: "error already handled in the application"},
407
+ * true
407
408
  * );
408
409
  * }
409
410
  *
@@ -414,12 +415,21 @@ API.prototype.addCustomSpanAttribute = function addCustomSpanAttribute(key, valu
414
415
  * The error to be traced.
415
416
  * @param {object} [customAttributes]
416
417
  * Optional. Any custom attributes to be displayed in the New Relic UI.
417
- * @returns {false|undefined} Retruns false when disabled/errored, otherwise undefined
418
+ * @param {boolean} expected
419
+ * Optional. False by default. True if the error is expected, meaning it should be collected
420
+ * for error events and traces, but should not impact error rate.
421
+ * @returns {false|undefined} Returns false when disabled/errored, otherwise undefined
418
422
  */
419
- API.prototype.noticeError = function noticeError(error, customAttributes) {
423
+ API.prototype.noticeError = function noticeError(error, customAttributes, expected = false) {
420
424
  const metric = this.agent.metrics.getOrCreateMetric(NAMES.SUPPORTABILITY.API + '/noticeError')
421
425
  metric.incrementCallCount()
422
426
 
427
+ // let users skip the custom attributes if they want
428
+ if (customAttributes && typeof customAttributes === 'boolean') {
429
+ expected = customAttributes
430
+ customAttributes = null
431
+ }
432
+
423
433
  if (!this.agent.config.api.notice_error_enabled) {
424
434
  logger.debug('Config.api.notice_error_enabled set to false, not collecting error')
425
435
  return false
@@ -446,7 +456,7 @@ API.prototype.noticeError = function noticeError(error, customAttributes) {
446
456
  }
447
457
 
448
458
  const transaction = this.agent.tracer.getTransaction()
449
- this.agent.errors.addUserError(transaction, error, filteredAttributes)
459
+ this.agent.errors.addUserError(transaction, error, filteredAttributes, expected)
450
460
  }
451
461
 
452
462
  /**
@@ -114,19 +114,27 @@ class ErrorCollector {
114
114
  *
115
115
  * @param {Transaction} transaction the collected exception's transaction
116
116
  * @param {number} collectedErrors the number of errors we've successfully .collect()-ed
117
- * @returns {number} the new number of errors successfully .collect()-ed
117
+ * @param {number} expectedErrors the number of errors marked as expected in noticeError
118
+ * @returns {Array.<number>} the updated [collectedErrors, expectedErrors] numbers post-processing
118
119
  */
119
- _processUserErrors(transaction, collectedErrors) {
120
+ _processUserErrors(transaction, collectedErrors, expectedErrors) {
120
121
  if (transaction.userErrors.length) {
121
122
  for (let i = 0; i < transaction.userErrors.length; i++) {
122
123
  const exception = transaction.userErrors[i]
123
124
  if (this.collect(transaction, exception)) {
124
125
  ++collectedErrors
126
+ // if we could collect it, then check if expected
127
+ if (
128
+ urltils.isExpectedError(this.config, transaction.statusCode) ||
129
+ errorHelper.isExpectedException(transaction, exception, this.config, urltils)
130
+ ) {
131
+ ++expectedErrors
132
+ }
125
133
  }
126
134
  }
127
135
  }
128
136
 
129
- return collectedErrors
137
+ return [collectedErrors, expectedErrors]
130
138
  }
131
139
 
132
140
  /**
@@ -145,7 +153,7 @@ class ErrorCollector {
145
153
  // if we could collect it, then check if expected
146
154
  if (
147
155
  urltils.isExpectedError(this.config, transaction.statusCode) ||
148
- errorHelper.isExpectedException(transaction, exception.error, this.config, urltils)
156
+ errorHelper.isExpectedException(transaction, exception, this.config, urltils)
149
157
  ) {
150
158
  ++expectedErrors
151
159
  }
@@ -196,7 +204,11 @@ class ErrorCollector {
196
204
 
197
205
  // errors from noticeError are currently exempt from
198
206
  // ignore and exclude rules
199
- collectedErrors = this._processUserErrors(transaction, collectedErrors)
207
+ ;[collectedErrors, expectedErrors] = this._processUserErrors(
208
+ transaction,
209
+ collectedErrors,
210
+ expectedErrors
211
+ )
200
212
 
201
213
  const isErroredTransaction = urltils.isError(this.config, transaction.statusCode)
202
214
  const isIgnoredErrorStatusCode = urltils.isIgnoredError(this.config, transaction.statusCode)
@@ -276,8 +288,9 @@ class ErrorCollector {
276
288
  * @param {?Transaction} transaction Transaction associated with the error.
277
289
  * @param {*} error The error passed into `API#noticeError()`
278
290
  * @param {object} customAttributes custom attributes to add to the error
291
+ * @param {boolean} expected Is the error expected?
279
292
  */
280
- addUserError(transaction, error, customAttributes) {
293
+ addUserError(transaction, error, customAttributes, expected) {
281
294
  if (!error) {
282
295
  return
283
296
  }
@@ -289,7 +302,7 @@ class ErrorCollector {
289
302
  }
290
303
 
291
304
  const timestamp = Date.now()
292
- const exception = new Exception({ error, timestamp, customAttributes })
305
+ const exception = new Exception({ error, timestamp, customAttributes, expected })
293
306
 
294
307
  if (transaction) {
295
308
  transaction.addUserError(exception)
@@ -34,10 +34,18 @@ module.exports = {
34
34
  )
35
35
  },
36
36
  isExpectedException: function isExpectedException(transaction, exception, config, urltils) {
37
- const { type, message } = this.extractErrorInformation(transaction, exception, config, urltils)
37
+ // this is getting JUST the exception.error
38
+ const { type, message } = this.extractErrorInformation(
39
+ transaction,
40
+ exception.error,
41
+ config,
42
+ urltils
43
+ )
38
44
 
39
45
  return (
40
- this.isExpectedErrorClass(config, type) || this.isExpectedErrorMessage(config, type, message)
46
+ exception._expected ||
47
+ this.isExpectedErrorClass(config, type) ||
48
+ this.isExpectedErrorMessage(config, type, message)
41
49
  )
42
50
  },
43
51
 
@@ -19,11 +19,12 @@ const Transaction = require('../transaction')
19
19
  const ERROR_EXPECTED_PATH = 'error.expected'
20
20
 
21
21
  class Exception {
22
- constructor({ error, timestamp, customAttributes, agentAttributes }) {
22
+ constructor({ error, timestamp, customAttributes, agentAttributes, expected }) {
23
23
  this.error = error
24
24
  this.timestamp = timestamp || 0
25
25
  this.customAttributes = customAttributes || {}
26
26
  this.agentAttributes = agentAttributes || {}
27
+ this._expected = expected
27
28
  }
28
29
 
29
30
  getErrorDetails(config) {
@@ -34,7 +35,7 @@ class Exception {
34
35
  }
35
36
 
36
37
  isExpected(config, { type, message }) {
37
- if (!this._expected) {
38
+ if (typeof this._expected === 'undefined') {
38
39
  this._expected =
39
40
  errorHelper.isExpectedErrorClass(config, type) ||
40
41
  errorHelper.isExpectedErrorMessage(config, type, message)
@@ -103,13 +104,8 @@ function createError(transaction, exception, config) {
103
104
 
104
105
  params.stack_trace = maybeAddStackTrace(exception, config)
105
106
 
106
- params.intrinsics[ERROR_EXPECTED_PATH] = errorHelper.isExpected(
107
- type,
108
- message,
109
- transaction,
110
- config,
111
- urltils
112
- )
107
+ params.intrinsics[ERROR_EXPECTED_PATH] =
108
+ exception._expected || errorHelper.isExpected(type, message, transaction, config, urltils)
113
109
 
114
110
  return [0, name, message, type, params]
115
111
  }
@@ -143,7 +143,7 @@ function instrumentRequest(agent, opts, makeRequest, hostname, segment) {
143
143
  outboundHeaders[NEWRELIC_SYNTHETICS_HEADER] = transaction.syntheticsHeader
144
144
  }
145
145
 
146
- maybeAddDtCatHeaders(agent, transaction, outboundHeaders, !!opts?.headers?.[symbols.disableDT])
146
+ maybeAddDtCatHeaders(agent, transaction, outboundHeaders, opts?.headers)
147
147
  opts.headers = assignOutgoingHeaders(opts.headers, outboundHeaders)
148
148
 
149
149
  const request = applySegment(opts, makeRequest, hostname, segment)
@@ -160,13 +160,18 @@ function instrumentRequest(agent, opts, makeRequest, hostname, segment) {
160
160
  * @param {Agent} agent Node.js agent
161
161
  * @param {Transaction} transaction active transaction
162
162
  * @param {object} outboundHeaders headers that are getting attached to external http call
163
- * @param {boolean} hasDtSym flag to tell if the disableDT header exists on headers
163
+ * @param {object} headers headers for http request
164
164
  */
165
165
  // TODO: abstract header logic shared with TransactionShim#insertCATRequestHeaders
166
- function maybeAddDtCatHeaders(agent, transaction, outboundHeaders, hasDtSym = false) {
166
+ function maybeAddDtCatHeaders(agent, transaction, outboundHeaders, headers = {}) {
167
167
  if (agent.config.distributed_tracing.enabled) {
168
- if (hasDtSym) {
168
+ if (!!(headers[symbols.disableDT] || headers['x-new-relic-disable-dt'])) {
169
169
  logger.trace('Distributed tracing disabled by instrumentation.')
170
+ // we do not need to remove symbol as it will get implicitly removed
171
+ // when the request is serialized. in fact removing the symbol will cause
172
+ // the same issue that we had to change this to a string header
173
+ // see: https://github.com/newrelic/node-newrelic-aws-sdk/issues/168
174
+ delete headers['x-new-relic-disable-dt']
170
175
  } else {
171
176
  transaction.insertDistributedTraceHeaders(outboundHeaders)
172
177
  }
@@ -860,7 +860,7 @@ Transaction.prototype.hasOnlyExpectedErrors = function hasOnlyExpectedErrors() {
860
860
  const exception = this.exceptions[i]
861
861
  // this exception is neither expected nor ignored
862
862
  const isUnexpected = !(
863
- errorHelper.isExpectedException(this, exception.error, this.agent.config, urltils) ||
863
+ errorHelper.isExpectedException(this, exception, this.agent.config, urltils) ||
864
864
  errorHelper.shouldIgnoreError(this, exception.error, this.agent.config)
865
865
  )
866
866
  if (isUnexpected) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "newrelic",
3
- "version": "9.11.0",
3
+ "version": "9.12.1",
4
4
  "author": "New Relic Node.js agent team <nodejs@newrelic.com>",
5
5
  "license": "Apache-2.0",
6
6
  "contributors": [
@@ -179,7 +179,7 @@
179
179
  "newrelic-naming-rules": "./bin/test-naming-rules.js"
180
180
  },
181
181
  "dependencies": {
182
- "@grpc/grpc-js": "^1.8.8",
182
+ "@grpc/grpc-js": "^1.8.9",
183
183
  "@grpc/proto-loader": "^0.7.5",
184
184
  "@newrelic/aws-sdk": "^5.0.2",
185
185
  "@newrelic/koa": "^7.1.1",