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.
- package/NEWS.md +44 -0
- package/THIRD_PARTY_NOTICES.md +219 -8
- package/api.js +1 -1
- package/esm-loader.mjs +6 -1
- package/lib/instrumentation/@azure/functions.js +8 -46
- package/lib/instrumentation/core/http-outbound.js +26 -10
- package/lib/instrumentation/core/http.js +20 -118
- package/lib/instrumentations.js +0 -14
- package/lib/otel/logs/index.js +80 -0
- package/lib/otel/metrics/index.js +119 -0
- package/lib/otel/setup-signal.js +37 -0
- package/lib/otel/setup.js +15 -25
- package/lib/otel/{attr-reconciler.js → traces/attr-reconciler.js} +2 -2
- package/lib/otel/{exception-mapping.js → traces/exception-mapping.js} +1 -1
- package/lib/otel/traces/index.js +40 -0
- package/lib/otel/{rules.js → traces/rules.js} +1 -1
- package/lib/otel/{segment-synthesis.js → traces/segment-synthesis.js} +5 -4
- package/lib/otel/{segments → traces/segments}/consumer.js +4 -4
- package/lib/otel/{segments → traces/segments}/database.js +6 -6
- package/lib/otel/{segments → traces/segments}/http-external.js +11 -8
- package/lib/otel/traces/segments/index.js +22 -0
- package/lib/otel/{segments → traces/segments}/internal.js +1 -1
- package/lib/otel/{segments → traces/segments}/producer.js +2 -2
- package/lib/otel/{segments → traces/segments}/server.js +4 -4
- package/lib/otel/{segments → traces/segments}/utils.js +1 -1
- package/lib/otel/{span-processor.js → traces/span-processor.js} +13 -19
- package/lib/otel/{transformation-rules.json → traces/transformation-rules.json} +3 -2
- package/lib/otel/{utils.js → traces/utils.js} +2 -1
- package/lib/serverless/aws-lambda.js +7 -68
- package/lib/shim/webframework-shim/middleware.js +1 -1
- package/lib/shimmer.js +2 -2
- package/lib/subscriber-configs.js +2 -1
- package/lib/subscribers/base.js +30 -0
- package/lib/subscribers/elasticsearch/config.js +1 -0
- package/lib/subscribers/mcp-sdk/client-request.js +66 -0
- package/lib/subscribers/mcp-sdk/config.js +13 -75
- package/lib/subscribers/openai/base.js +21 -0
- package/lib/subscribers/openai/chat-responses.js +15 -0
- package/lib/subscribers/openai/chat.js +85 -0
- package/lib/subscribers/openai/client.js +31 -0
- package/lib/subscribers/openai/config.js +85 -0
- package/lib/subscribers/openai/embeddings.js +54 -0
- package/lib/subscribers/openai/utils.js +349 -0
- package/lib/transaction/index.js +157 -56
- package/lib/transaction/trace/segment.js +5 -2
- package/lib/util/urltils.js +158 -192
- package/lib/utilization/common.js +0 -6
- package/package.json +3 -4
- package/lib/instrumentation/openai.js +0 -482
- package/lib/otel/logs/bootstrap-logs.js +0 -84
- package/lib/otel/metrics/bootstrap-metrics.js +0 -117
- package/lib/otel/segments/index.js +0 -22
- package/lib/patch-module.js +0 -70
- package/lib/subscribers/mcp-sdk/client-prompt.js +0 -23
- package/lib/subscribers/mcp-sdk/client-resource.js +0 -24
- package/lib/subscribers/mcp-sdk/client-tool.js +0 -23
- package/lib/subscribers/mcp-sdk/client.js +0 -29
- /package/lib/otel/{constants.js → traces/constants.js} +0 -0
- /package/lib/otel/{sampler.js → traces/sampler.js} +0 -0
package/lib/transaction/index.js
CHANGED
|
@@ -16,8 +16,11 @@ const Timer = require('../timer')
|
|
|
16
16
|
const Trace = require('./trace')
|
|
17
17
|
const synthetics = require('../synthetics')
|
|
18
18
|
const urltils = require('../util/urltils')
|
|
19
|
+
const cat = require('../util/cat')
|
|
19
20
|
const TraceContext = require('./tracecontext').TraceContext
|
|
20
21
|
const Logs = require('./logs')
|
|
22
|
+
const headerAttributes = require('../header-attributes')
|
|
23
|
+
const headerProcessing = require('../header-processing')
|
|
21
24
|
const DT_ACCEPT_PAYLOAD_EXCEPTION_METRIC = 'DistributedTrace/AcceptPayload/Exception'
|
|
22
25
|
const DT_ACCEPT_PAYLOAD_PARSE_EXCEPTION_METRIC = 'DistributedTrace/AcceptPayload/ParseException'
|
|
23
26
|
const REQUEST_PARAMS_PATH = 'request.parameters.'
|
|
@@ -119,7 +122,6 @@ function Transaction(agent, traceId) {
|
|
|
119
122
|
this.syntheticsData = null
|
|
120
123
|
this.syntheticsInfoData = null
|
|
121
124
|
this.url = null
|
|
122
|
-
this.parsedUrl = null
|
|
123
125
|
this.verb = null
|
|
124
126
|
this.baseSegment = null
|
|
125
127
|
this.type = TYPES.WEB
|
|
@@ -317,8 +319,9 @@ Transaction.prototype.setPartialName = function setPartialName(name) {
|
|
|
317
319
|
* boolean flag in `ignore`.
|
|
318
320
|
*/
|
|
319
321
|
Transaction.prototype._partialNameFromUri = _partialNameFromUri
|
|
320
|
-
function _partialNameFromUri(
|
|
321
|
-
const scrubbedUrl =
|
|
322
|
+
function _partialNameFromUri() {
|
|
323
|
+
const scrubbedUrl = this.url
|
|
324
|
+
const status = this.statusCode
|
|
322
325
|
|
|
323
326
|
// 0. If there is a name in the name-state stack, use it.
|
|
324
327
|
let partialName = this._partialName
|
|
@@ -386,21 +389,69 @@ Transaction.prototype.isIgnored = function getIgnore() {
|
|
|
386
389
|
}
|
|
387
390
|
|
|
388
391
|
/**
|
|
389
|
-
*
|
|
392
|
+
* Finalize a web transaction. This includes naming the transaction, collecting
|
|
393
|
+
* response headers, and ending the transaction and its base segment.
|
|
394
|
+
*
|
|
395
|
+
* @param {object} params The parameters for finalizing the transaction.
|
|
396
|
+
* @param {number} params.statusCode The response status code.
|
|
397
|
+
* @param {string} [params.statusMessage] The response status message.
|
|
398
|
+
* @param {object} [params.headers] The response headers.
|
|
399
|
+
* @param {Boolean} params.end Whether to end the transaction and baseSegment.
|
|
400
|
+
*/
|
|
401
|
+
Transaction.prototype.finalizeWeb = function finalizeWeb({ statusCode, statusMessage, headers, end }) {
|
|
402
|
+
// Naming must happen before the segment and transaction are ended
|
|
403
|
+
// because metrics recording depends on naming's side effects.
|
|
404
|
+
this.finalizeNameFromWeb(statusCode)
|
|
405
|
+
if (statusCode != null) {
|
|
406
|
+
const responseCode = String(statusCode)
|
|
407
|
+
|
|
408
|
+
if (/^\d+$/.test(responseCode)) {
|
|
409
|
+
this.trace.attributes.addAttribute(
|
|
410
|
+
DESTS.TRANS_COMMON,
|
|
411
|
+
'http.statusCode',
|
|
412
|
+
responseCode
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
this.baseSegment.addSpanAttribute('http.statusCode', responseCode)
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if (statusMessage !== undefined) {
|
|
420
|
+
this.trace.attributes.addAttribute(
|
|
421
|
+
DESTS.TRANS_COMMON,
|
|
422
|
+
'http.statusText',
|
|
423
|
+
statusMessage
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
this.baseSegment.addSpanAttribute('http.statusText', statusMessage)
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (headers) {
|
|
430
|
+
headerAttributes.collectResponseHeaders(headers, this)
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (end) {
|
|
434
|
+
// And we are done! End the segment and transaction.
|
|
435
|
+
this.baseSegment.end()
|
|
436
|
+
this.end()
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Derives the transaction's name from `transaction.url` and status code.
|
|
390
442
|
*
|
|
391
443
|
* The transaction's name will be set after this as well as its ignored status
|
|
392
444
|
* based on the derived name.
|
|
393
445
|
*
|
|
394
|
-
* @param {string} requestURL - The URL to derive the request's name and status from.
|
|
395
446
|
* @param {number} statusCode - The response status code.
|
|
396
447
|
*/
|
|
397
|
-
Transaction.prototype.
|
|
448
|
+
Transaction.prototype.finalizeNameFromWeb = finalizeNameFromWeb
|
|
398
449
|
|
|
399
|
-
function
|
|
450
|
+
function finalizeNameFromWeb(statusCode) {
|
|
400
451
|
if (logger.traceEnabled()) {
|
|
401
452
|
logger.trace(
|
|
402
453
|
{
|
|
403
|
-
requestURL,
|
|
454
|
+
requestURL: this.url,
|
|
404
455
|
statusCode,
|
|
405
456
|
transactionId: this.id,
|
|
406
457
|
transactionName: this.name
|
|
@@ -409,10 +460,6 @@ function finalizeNameFromUri(requestURL, statusCode) {
|
|
|
409
460
|
)
|
|
410
461
|
}
|
|
411
462
|
|
|
412
|
-
if (!this.agent.config.url_obfuscation.enabled) {
|
|
413
|
-
this.url = urltils.scrub(requestURL)
|
|
414
|
-
}
|
|
415
|
-
|
|
416
463
|
this.statusCode = statusCode
|
|
417
464
|
this.name = this.getFullName()
|
|
418
465
|
|
|
@@ -426,7 +473,16 @@ function finalizeNameFromUri(requestURL, statusCode) {
|
|
|
426
473
|
this.ignore = this.forceIgnore
|
|
427
474
|
}
|
|
428
475
|
|
|
429
|
-
this.
|
|
476
|
+
const obfuscatedUrl = urltils.obfuscatePath(this.agent.config, this.url)
|
|
477
|
+
this.url = obfuscatedUrl
|
|
478
|
+
// URL is sent as an agent attribute with transaction events
|
|
479
|
+
this.trace.attributes.addAttribute(
|
|
480
|
+
DESTS.TRANS_EVENT | DESTS.ERROR_EVENT,
|
|
481
|
+
'request.uri',
|
|
482
|
+
obfuscatedUrl
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
this?.baseSegment?.markAsWeb(this, obfuscatedUrl)
|
|
430
486
|
|
|
431
487
|
this._copyNameToActiveSpan(this.name)
|
|
432
488
|
|
|
@@ -471,37 +527,6 @@ Transaction.prototype._copyNameToActiveSpan = function _copyNameToActiveSpan(nam
|
|
|
471
527
|
spanContext.addIntrinsicAttribute('transaction.name', name)
|
|
472
528
|
}
|
|
473
529
|
|
|
474
|
-
/**
|
|
475
|
-
* Copies final base segment parameters to trace attributes before reapplying
|
|
476
|
-
* them to the segment.
|
|
477
|
-
*
|
|
478
|
-
* Handles adding query parameters to `request.parameter.*` attributes
|
|
479
|
-
*
|
|
480
|
-
* @param {string} rawURL The URL, as it came in, for parameter extraction.
|
|
481
|
-
*/
|
|
482
|
-
Transaction.prototype._markAsWeb = function _markAsWeb(rawURL) {
|
|
483
|
-
// Because we are assured we have the URL here, lets grab query params.
|
|
484
|
-
const params = urltils.parseParameters(rawURL)
|
|
485
|
-
for (const key in params) {
|
|
486
|
-
if (props.hasOwn(params, key)) {
|
|
487
|
-
this.trace.attributes.addAttribute(DESTS.NONE, REQUEST_PARAMS_PATH + key, params[key])
|
|
488
|
-
|
|
489
|
-
const segment = this.agent.tracer.getSegment()
|
|
490
|
-
|
|
491
|
-
if (!segment) {
|
|
492
|
-
logger.trace(
|
|
493
|
-
'Active segment not available, not adding request.parameters span attribute for %s',
|
|
494
|
-
key
|
|
495
|
-
)
|
|
496
|
-
} else {
|
|
497
|
-
segment.attributes.addAttribute(DESTS.NONE, REQUEST_PARAMS_PATH + key, params[key])
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
this.baseSegment.markAsWeb(this)
|
|
503
|
-
}
|
|
504
|
-
|
|
505
530
|
/**
|
|
506
531
|
* Sets the transaction's name and determines if it will be ignored.
|
|
507
532
|
*
|
|
@@ -514,7 +539,7 @@ Transaction.prototype.finalizeName = function finalizeName(name) {
|
|
|
514
539
|
// If no name is given, and this is a web transaction with a url, then
|
|
515
540
|
// finalize the name using the stored url.
|
|
516
541
|
if (name == null && this.isWeb() && this.url) {
|
|
517
|
-
return this.
|
|
542
|
+
return this.finalizeNameFromWeb(this.statusCode)
|
|
518
543
|
}
|
|
519
544
|
|
|
520
545
|
// this may seem out of place but certain API methods
|
|
@@ -566,7 +591,7 @@ Transaction.prototype.finalizeName = function finalizeName(name) {
|
|
|
566
591
|
*/
|
|
567
592
|
Transaction.prototype.getName = function getName() {
|
|
568
593
|
if (this.isWeb() && this.url) {
|
|
569
|
-
const finalName = this._partialNameFromUri(
|
|
594
|
+
const finalName = this._partialNameFromUri()
|
|
570
595
|
if (finalName.ignore) {
|
|
571
596
|
this.ignore = true
|
|
572
597
|
}
|
|
@@ -1427,18 +1452,16 @@ Transaction.prototype.addRequestParameters = addRequestParameters
|
|
|
1427
1452
|
* @param {Object<string, string>} requestParameters of the request object
|
|
1428
1453
|
*/
|
|
1429
1454
|
function addRequestParameters(requestParameters) {
|
|
1430
|
-
for (const key
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
)
|
|
1455
|
+
for (const [key, value] of Object.entries(requestParameters)) {
|
|
1456
|
+
this.trace.attributes.addAttribute(
|
|
1457
|
+
DESTS.NONE,
|
|
1458
|
+
REQUEST_PARAMS_PATH + key,
|
|
1459
|
+
value
|
|
1460
|
+
)
|
|
1437
1461
|
|
|
1438
|
-
|
|
1462
|
+
const segment = this.baseSegment
|
|
1439
1463
|
|
|
1440
|
-
|
|
1441
|
-
}
|
|
1464
|
+
segment.attributes.addAttribute(DESTS.NONE, REQUEST_PARAMS_PATH + key, value)
|
|
1442
1465
|
}
|
|
1443
1466
|
}
|
|
1444
1467
|
|
|
@@ -1453,4 +1476,82 @@ Transaction.prototype.incrementCounters = function incrementCounters() {
|
|
|
1453
1476
|
this.agent.incrementCounters()
|
|
1454
1477
|
}
|
|
1455
1478
|
|
|
1479
|
+
/**
|
|
1480
|
+
* Initializes a web transaction with request information:
|
|
1481
|
+
* Assigns type(web), verb, url, port attributes on transaction.
|
|
1482
|
+
* Collects request headers as attributes on the transaction.
|
|
1483
|
+
* Applies user naming rules to the transaction.
|
|
1484
|
+
* Calculates queue time if possible.
|
|
1485
|
+
* Assigns synthetics information if present.
|
|
1486
|
+
* Adds distributed trace or cat headers if present.
|
|
1487
|
+
*
|
|
1488
|
+
* @param {object} params - Parameters to initialize the web transaction.
|
|
1489
|
+
* @param {string} params.absoluteUrl - Full URL of the request.
|
|
1490
|
+
* @param {string} params.method - HTTP method of the request.
|
|
1491
|
+
* @param {number} params.port - Port of the request.
|
|
1492
|
+
* @param {object} [params.headers] - HTTP headers of the request.
|
|
1493
|
+
* @param {string} [params.transport] - Transport type that delivered the request.
|
|
1494
|
+
*/
|
|
1495
|
+
Transaction.prototype.initializeWeb = function initializeWeb({ absoluteUrl, method, port, headers = {}, transport }) {
|
|
1496
|
+
this.type = TYPES.WEB
|
|
1497
|
+
headerAttributes.collectRequestHeaders(headers, this)
|
|
1498
|
+
|
|
1499
|
+
if (method != null) {
|
|
1500
|
+
this.trace.attributes.addAttribute(DESTS.TRANS_COMMON, 'request.method', method)
|
|
1501
|
+
this.baseSegment.addSpanAttribute('request.method', method)
|
|
1502
|
+
this.verb = method
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
this.port = port
|
|
1506
|
+
|
|
1507
|
+
// the error tracer needs a URL for tracing, even though naming overwrites
|
|
1508
|
+
try {
|
|
1509
|
+
const parsedUrl = new URL(absoluteUrl)
|
|
1510
|
+
const data = urltils.scrubAndParseParameters(parsedUrl)
|
|
1511
|
+
this.url = data.path
|
|
1512
|
+
this.addRequestParameters(data.parameters)
|
|
1513
|
+
} catch (err) {
|
|
1514
|
+
logger.debug('Could not parse URL %s: %s', absoluteUrl, err.message)
|
|
1515
|
+
this.url = '/unknown'
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
// need to set any config-driven names early for RUM
|
|
1519
|
+
logger.trace({ url: this.url, transaction: this.id },
|
|
1520
|
+
'Appplying user naming rules for RUM.')
|
|
1521
|
+
|
|
1522
|
+
this.applyUserNamingRules(this.url)
|
|
1523
|
+
|
|
1524
|
+
const queueTimeStamp = headerProcessing.getQueueTime(logger, headers)
|
|
1525
|
+
if (queueTimeStamp) {
|
|
1526
|
+
this.queueTime = Date.now() - queueTimeStamp
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
synthetics.assignHeadersToTransaction(this.agent.config, this, headers)
|
|
1530
|
+
this.addDtCatHeaders({ headers, transport })
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
/**
|
|
1534
|
+
* Handles accepting upstream DT headers(traceparent/tracestate or newrelic) if present and DT is enabled.
|
|
1535
|
+
* If CAT is enabled, handles accepting CAT headers and assigns to transaction.
|
|
1536
|
+
*
|
|
1537
|
+
* @param {object} params - Parameters for adding DT or CAT headers.
|
|
1538
|
+
* @param {object} params.headers - HTTP headers of the request(must be lower-cased, by default http instrumentation has headers lower case, other libraries must pass this in lowercased).
|
|
1539
|
+
* @param {string} [params.transport] - Transport type that delivered the request.
|
|
1540
|
+
*/
|
|
1541
|
+
Transaction.prototype.addDtCatHeaders = function addDtCatHeaders({ headers, transport }) {
|
|
1542
|
+
if (this.agent.config.distributed_tracing.enabled) {
|
|
1543
|
+
// Node http request headers are automatically lowercase
|
|
1544
|
+
// need to pass in lower case for other instrumentation
|
|
1545
|
+
this.acceptDistributedTraceHeaders(transport, headers)
|
|
1546
|
+
} else if (this.agent.config.cross_application_tracer.enabled) {
|
|
1547
|
+
const { id, transactionId } = cat.extractCatHeaders(headers)
|
|
1548
|
+
const { externalId, externalTransaction } = cat.parseCatData(
|
|
1549
|
+
id,
|
|
1550
|
+
transactionId,
|
|
1551
|
+
this.agent.config.encoding_key
|
|
1552
|
+
)
|
|
1553
|
+
cat.assignCatToTransaction(externalId, externalTransaction, this)
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1456
1557
|
module.exports = Transaction
|
|
@@ -133,13 +133,14 @@ TraceSegment.prototype.setNameFromTransaction = function setNameFromTransaction(
|
|
|
133
133
|
/**
|
|
134
134
|
* Once a transaction is named, the web segment also needs to be updated to
|
|
135
135
|
* match it (which implies this method must be called subsequent to
|
|
136
|
-
* transaction.
|
|
136
|
+
* transaction.finalizeNameFromWeb). To properly name apdex metrics during metric
|
|
137
137
|
* recording, it's also necessary to copy the transaction's partial name. And
|
|
138
138
|
* finally, marking the trace segment as being a web segment copies the
|
|
139
139
|
* segment's parameters onto the transaction.
|
|
140
140
|
* @param {Transaction} transaction The transaction to which this segment will be bound.
|
|
141
|
+
* @param obfuscatedUrl
|
|
141
142
|
*/
|
|
142
|
-
TraceSegment.prototype.markAsWeb = function markAsWeb(transaction) {
|
|
143
|
+
TraceSegment.prototype.markAsWeb = function markAsWeb(transaction, obfuscatedUrl) {
|
|
143
144
|
this.setNameFromTransaction(transaction)
|
|
144
145
|
|
|
145
146
|
const traceAttrs = transaction.trace.attributes.get(DESTINATIONS.TRANS_TRACE)
|
|
@@ -148,6 +149,8 @@ TraceSegment.prototype.markAsWeb = function markAsWeb(transaction) {
|
|
|
148
149
|
this.addAttribute(key, traceAttrs[key])
|
|
149
150
|
}
|
|
150
151
|
})
|
|
152
|
+
|
|
153
|
+
this.addSpanAttribute('request.uri', obfuscatedUrl)
|
|
151
154
|
}
|
|
152
155
|
|
|
153
156
|
/**
|