newrelic 13.2.0 → 13.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.
Files changed (59) hide show
  1. package/NEWS.md +44 -0
  2. package/THIRD_PARTY_NOTICES.md +219 -8
  3. package/api.js +1 -1
  4. package/esm-loader.mjs +6 -1
  5. package/lib/instrumentation/@azure/functions.js +8 -46
  6. package/lib/instrumentation/core/http-outbound.js +26 -10
  7. package/lib/instrumentation/core/http.js +20 -118
  8. package/lib/instrumentations.js +0 -14
  9. package/lib/otel/logs/index.js +80 -0
  10. package/lib/otel/metrics/index.js +119 -0
  11. package/lib/otel/setup-signal.js +37 -0
  12. package/lib/otel/setup.js +15 -25
  13. package/lib/otel/{attr-reconciler.js → traces/attr-reconciler.js} +2 -2
  14. package/lib/otel/{exception-mapping.js → traces/exception-mapping.js} +1 -1
  15. package/lib/otel/traces/index.js +40 -0
  16. package/lib/otel/{rules.js → traces/rules.js} +1 -1
  17. package/lib/otel/{segment-synthesis.js → traces/segment-synthesis.js} +5 -4
  18. package/lib/otel/{segments → traces/segments}/consumer.js +4 -4
  19. package/lib/otel/{segments → traces/segments}/database.js +6 -6
  20. package/lib/otel/{segments → traces/segments}/http-external.js +11 -8
  21. package/lib/otel/traces/segments/index.js +22 -0
  22. package/lib/otel/{segments → traces/segments}/internal.js +1 -1
  23. package/lib/otel/{segments → traces/segments}/producer.js +2 -2
  24. package/lib/otel/{segments → traces/segments}/server.js +4 -4
  25. package/lib/otel/{segments → traces/segments}/utils.js +1 -1
  26. package/lib/otel/{span-processor.js → traces/span-processor.js} +13 -19
  27. package/lib/otel/{transformation-rules.json → traces/transformation-rules.json} +3 -2
  28. package/lib/otel/{utils.js → traces/utils.js} +2 -1
  29. package/lib/serverless/aws-lambda.js +7 -68
  30. package/lib/shim/webframework-shim/middleware.js +1 -1
  31. package/lib/shimmer.js +2 -2
  32. package/lib/subscriber-configs.js +2 -1
  33. package/lib/subscribers/base.js +30 -0
  34. package/lib/subscribers/elasticsearch/config.js +1 -0
  35. package/lib/subscribers/mcp-sdk/client-request.js +66 -0
  36. package/lib/subscribers/mcp-sdk/config.js +13 -75
  37. package/lib/subscribers/openai/base.js +21 -0
  38. package/lib/subscribers/openai/chat-responses.js +15 -0
  39. package/lib/subscribers/openai/chat.js +85 -0
  40. package/lib/subscribers/openai/client.js +31 -0
  41. package/lib/subscribers/openai/config.js +85 -0
  42. package/lib/subscribers/openai/embeddings.js +54 -0
  43. package/lib/subscribers/openai/utils.js +349 -0
  44. package/lib/transaction/index.js +157 -56
  45. package/lib/transaction/trace/segment.js +5 -2
  46. package/lib/util/urltils.js +158 -192
  47. package/lib/utilization/common.js +0 -6
  48. package/package.json +3 -4
  49. package/lib/instrumentation/openai.js +0 -482
  50. package/lib/otel/logs/bootstrap-logs.js +0 -84
  51. package/lib/otel/metrics/bootstrap-metrics.js +0 -117
  52. package/lib/otel/segments/index.js +0 -22
  53. package/lib/patch-module.js +0 -70
  54. package/lib/subscribers/mcp-sdk/client-prompt.js +0 -23
  55. package/lib/subscribers/mcp-sdk/client-resource.js +0 -24
  56. package/lib/subscribers/mcp-sdk/client-tool.js +0 -23
  57. package/lib/subscribers/mcp-sdk/client.js +0 -29
  58. /package/lib/otel/{constants.js → traces/constants.js} +0 -0
  59. /package/lib/otel/{sampler.js → traces/sampler.js} +0 -0
