newrelic 12.11.1 → 12.11.3
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/lib/db/utils.js +4 -4
- package/lib/header-attributes.js +4 -4
- package/lib/instrumentation/aws-sdk/v3/bedrock.js +25 -14
- package/lib/instrumentation/when/contextualizer.js +2 -1
- package/lib/llm-events/aws-bedrock/bedrock-command.js +55 -21
- package/lib/llm-events/aws-bedrock/bedrock-response.js +3 -1
- package/lib/llm-events/aws-bedrock/chat-completion-message.js +4 -13
- package/lib/llm-events/aws-bedrock/chat-completion-summary.js +1 -1
- package/lib/llm-events/aws-bedrock/embedding.js +6 -4
- package/lib/llm-events/aws-bedrock/utils.js +36 -0
- package/lib/shim/promise-shim.js +5 -6
- package/lib/shim/shim.js +2 -2
- package/lib/shim/transaction-shim.js +6 -4
- package/package.json +1 -1
package/NEWS.md
CHANGED
|
@@ -1,3 +1,44 @@
|
|
|
1
|
+
### v12.11.3 (2025-01-29)
|
|
2
|
+
|
|
3
|
+
#### Bug fixes
|
|
4
|
+
|
|
5
|
+
* Fixed issue with `bluebird` and `when` instrumentation where checking active context crashed when transaction prematurely ends ([#2909](https://github.com/newrelic/node-newrelic/pull/2909)) ([4a30d5c](https://github.com/newrelic/node-newrelic/commit/4a30d5c5082e963cca3664f2ed152017f6360d21))
|
|
6
|
+
* Fixed transaction-shim to properly create new transactions when the existing transaction is not active ([#2912](https://github.com/newrelic/node-newrelic/pull/2912)) ([3ad8c59](https://github.com/newrelic/node-newrelic/commit/3ad8c59e15e037a366ddf6803729b61ecfa701f3))
|
|
7
|
+
|
|
8
|
+
#### Documentation
|
|
9
|
+
|
|
10
|
+
* Updated compatibility report ([#2902](https://github.com/newrelic/node-newrelic/pull/2902)) ([cb16516](https://github.com/newrelic/node-newrelic/commit/cb16516e90a3dc2cefb98e6131a7243412aefbfc))
|
|
11
|
+
|
|
12
|
+
#### Miscellaneous chores
|
|
13
|
+
|
|
14
|
+
* Updated lint rule suppression comment ([#2895](https://github.com/newrelic/node-newrelic/pull/2895)) ([559dc98](https://github.com/newrelic/node-newrelic/commit/559dc98e18c8ba8280b73779780f3efc1c946ed7))
|
|
15
|
+
|
|
16
|
+
#### Continuous integration
|
|
17
|
+
|
|
18
|
+
* Move init container release from lambda to GHA ([#2848](https://github.com/newrelic/node-newrelic/pull/2848)) ([8d8608d](https://github.com/newrelic/node-newrelic/commit/8d8608d1089cafaeb8c17354034c96fe1b49597a))
|
|
19
|
+
|
|
20
|
+
### v12.11.2 (2025-01-23)
|
|
21
|
+
|
|
22
|
+
#### Features
|
|
23
|
+
|
|
24
|
+
* Added support for Claude 3+ Chat API in Bedrock ([#2870](https://github.com/newrelic/node-newrelic/pull/2870)) ([6a83abf](https://github.com/newrelic/node-newrelic/commit/6a83abf8b1a0cb0f993e9d9285566a09677d7d2e))
|
|
25
|
+
|
|
26
|
+
#### Bug fixes
|
|
27
|
+
|
|
28
|
+
* Added defensive code in shim to prevent crashing when checking parent segment ([#2898](https://github.com/newrelic/node-newrelic/pull/2898)) ([751eb96](https://github.com/newrelic/node-newrelic/commit/751eb9608d7401d1123a0e810eac9dc554127e4e))
|
|
29
|
+
|
|
30
|
+
#### Documentation
|
|
31
|
+
|
|
32
|
+
* Updated compatibility report ([#2888](https://github.com/newrelic/node-newrelic/pull/2888)) ([dce9deb](https://github.com/newrelic/node-newrelic/commit/dce9debeda6c5ed30c0ed6dbc00f73cf11c8f40f))
|
|
33
|
+
|
|
34
|
+
#### Miscellaneous chores
|
|
35
|
+
|
|
36
|
+
* Replaced backtracking regex with new algorithm ([#2887](https://github.com/newrelic/node-newrelic/pull/2887)) ([46462d0](https://github.com/newrelic/node-newrelic/commit/46462d00b68c4a4cedd60d46d531b2f31800df98))
|
|
37
|
+
|
|
38
|
+
#### Tests
|
|
39
|
+
|
|
40
|
+
* Improved test coverage of normalizing claude 3 messages ([#2893](https://github.com/newrelic/node-newrelic/pull/2893)) ([cc65763](https://github.com/newrelic/node-newrelic/commit/cc657633b81daf4b372e5715e696ed3c23ecb678))
|
|
41
|
+
|
|
1
42
|
### v12.11.1 (2025-01-16)
|
|
2
43
|
|
|
3
44
|
#### Bug fixes
|
package/lib/db/utils.js
CHANGED
|
@@ -11,9 +11,9 @@ function extractDatabaseChangeFromUse(sql) {
|
|
|
11
11
|
// The character ranges for this were pulled from
|
|
12
12
|
// http://dev.mysql.com/doc/refman/5.7/en/identifiers.html
|
|
13
13
|
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
// eslint-disable-next-line sonarjs/slow-regex
|
|
17
|
-
const match = /^\s*use[^\w`]+([\w
|
|
14
|
+
// The lint rule being suppressed here has been evaluated, and it has been
|
|
15
|
+
// determined that the regular expression is sufficient for our use case.
|
|
16
|
+
// eslint-disable-next-line sonarjs/slow-regex
|
|
17
|
+
const match = /^\s*use[^\w`]+([\w$\u0080-\uFFFF]+|`[^`]+`)[\s;]*$/i.exec(sql)
|
|
18
18
|
return (match && match[1]) || null
|
|
19
19
|
}
|
package/lib/header-attributes.js
CHANGED
|
@@ -95,10 +95,10 @@ function _headerToCamelCase(header) {
|
|
|
95
95
|
const newHeader = header.charAt(0).toLowerCase() + header.slice(1)
|
|
96
96
|
|
|
97
97
|
// Converts headers in the form 'header-name' to be in the form 'headerName'
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return
|
|
101
|
-
})
|
|
98
|
+
return newHeader.split(/[\W_]/).map((ele, i) => {
|
|
99
|
+
if (i === 0) return ele
|
|
100
|
+
return ele.slice(0, 1).toUpperCase() + ele.slice(1)
|
|
101
|
+
}).join('')
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
function _collectHeaders(headers, nameMap, prefix, transaction) {
|
|
@@ -118,18 +118,24 @@ function recordChatCompletionMessages({
|
|
|
118
118
|
isError: err !== null
|
|
119
119
|
})
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
121
|
+
// Record context message(s)
|
|
122
|
+
const promptContextMessages = bedrockCommand.prompt
|
|
123
|
+
promptContextMessages.forEach((contextMessage, promptIndex) => {
|
|
124
|
+
const msg = new LlmChatCompletionMessage({
|
|
125
|
+
agent,
|
|
126
|
+
segment,
|
|
127
|
+
transaction,
|
|
128
|
+
bedrockCommand,
|
|
129
|
+
content: contextMessage.content,
|
|
130
|
+
role: contextMessage.role,
|
|
131
|
+
bedrockResponse,
|
|
132
|
+
index: promptIndex,
|
|
133
|
+
completionId: summary.id
|
|
134
|
+
})
|
|
135
|
+
recordEvent({ agent, type: 'LlmChatCompletionMessage', msg })
|
|
129
136
|
})
|
|
130
|
-
recordEvent({ agent, type: 'LlmChatCompletionMessage', msg })
|
|
131
137
|
|
|
132
|
-
bedrockResponse.completions.forEach((content,
|
|
138
|
+
bedrockResponse.completions.forEach((content, completionIndex) => {
|
|
133
139
|
const chatCompletionMessage = new LlmChatCompletionMessage({
|
|
134
140
|
agent,
|
|
135
141
|
segment,
|
|
@@ -137,8 +143,9 @@ function recordChatCompletionMessages({
|
|
|
137
143
|
bedrockCommand,
|
|
138
144
|
bedrockResponse,
|
|
139
145
|
isResponse: true,
|
|
140
|
-
index:
|
|
146
|
+
index: promptContextMessages.length + completionIndex,
|
|
141
147
|
content,
|
|
148
|
+
role: 'assistant',
|
|
142
149
|
completionId: summary.id
|
|
143
150
|
})
|
|
144
151
|
recordEvent({ agent, type: 'LlmChatCompletionMessage', msg: chatCompletionMessage })
|
|
@@ -179,18 +186,22 @@ function recordEmbeddingMessage({
|
|
|
179
186
|
return
|
|
180
187
|
}
|
|
181
188
|
|
|
182
|
-
const
|
|
189
|
+
const embeddings = bedrockCommand.prompt.map(prompt => new LlmEmbedding({
|
|
183
190
|
agent,
|
|
184
191
|
segment,
|
|
185
192
|
transaction,
|
|
186
193
|
bedrockCommand,
|
|
194
|
+
input: prompt.content,
|
|
187
195
|
bedrockResponse,
|
|
188
196
|
isError: err !== null
|
|
197
|
+
}))
|
|
198
|
+
|
|
199
|
+
embeddings.forEach(embedding => {
|
|
200
|
+
recordEvent({ agent, type: 'LlmEmbedding', msg: embedding })
|
|
189
201
|
})
|
|
190
202
|
|
|
191
|
-
recordEvent({ agent, type: 'LlmEmbedding', msg: embedding })
|
|
192
203
|
if (err) {
|
|
193
|
-
const llmError = new LlmError({ bedrockResponse, err, embedding })
|
|
204
|
+
const llmError = new LlmError({ bedrockResponse, err, embedding: embeddings.length === 1 ? embeddings[0] : undefined })
|
|
194
205
|
agent.errors.add(transaction, err, llmError)
|
|
195
206
|
}
|
|
196
207
|
}
|
|
@@ -116,7 +116,8 @@ Contextualizer.prototype = Object.create(null)
|
|
|
116
116
|
Contextualizer.prototype.isActive = function isActive() {
|
|
117
117
|
const segments = this.context.segments
|
|
118
118
|
const segment = segments[this.idx] || segments[this.parentIdx] || segments[0]
|
|
119
|
-
|
|
119
|
+
const transaction = this.getTransaction()
|
|
120
|
+
return segment && transaction?.isActive()
|
|
120
121
|
}
|
|
121
122
|
|
|
122
123
|
/**
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
+
const { stringifyClaudeChunkedMessage } = require('./utils')
|
|
9
|
+
|
|
8
10
|
/**
|
|
9
11
|
* Parses an AWS invoke command instance into a re-usable entity.
|
|
10
12
|
*/
|
|
@@ -68,37 +70,34 @@ class BedrockCommand {
|
|
|
68
70
|
/**
|
|
69
71
|
* The question posed to the LLM.
|
|
70
72
|
*
|
|
71
|
-
* @returns {
|
|
73
|
+
* @returns {object[]} The array of context messages passed to the LLM (or a single user prompt for legacy "non-chat" models)
|
|
72
74
|
*/
|
|
73
75
|
get prompt() {
|
|
74
|
-
let result
|
|
75
76
|
if (this.isTitan() === true || this.isTitanEmbed() === true) {
|
|
76
|
-
|
|
77
|
+
return [
|
|
78
|
+
{
|
|
79
|
+
role: 'user',
|
|
80
|
+
content: this.#body.inputText
|
|
81
|
+
}
|
|
82
|
+
]
|
|
77
83
|
} else if (this.isCohereEmbed() === true) {
|
|
78
|
-
|
|
84
|
+
return [
|
|
85
|
+
{
|
|
86
|
+
role: 'user',
|
|
87
|
+
content: this.#body.texts.join(' ')
|
|
88
|
+
}
|
|
89
|
+
]
|
|
79
90
|
} else if (
|
|
80
|
-
this.
|
|
91
|
+
this.isClaudeTextCompletionApi() === true ||
|
|
81
92
|
this.isAi21() === true ||
|
|
82
93
|
this.isCohere() === true ||
|
|
83
94
|
this.isLlama() === true
|
|
84
95
|
) {
|
|
85
|
-
|
|
86
|
-
} else if (this.
|
|
87
|
-
|
|
88
|
-
for (const message of this.#body?.messages) {
|
|
89
|
-
if (message?.role === 'assistant') {
|
|
90
|
-
continue
|
|
91
|
-
}
|
|
92
|
-
if (typeof message?.content === 'string') {
|
|
93
|
-
collected.push(message?.content)
|
|
94
|
-
continue
|
|
95
|
-
}
|
|
96
|
-
const mappedMsgObj = message?.content.map((msgContent) => msgContent.text)
|
|
97
|
-
collected.push(mappedMsgObj)
|
|
98
|
-
}
|
|
99
|
-
result = collected.join(' ')
|
|
96
|
+
return [{ role: 'user', content: this.#body.prompt }]
|
|
97
|
+
} else if (this.isClaudeMessagesApi() === true) {
|
|
98
|
+
return normalizeClaude3Messages(this.#body?.messages)
|
|
100
99
|
}
|
|
101
|
-
return
|
|
100
|
+
return []
|
|
102
101
|
}
|
|
103
102
|
|
|
104
103
|
/**
|
|
@@ -151,6 +150,41 @@ class BedrockCommand {
|
|
|
151
150
|
isTitanEmbed() {
|
|
152
151
|
return this.#modelId.startsWith('amazon.titan-embed')
|
|
153
152
|
}
|
|
153
|
+
|
|
154
|
+
isClaudeMessagesApi() {
|
|
155
|
+
return (this.isClaude3() === true || this.isClaude() === true) && 'messages' in this.#body
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
isClaudeTextCompletionApi() {
|
|
159
|
+
return this.isClaude() === true && 'prompt' in this.#body
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Claude v3 requests in Bedrock can have two different "chat" flavors. This function normalizes them into a consistent
|
|
165
|
+
* format per the AIM agent spec
|
|
166
|
+
*
|
|
167
|
+
* @param messages - The raw array of messages passed to the invoke API
|
|
168
|
+
* @returns {number|undefined} - The normalized messages
|
|
169
|
+
*/
|
|
170
|
+
function normalizeClaude3Messages(messages) {
|
|
171
|
+
const result = []
|
|
172
|
+
for (const message of messages ?? []) {
|
|
173
|
+
if (message == null) {
|
|
174
|
+
continue
|
|
175
|
+
}
|
|
176
|
+
if (typeof message.content === 'string') {
|
|
177
|
+
// Messages can be specified with plain string content
|
|
178
|
+
result.push({ role: message.role, content: message.content })
|
|
179
|
+
} else if (Array.isArray(message.content)) {
|
|
180
|
+
// Or in a "chunked" format for multi-modal support
|
|
181
|
+
result.push({
|
|
182
|
+
role: message.role,
|
|
183
|
+
content: stringifyClaudeChunkedMessage(message.content)
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return result
|
|
154
188
|
}
|
|
155
189
|
|
|
156
190
|
module.exports = BedrockCommand
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
+
const { stringifyClaudeChunkedMessage } = require('./utils')
|
|
9
|
+
|
|
8
10
|
/**
|
|
9
11
|
* @typedef {object} AwsBedrockMiddlewareResponse
|
|
10
12
|
* @property {object} response Has a `body` property that is an IncomingMessage,
|
|
@@ -63,7 +65,7 @@ class BedrockResponse {
|
|
|
63
65
|
// Streamed response
|
|
64
66
|
this.#completions = body.completions
|
|
65
67
|
} else {
|
|
66
|
-
this.#completions = body?.content
|
|
68
|
+
this.#completions = [stringifyClaudeChunkedMessage(body?.content)]
|
|
67
69
|
}
|
|
68
70
|
this.#id = body.id
|
|
69
71
|
} else if (cmd.isCohere() === true) {
|
|
@@ -39,7 +39,7 @@ class LlmChatCompletionMessage extends LlmEvent {
|
|
|
39
39
|
params = Object.assign({}, defaultParams, params)
|
|
40
40
|
super(params)
|
|
41
41
|
|
|
42
|
-
const { agent, content, isResponse, index, completionId } = params
|
|
42
|
+
const { agent, content, isResponse, index, completionId, role } = params
|
|
43
43
|
const recordContent = agent.config?.ai_monitoring?.record_content?.enabled
|
|
44
44
|
const tokenCB = agent?.llm?.tokenCountCallback
|
|
45
45
|
|
|
@@ -47,20 +47,11 @@ class LlmChatCompletionMessage extends LlmEvent {
|
|
|
47
47
|
this.completion_id = completionId
|
|
48
48
|
this.sequence = index
|
|
49
49
|
this.content = recordContent === true ? content : undefined
|
|
50
|
-
this.role =
|
|
50
|
+
this.role = role
|
|
51
51
|
|
|
52
52
|
this.#setId(index)
|
|
53
|
-
if (
|
|
54
|
-
this.
|
|
55
|
-
if (typeof tokenCB === 'function') {
|
|
56
|
-
this.token_count = tokenCB(this.bedrockCommand.modelId, content)
|
|
57
|
-
}
|
|
58
|
-
} else {
|
|
59
|
-
this.role = 'user'
|
|
60
|
-
this.content = recordContent === true ? this.bedrockCommand.prompt : undefined
|
|
61
|
-
if (typeof tokenCB === 'function') {
|
|
62
|
-
this.token_count = tokenCB(this.bedrockCommand.modelId, this.bedrockCommand.prompt)
|
|
63
|
-
}
|
|
53
|
+
if (typeof tokenCB === 'function') {
|
|
54
|
+
this.token_count = tokenCB(this.bedrockCommand.modelId, content)
|
|
64
55
|
}
|
|
65
56
|
}
|
|
66
57
|
|
|
@@ -36,7 +36,7 @@ class LlmChatCompletionSummary extends LlmEvent {
|
|
|
36
36
|
const cmd = this.bedrockCommand
|
|
37
37
|
this[cfr] = this.bedrockResponse.finishReason
|
|
38
38
|
this[rt] = cmd.temperature
|
|
39
|
-
this[nm] =
|
|
39
|
+
this[nm] = (this.bedrockCommand.prompt.length) + this.bedrockResponse.completions.length
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -10,7 +10,7 @@ const LlmEvent = require('./event')
|
|
|
10
10
|
/**
|
|
11
11
|
* @typedef {object} LlmEmbeddingParams
|
|
12
12
|
* @augments LlmEventParams
|
|
13
|
-
* @property
|
|
13
|
+
* @property {string} input - The input message for the embedding call
|
|
14
14
|
*/
|
|
15
15
|
/**
|
|
16
16
|
* @type {LlmEmbeddingParams}
|
|
@@ -20,16 +20,18 @@ const defaultParams = {}
|
|
|
20
20
|
class LlmEmbedding extends LlmEvent {
|
|
21
21
|
constructor(params = defaultParams) {
|
|
22
22
|
super(params)
|
|
23
|
-
const { agent } = params
|
|
23
|
+
const { agent, input } = params
|
|
24
24
|
const tokenCb = agent?.llm?.tokenCountCallback
|
|
25
25
|
|
|
26
26
|
this.input = agent.config?.ai_monitoring?.record_content?.enabled
|
|
27
|
-
?
|
|
27
|
+
? input
|
|
28
28
|
: undefined
|
|
29
29
|
this.error = params.isError
|
|
30
30
|
this.duration = params.segment.getDurationInMillis()
|
|
31
|
+
|
|
32
|
+
// Even if not recording content, we should use the local token counting callback to record token usage
|
|
31
33
|
if (typeof tokenCb === 'function') {
|
|
32
|
-
this.token_count = tokenCb(this.bedrockCommand.modelId,
|
|
34
|
+
this.token_count = tokenCb(this.bedrockCommand.modelId, input)
|
|
33
35
|
}
|
|
34
36
|
}
|
|
35
37
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2024 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @param {object[]} chunks - The "chunks" that make up a single conceptual message. In a multi-modal scenario, a single message
|
|
11
|
+
* might have a number of different-typed chunks interspersed
|
|
12
|
+
* @returns {string} - A stringified version of the message. We make a best-effort effort attempt to represent non-text chunks. In the future
|
|
13
|
+
* we may want to extend the agent to support these non-text chunks in a richer way. Placeholders are represented in an XML-like format but
|
|
14
|
+
* are NOT intended to be parsed as valid XML
|
|
15
|
+
*/
|
|
16
|
+
function stringifyClaudeChunkedMessage(chunks) {
|
|
17
|
+
const stringifiedChunks = chunks.map((msgContent) => {
|
|
18
|
+
switch (msgContent.type) {
|
|
19
|
+
case 'text':
|
|
20
|
+
return msgContent.text
|
|
21
|
+
case 'image':
|
|
22
|
+
return '<image>'
|
|
23
|
+
case 'tool_use':
|
|
24
|
+
return `<tool_use>${msgContent.name}</tool_use>`
|
|
25
|
+
case 'tool_result':
|
|
26
|
+
return `<tool_result>${msgContent.content}</tool_result>`
|
|
27
|
+
default:
|
|
28
|
+
return '<unknown_chunk>'
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
return stringifiedChunks.join('\n\n')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = {
|
|
35
|
+
stringifyClaudeChunkedMessage
|
|
36
|
+
}
|
package/lib/shim/promise-shim.js
CHANGED
|
@@ -121,7 +121,7 @@ class PromiseShim extends Shim {
|
|
|
121
121
|
const transaction = shim.tracer.getTransaction()
|
|
122
122
|
// This extra property is added by `_wrapExecutorContext` in the pre step.
|
|
123
123
|
const executor = args[0]
|
|
124
|
-
const context = executor
|
|
124
|
+
const context = executor?.[symbols.executorContext]
|
|
125
125
|
if (!context || !shim.isFunction(context.executor)) {
|
|
126
126
|
return
|
|
127
127
|
}
|
|
@@ -387,9 +387,7 @@ function _wrapExecutorContext(shim, args) {
|
|
|
387
387
|
function _wrapResolver(context, fn) {
|
|
388
388
|
return function wrappedResolveReject(val) {
|
|
389
389
|
const promise = context.promise
|
|
390
|
-
|
|
391
|
-
promise[symbols.context].getSegment().touch()
|
|
392
|
-
}
|
|
390
|
+
promise?.[symbols.context]?.getSegment()?.touch()
|
|
393
391
|
fn(val)
|
|
394
392
|
}
|
|
395
393
|
}
|
|
@@ -416,7 +414,7 @@ function wrapHandler({ handler, index, argsLength, useAllParams, ctx, shim }) {
|
|
|
416
414
|
}
|
|
417
415
|
|
|
418
416
|
return function __NR_wrappedThenHandler() {
|
|
419
|
-
if (!ctx
|
|
417
|
+
if (!ctx?.handler?.[symbols.context]) {
|
|
420
418
|
return handler.apply(this, arguments)
|
|
421
419
|
}
|
|
422
420
|
|
|
@@ -591,7 +589,8 @@ class Contextualizer {
|
|
|
591
589
|
isActive() {
|
|
592
590
|
const segments = this.context.segments
|
|
593
591
|
const segment = segments[this.idx] || segments[this.parentIdx] || segments[0]
|
|
594
|
-
|
|
592
|
+
const transaction = this.getTransaction()
|
|
593
|
+
return segment && transaction?.isActive()
|
|
595
594
|
}
|
|
596
595
|
|
|
597
596
|
getTransaction() {
|
package/lib/shim/shim.js
CHANGED
|
@@ -677,7 +677,7 @@ function recordWrapper({ shim, fn, name, recordNamer }) {
|
|
|
677
677
|
return fnApply.call(fn, this, args)
|
|
678
678
|
}
|
|
679
679
|
|
|
680
|
-
//
|
|
680
|
+
// middleware recorders pass in parent segment
|
|
681
681
|
// we need to destructure this as it is not needed past this function
|
|
682
682
|
// and will overwhelm trace level loggers with logging the entire spec
|
|
683
683
|
const { parent: specParent, ...segDesc } = spec
|
|
@@ -686,7 +686,7 @@ function recordWrapper({ shim, fn, name, recordNamer }) {
|
|
|
686
686
|
const transaction = context.transaction
|
|
687
687
|
const parent = transaction?.isActive() && specParent ? specParent : context.segment
|
|
688
688
|
|
|
689
|
-
if (!transaction?.isActive()) {
|
|
689
|
+
if (!transaction?.isActive() || !parent) {
|
|
690
690
|
shim.logger.debug('Not recording function %s, not in a transaction.', name)
|
|
691
691
|
return fnApply.call(fn, this, arguments)
|
|
692
692
|
}
|
|
@@ -372,12 +372,13 @@ function _makeNestedTransWrapper(shim, func, name, spec) {
|
|
|
372
372
|
}
|
|
373
373
|
|
|
374
374
|
let context = shim.tracer.getContext()
|
|
375
|
+
let transaction = shim.tracer.getTransaction()
|
|
375
376
|
|
|
376
377
|
// Only create a new transaction if we either do not have a current
|
|
377
378
|
// transaction _or_ the current transaction is not of the type we want.
|
|
378
|
-
if (!
|
|
379
|
+
if (!transaction || spec.type !== transaction?.type) {
|
|
379
380
|
shim.logger.trace('Creating new nested %s transaction for %s', spec.type, name)
|
|
380
|
-
|
|
381
|
+
transaction = new Transaction(shim.agent)
|
|
381
382
|
transaction.type = spec.type
|
|
382
383
|
context = context.enterTransaction(transaction)
|
|
383
384
|
}
|
|
@@ -405,10 +406,11 @@ function _makeNestedTransWrapper(shim, func, name, spec) {
|
|
|
405
406
|
*/
|
|
406
407
|
function _makeTransWrapper(shim, func, name, spec) {
|
|
407
408
|
return function transactionWrapper() {
|
|
408
|
-
// Don't nest transactions, reuse existing ones!
|
|
409
409
|
let context = shim.tracer.getContext()
|
|
410
|
-
|
|
410
|
+
// Don't nest transactions, reuse existing ones!
|
|
411
|
+
const existingTransaction = shim.tracer.getTransaction()
|
|
411
412
|
if (!shim.agent.canCollectData() || existingTransaction) {
|
|
413
|
+
shim.logger.trace('Transaction %s exists, not creating new transaction %s for %s', existingTransaction?.id, spec.type, name)
|
|
412
414
|
return func.apply(this, arguments)
|
|
413
415
|
}
|
|
414
416
|
|