newrelic 11.19.0 → 11.20.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 CHANGED
@@ -1,3 +1,37 @@
1
+ ### v11.20.0 (2024-06-24)
2
+
3
+ #### Features
4
+
5
+ * Added support for Anthropic Claude 3 messages API ([#2278](https://github.com/newrelic/node-newrelic/pull/2278)) ([7e3cab9](https://github.com/newrelic/node-newrelic/commit/7e3cab9739a9924b904ce78380fd70b1e30cd89f))
6
+
7
+ #### Code refactoring
8
+
9
+ * Replaced instances of `substr()` with `substring()` ([#2274](https://github.com/newrelic/node-newrelic/pull/2274)) ([8f96c73](https://github.com/newrelic/node-newrelic/commit/8f96c734862d42f459dd4de8ed9d498ef7d693de))
10
+
11
+ #### Documentation
12
+
13
+ * Fixed typos in API jsdoc ([#2287](https://github.com/newrelic/node-newrelic/pull/2287)) ([7b3c8d1](https://github.com/newrelic/node-newrelic/commit/7b3c8d1445ea9876b36eda31d979dac9b65dad14))
14
+ * Updated compatibility report ([#2285](https://github.com/newrelic/node-newrelic/pull/2285)) ([b1b5e3e](https://github.com/newrelic/node-newrelic/commit/b1b5e3e54074cc8b535927f4edad07925618260c))
15
+
16
+ #### Miscellaneous chores
17
+
18
+ * Added a missing library we instrument to be picked up by the compatibility report ([#2261](https://github.com/newrelic/node-newrelic/pull/2261)) ([6c964b2](https://github.com/newrelic/node-newrelic/commit/6c964b2029874353908486228113a468959b1597))
19
+ * Added a script that generates Dashboard json for reporting on libraries by version ([#2267](https://github.com/newrelic/node-newrelic/pull/2267)) ([d2877c1](https://github.com/newrelic/node-newrelic/commit/d2877c17c7c2f4432b2ce4056c94200a2e7334b2))
20
+ * Added AI support docs for automation ([#2249](https://github.com/newrelic/node-newrelic/pull/2249)) ([e2efc1f](https://github.com/newrelic/node-newrelic/commit/e2efc1fb202a3e87be710f352546a00df6bf6cef))
21
+ * Fixed comment about transaction_tracer.transaction_threshold ([#2258](https://github.com/newrelic/node-newrelic/pull/2258)) ([7cd6aef](https://github.com/newrelic/node-newrelic/commit/7cd6aef7ecc32d8647f0313b36be368bfa14a0e9))
22
+ * Made elastic versioned tests work on Node 16 ([#2284](https://github.com/newrelic/node-newrelic/pull/2284)) ([143b475](https://github.com/newrelic/node-newrelic/commit/143b4757c27d497a25d1b3c7fd56b32bcede619f))
23
+ * Updated docker compose configuration ([#2268](https://github.com/newrelic/node-newrelic/pull/2268)) ([eb1cce9](https://github.com/newrelic/node-newrelic/commit/eb1cce9143fe87eed1bdd077471942f85cf14f21))
24
+ * Updated GitHub Actions versions ([#2272](https://github.com/newrelic/node-newrelic/pull/2272)) ([07a841b](https://github.com/newrelic/node-newrelic/commit/07a841b9acf0a0dcb1a495c5cb0ee8f77e283fc9))
25
+ * Updated mysql tests to use MySQL 8.3 ([#2280](https://github.com/newrelic/node-newrelic/pull/2280)) ([11e0f8c](https://github.com/newrelic/node-newrelic/commit/11e0f8cf63a5f792419382635496a29c0286c737))
26
+ * Updated mysql2 tests to fix CI issue ([#2282](https://github.com/newrelic/node-newrelic/pull/2282)) ([5a37971](https://github.com/newrelic/node-newrelic/commit/5a37971b03fe8d69b39db66d97ecfc1176c42902))
27
+ * Updated versioned security agent workflow with simpler setup ([#2259](https://github.com/newrelic/node-newrelic/pull/2259)) ([a886187](https://github.com/newrelic/node-newrelic/commit/a886187bf1bf29d2430e38223d0215436e006540))
28
+
29
+ #### Continuous integration
30
+
31
+ * Added ability to run a build step in create release ([#2273](https://github.com/newrelic/node-newrelic/pull/2273)) ([4c2f24c](https://github.com/newrelic/node-newrelic/commit/4c2f24cb6e94dd05f269998eeb763196c3fac274))
32
+ * Updated security agent workflow to use large runners when available ([#2271](https://github.com/newrelic/node-newrelic/pull/2271)) ([181ec1b](https://github.com/newrelic/node-newrelic/commit/181ec1bfa8d420514fca3d6de6c3989e796a29db))
33
+ * Updated security agent workflow to use large runners when available ([#2270](https://github.com/newrelic/node-newrelic/pull/2270)) ([761fcd5](https://github.com/newrelic/node-newrelic/commit/761fcd5ca5ae32ba922d0880979dbfff97604641))
34
+
1
35
  ### v11.19.0 (2024-06-06)
2
36
 
3
37
  #### Features
package/api.js CHANGED
@@ -244,14 +244,14 @@ API.prototype.setControllerName = function setControllerName(name, action) {
244
244
  }
245
245
 
246
246
  /**
247
- * Add a custom attribute to the current transaction. Some attributes are
247
+ * Add a custom attribute to the current transaction and span. Some attributes are
248
248
  * reserved (see CUSTOM_DENYLIST for the current, very short list), and
249
249
  * as with most API methods, this must be called in the context of an
250
250
  * active transaction. Most recently set value wins.
251
251
  *
252
252
  * @param {string} key The key you want displayed in the RPM UI.
253
253
  * @param {string} value The value you want displayed. Must be serializable.
254
- * @returns {false|undefined} Retruns false when disabled/errored, otherwise undefined
254
+ * @returns {false|undefined} Returns false when disabled/errored, otherwise undefined
255
255
  */
256
256
  API.prototype.addCustomAttribute = function addCustomAttribute(key, value) {
257
257
  const metric = this.agent.metrics.getOrCreateMetric(
@@ -298,7 +298,7 @@ API.prototype.addCustomAttribute = function addCustomAttribute(key, value) {
298
298
  }
299
299
 
300
300
  /**
301
- * Adds all custom attributes in an object to the current transaction.
301
+ * Adds all custom attributes in an object to the current transaction and span.
302
302
  *
303
303
  * See documentation for newrelic.addCustomAttribute for more information on
304
304
  * setting custom attributes.
@@ -360,7 +360,7 @@ API.prototype.addCustomSpanAttributes = function addCustomSpanAttributes(atts) {
360
360
  *
361
361
  * @param {string} key The key you want displayed in the RPM UI.
362
362
  * @param {string} value The value you want displayed. Must be serializable.
363
- * @returns {false|undefined} Retruns false when disabled/errored, otherwise undefined
363
+ * @returns {false|undefined} Returns false when disabled/errored, otherwise undefined
364
364
  */
365
365
  API.prototype.addCustomSpanAttribute = function addCustomSpanAttribute(key, value) {
366
366
  const metric = this.agent.metrics.getOrCreateMetric(
@@ -807,7 +807,7 @@ API.prototype.getBrowserTimingHeader = function getBrowserTimingHeader(options =
807
807
  * Only the first 13 chars of the license should be used for hashing with
808
808
  * the transaction name.
809
809
  */
810
- const key = config.license_key.substr(0, 13)
810
+ const key = config.license_key.substring(0, 13)
811
811
  rumHash.transactionName = hashes.obfuscateNameUsingKey(name, key)
812
812
 
813
813
  rumHash.queueTime = trans.queueTime
@@ -938,7 +938,7 @@ API.prototype.startSegment = function startSegment(name, record, handler, callba
938
938
  * })
939
939
  * @param {string} url
940
940
  * The URL of the transaction. It is used to name and group related transactions in APM,
941
- * so it should be a generic name and not iclude any variable parameters.
941
+ * so it should be a generic name and not include any variable parameters.
942
942
  * @param {Function} handle
943
943
  * Function that represents the transaction work.
944
944
  * @returns {null|*} Returns null if handle is not a function, otherwise the return value of handle
@@ -1026,7 +1026,7 @@ API.prototype.startBackgroundTransaction = startBackgroundTransaction
1026
1026
  * })
1027
1027
  * @param {string} name
1028
1028
  * The name of the transaction. It is used to name and group related
1029
- * transactions in APM, so it should be a generic name and not iclude any
1029
+ * transactions in APM, so it should be a generic name and not include any
1030
1030
  * variable parameters.
1031
1031
  * @param {string} [group]
1032
1032
  * Optional, used for grouping background transactions in APM. For more
@@ -1297,14 +1297,14 @@ API.prototype.recordCustomEvent = function recordCustomEvent(eventType, attribut
1297
1297
  // Filter all object type valued attributes out
1298
1298
  const filteredAttributes = _filterAttributes(attributes, `${eventType} custom event`)
1299
1299
 
1300
- const instrinics = {
1300
+ const intrinsics = {
1301
1301
  type: eventType,
1302
1302
  timestamp: Date.now()
1303
1303
  }
1304
1304
 
1305
1305
  const tx = this.agent.getTransaction()
1306
1306
  const priority = (tx && tx.priority) || Math.random()
1307
- this.agent.customEventAggregator.add([instrinics, filteredAttributes], priority)
1307
+ this.agent.customEventAggregator.add([intrinsics, filteredAttributes], priority)
1308
1308
  }
1309
1309
 
1310
1310
  /**
@@ -1342,7 +1342,7 @@ API.prototype.instrument = function instrument(moduleName, onRequire, onError) {
1342
1342
  * Registers an instrumentation function.
1343
1343
  *
1344
1344
  * - `newrelic.instrumentConglomerate(moduleName, onRequire [, onError])`
1345
- * - `newrelic.isntrumentConglomerate(options)`
1345
+ * - `newrelic.instrumentConglomerate(options)`
1346
1346
  *
1347
1347
  * @param {string|object} moduleName The module name given to require to load the module, or the instrumentation specification
1348
1348
  * @param {string} moduleName.moduleName The module name given to require to load the module
@@ -367,7 +367,7 @@ function _convertRulesToRegex(rules) {
367
367
  if (i !== r.length - 1) {
368
368
  v += '.'
369
369
  } else if (/\\\*$/.test(v)) {
370
- v = v.substr(0, v.length - 2)
370
+ v = v.substring(0, v.length - 2)
371
371
  }
372
372
 
373
373
  const idx = c.findIndex(function findV(a) {
@@ -519,12 +519,12 @@ defaultConfig.definition = () => ({
519
519
  env: 'NEW_RELIC_TRACER_ENABLED'
520
520
  },
521
521
  /**
522
- * The duration at below which the slow transaction tracer should collect a
523
- * transaction trace. If set to 'apdex_f', the threshold will be set to
522
+ * Sets the time, in seconds, for a transaction to be considered slow.
523
+ * When a transaction exceeds this threshold, a transaction trace will be recorded. When set to 'apdex_f', the threshold will be set to
524
524
  * 4 * apdex_t, which with a default apdex_t value of 500 milliseconds will
525
525
  * be 2 seconds.
526
526
  *
527
- * If a time is provided, it is set in seconds.
527
+ * If a number is provided, it is set in seconds.
528
528
  */
529
529
  transaction_threshold: {
530
530
  formatter: float,
@@ -14,7 +14,7 @@ function grabLastUrlSegment(url = '/') {
14
14
  // string for null, undefined, NaN etc.
15
15
  url = '' + (url || '/')
16
16
  const lastSlashIndex = url.lastIndexOf('/')
17
- return url.substr(lastSlashIndex + 1)
17
+ return url.substring(lastSlashIndex + 1)
18
18
  }
19
19
 
20
20
  /**
@@ -35,7 +35,7 @@ class BedrockCommand {
35
35
  result = this.#body.maxTokens
36
36
  } else if (this.isClaude() === true) {
37
37
  result = this.#body.max_tokens_to_sample
38
- } else if (this.isCohere() === true) {
38
+ } else if (this.isClaude3() === true || this.isCohere() === true) {
39
39
  result = this.#body.max_tokens
40
40
  } else if (this.isLlama2() === true) {
41
41
  result = this.#body.max_gen_length
@@ -83,6 +83,11 @@ class BedrockCommand {
83
83
  this.isLlama2() === true
84
84
  ) {
85
85
  result = this.#body.prompt
86
+ } else if (this.isClaude3() === true) {
87
+ result = this.#body?.messages?.reduce((acc, curr) => {
88
+ acc += curr?.content ?? ''
89
+ return acc
90
+ }, '')
86
91
  }
87
92
  return result
88
93
  }
@@ -96,6 +101,7 @@ class BedrockCommand {
96
101
  result = this.#body.textGenerationConfig?.temperature
97
102
  } else if (
98
103
  this.isClaude() === true ||
104
+ this.isClaude3() === true ||
99
105
  this.isAi21() === true ||
100
106
  this.isCohere() === true ||
101
107
  this.isLlama2() === true
@@ -110,7 +116,11 @@ class BedrockCommand {
110
116
  }
111
117
 
112
118
  isClaude() {
113
- return this.#modelId.startsWith('anthropic.claude')
119
+ return this.#modelId.startsWith('anthropic.claude-v')
120
+ }
121
+
122
+ isClaude3() {
123
+ return this.#modelId.startsWith('anthropic.claude-3')
114
124
  }
115
125
 
116
126
  isCohere() {
@@ -30,10 +30,12 @@ class BedrockResponse {
30
30
  #completions = []
31
31
  #id
32
32
 
33
+ /* eslint-disable sonarjs/cognitive-complexity */
33
34
  /**
34
35
  * @param {object} params
35
36
  * @param {AwsBedrockMiddlewareResponse} params.response
36
37
  * @param {BedrockCommand} params.bedrockCommand
38
+ * @param params.isError
37
39
  */
38
40
  constructor({ response, bedrockCommand, isError = false }) {
39
41
  this.#innerResponse = isError ? response.$response : response.response
@@ -57,6 +59,14 @@ class BedrockResponse {
57
59
  } else if (cmd.isClaude() === true) {
58
60
  // TODO: can we make this thing give more than one completion?
59
61
  body.completion && this.#completions.push(body.completion)
62
+ } else if (cmd.isClaude3() === true) {
63
+ if (body?.type === 'message_stop') {
64
+ // Streamed response
65
+ this.#completions = body.completions
66
+ } else {
67
+ this.#completions = body?.content?.map((c) => c.text)
68
+ }
69
+ this.#id = body.id
60
70
  } else if (cmd.isCohere() === true) {
61
71
  this.#completions = body.generations?.map((g) => g.text) ?? []
62
72
  this.#id = body.id
@@ -66,6 +76,7 @@ class BedrockResponse {
66
76
  this.#completions = body.results?.map((r) => r.outputText) ?? []
67
77
  }
68
78
  }
79
+ /* eslint-enable sonarjs/cognitive-complexity */
69
80
 
70
81
  /**
71
82
  * The prompt responses returned by the model.
@@ -92,7 +103,7 @@ class BedrockResponse {
92
103
  const cmd = this.#command
93
104
  if (cmd.isAi21() === true) {
94
105
  result = this.#parsedBody.completions?.[0]?.finishReason.reason
95
- } else if (cmd.isClaude() === true) {
106
+ } else if (cmd.isClaude() === true || cmd.isClaude3() === true) {
96
107
  result = this.#parsedBody.stop_reason
97
108
  } else if (cmd.isCohere() === true) {
98
109
  result = this.#parsedBody.generations?.find((r) => r.finish_reason !== null)?.finish_reason
@@ -105,6 +105,9 @@ class StreamHandler {
105
105
  if (bedrockCommand.isClaude() === true) {
106
106
  this.stopReasonKey = 'stop_reason'
107
107
  this.generator = handleClaude
108
+ } else if (bedrockCommand.isClaude3() === true) {
109
+ this.stopReasonKey = 'stop_reason'
110
+ this.generator = handleClaude3
108
111
  } else if (bedrockCommand.isCohere() === true) {
109
112
  this.stopReasonKey = 'generations.0.finish_reason'
110
113
  this.generator = handleCohere
@@ -207,6 +210,31 @@ async function* handleClaude() {
207
210
  }
208
211
  }
209
212
 
213
+ async function* handleClaude3() {
214
+ let currentBody = {}
215
+ let stopReason
216
+ const completions = []
217
+
218
+ try {
219
+ for await (const event of this.stream) {
220
+ yield event
221
+ const parsed = this.parseEvent(event)
222
+ this.updateHeaders(parsed)
223
+ currentBody = parsed
224
+ if (parsed.type === 'content_block_delta') {
225
+ completions.push(parsed.delta.text)
226
+ } else if (parsed.type === 'message_delta') {
227
+ stopReason = parsed.delta.stop_reason
228
+ }
229
+ }
230
+ } finally {
231
+ currentBody.completions = completions
232
+ currentBody.stop_reason = stopReason
233
+ this.response.output.body = currentBody
234
+ this.finish()
235
+ }
236
+ }
237
+
210
238
  async function* handleCohere() {
211
239
  let currentBody = {}
212
240
  const generations = []
@@ -376,10 +376,10 @@ function parseQuery(query, nodule) {
376
376
  // strip enclosing special characters from collection (table) name
377
377
  if (typeof collection === 'string' && collection.length > 2) {
378
378
  if (/^[\[{'"`]/.test(collection)) {
379
- collection = collection.substr(1)
379
+ collection = collection.substring(1)
380
380
  }
381
381
  if (/[\]}'"`]$/.test(collection)) {
382
- collection = collection.substr(0, collection.length - 1)
382
+ collection = collection.substring(0, collection.length - 1)
383
383
  }
384
384
  }
385
385
 
@@ -187,7 +187,7 @@ NameState.prototype.getPath = function getPath() {
187
187
  if (a[0] !== '/' && path[path.length - 1] !== '/') {
188
188
  path += '/'
189
189
  } else if (a[0] === '/' && path[path.length - 1] === '/') {
190
- a = a.substr(1)
190
+ a = a.substring(1)
191
191
  }
192
192
  path += a
193
193
  }
@@ -41,7 +41,8 @@ function calculatePathHash(appName, pathName, referingPathHash) {
41
41
  const result = (rotated ^ hash) >>> 0
42
42
 
43
43
  // This is a trick to pad it out to 8 chars regardless of length.
44
- return ('00000000' + result.toString(16)).substr(-8)
44
+ const str = '00000000' + result.toString(16)
45
+ return str.substring(str.length - 8)
45
46
  }
46
47
 
47
48
  function getHash(appName, txName) {
@@ -78,7 +79,7 @@ function int32ToByteArray(int32) {
78
79
  // Lookup table for converting byte values to hex
79
80
  const byteToHex = []
80
81
  for (let i = 0; i < 256; ++i) {
81
- byteToHex[i] = (i + 0x100).toString(16).substr(1)
82
+ byteToHex[i] = (i + 0x100).toString(16).substring(1)
82
83
  }
83
84
 
84
85
  function makeId(length = 16) {
@@ -41,7 +41,7 @@ module.exports.getBootId = function getBootId(agent, callback) {
41
41
  if (data.length !== 36) {
42
42
  bootIdError()
43
43
  if (data.length > 128) {
44
- data = data.substr(0, 128)
44
+ data = data.substring(0, 128)
45
45
  }
46
46
  }
47
47
 
@@ -54,8 +54,10 @@ function fetchGCPInfo(agent, callback) {
54
54
  agent.metrics.getOrCreateMetric(NAMES.UTILIZATION.GCP_ERROR).incrementCallCount()
55
55
  } else {
56
56
  // normalize
57
- results.machineType = results.machineType.substr(results.machineType.lastIndexOf('/') + 1)
58
- results.zone = results.zone.substr(results.zone.lastIndexOf('/') + 1)
57
+ results.machineType = results.machineType.substring(
58
+ results.machineType.lastIndexOf('/') + 1
59
+ )
60
+ results.zone = results.zone.substring(results.zone.lastIndexOf('/') + 1)
59
61
 
60
62
  resultDict = results
61
63
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "newrelic",
3
- "version": "11.19.0",
3
+ "version": "11.20.0",
4
4
  "author": "New Relic Node.js agent team <nodejs@newrelic.com>",
5
5
  "license": "Apache-2.0",
6
6
  "contributors": [
@@ -163,7 +163,7 @@
163
163
  "lint:fix": "eslint --fix, ./*.{js,mjs} lib test bin examples",
164
164
  "public-docs": "jsdoc -c ./jsdoc-conf.jsonc && cp examples/shim/*.png out/",
165
165
  "publish-docs": "./bin/publish-docs.sh",
166
- "services": "docker compose up -d --wait",
166
+ "services": "DOCKER_PLATFORM=linux/$(uname -m) docker compose up -d --wait",
167
167
  "services:stop": "docker compose down",
168
168
  "smoke": "npm run ssl && time tap test/smoke/**/**/*.tap.js --timeout=180 --no-coverage",
169
169
  "ssl": "./bin/ssl.sh",