newrelic 13.0.0 → 13.2.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 (68) hide show
  1. package/NEWS.md +92 -0
  2. package/README.md +2 -4
  3. package/THIRD_PARTY_NOTICES.md +429 -9
  4. package/esm-loader.mjs +9 -1
  5. package/index.js +38 -3
  6. package/lib/agent.js +8 -2
  7. package/lib/config/build-instrumentation-config.js +3 -0
  8. package/lib/config/default.js +1397 -1383
  9. package/lib/config/index.js +15 -19
  10. package/lib/context-manager/context.js +13 -4
  11. package/lib/harvester.js +11 -13
  12. package/lib/instrumentation/@google/genai.js +8 -3
  13. package/lib/instrumentation/@hapi/hapi.js +4 -6
  14. package/lib/instrumentation/@nestjs/core.js +12 -14
  15. package/lib/instrumentation/aws-sdk/v3/bedrock.js +2 -2
  16. package/lib/instrumentation/core/http-outbound.js +11 -26
  17. package/lib/instrumentation/kafkajs/producer.js +13 -19
  18. package/lib/instrumentation/openai.js +2 -2
  19. package/lib/instrumentation/undici.js +48 -40
  20. package/lib/instrumentations.js +14 -5
  21. package/lib/llm-events/aws-bedrock/utils.js +1 -1
  22. package/lib/metrics/names.js +8 -0
  23. package/lib/metrics/normalizer.js +1 -3
  24. package/lib/otel/context.js +18 -14
  25. package/lib/otel/logs/bootstrap-logs.js +84 -0
  26. package/lib/otel/logs/no-op-exporter.js +25 -0
  27. package/lib/otel/logs/normalize-timestamp.js +59 -0
  28. package/lib/otel/logs/proxying-provider.js +46 -0
  29. package/lib/otel/logs/severity-to-string.js +56 -0
  30. package/lib/otel/metrics/bootstrap-metrics.js +1 -1
  31. package/lib/otel/setup.js +21 -8
  32. package/lib/patch-module.js +70 -0
  33. package/lib/serverless/aws-lambda.js +1 -3
  34. package/lib/shim/webframework-shim/middleware-mounter.js +1 -3
  35. package/lib/shimmer.js +56 -8
  36. package/lib/subscriber-configs.js +17 -0
  37. package/lib/subscribers/application-logs.js +55 -0
  38. package/lib/subscribers/base.js +177 -0
  39. package/lib/subscribers/create-config.js +27 -0
  40. package/lib/subscribers/db-operation.js +21 -0
  41. package/lib/subscribers/db-query.js +54 -0
  42. package/lib/subscribers/db.js +57 -0
  43. package/lib/subscribers/elasticsearch/config.js +49 -0
  44. package/lib/subscribers/elasticsearch/elasticsearch.js +42 -0
  45. package/lib/subscribers/elasticsearch/opensearch.js +15 -0
  46. package/lib/subscribers/elasticsearch/transport.js +14 -0
  47. package/lib/subscribers/ioredis/config.js +37 -0
  48. package/lib/subscribers/ioredis/index.js +48 -0
  49. package/lib/subscribers/mcp-sdk/client-prompt.js +23 -0
  50. package/lib/subscribers/mcp-sdk/client-resource.js +24 -0
  51. package/lib/subscribers/mcp-sdk/client-tool.js +23 -0
  52. package/lib/subscribers/mcp-sdk/client.js +29 -0
  53. package/lib/subscribers/mcp-sdk/config.js +104 -0
  54. package/lib/subscribers/pino/config.js +20 -0
  55. package/lib/subscribers/pino/index.js +102 -0
  56. package/lib/transaction/index.js +4 -1
  57. package/lib/transaction/trace/aggregator.js +7 -9
  58. package/lib/util/camel-case.js +1 -3
  59. package/lib/util/get-package-version.js +34 -0
  60. package/lib/util/urltils.js +19 -13
  61. package/lib/w3c/tracestate.js +3 -3
  62. package/newrelic.js +10 -0
  63. package/package.json +9 -5
  64. package/lib/instrumentation/@elastic/elasticsearch.js +0 -62
  65. package/lib/instrumentation/@opensearch-project/opensearch.js +0 -66
  66. package/lib/instrumentation/ioredis.js +0 -50
  67. package/lib/instrumentation/pino/nr-hooks.js +0 -19
  68. package/lib/instrumentation/pino/pino.js +0 -168