@@ -5,9 +5,17 @@
5
5
 
6
6
  'use strict'
7
7
 
8
- const url = require('url')
9
8
  const logger = require('../logger').child({ component: 'urltils' })
9
+ /**
10
+ * Utility functions for enforcing New Relic naming conditions on URLs,
11
+ * and extracting and setting parameters on traces / web trace segments.
12
+ */
10
13
 
14
+ /**
15
+ * Dictionary whose keys are all synonyms for localhost.
16
+ *
17
+ * @constant
18
+ */
11
19
  const LOCALHOST_NAMES = {
12
20
  localhost: true,
13
21
  '127.0.0.1': true,
@@ -19,214 +27,161 @@ const LOCALHOST_NAMES = {
19
27
  }
20
28
 
21
29
  /**
22
- * Utility functions for enforcing New Relic naming conditions on URLs,
23
- * and extracting and setting parameters on traces / web trace segments.
30
+ * Checks if the given name is in the dictionary of localhost names.
31
+ *
32
+ * @param {string} host - The hostname to lookup.
33
+ * @returns {boolean} - True if the given hostname is a synonym for localhost.
24
34
  */
25
- module.exports = {
26
- /**
27
- * Dictionary whose keys are all synonyms for localhost.
28
- *
29
- * @constant
30
- */
31
- LOCALHOST_NAMES,
35
+ function isLocalhost(host) {
36
+ return LOCALHOST_NAMES[host] != null
37
+ }
32
38
 
33
- /**
34
- * Checks if the given name is in the dictionary of localhost names.
35
- *
36
- * @param {string} host - The hostname to lookup.
37
- * @returns {boolean} - True if the given hostname is a synonym for localhost.
38
- */
39
- isLocalhost: function isLocahost(host) {
40
- return LOCALHOST_NAMES[host] != null
41
- },
42
-
43
- /**
44
- * This was handed down from the prototype as the canonical list of status
45
- * codes that short-circuit naming and normalization. The agent can be
46
- * configured to mark HTTP status codes as not being errors.
47
- *
48
- * @param {Config} config The configuration containing the error list.
49
- * @param {string} code The HTTP status code to check.
50
- * @returns {boolean} Whether the status code should be ignored.
51
- */
52
- isError: function isError(config, code) {
53
- return code >= 400 && !isIgnoredStatusCodeForErrors(config, code)
54
- },
55
-
56
- /**
57
- * Returns true if the status code is an HTTP error, and it is configured to be ignored.
58
- *
59
- * @param {Config} config The configuration containing the error list.
60
- * @param {string} code The HTTP status code to check.
61
- * @returns {boolean} Whether the status code should be ignored.
62
- */
63
- isIgnoredError: function isIgnoredError(config, code) {
64
- return code >= 400 && isIgnoredStatusCodeForErrors(config, code)
65
- },
66
-
67
- /**
68
- * Returns true if the status code is configured to be expected
69
- *
70
- * @param {Config} config The configuration containing the error list.
71
- * @param {string} code The HTTP status code to check.
72
- * @returns {boolean} Whether the status code is expected.
73
- */
74
- isExpectedError: function isExpectedError(config, code) {
75
- return isExpectedStatusCodeForErrors(config, code)
76
- },
77
-
78
- /**
79
- * Get back the pieces of the URL that New Relic cares about. Apply these
80
- * restrictions, in order:
81
- *
82
- * 1. Ensure that after parsing the URL, there's at least '/'
83
- * 2. Strip off session trackers after ';' (a New Relic convention)
84
- * 3. Remove trailing slash.
85
- *
86
- * @param {string|url.URL} requestURL The URL fragment to be scrubbed.
87
- * @returns {string} The cleaned URL.
88
- */
89
- scrub: function scrub(requestURL) {
90
- if (typeof requestURL === 'string') {
91
- requestURL = url.parse(requestURL)
92
- }
39
+ /**
40
+ * This was handed down from the prototype as the canonical list of status
41
+ * codes that short-circuit naming and normalization. The agent can be
42
+ * configured to mark HTTP status codes as not being errors.
43
+ *
44
+ * @param {Config} config The configuration containing the error list.
45
+ * @param {string} code The HTTP status code to check.
46
+ * @returns {boolean} Whether the status code should be ignored.
47
+ */
48
+ function isError(config, code) {
49
+ return code >= 400 && !isIgnoredStatusCodeForErrors(config, code)
50
+ }
51
+
52
+ /**
53
+ * Returns true if the status code is an HTTP error, and it is configured to be ignored.
54
+ *
55
+ * @param {Config} config The configuration containing the error list.
56
+ * @param {string} code The HTTP status code to check.
57
+ * @returns {boolean} Whether the status code should be ignored.
58
+ */
59
+ function isIgnoredError(config, code) {
60
+ return code >= 400 && isIgnoredStatusCodeForErrors(config, code)
61
+ }
62
+
63
+ /**
64
+ * Returns true if the status code is configured to be expected
65
+ *
66
+ * @param {Config} config The configuration containing the error list.
67
+ * @param {string} code The HTTP status code to check.
68
+ * @returns {boolean} Whether the status code is expected.
69
+ */
70
+ function isExpectedError(config, code) {
71
+ return isExpectedStatusCodeForErrors(config, code)
72
+ }
93
73
 
94
- let path = requestURL.pathname
74
+ /**
75
+ * Get back the pieces of the URL that New Relic cares about. Apply these
76
+ * restrictions, in order:
77
+ *
78
+ * 1. Ensure that after parsing the URL, there's at least '/'
79
+ * 2. Strip off session trackers after ';' (a New Relic convention)
80
+ * 3. Remove trailing slash.
81
+ *
82
+ * @param {url.URL} requestURL The URL fragment to be scrubbed.
83
+ * @returns {string} The cleaned URL.
84
+ * @private
85
+ */
86
+ function scrub(requestURL) {
87
+ let path = requestURL.pathname
95
88
 
96
- if (path) {
97
- path = path.split(';')[0]
89
+ if (path) {
90
+ path = path.split(';')[0]
98
91
 
99
- if (path !== '/' && path.charAt(path.length - 1) === '/') {
100
- path = path.substring(0, path.length - 1)
101
- }
102
- } else {
103
- path = '/'
92
+ if (path !== '/' && path.charAt(path.length - 1) === '/') {
93
+ path = path.substring(0, path.length - 1)
104
94
  }
95
+ } else {
96
+ path = '/'
97
+ }
105
98
 
106
- return path
107
- },
108
-
109
- /**
110
- * Extract query parameters, dealing with bare parameters and parameters with
111
- * no value as appropriate:
112
- *
113
- * 'var1&var2=value' is not necessarily the same as 'var1=&var2=value'
114
- *
115
- * In my world, one is an assertion of presence, and the other is an empty
116
- * variable. Some web frameworks behave this way as well, so don't lose
117
- * information.
118
- *
119
- * @param {string|url.URL} requestURL The URL to be parsed.
120
- * @returns {object} The parameters parsed from the request
121
- */
122
- parseParameters: function parseParameters(requestURL) {
123
- let parsed = requestURL
124
- const parameters = Object.create(null)
125
-
126
- function addParam(key, value, raw) {
127
- if (value === '' && raw.indexOf(key + '=') === -1) {
99
+ return path
100
+ }
101
+
102
+ /**
103
+ * Extract query parameters, dealing with bare parameters and parameters with
104
+ * no value as appropriate:
105
+ *
106
+ * 'var1&var2=value' is not necessarily the same as 'var1=&var2=value'
107
+ *
108
+ * In my world, one is an assertion of presence, and the other is an empty
109
+ * variable. Some web frameworks behave this way as well, so don't lose
110
+ * information.
111
+ *
112
+ * @param {url.URL} requestURL The URL to be parsed.
113
+ * @returns {object} The parameters parsed from the request
114
+ * @private
115
+ */
116
+ function parseParameters(requestURL) {
117
+ const parsed = requestURL
118
+ const parameters = Object.create(null)
119
+
120
+ if (parsed.searchParams) {
121
+ for (const [key, value] of parsed.searchParams) {
122
+ if (value === '' && parsed.search.indexOf(`?${key}=`) === -1 && parsed.search.indexOf(`&${key}=`) === -1) {
128
123
  parameters[key] = true
129
124
  } else {
130
125
  parameters[key] = value
131
126
  }
132
127
  }
128
+ }
133
129
 
134
- if (typeof requestURL === 'string') {
135
- parsed = url.parse(requestURL, true)
136
- }
130
+ return parameters
131
+ }
137
132
 
138
- if (parsed.query) {
139
- for (const key of Object.keys(parsed.query)) {
140
- addParam(key, parsed.query[key], parsed.path || '')
141
- }
142
- }
133
+ /**
134
+ * Performs the logic of `scrub` and `parseParameters` with
135
+ * only a single parse of the given URL.
136
+ *
137
+ * @param {url.URL} requestURL - The URL to scrub and extra parameters from.
138
+ * @returns {object} An object containing the scrubbed url at `.path` and the
139
+ * parsed parameters at `.parameters` and `.protocol`.
140
+ */
141
+ function scrubAndParseParameters(requestURL) {
142
+ return {
143
+ protocol: requestURL.protocol,
144
+ path: scrub(requestURL),
145
+ parameters: parseParameters(requestURL)
146
+ }
147
+ }
143
148
 
144
- if (parsed.searchParams) {
145
- for (const [key, value] of parsed.searchParams) {
146
- addParam(key, value, parsed.pathname || '')
147
- }
148
- }
149
+ /**
150
+ * Obfuscates path parameters with regex from config
151
+ *
152
+ * @param {Config} config The configuration containing the regex
153
+ * @param {string} path The path to be obfuscated
154
+ * @returns {string} The obfuscated path or the original path
155
+ */
156
+ function obfuscatePath(config, path) {
157
+ const { enabled, regex } = config.url_obfuscation
158
+ if (typeof path !== 'string' || !enabled || !regex) {
159
+ return path
160
+ }
149
161
 
150
- return parameters
151
- },
152
-
153
- /**
154
- * Performs the logic of `urltils.scrub` and `urltils.parseParameters` with
155
- * only a single parse of the given URL.
156
- *
157
- * @param {string|url.URL} requestURL - The URL to scrub and extra parameters from.
158
- * @returns {object} An object containing the scrubbed url at `.path` and the
159
- * parsed parameters at `.parameters`.
160
- */
161
- scrubAndParseParameters: function scrubAndParseParameters(requestURL) {
162
- if (typeof requestURL === 'string') {
163
- requestURL = url.parse(requestURL, true)
164
- }
165
- return {
166
- protocol: requestURL.protocol,
167
- path: this.scrub(requestURL),
168
- parameters: this.parseParameters(requestURL)
169
- }
170
- },
171
-
172
- /**
173
- * Obfuscates path parameters with regex from config
174
- *
175
- * @param {Config} config The configuration containing the regex
176
- * @param {string} path The path to be obfuscated
177
- * @returns {string} The obfuscated path or the original path
178
- */
179
- obfuscatePath: function obfuscatePath(config, path) {
180
- const { enabled, regex } = config.url_obfuscation
181
- if (typeof path !== 'string' || !enabled || !regex) {
182
- return path
183
- }
162
+ const { pattern, flags = '', replacement = '' } = regex
163
+ try {
164
+ const regexPattern = new RegExp(pattern, flags)
165
+ return path.replace(regexPattern, replacement)
166
+ } catch {
167
+ logger.warn('Invalid regular expression for url_obfuscation.regex.pattern', pattern)
168
+ return path
169
+ }
170
+ }
184
171
 
185
- const { pattern, flags = '', replacement = '' } = regex
186
- try {
187
- const regexPattern = new RegExp(pattern, flags)
188
- return path.replace(regexPattern, replacement)
189
- } catch {
190
- logger.warn('Invalid regular expression for url_obfuscation.regex.pattern', pattern)
191
- return path
192
- }
193
- },
194
-
195
- /**
196
- * Copy a set of request parameters from one object to another,
197
- * but do not overwrite any existing parameters in destination,
198
- * including parameters set to null or undefined.
199
- *
200
- * @param {object} source Parameters to be copied (not changed).
201
- * @param {object} destination Dictionary to which parameters are copied
202
- * (mutated in place).
203
- */
204
- copyParameters: function copyParameters(source, destination) {
205
- if (source && destination) {
206
- const keys = Object.keys(source)
207
- for (let i = 0; i < keys.length; i++) {
208
- const key = keys[i]
209
- if (!(key in destination)) {
210
- destination[key] = source[key]
211
- }
212
- }
213
- }
214
- },
215
-
216
- /**
217
- * Copy a set of request parameters from one object to another.
218
- * Existing attributes on the `destination` will be overwritten.
219
- *
220
- * @param {object} source Parameters to be copied (not changed).
221
- * @param {object} destination Dictionary to which parameters are copied
222
- * (mutated in place).
223
- */
224
- overwriteParameters: function overwriteParameters(source, destination) {
225
- const keys = Object.keys(source)
226
- for (let i = 0; i < keys.length; i++) {
227
- const key = keys[i]
228
- destination[key] = source[key]
229
- }
172
+ /**
173
+ * Copy a set of request parameters from one object to another.
174
+ * Existing attributes on the `destination` will be overwritten.
175
+ *
176
+ * @param {object} source Parameters to be copied (not changed).
177
+ * @param {object} destination Dictionary to which parameters are copied
178
+ * (mutated in place).
179
+ */
180
+ function overwriteParameters(source, destination) {
181
+ const keys = Object.keys(source)
182
+ for (let i = 0; i < keys.length; i++) {
183
+ const key = keys[i]
184
+ destination[key] = source[key]
230
185
  }
231
186
  }
232
187
 
@@ -245,3 +200,14 @@ function isExpectedStatusCodeForErrors(config, code) {
245
200
  }
246
201
  return codes.indexOf(parseInt(code, 10)) >= 0
247
202
  }
203
+
204
+ module.exports = {
205
+ LOCALHOST_NAMES,
206
+ isLocalhost,
207
+ isError,
208
+ isIgnoredError,
209
+ isExpectedError,
210
+ scrubAndParseParameters,
211
+ obfuscatePath,
212
+ overwriteParameters
213
+ }
@@ -10,7 +10,6 @@ const http = require('http')
10
10
  const logger = require('../logger').child({ component: 'utilization-request' })
11
11
  const fs = require('../util/unwrapped-core').fs
12
12
  const properties = require('../util/properties')
13
- const url = require('url')
14
13
 
15
14
  exports.checkValueString = checkValueString
16
15
  function checkValueString(str) {
@@ -65,11 +64,6 @@ exports.getKeys = function getKeys(data, keys, allValuesMustBeValid = true) {
65
64
 
66
65
  exports.request = function request(opts, agent, cb) {
67
66
  // Add default timeout of a second to the request
68
-
69
- if (typeof opts === 'string') {
70
- opts = url.parse(opts)
71
- }
72
-
73
67
  opts.timeout = opts.timeout || 1000
74
68
 
75
69
  // This can make more that GET requests if you pass in an object
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "newrelic",
3
- "version": "13.2.0",
3
+ "version": "13.3.0",
4
4
  "author": "New Relic Node.js agent team <nodejs@newrelic.com>",
5
5
  "license": "Apache-2.0",
6
6
  "contributors": [
@@ -201,7 +201,7 @@
201
201
  "#test/assert": "./test/lib/custom-assertions/index.js"
202
202
  },
203
203
  "dependencies": {
204
- "@apm-js-collab/code-transformer": "^0.6.0",
204
+ "@apm-js-collab/tracing-hooks": "^0.1.0",
205
205
  "@grpc/grpc-js": "^1.13.2",
206
206
  "@grpc/proto-loader": "^0.7.5",
207
207
  "@newrelic/security-agent": "^2.4.2",
@@ -272,8 +272,7 @@
272
272
  "self-cert": "^2.0.0",
273
273
  "should": "*",
274
274
  "sinon": "^5.1.1",
275
- "superagent": "^9.0.1",
276
- "testdouble": "^3.20.2"
275
+ "superagent": "^9.0.1"
277
276
  },
278
277
  "repository": {
279
278
  "type": "git",