newrelic 13.19.2 → 13.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 +41 -0
- package/THIRD_PARTY_NOTICES.md +11 -11
- package/lib/collector/remote-method.js +3 -1
- package/lib/config/index.js +20 -0
- package/lib/context-manager/async-local-context-manager.js +1 -1
- package/lib/instrumentation/core/domain.js +2 -13
- package/lib/instrumentation/core/globals.js +0 -1
- package/lib/instrumentations.js +0 -3
- package/lib/llm-events/ai-agent.js +28 -0
- package/lib/llm-events/google-genai/chat-completion-message.js +6 -3
- package/lib/message-broker-description.js +29 -12
- package/lib/metrics/names.js +14 -8
- package/lib/subscriber-configs.js +4 -0
- package/lib/subscribers/amqplib/consume.js +1 -1
- package/lib/subscribers/aws-sdk/config.js +41 -3
- package/lib/subscribers/aws-sdk/core-send.js +16 -0
- package/lib/subscribers/aws-sdk/middleware/sqs/index.js +10 -13
- package/lib/subscribers/azure-functions/azure-handler-base.js +138 -0
- package/lib/subscribers/azure-functions/background-handler.js +29 -0
- package/lib/subscribers/azure-functions/config.js +44 -0
- package/lib/subscribers/azure-functions/http-handler.js +58 -0
- package/lib/subscribers/azure-functions/index.js +74 -0
- package/lib/subscribers/azure-functions/logger.js +72 -0
- package/lib/subscribers/connect/config.js +42 -0
- package/lib/subscribers/connect/use.js +31 -0
- package/lib/subscribers/google-adk/agent-run-async.js +119 -0
- package/lib/subscribers/google-adk/config.js +59 -0
- package/lib/subscribers/google-adk/tool-run-async.js +87 -0
- package/lib/subscribers/kafkajs/client-constructor.js +349 -0
- package/lib/subscribers/kafkajs/config.js +25 -0
- package/lib/subscribers/kafkajs/utils/record-data-metrics.js +48 -0
- package/lib/subscribers/kafkajs/utils/record-linking-metrics.js +30 -0
- package/lib/{instrumentation/kafkajs → subscribers/kafkajs/utils}/record-method-metric.js +3 -2
- package/lib/subscribers/langgraph/graph-stream.js +2 -1
- package/lib/subscribers/message-consumer-tools.js +161 -0
- package/lib/subscribers/message-consumer.js +43 -61
- package/lib/subscribers/undici/index.js +5 -7
- package/lib/transaction/tracer/index.js +26 -2
- package/package.json +2 -2
- package/lib/instrumentation/@azure/functions.js +0 -323
- package/lib/instrumentation/connect.js +0 -83
- package/lib/instrumentation/kafkajs/consumer.js +0 -145
- package/lib/instrumentation/kafkajs/index.js +0 -34
- package/lib/instrumentation/kafkajs/producer.js +0 -83
- package/lib/instrumentation/kafkajs/record-linking-metrics.js +0 -17
- package/lib/instrumentation/kafkajs.js +0 -7
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
const Transaction = require('#agentlib/transaction/index.js')
|
|
9
|
+
const { DESTINATIONS: DESTS } = Transaction
|
|
10
|
+
|
|
11
|
+
module.exports = class AzureHandler {
|
|
12
|
+
constructor(subscriber) {
|
|
13
|
+
this.subscriber = subscriber
|
|
14
|
+
this.agent = subscriber.agent
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
handleColdStart(transaction) {
|
|
18
|
+
if (this.subscriber.coldStart === true) {
|
|
19
|
+
transaction.trace.attributes.addAttribute(DESTS.TRANS_COMMON, 'faas.coldStart', true)
|
|
20
|
+
this.subscriber.coldStart = false
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
createTransaction({ handlerArgs, ctx }) {
|
|
25
|
+
const [, context] = handlerArgs
|
|
26
|
+
const transaction = new Transaction(this.agent)
|
|
27
|
+
transaction.type = this.type
|
|
28
|
+
transaction.setPartialName(`AzureFunction/${context.functionName}`)
|
|
29
|
+
ctx = ctx.enterTransaction(transaction)
|
|
30
|
+
const newCtx = this.createSegment({ handlerArgs, ctx })
|
|
31
|
+
transaction.baseSegment = newCtx.segment
|
|
32
|
+
return newCtx
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async handle({ thisArg, originalHandler, handlerArgs }) {
|
|
36
|
+
const ctx = this.agent.tracer.getContext()
|
|
37
|
+
if (ctx.transaction != null) {
|
|
38
|
+
return originalHandler.apply(thisArg, handlerArgs)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const [, context] = handlerArgs
|
|
42
|
+
const newCtx = this.createTransaction({ handlerArgs, ctx })
|
|
43
|
+
const transaction = newCtx?.transaction
|
|
44
|
+
this.addFaasAttributes(transaction, context)
|
|
45
|
+
const result = await this.runHandlerInContext({ originalHandler, ctx: newCtx, thisArg, handlerArgs })
|
|
46
|
+
this.handleColdStart(transaction)
|
|
47
|
+
return this.finalizeTransaction({ result, transaction })
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
runHandlerInContext({ originalHandler, ctx, thisArg, handlerArgs }) {
|
|
51
|
+
return this.agent.tracer.bindFunction(originalHandler, ctx).apply(thisArg, handlerArgs)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
finalizeTransaction({ result, transaction }) {
|
|
55
|
+
transaction.end()
|
|
56
|
+
return result
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
addFaasAttributes(transaction, functionContext) {
|
|
60
|
+
transaction.trace.attributes.addAttribute(
|
|
61
|
+
DESTS.TRANS_COMMON,
|
|
62
|
+
'faas.invocation_id',
|
|
63
|
+
functionContext.invocationId ?? 'unknown'
|
|
64
|
+
)
|
|
65
|
+
transaction.trace.attributes.addAttribute(
|
|
66
|
+
DESTS.TRANS_COMMON,
|
|
67
|
+
'faas.name',
|
|
68
|
+
functionContext.functionName ?? 'unknown'
|
|
69
|
+
)
|
|
70
|
+
transaction.trace.attributes.addAttribute(
|
|
71
|
+
DESTS.TRANS_COMMON,
|
|
72
|
+
'faas.trigger',
|
|
73
|
+
this.mapTriggerType(functionContext)
|
|
74
|
+
)
|
|
75
|
+
transaction.trace.attributes.addAttribute(
|
|
76
|
+
DESTS.TRANS_COMMON,
|
|
77
|
+
'cloud.resource_id',
|
|
78
|
+
this.buildCloudResourceId(functionContext)
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
mapTriggerType(functionContext) {
|
|
83
|
+
const input = functionContext.options?.trigger?.type
|
|
84
|
+
|
|
85
|
+
// Input types are found at:
|
|
86
|
+
// https://github.com/Azure/azure-functions-nodejs-library/blob/138c021/src/trigger.ts
|
|
87
|
+
// https://learn.microsoft.com/en-us/azure/azure-functions/functions-triggers-bindings?tabs=isolated-process%2Cnode-v4%2Cpython-v2&pivots=programming-language-javascript#supported-bindings
|
|
88
|
+
switch (input) {
|
|
89
|
+
case 'httpTrigger': {
|
|
90
|
+
return 'http'
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
case 'timerTrigger': {
|
|
94
|
+
return 'timer'
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
case 'blobTrigger':
|
|
98
|
+
case 'cosmosDBTrigger':
|
|
99
|
+
case 'daprBindingTrigger':
|
|
100
|
+
case 'mysqlTrigger':
|
|
101
|
+
case 'queueTrigger':
|
|
102
|
+
case 'sqlTrigger': {
|
|
103
|
+
return 'datasource'
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
case 'daprTopicTrigger':
|
|
107
|
+
case 'eventGridTrigger':
|
|
108
|
+
case 'eventHubTrigger':
|
|
109
|
+
case 'kafkaTrigger':
|
|
110
|
+
case 'rabbitMQTrigger':
|
|
111
|
+
case 'redisListTrigger':
|
|
112
|
+
case 'redisPubSubTrigger':
|
|
113
|
+
case 'redisStreamTrigger':
|
|
114
|
+
case 'serviceBusTrigger':
|
|
115
|
+
case 'signalRTrigger':
|
|
116
|
+
case 'webPubSubTrigger': {
|
|
117
|
+
return 'pubsub'
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
default: {
|
|
121
|
+
return 'other'
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
buildCloudResourceId(functionContext) {
|
|
127
|
+
return [
|
|
128
|
+
'/subscriptions/',
|
|
129
|
+
this.subscriber.subscriptionId,
|
|
130
|
+
'/resourceGroups/',
|
|
131
|
+
this.subscriber.resourceGroup,
|
|
132
|
+
'/providers/Microsoft.Web/sites/',
|
|
133
|
+
this.subscriber.azureFunctionAppName,
|
|
134
|
+
'/functions/',
|
|
135
|
+
functionContext.functionName
|
|
136
|
+
].join('')
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
const AzureHandler = require('#agentlib/subscribers/azure-functions/azure-handler-base.js')
|
|
9
|
+
const Transaction = require('#agentlib/transaction/index.js')
|
|
10
|
+
const backgroundRecorder = require('#agentlib/metrics/recorders/other.js')
|
|
11
|
+
const { TYPES } = Transaction
|
|
12
|
+
|
|
13
|
+
module.exports = class BackgroundHandler extends AzureHandler {
|
|
14
|
+
constructor({ subscriber }) {
|
|
15
|
+
super(subscriber)
|
|
16
|
+
this.type = TYPES.BG
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
createSegment({ handlerArgs, ctx }) {
|
|
20
|
+
const [, context] = handlerArgs
|
|
21
|
+
const triggerType = context.options?.trigger?.type ?? 'unknown'
|
|
22
|
+
const methodName = triggerType.replace(/Trigger$/, '')
|
|
23
|
+
return this.subscriber.createSegment({
|
|
24
|
+
name: `${methodName}-trigger`,
|
|
25
|
+
recorder: backgroundRecorder,
|
|
26
|
+
ctx
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
'use strict'
|
|
6
|
+
|
|
7
|
+
const modName = '@azure/functions'
|
|
8
|
+
const filePath = 'dist/azure-functions.js'
|
|
9
|
+
const versionRange = '>=4.7.0'
|
|
10
|
+
|
|
11
|
+
const generic = {
|
|
12
|
+
path: './azure-functions/index.js',
|
|
13
|
+
instrumentations: [
|
|
14
|
+
{
|
|
15
|
+
channelName: 'nr_generic',
|
|
16
|
+
module: { name: modName, versionRange, filePath },
|
|
17
|
+
functionQuery: {
|
|
18
|
+
functionName: 'generic',
|
|
19
|
+
kind: 'Sync'
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const logger = {
|
|
26
|
+
path: './azure-functions/logger.js',
|
|
27
|
+
instrumentations: [
|
|
28
|
+
{
|
|
29
|
+
channelName: 'nr_logger',
|
|
30
|
+
module: { name: modName, versionRange, filePath },
|
|
31
|
+
functionQuery: {
|
|
32
|
+
functionName: 'tryGetCoreApiLazy',
|
|
33
|
+
kind: 'Sync'
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = {
|
|
40
|
+
[modName]: [
|
|
41
|
+
generic,
|
|
42
|
+
logger
|
|
43
|
+
]
|
|
44
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
const AzureHandler = require('#agentlib/subscribers/azure-functions/azure-handler-base.js')
|
|
9
|
+
const Transaction = require('#agentlib/transaction/index.js')
|
|
10
|
+
const { TYPES } = Transaction
|
|
11
|
+
const { Transform } = require('node:stream')
|
|
12
|
+
const recordWeb = require('#agentlib/metrics/recorders/http.js')
|
|
13
|
+
|
|
14
|
+
module.exports = class HttpHandler extends AzureHandler {
|
|
15
|
+
constructor({ subscriber }) {
|
|
16
|
+
super(subscriber)
|
|
17
|
+
this.type = TYPES.WEB
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
#initializeWeb(transaction, request) {
|
|
21
|
+
const absoluteUrl = request.url
|
|
22
|
+
const url = new URL(absoluteUrl)
|
|
23
|
+
const transport = url.protocol === 'https:' ? 'HTTPS' : 'HTTP'
|
|
24
|
+
const port = url.port || (transport === 'HTTPS' ? 443 : 80)
|
|
25
|
+
transaction.initializeWeb({ absoluteUrl, method: request.method, port, headers: request.headers, transport })
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
runHandlerInContext({ originalHandler, ctx, thisArg, handlerArgs }) {
|
|
29
|
+
const { transaction } = ctx
|
|
30
|
+
const [request] = handlerArgs
|
|
31
|
+
const self = this
|
|
32
|
+
function inContext() {
|
|
33
|
+
self.#initializeWeb(transaction, request)
|
|
34
|
+
return originalHandler.apply(this, arguments)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return this.agent.tracer.bindFunction(inContext, ctx).apply(thisArg, handlerArgs)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
finalizeTransaction({ result, transaction }) {
|
|
41
|
+
transaction.finalizeWeb({ statusCode: result?.status, headers: result?.headers, end: false })
|
|
42
|
+
if (result?.body instanceof Transform) {
|
|
43
|
+
result.body.on('close', () => transaction.end())
|
|
44
|
+
} else {
|
|
45
|
+
transaction.end()
|
|
46
|
+
}
|
|
47
|
+
return result
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
createSegment({ handlerArgs, ctx }) {
|
|
51
|
+
const [request] = handlerArgs
|
|
52
|
+
return this.subscriber.createSegment({
|
|
53
|
+
name: request.url,
|
|
54
|
+
recorder: recordWeb,
|
|
55
|
+
ctx
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 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
|
+
const HttpHandler = require('#agentlib/subscribers/azure-functions/http-handler.js')
|
|
10
|
+
const BackgroundHandler = require('#agentlib/subscribers/azure-functions/background-handler.js')
|
|
11
|
+
|
|
12
|
+
module.exports = class AzureFunctionsSubscriber extends Subscriber {
|
|
13
|
+
constructor({ agent, logger }) {
|
|
14
|
+
super({ agent, logger, channelName: 'nr_generic', packageName: '@azure/functions' })
|
|
15
|
+
this.requireActiveTx = false
|
|
16
|
+
this.coldStart = true
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
handler(data, ctx) {
|
|
20
|
+
if (this.missingEnvVars) {
|
|
21
|
+
this.logger.warn(
|
|
22
|
+
{
|
|
23
|
+
data: {
|
|
24
|
+
expectedVars: ['WEBSITE_OWNER_NAME', 'WEBSITE_RESOURCE_GROUP', 'WEBSITE_SITE_NAME'],
|
|
25
|
+
found: { WEBSITE_OWNER_NAME: this.subscriptionId, WEBSITE_RESOURCE_GROUP: this.resourceGroup, WEBSITE_SITE_NAME: this.azureFunctionAppName }
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
'could not initialize azure functions instrumentation due to missing environment variables'
|
|
29
|
+
)
|
|
30
|
+
return ctx
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const { arguments: args } = data
|
|
34
|
+
const [, options] = args
|
|
35
|
+
const self = this
|
|
36
|
+
const originalHandler = options.handler
|
|
37
|
+
|
|
38
|
+
args[1].handler = async function wrappedHandler(...handlerArgs) {
|
|
39
|
+
let handler
|
|
40
|
+
if (options?.return?.type === 'http') {
|
|
41
|
+
handler = new HttpHandler({ subscriber: self })
|
|
42
|
+
} else {
|
|
43
|
+
handler = new BackgroundHandler({ subscriber: self })
|
|
44
|
+
}
|
|
45
|
+
return handler.handle({ thisArg: this, originalHandler, handlerArgs })
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get missingEnvVars() {
|
|
50
|
+
return !this.subscriptionId || !this.resourceGroup || !this.azureFunctionAppName
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get subscriptionId() {
|
|
54
|
+
if (!process.env.WEBSITE_OWNER_NAME) {
|
|
55
|
+
return null
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return process.env.WEBSITE_OWNER_NAME?.split('+').shift()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get resourceGroup() {
|
|
62
|
+
const { WEBSITE_RESOURCE_GROUP, WEBSITE_OWNER_NAME } = process.env
|
|
63
|
+
if (!WEBSITE_RESOURCE_GROUP && WEBSITE_OWNER_NAME) {
|
|
64
|
+
return WEBSITE_OWNER_NAME.split('+').pop().split('-Linux').shift()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return WEBSITE_RESOURCE_GROUP
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
get azureFunctionAppName() {
|
|
71
|
+
const { WEBSITE_SITE_NAME } = process.env
|
|
72
|
+
return WEBSITE_SITE_NAME
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 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
|
+
const {
|
|
10
|
+
isApplicationLoggingEnabled,
|
|
11
|
+
isLogForwardingEnabled,
|
|
12
|
+
isMetricsEnabled,
|
|
13
|
+
incrementLoggingLinesMetrics
|
|
14
|
+
} = require('#agentlib/util/application-logging.js')
|
|
15
|
+
|
|
16
|
+
// Azure Functions uses 'information' as the context level for context.log and
|
|
17
|
+
// context.info and uses 'warning' as the context level for context.warn.
|
|
18
|
+
// These map to the NR standard names that LOGGING.LEVELS recognizes ('info', 'warn').
|
|
19
|
+
const AZURE_TO_NR_LEVEL = {
|
|
20
|
+
information: 'info',
|
|
21
|
+
warning: 'warn'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = class AzureFunctionsSubscriber extends Subscriber {
|
|
25
|
+
constructor({ agent, logger }) {
|
|
26
|
+
super({ agent, logger, channelName: 'nr_logger', packageName: '@azure/functions' })
|
|
27
|
+
this.logHookRegistered = false
|
|
28
|
+
this.events = ['end']
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
end(data) {
|
|
32
|
+
const coreApi = data.result
|
|
33
|
+
this.registerLogHook(coreApi)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
registerLogHook(coreApi) {
|
|
37
|
+
if (this.logHookRegistered) {
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
this.logHookRegistered = true
|
|
42
|
+
|
|
43
|
+
if (!isApplicationLoggingEnabled(this.agent.config)) {
|
|
44
|
+
this.logger.debug('Application logging not enabled. Not auto capturing logs from Azure Functions.')
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const agent = this.agent
|
|
49
|
+
|
|
50
|
+
coreApi.registerHook('log', (context) => {
|
|
51
|
+
const logLevel = AZURE_TO_NR_LEVEL[context.level] ?? context.level ?? 'info'
|
|
52
|
+
|
|
53
|
+
if (isLogForwardingEnabled(agent.config, agent)) {
|
|
54
|
+
const meta = agent.getLinkingMetadata(true)
|
|
55
|
+
|
|
56
|
+
const logData = {
|
|
57
|
+
message: context.message ?? 'unknown',
|
|
58
|
+
level: logLevel,
|
|
59
|
+
timestamp: Date.now(),
|
|
60
|
+
category: context.category ?? 'user',
|
|
61
|
+
...meta
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
agent.logs.add(logData)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (isMetricsEnabled(agent.config)) {
|
|
68
|
+
incrementLoggingLinesMetrics(logLevel, agent.metrics)
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
const modName = 'connect'
|
|
9
|
+
|
|
10
|
+
module.exports = {
|
|
11
|
+
[modName]: [
|
|
12
|
+
{
|
|
13
|
+
path: './connect/use.js',
|
|
14
|
+
instrumentations: [
|
|
15
|
+
{
|
|
16
|
+
channelName: 'nr_use',
|
|
17
|
+
module: {
|
|
18
|
+
name: modName,
|
|
19
|
+
filePath: 'index.js',
|
|
20
|
+
versionRange: '>=3.4.0'
|
|
21
|
+
},
|
|
22
|
+
functionQuery: {
|
|
23
|
+
expressionName: 'use',
|
|
24
|
+
kind: 'Sync'
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
channelName: 'nr_use',
|
|
29
|
+
module: {
|
|
30
|
+
name: modName,
|
|
31
|
+
filePath: 'lib/proto.js',
|
|
32
|
+
versionRange: '>=3.0.0 <3.4.0'
|
|
33
|
+
},
|
|
34
|
+
functionQuery: {
|
|
35
|
+
expressionName: 'use',
|
|
36
|
+
kind: 'Sync'
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
const MiddlewareSubscriber = require('../middleware.js')
|
|
9
|
+
|
|
10
|
+
module.exports = class CreateServerSubscriber extends MiddlewareSubscriber {
|
|
11
|
+
constructor({ agent, logger }) {
|
|
12
|
+
super({
|
|
13
|
+
agent,
|
|
14
|
+
logger,
|
|
15
|
+
channelName: 'nr_use',
|
|
16
|
+
packageName: 'connect',
|
|
17
|
+
system: 'Connect'
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
handler(data, ctx) {
|
|
22
|
+
const { arguments: args } = data
|
|
23
|
+
const [route, mw] = args
|
|
24
|
+
if (typeof route === 'string') {
|
|
25
|
+
data.arguments[1] = this.wrapper.wrap({ handler: mw, route })
|
|
26
|
+
} else {
|
|
27
|
+
data.arguments[0] = this.wrapper.wrap({ handler: route, route: '/' })
|
|
28
|
+
}
|
|
29
|
+
return ctx
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const AiMonitoringSubscriber = require('../ai-monitoring/base')
|
|
7
|
+
const LlmAgent = require('#agentlib/llm-events/ai-agent.js')
|
|
8
|
+
const LlmErrorMessage = require('#agentlib/llm-events/error-message.js')
|
|
9
|
+
const { AI: { GOOGLE_ADK } } = require('#agentlib/metrics/names.js')
|
|
10
|
+
|
|
11
|
+
module.exports = class GoogleAdkAgentRunSubscriber extends AiMonitoringSubscriber {
|
|
12
|
+
constructor({ agent, logger }) {
|
|
13
|
+
super({
|
|
14
|
+
agent,
|
|
15
|
+
logger,
|
|
16
|
+
packageName: '@google/adk',
|
|
17
|
+
channelName: 'nr_agentRunAsync',
|
|
18
|
+
name: `${GOOGLE_ADK.AGENT}/runAsync/agent`,
|
|
19
|
+
trackingPrefix: GOOGLE_ADK.TRACKING_PREFIX
|
|
20
|
+
})
|
|
21
|
+
this.events = ['end']
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
handler(data, ctx) {
|
|
25
|
+
this.aiAgentName = data?.self?.name ?? 'agent'
|
|
26
|
+
this.name = `${GOOGLE_ADK.AGENT}/runAsync/${this.aiAgentName}`
|
|
27
|
+
return super.handler(data, ctx)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// BaseAgent.runAsync is an async generator. The tracePromise wrapper returns
|
|
31
|
+
// the generator object synchronously (it has no .then), so `asyncEnd` is
|
|
32
|
+
// never published. We use `end` instead, which fires right after the
|
|
33
|
+
// generator is created but before it is consumed by the caller.
|
|
34
|
+
end(data) {
|
|
35
|
+
const { agent, logger } = this
|
|
36
|
+
if (!this.enabled) {
|
|
37
|
+
logger.debug('Google ADK instrumentation is disabled, not instrumenting runAsync.')
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const ctx = agent.tracer.getContext()
|
|
42
|
+
const { segment, transaction } = ctx
|
|
43
|
+
if (!(segment || transaction) || (transaction?.isActive() !== true)) {
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
segment.addSpanAttribute('subcomponent', `{"type": "APM-AI_AGENT", "name": "${this.aiAgentName}"}`)
|
|
47
|
+
|
|
48
|
+
const { result: generator } = data
|
|
49
|
+
if (generator && typeof generator[Symbol.asyncIterator] === 'function') {
|
|
50
|
+
this.#instrumentGenerator({ generator, ctx })
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Wraps the async generator returned by BaseAgent.runAsync() so that
|
|
56
|
+
* child instrumentation (e.g. Gemini, FunctionTool) runs within the
|
|
57
|
+
* agent segment context. Records the LlmAgent event when the generator
|
|
58
|
+
* completes or throws.
|
|
59
|
+
*
|
|
60
|
+
* @param {object} params function parameters
|
|
61
|
+
* @param {object} params.ctx The NR async context to bind generator calls to
|
|
62
|
+
* @param {AsyncGenerator} params.generator The async generator from runAsync
|
|
63
|
+
*/
|
|
64
|
+
#instrumentGenerator({ ctx, generator }) {
|
|
65
|
+
const self = this
|
|
66
|
+
const origNext = generator.next
|
|
67
|
+
|
|
68
|
+
generator.next = async function wrappedNext(...args) {
|
|
69
|
+
try {
|
|
70
|
+
// Bind to the segment context so that child instrumentation
|
|
71
|
+
// (e.g. Gemini) creates spans as children of this agent span.
|
|
72
|
+
const boundNext = self.agent.tracer.bindFunction(origNext, ctx)
|
|
73
|
+
const result = await boundNext.apply(this, args)
|
|
74
|
+
if (result?.done) {
|
|
75
|
+
self.#recordAgentEvent({ ctx, error: false })
|
|
76
|
+
}
|
|
77
|
+
return result
|
|
78
|
+
} catch (err) {
|
|
79
|
+
self.#recordAgentEvent({ ctx, error: true })
|
|
80
|
+
throw err
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Records a Google ADK LlmAgent event.
|
|
87
|
+
*
|
|
88
|
+
* @param {object} params function parameters
|
|
89
|
+
* @param {object} params.ctx The active tracer context containing the segment and transaction
|
|
90
|
+
* @param {boolean} params.error Whether an error occurred
|
|
91
|
+
*/
|
|
92
|
+
#recordAgentEvent({ ctx, error }) {
|
|
93
|
+
const { agent, aiAgentName } = this
|
|
94
|
+
const { segment, transaction } = ctx
|
|
95
|
+
segment.end()
|
|
96
|
+
const agentEvent = new LlmAgent({
|
|
97
|
+
agent,
|
|
98
|
+
segment,
|
|
99
|
+
transaction,
|
|
100
|
+
aiAgentName,
|
|
101
|
+
vendor: 'google_adk',
|
|
102
|
+
error: error || undefined
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
this.recordEvent({ type: 'LlmAgent', msg: agentEvent })
|
|
106
|
+
|
|
107
|
+
if (error) {
|
|
108
|
+
agent.errors.add(
|
|
109
|
+
transaction,
|
|
110
|
+
error,
|
|
111
|
+
new LlmErrorMessage({
|
|
112
|
+
response: {},
|
|
113
|
+
cause: error,
|
|
114
|
+
aiAgent: agentEvent
|
|
115
|
+
})
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const agentRunAsync = {
|
|
7
|
+
path: './google-adk/agent-run-async.js',
|
|
8
|
+
instrumentations: [
|
|
9
|
+
{
|
|
10
|
+
channelName: 'nr_agentRunAsync',
|
|
11
|
+
module: { name: '@google/adk', versionRange: '>=1.1.0', filePath: 'dist/cjs/agents/base_agent.js' },
|
|
12
|
+
functionQuery: {
|
|
13
|
+
className: 'BaseAgent',
|
|
14
|
+
methodName: 'runAsync',
|
|
15
|
+
kind: 'Async'
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
channelName: 'nr_agentRunAsync',
|
|
20
|
+
module: { name: '@google/adk', versionRange: '>=1.1.0', filePath: 'dist/esm/agents/base_agent.js' },
|
|
21
|
+
functionQuery: {
|
|
22
|
+
className: 'BaseAgent',
|
|
23
|
+
methodName: 'runAsync',
|
|
24
|
+
kind: 'Async'
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const toolRunAsync = {
|
|
31
|
+
path: './google-adk/tool-run-async.js',
|
|
32
|
+
instrumentations: [
|
|
33
|
+
{
|
|
34
|
+
channelName: 'nr_toolRunAsync',
|
|
35
|
+
module: { name: '@google/adk', versionRange: '>=1.1.0', filePath: 'dist/cjs/tools/function_tool.js' },
|
|
36
|
+
functionQuery: {
|
|
37
|
+
className: 'FunctionTool',
|
|
38
|
+
methodName: 'runAsync',
|
|
39
|
+
kind: 'Async'
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
channelName: 'nr_toolRunAsync',
|
|
44
|
+
module: { name: '@google/adk', versionRange: '>=1.1.0', filePath: 'dist/esm/tools/function_tool.js' },
|
|
45
|
+
functionQuery: {
|
|
46
|
+
className: 'FunctionTool',
|
|
47
|
+
methodName: 'runAsync',
|
|
48
|
+
kind: 'Async'
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module.exports = {
|
|
55
|
+
'@google/adk': [
|
|
56
|
+
agentRunAsync,
|
|
57
|
+
toolRunAsync
|
|
58
|
+
]
|
|
59
|
+
}
|