@@ -0,0 +1,29 @@
1
+ /*
2
+ * Copyright 2025 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ 'use strict'
7
+
8
+ const Subscriber = require('../base')
9
+
10
+ class McpClientSubscriber extends Subscriber {
11
+ constructor({ agent, logger, channelName }) {
12
+ super({ agent, logger, packageName: '@modelcontextprotocol/sdk', channelName })
13
+ this.events = ['asyncEnd']
14
+ this.segmentName = 'Unknown'
15
+ }
16
+
17
+ get enabled() {
18
+ return super.enabled && this.config.ai_monitoring.enabled === true
19
+ }
20
+
21
+ handler(ctx) {
22
+ return this.createSegment({
23
+ name: this.segmentName,
24
+ ctx
25
+ })
26
+ }
27
+ }
28
+
29
+ module.exports = McpClientSubscriber
@@ -0,0 +1,104 @@
1
+ /*
2
+ * Copyright 2025 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ const mcpClientToolConfig = {
7
+ path: './mcp-sdk/client-tool',
8
+ instrumentations: [
9
+ {
10
+ channelName: 'nr_callTool',
11
+ module: {
12
+ name: '@modelcontextprotocol/sdk',
13
+ versionRange: '>=1.13.0',
14
+ filePath: 'dist/cjs/client/index.js'
15
+ },
16
+ functionQuery: {
17
+ className: 'Client',
18
+ methodName: 'callTool', // must be methodName, not functionName
19
+ kind: 'Async'
20
+ }
21
+ },
22
+ {
23
+ channelName: 'nr_callTool',
24
+ module: {
25
+ name: '@modelcontextprotocol/sdk',
26
+ versionRange: '>=1.13.0',
27
+ filePath: 'dist/esm/client/index.js'
28
+ },
29
+ functionQuery: {
30
+ className: 'Client',
31
+ methodName: 'callTool',
32
+ kind: 'Async'
33
+ }
34
+ },
35
+ ]
36
+ }
37
+
38
+ const mcpClientResourceConfig = {
39
+ path: './mcp-sdk/client-resource',
40
+ instrumentations: [
41
+ {
42
+ channelName: 'nr_readResource',
43
+ module: {
44
+ name: '@modelcontextprotocol/sdk',
45
+ versionRange: '>=1.13.0',
46
+ filePath: 'dist/cjs/client/index.js'
47
+ },
48
+ functionQuery: {
49
+ className: 'Client',
50
+ methodName: 'readResource',
51
+ kind: 'Async'
52
+ }
53
+ },
54
+ {
55
+ channelName: 'nr_readResource',
56
+ module: {
57
+ name: '@modelcontextprotocol/sdk',
58
+ versionRange: '>=1.13.0',
59
+ filePath: 'dist/esm/client/index.js'
60
+ },
61
+ functionQuery: {
62
+ className: 'Client',
63
+ methodName: 'readResource',
64
+ kind: 'Async'
65
+ }
66
+ },
67
+ ]
68
+ }
69
+
70
+ const mcpClientPromptConfig = {
71
+ path: './mcp-sdk/client-prompt',
72
+ instrumentations: [
73
+ {
74
+ channelName: 'nr_getPrompt',
75
+ module: {
76
+ name: '@modelcontextprotocol/sdk',
77
+ versionRange: '>=1.13.0',
78
+ filePath: 'dist/cjs/client/index.js'
79
+ },
80
+ functionQuery: {
81
+ className: 'Client',
82
+ methodName: 'getPrompt',
83
+ kind: 'Async'
84
+ }
85
+ },
86
+ {
87
+ channelName: 'nr_getPrompt',
88
+ module: {
89
+ name: '@modelcontextprotocol/sdk',
90
+ versionRange: '>=1.13.0',
91
+ filePath: 'dist/esm/client/index.js'
92
+ },
93
+ functionQuery: {
94
+ className: 'Client',
95
+ methodName: 'getPrompt',
96
+ kind: 'Async'
97
+ }
98
+ },
99
+ ]
100
+ }
101
+
102
+ module.exports = {
103
+ '@modelcontextprotocol/sdk': [mcpClientToolConfig, mcpClientResourceConfig, mcpClientPromptConfig],
104
+ }
@@ -0,0 +1,20 @@
1
+ /*
2
+ * Copyright 2025 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ module.exports = {
7
+ pino: [{
8
+ path: './pino',
9
+ instrumentations: [
10
+ {
11
+ channelName: 'nr_asJson',
12
+ module: { name: 'pino', versionRange: '>=8.0.0', filePath: 'lib/tools.js' },
13
+ functionQuery: {
14
+ functionName: 'asJson',
15
+ kind: 'Sync'
16
+ }
17
+ }
18
+ ]
19
+ }]
20
+ }
@@ -0,0 +1,102 @@
1
+ /*
2
+ * Copyright 2025 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ 'use strict'
7
+ const ApplicationLogsSubscriber = require('../application-logs')
8
+ const { truncate } = require('../../util/application-logging')
9
+
10
+ class PinoSubscriber extends ApplicationLogsSubscriber {
11
+ constructor({ agent, logger }) {
12
+ super({ agent, logger, packageName: 'pino', channelName: 'nr_asJson' })
13
+ this.events = ['end']
14
+ }
15
+
16
+ handler(data, ctx) {
17
+ this.createModuleUsageMetric('pino')
18
+ const { self, arguments: args } = data
19
+ const level = self?.levels?.labels?.[args[2]]
20
+ this.incrementLinesMetric(level)
21
+ const useMergeObj = this.decorateLogLine(data)
22
+ ctx.extras = { useMergeObj }
23
+ return ctx
24
+ }
25
+
26
+ decorateLogLine(data) {
27
+ // Pino log methods accept a singular object (a merging object) that can
28
+ // have a `msg` property for the log message. In such cases, we need to
29
+ // update that log property instead of the second parameter.
30
+ const useMergeObj = data.arguments[1] === undefined && Object.hasOwn(data.arguments[0], 'msg')
31
+ const meta = super.decorateLogLine()
32
+ if (meta) {
33
+ if (useMergeObj === true) {
34
+ data.arguments[0].msg += this.agent.getNRLinkingMetadata()
35
+ } else {
36
+ data.arguments[1] += this.agent.getNRLinkingMetadata()
37
+ }
38
+ }
39
+ return useMergeObj
40
+ }
41
+
42
+ end(data) {
43
+ this.forwardLogLine(data)
44
+ }
45
+
46
+ /**
47
+ * reformats error and assigns NR context data
48
+ * to log line
49
+ *
50
+ * @param {object} data event passed to the end handler
51
+ * @param {object} ctx agent context object
52
+ * @returns {function} wrapped log formatter function
53
+ */
54
+ reformatLogLine(data, ctx) {
55
+ const subscriber = this
56
+ const { self, result: logLine, arguments: args } = data
57
+ const msg = ctx?.extras?.useMergeObj === true ? args[0].msg : args[1]
58
+ const level = self?.levels?.labels?.[args[2]]
59
+ const metadata = this.agent.getLinkingMetadata(true)
60
+
61
+ const agentMeta = Object.assign({}, { timestamp: Date.now() }, metadata)
62
+ // eslint-disable-next-line eqeqeq
63
+ if (msg != undefined) {
64
+ // The spec lists `message` as "MUST" under the required column, but then
65
+ // details that it "MUST be omitted" if the value is "empty". Additionally,
66
+ // if someone has logged only a merging object, and that object contains a
67
+ // message key, we do not want to overwrite their value. See issue 2595.
68
+ agentMeta.message = msg
69
+ }
70
+
71
+ /**
72
+ * A function that gets executed in `_toPayloadSync` of log aggregator.
73
+ * This will parse the serialized log line and then add the relevant NR
74
+ * context metadata and rename the time/msg keys to timestamp/message
75
+ * @returns {object} formatted log line
76
+ */
77
+ return function formatLogLine() {
78
+ let formattedLog
79
+ try {
80
+ formattedLog = JSON.parse(logLine)
81
+ } catch (err) {
82
+ subscriber.logger.error('Failed to parse log line as json: %s', err.message)
83
+ return
84
+ }
85
+
86
+ if (formattedLog.err) {
87
+ formattedLog['error.message'] = truncate(formattedLog.err.message)
88
+ formattedLog['error.stack'] = truncate(formattedLog.err.stack)
89
+ formattedLog['error.class'] = formattedLog.err.type
90
+ delete formattedLog.err
91
+ }
92
+
93
+ Object.assign(formattedLog, agentMeta)
94
+ formattedLog.level = level
95
+ delete formattedLog.time
96
+ delete formattedLog.msg
97
+ return formattedLog
98
+ }
99
+ }
100
+ }
101
+
102
+ module.exports = PinoSubscriber
@@ -409,7 +409,10 @@ function finalizeNameFromUri(requestURL, statusCode) {
409
409
  )
410
410
  }
411
411
 
412
- this.url = urltils.scrub(requestURL)
412
+ if (!this.agent.config.url_obfuscation.enabled) {
413
+ this.url = urltils.scrub(requestURL)
414
+ }
415
+
413
416
  this.statusCode = statusCode
414
417
  this.name = this.getFullName()
415
418
 
@@ -190,16 +190,14 @@ class TransactionTraceAggregator extends TraceAggregator {
190
190
  return callback(null, traces)
191
191
  }
192
192
 
193
- const tracePromises = traces.map((trace) => {
194
- return new Promise((resolve, reject) => {
195
- trace.generateJSON((err, data) => {
196
- if (err) {
197
- reject(err)
198
- }
199
- resolve(data)
200
- })
193
+ const tracePromises = traces.map((trace) => new Promise((resolve, reject) => {
194
+ trace.generateJSON((err, data) => {
195
+ if (err) {
196
+ reject(err)
197
+ }
198
+ resolve(data)
201
199
  })
202
- })
200
+ }))
203
201
 
204
202
  try {
205
203
  const encodedTraces = await Promise.all(tracePromises)
@@ -19,8 +19,6 @@ const words = (string) => string.match(wordPattern) || []
19
19
  */
20
20
  module.exports = function toCamelCase(string) {
21
21
  return words(string)
22
- .map((word, index) =>
23
- index === 0 ? word.toLowerCase() : word.slice(0, 1).toUpperCase() + word.slice(1)
24
- )
22
+ .map((word, index) => (index === 0 ? word.toLowerCase() : word.slice(0, 1).toUpperCase() + word.slice(1)))
25
23
  .join('')
26
24
  }
@@ -0,0 +1,34 @@
1
+ /*
2
+ * Copyright 2025 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ 'use strict'
7
+ const { readFileSync } = require('node:fs')
8
+ const { join } = require('node:path')
9
+
10
+ const packageVersions = new Map()
11
+
12
+ /**
13
+ * Retrieves the version of a package from its package.json file.
14
+ * If the package.json file cannot be read, it defaults to the Node.js version.
15
+ * @param {string} baseDir - The base directory where the package.json file is located.
16
+ * @returns {string} The version of the package or the Node.js version if the package.json cannot be read.
17
+ */
18
+ function getPackageVersion(baseDir) {
19
+ if (packageVersions.has(baseDir)) {
20
+ return packageVersions.get(baseDir)
21
+ }
22
+
23
+ try {
24
+ const packageJsonPath = join(baseDir, 'package.json')
25
+ const jsonFile = readFileSync(packageJsonPath)
26
+ const { version } = JSON.parse(jsonFile)
27
+ packageVersions.set(baseDir, version)
28
+ return version
29
+ } catch {
30
+ return process.version.slice(1)
31
+ }
32
+ }
33
+
34
+ module.exports = getPackageVersion
@@ -83,7 +83,7 @@ module.exports = {
83
83
  * 2. Strip off session trackers after ';' (a New Relic convention)
84
84
  * 3. Remove trailing slash.
85
85
  *
86
- * @param {string} requestURL The URL fragment to be scrubbed.
86
+ * @param {string|url.URL} requestURL The URL fragment to be scrubbed.
87
87
  * @returns {string} The cleaned URL.
88
88
  */
89
89
  scrub: function scrub(requestURL) {
@@ -116,28 +116,34 @@ module.exports = {
116
116
  * variable. Some web frameworks behave this way as well, so don't lose
117
117
  * information.
118
118
  *
119
- * @param {string} requestURL The URL to be parsed.
119
+ * @param {string|url.URL} requestURL The URL to be parsed.
120
120
  * @returns {object} The parameters parsed from the request
121
121
  */
122
122
  parseParameters: function parseParameters(requestURL) {
123
123
  let parsed = requestURL
124
+ const parameters = Object.create(null)
125
+
126
+ function addParam(key, value, raw) {
127
+ if (value === '' && raw.indexOf(key + '=') === -1) {
128
+ parameters[key] = true
129
+ } else {
130
+ parameters[key] = value
131
+ }
132
+ }
124
133
 
125
134
  if (typeof requestURL === 'string') {
126
135
  parsed = url.parse(requestURL, true)
127
136
  }
128
137
 
129
- const parameters = Object.create(null)
130
-
131
138
  if (parsed.query) {
132
- const keys = Object.keys(parsed.query)
139
+ for (const key of Object.keys(parsed.query)) {
140
+ addParam(key, parsed.query[key], parsed.path || '')
141
+ }
142
+ }
133
143
 
134
- for (let i = 0, l = keys.length; i < l; ++i) {
135
- const key = keys[i]
136
- if (parsed.query[key] === '' && parsed.path.indexOf(key + '=') === -1) {
137
- parameters[key] = true
138
- } else {
139
- parameters[key] = parsed.query[key]
140
- }
144
+ if (parsed.searchParams) {
145
+ for (const [key, value] of parsed.searchParams) {
146
+ addParam(key, value, parsed.pathname || '')
141
147
  }
142
148
  }
143
149
 
@@ -148,7 +154,7 @@ module.exports = {
148
154
  * Performs the logic of `urltils.scrub` and `urltils.parseParameters` with
149
155
  * only a single parse of the given URL.
150
156
  *
151
- * @param {string} requestURL - The URL to scrub and extra parameters from.
157
+ * @param {string|url.URL} requestURL - The URL to scrub and extra parameters from.
152
158
  * @returns {object} An object containing the scrubbed url at `.path` and the
153
159
  * parsed parameters at `.parameters`.
154
160
  */
@@ -69,7 +69,7 @@ class Tracestate {
69
69
  const vendors = new Set()
70
70
  const listMembers = new Map()
71
71
  for (const listMember of kvPairs) {
72
- const parts = listMember.split('=', 2).filter(v => Boolean(v))
72
+ const parts = listMember.split('=', 2).filter((v) => Boolean(v))
73
73
  if (parts.length !== 2) {
74
74
  this.#logger.debug('Unable to parse tracestate list members.')
75
75
  this.#agent.recordSupportability('TraceContext/TraceState/Parse/Exception/ListMember')
@@ -94,7 +94,7 @@ class Tracestate {
94
94
  let intrinsics
95
95
  if (nrTraceStateValue) {
96
96
  intrinsics = new TracestateIntrinsics()
97
- const values = nrTraceStateValue.split('-').map(v => v === '' ? null : v)
97
+ const values = nrTraceStateValue.split('-').map((v) => (v === '' ? null : v))
98
98
  intrinsics.version = values[0]
99
99
  intrinsics.parentType = values[1]
100
100
  intrinsics.accountId = values[2]
@@ -150,7 +150,7 @@ class Tracestate {
150
150
  if (typeof header !== 'string') {
151
151
  throw Error('header value must be a string')
152
152
  }
153
- const kvPairs = header.split(',').map(item => item.trim()).filter(Boolean)
153
+ const kvPairs = header.split(',').map((item) => item.trim()).filter(Boolean)
154
154
  return new Tracestate({ agent, logger, kvPairs })
155
155
  }
156
156
 
package/newrelic.js CHANGED
@@ -22,6 +22,16 @@ exports.config = {
22
22
  */
23
23
  level: 'info'
24
24
  },
25
+ /**
26
+ * This provides instrumentation for `setTimeout` and `setInterval` calls.
27
+ * We recommend you disable this instrumentation as it does not not provide
28
+ * much value and creates a lot of unncessary TraceSegments/Span events.
29
+ */
30
+ instrumentation: {
31
+ timers: {
32
+ enabled: false
33
+ }
34
+ },
25
35
  /**
26
36
  * When true, all request headers except for those listed in attributes.exclude
27
37
  * will be captured for all traces, unless otherwise specified in a destination's
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "newrelic",
3
- "version": "13.0.0",
3
+ "version": "13.2.0",
4
4
  "author": "New Relic Node.js agent team <nodejs@newrelic.com>",
5
5
  "license": "Apache-2.0",
6
6
  "contributors": [
@@ -172,11 +172,11 @@
172
172
  "services": "DOCKER_PLATFORM=linux/$(uname -m) docker compose up -d --wait",
173
173
  "services:start": "npm run services",
174
174
  "services:stop": "docker compose down",
175
- "smoke": "time borp --timeout 180000 --reporter ./test/lib/test-reporter.mjs 'test/smoke/**/*.{test,tap}.js'",
175
+ "smoke": "time borp --timeout 180000 --reporter ./test/lib/test-reporter.mjs 'test/smoke/**/*.test.js'",
176
176
  "sub-install": "node test/bin/install_sub_deps",
177
177
  "test": "npm run integration && npm run unit",
178
178
  "third-party-updates": "oss third-party manifest --includeOptDeps && oss third-party notices --includeOptDeps && git add THIRD_PARTY_NOTICES.md third_party_manifest.json",
179
- "unit": "rm -f newrelic_agent.log && time c8 -o ./coverage/unit borp --timeout 180000 --reporter ./test/lib/test-reporter.mjs 'test/unit/**/*.test.js'",
179
+ "unit": "rm -f newrelic_agent.log && time c8 -o ./coverage/unit borp --timeout 180000 --reporter ./test/lib/test-reporter.mjs 'test/unit/**/*.test.{js,mjs}'",
180
180
  "unit:scripts": "time c8 -o ./coverage/scripts-unit borp --reporter ./test/lib/test-reporter.mjs 'bin/test/*.test.js'",
181
181
  "update-cross-agent-tests": "./bin/update-cats.sh",
182
182
  "versioned-tests": "./bin/run-versioned-tests.sh",
@@ -201,13 +201,16 @@
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
205
  "@grpc/grpc-js": "^1.13.2",
205
206
  "@grpc/proto-loader": "^0.7.5",
206
207
  "@newrelic/security-agent": "^2.4.2",
207
208
  "@opentelemetry/api": "^1.9.0",
209
+ "@opentelemetry/api-logs": "^0.203.0",
208
210
  "@opentelemetry/core": "^2.0.0",
209
211
  "@opentelemetry/exporter-metrics-otlp-proto": "^0.201.1",
210
212
  "@opentelemetry/resources": "^2.0.1",
213
+ "@opentelemetry/sdk-logs": "^0.203.0",
211
214
  "@opentelemetry/sdk-metrics": "^2.0.1",
212
215
  "@opentelemetry/sdk-trace-base": "^2.0.0",
213
216
  "@tyriar/fibonacci-heap": "^2.0.7",
@@ -232,7 +235,7 @@
232
235
  "@aws-sdk/s3-request-presigner": "^3.556.0",
233
236
  "@koa/router": "^12.0.1",
234
237
  "@matteo.collina/tspl": "^0.1.1",
235
- "@newrelic/eslint-config": "^0.5.0",
238
+ "@newrelic/eslint-config": "^0.6.0",
236
239
  "@newrelic/newrelic-oss-cli": "^0.1.2",
237
240
  "@newrelic/test-utilities": "^10.0.0",
238
241
  "@octokit/rest": "^18.0.15",
@@ -269,7 +272,8 @@
269
272
  "self-cert": "^2.0.0",
270
273
  "should": "*",
271
274
  "sinon": "^5.1.1",
272
- "superagent": "^9.0.1"
275
+ "superagent": "^9.0.1",
276
+ "testdouble": "^3.20.2"
273
277
  },
274
278
  "repository": {
275
279
  "type": "git",
@@ -1,62 +0,0 @@
1
- /*
2
- * Copyright 2023 New Relic Corporation. All rights reserved.
3
- * SPDX-License-Identifier: Apache-2.0
4
- */
5
-
6
- 'use strict'
7
-
8
- const { QuerySpec } = require('../../shim/specs')
9
- const semver = require('semver')
10
- const { queryParser } = require('../../db/query-parsers/elasticsearch')
11
-
12
- /**
13
- * Instruments the `@elastic/elasticsearch` module. This function is
14
- * passed to `onRequire` when instantiating instrumentation.
15
- *
16
- * @param {object} _agent New Relic agent
17
- * @param {object} elastic resolved module
18
- * @param {string} _moduleName string representation of require/import path
19
- * @param {object} shim New Relic shim
20
- * @returns {void}
21
- */
22
- module.exports = function initialize(_agent, elastic, _moduleName, shim) {
23
- const pkgVersion = shim.pkgVersion
24
- if (semver.lt(pkgVersion, '7.16.0')) {
25
- shim &&
26
- shim.logger.debug(
27
- `ElasticSearch support is for versions 7.16.0 and above. Not instrumenting ${pkgVersion}.`
28
- )
29
- return
30
- }
31
-
32
- shim.setDatastore(shim.ELASTICSEARCH)
33
- shim.setParser(queryParser)
34
-
35
- shim.recordQuery(elastic.Transport.prototype, 'request', function wrapQuery(shim, _, __, args) {
36
- const ctx = this
37
- return new QuerySpec({
38
- query: JSON.stringify(args?.[0]),
39
- promise: true,
40
- opaque: true,
41
- inContext: function inContext() {
42
- getConnection.call(ctx, shim)
43
- }
44
- })
45
- })
46
- }
47
-
48
- /**
49
- * Convenience function for deriving connection information from
50
- * elasticsearch
51
- *
52
- * @param {object} shim The New Relic datastore-shim
53
- * @returns {Function} captureInstanceAttributes method of shim
54
- */
55
- function getConnection(shim) {
56
- const connectionPool = this.connectionPool.connections[0]
57
- const host = connectionPool.url.host.split(':')
58
- const port = connectionPool.url.port || host?.[1]
59
- return shim.captureInstanceAttributes(host[0], port)
60
- }
61
-
62
- module.exports.getConnection = getConnection
@@ -1,66 +0,0 @@
1
- /*
2
- * Copyright 2024 New Relic Corporation. All rights reserved.
3
- * SPDX-License-Identifier: Apache-2.0
4
- */
5
-
6
- 'use strict'
7
-
8
- const { QuerySpec } = require('../../shim/specs')
9
- const semver = require('semver')
10
- const { queryParser } = require('../../db/query-parsers/elasticsearch')
11
-
12
- /**
13
- * Instruments the `@opensearch-project/opensearch` module. This function is
14
- * passed to `onRequire` when instantiating instrumentation.
15
- *
16
- * @param {object} _agent New Relic agent
17
- * @param {object} opensearch resolved module
18
- * @param {string} _moduleName string representation of require/import path
19
- * @param {object} shim New Relic shim
20
- * @returns {void}
21
- */
22
- module.exports = function initialize(_agent, opensearch, _moduleName, shim) {
23
- const pkgVersion = shim.pkgVersion
24
- if (semver.lt(pkgVersion, '2.1.0')) {
25
- shim &&
26
- shim.logger.debug(
27
- `Opensearch support is for versions 2.1.0 and above. Not instrumenting ${pkgVersion}.`
28
- )
29
- return
30
- }
31
-
32
- shim.setDatastore(shim.OPENSEARCH)
33
- shim.setParser(queryParser)
34
-
35
- shim.recordQuery(
36
- opensearch.Transport.prototype,
37
- 'request',
38
- function wrapQuery(shim, _, __, args) {
39
- const ctx = this
40
- return new QuerySpec({
41
- query: JSON.stringify(args?.[0]),
42
- promise: true,
43
- opaque: true,
44
- inContext: function inContext() {
45
- getConnection.call(ctx, shim)
46
- }
47
- })
48
- }
49
- )
50
- }
51
-
52
- /**
53
- * Convenience function for deriving connection information from
54
- * opensearch
55
- *
56
- * @param {object} shim The New Relic datastore-shim
57
- * @returns {Function} captureInstanceAttributes method of shim
58
- */
59
- function getConnection(shim) {
60
- const connectionPool = this.connectionPool.connections[0]
61
- const host = connectionPool.url.host.split(':')
62
- const port = connectionPool.url.port || host?.[1]
63
- return shim.captureInstanceAttributes(host[0], port)
64
- }
65
-
66
- module.exports.getConnection = getConnection