newrelic 12.22.0 → 12.23.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 +21 -0
- package/index.js +3 -3
- package/lib/config/default.js +13 -0
- package/lib/spans/helpers.js +63 -1
- package/lib/spans/span-event-aggregator.js +6 -3
- package/lib/spans/span-event.js +10 -4
- package/lib/spans/streaming-span-event-aggregator.js +6 -2
- package/lib/spans/streaming-span-event.js +10 -4
- package/lib/util/code-level-metrics.js +1 -1
- package/package.json +3 -3
package/NEWS.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
### v12.23.0 (2025-06-30)
|
|
2
|
+
|
|
3
|
+
#### Features
|
|
4
|
+
|
|
5
|
+
* Added ability to report only on entry and exit spans ([#3184](https://github.com/newrelic/node-newrelic/pull/3184)) ([1f909d3](https://github.com/newrelic/node-newrelic/commit/1f909d389f790733c8787a9db8b0ee71c26bb5ed))
|
|
6
|
+
* Added Node.js 24 support ([#3080](https://github.com/newrelic/node-newrelic/pull/3080)) ([a538c2a](https://github.com/newrelic/node-newrelic/commit/a538c2a5e23b96be40fa3c014e60b912f695423e))
|
|
7
|
+
|
|
8
|
+
#### Documentation
|
|
9
|
+
|
|
10
|
+
* Updated compatibility report ([#3186](https://github.com/newrelic/node-newrelic/pull/3186)) ([5498c15](https://github.com/newrelic/node-newrelic/commit/5498c15bb6cf3329fe50595da46ab4f2b1385170))
|
|
11
|
+
|
|
12
|
+
#### Miscellaneous chores
|
|
13
|
+
|
|
14
|
+
* Fix issues on Node 24 ([#3181](https://github.com/newrelic/node-newrelic/pull/3181)) ([24832df](https://github.com/newrelic/node-newrelic/commit/24832df2984df960a4e44375525a8127a00a637c))
|
|
15
|
+
* Removed force labels on main CI workflow ([#3183](https://github.com/newrelic/node-newrelic/pull/3183)) ([3aaee17](https://github.com/newrelic/node-newrelic/commit/3aaee17586f817ae1a2ab0573570a740bd6397ef))
|
|
16
|
+
* Updated undici tests to unblock CI ([#3185](https://github.com/newrelic/node-newrelic/pull/3185)) ([08261eb](https://github.com/newrelic/node-newrelic/commit/08261ebcdbafdb625a451f4ccec9b0cba7641cc2))
|
|
17
|
+
|
|
18
|
+
#### Continuous integration
|
|
19
|
+
|
|
20
|
+
* Fixed the name of todo colum in add to board reusable workflow ([#3178](https://github.com/newrelic/node-newrelic/pull/3178)) ([f216e0c](https://github.com/newrelic/node-newrelic/commit/f216e0c48adf0291bfa38b3edbb04c9dcc96f92c))
|
|
21
|
+
|
|
1
22
|
### v12.22.0 (2025-06-24)
|
|
2
23
|
|
|
3
24
|
#### Features
|
package/index.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
const HealthReporter = require('./lib/health-reporter')
|
|
8
|
+
const HealthReporter = require('./lib/health-reporter.js')
|
|
9
9
|
|
|
10
10
|
// Record opening times before loading any other files.
|
|
11
11
|
const preAgentTime = process.uptime()
|
|
@@ -64,8 +64,8 @@ function initialize() {
|
|
|
64
64
|
throw new Error(message)
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
// TODO: Update this check when Node
|
|
68
|
-
if (psemver.satisfies('>=
|
|
67
|
+
// TODO: Update this check when Node v26 support is added
|
|
68
|
+
if (psemver.satisfies('>=25.0.0')) {
|
|
69
69
|
logger.warn(
|
|
70
70
|
'New Relic for Node.js %s has not been tested on Node.js %s. Please ' +
|
|
71
71
|
'update the agent or downgrade your version of Node.js',
|
package/lib/config/default.js
CHANGED
|
@@ -1120,6 +1120,19 @@ defaultConfig.definition = () => ({
|
|
|
1120
1120
|
default: false
|
|
1121
1121
|
},
|
|
1122
1122
|
|
|
1123
|
+
/**
|
|
1124
|
+
* Controls whether the agent will generate spans for in-process actions.
|
|
1125
|
+
* When disabled, this will only create spans for entry and exit spans.
|
|
1126
|
+
* entry spans - initial actions for web servers and messsage queue consumption.
|
|
1127
|
+
* exit spans - all outgoing calls to external services(external and database calls)
|
|
1128
|
+
*/
|
|
1129
|
+
in_process_spans: {
|
|
1130
|
+
enabled: {
|
|
1131
|
+
formatter: boolean,
|
|
1132
|
+
default: true
|
|
1133
|
+
}
|
|
1134
|
+
},
|
|
1135
|
+
|
|
1123
1136
|
sampler: {
|
|
1124
1137
|
/**
|
|
1125
1138
|
* When set to `always_on`, the sampled flag in the `traceparent` header
|
package/lib/spans/helpers.js
CHANGED
|
@@ -60,10 +60,72 @@ function addSpanKind({ segment, span }) {
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Checks if the segment is an entry point span.
|
|
65
|
+
* An entry point span is defined as the base segment of a transaction.
|
|
66
|
+
* @param {object} params to function
|
|
67
|
+
* @param {Transaction} params.transaction active transaction
|
|
68
|
+
* @param {TraceSegment} params.segment segment that is creating span
|
|
69
|
+
* @returns {boolean} true if the segment is an entry point span
|
|
70
|
+
*/
|
|
71
|
+
function isEntryPointSpan({ transaction, segment }) {
|
|
72
|
+
return transaction?.baseSegment === segment
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Checks if the segment is an exit span.
|
|
77
|
+
* An exit span is defined as a segment that is an external call,
|
|
78
|
+
* datastore operation, or message broker operation.
|
|
79
|
+
* @param {TraceSegment} segment segment that is creating span
|
|
80
|
+
* @returns {boolean} true if the segment is an exit span
|
|
81
|
+
*/
|
|
82
|
+
function isExitSpan(segment) {
|
|
83
|
+
return REGEXS.CLIENT.EXTERNAL.test(segment.name) || REGEXS.CLIENT.DATASTORE.test(segment.name) || REGEXS.PRODUCER.test(segment.name)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Determines if a span should be created based on the segment and transaction.
|
|
88
|
+
* If the segment is an entry point span or an exit span, a span should be created.
|
|
89
|
+
* @param {object} params to function
|
|
90
|
+
* @param {boolean} params.entryPoint true if the segment is an entry point span
|
|
91
|
+
* @param {TraceSegment} params.segment segment that is creating span
|
|
92
|
+
* @returns {boolean} true if a span should be created
|
|
93
|
+
*/
|
|
94
|
+
function shouldCreateSpan({ entryPoint, segment }) {
|
|
95
|
+
return entryPoint ||
|
|
96
|
+
isExitSpan(segment)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Reparents a span based on the transaction and inProcessSpans.
|
|
101
|
+
* If inProcessSpans is true or the transaction has accepted distributed trace and it's the root segment,
|
|
102
|
+
* the parentId is not changed.
|
|
103
|
+
* If there is a parentId and the transaction has a base segment, the span is reparented to the base segment.
|
|
104
|
+
* If there is no parentId, the span is not reparented(indicates an entry root span for a DT trace).
|
|
105
|
+
* @param {object} params to function
|
|
106
|
+
* @param {boolean} params.inProcessSpans true if in-process spans are enabled
|
|
107
|
+
* @param {boolean} params.isRoot true if the segment is the root segment
|
|
108
|
+
* @param {string} params.parentId the parent id of the segment
|
|
109
|
+
* @param {Transaction} params.transaction active transaction
|
|
110
|
+
* @returns {string|null} the new parentId for the span
|
|
111
|
+
*/
|
|
112
|
+
function reparentSpan({ inProcessSpans, isRoot, parentId, transaction }) {
|
|
113
|
+
if (inProcessSpans || (transaction.acceptedDistributedTrace && isRoot)) {
|
|
114
|
+
return parentId
|
|
115
|
+
} else if (parentId && transaction?.baseSegment?.id) {
|
|
116
|
+
return transaction.baseSegment.id
|
|
117
|
+
} else {
|
|
118
|
+
return null
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
63
122
|
module.exports = {
|
|
64
123
|
HTTP_LIBRARY,
|
|
65
124
|
CATEGORIES,
|
|
66
125
|
SPAN_KIND,
|
|
67
126
|
REGEXS,
|
|
68
|
-
addSpanKind
|
|
127
|
+
addSpanKind,
|
|
128
|
+
isEntryPointSpan,
|
|
129
|
+
reparentSpan,
|
|
130
|
+
shouldCreateSpan
|
|
69
131
|
}
|
|
@@ -21,6 +21,7 @@ class SpanEventAggregator extends EventAggregator {
|
|
|
21
21
|
opts.metricNames = opts.metricNames || NAMES.SPAN_EVENTS
|
|
22
22
|
|
|
23
23
|
super(opts, agent)
|
|
24
|
+
this.inProcessSpans = agent.config.distributed_tracing.in_process_spans.enabled
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
_toPayloadSync() {
|
|
@@ -66,7 +67,6 @@ class SpanEventAggregator extends EventAggregator {
|
|
|
66
67
|
* @param {Transaction} params.transaction active transaction
|
|
67
68
|
* @param {string} [params.parentId] GUID of the parent span.
|
|
68
69
|
* @param {boolean} params.isRoot if segment is root segment
|
|
69
|
-
* @returns {boolean} True if the segment was added, or false if it was discarded.
|
|
70
70
|
*/
|
|
71
71
|
addSegment({ segment, transaction, parentId, isRoot }) {
|
|
72
72
|
// Check if the priority would be accepted before creating the event object.
|
|
@@ -77,8 +77,11 @@ class SpanEventAggregator extends EventAggregator {
|
|
|
77
77
|
|
|
78
78
|
return false
|
|
79
79
|
}
|
|
80
|
-
const span = SpanEvent.fromSegment(segment, transaction, parentId
|
|
81
|
-
|
|
80
|
+
const span = SpanEvent.fromSegment({ segment, transaction, parentId, isRoot, inProcessSpans: this.inProcessSpans })
|
|
81
|
+
|
|
82
|
+
if (span) {
|
|
83
|
+
this.add(span, transaction.priority)
|
|
84
|
+
}
|
|
82
85
|
}
|
|
83
86
|
|
|
84
87
|
/**
|
package/lib/spans/span-event.js
CHANGED
|
@@ -9,7 +9,7 @@ const Config = require('../config')
|
|
|
9
9
|
const { truncate } = require('../util/byte-limit')
|
|
10
10
|
|
|
11
11
|
const { DESTINATIONS } = require('../config/attribute-filter')
|
|
12
|
-
const { addSpanKind, HTTP_LIBRARY, REGEXS, SPAN_KIND, CATEGORIES } = require('./helpers')
|
|
12
|
+
const { addSpanKind, isEntryPointSpan, reparentSpan, shouldCreateSpan, HTTP_LIBRARY, REGEXS, SPAN_KIND, CATEGORIES } = require('./helpers')
|
|
13
13
|
const EMPTY_USER_ATTRS = Object.freeze(Object.create(null))
|
|
14
14
|
const SERVER_ADDRESS = 'server.address'
|
|
15
15
|
|
|
@@ -93,9 +93,15 @@ class SpanEvent {
|
|
|
93
93
|
* @param {Transaction} transaction active transaction
|
|
94
94
|
* @param {?string} [parentId] ID of the segment's parent.
|
|
95
95
|
* @param {boolean} isRoot if segment is root segment
|
|
96
|
+
* @param {boolean} inProcessSpans if the segment is in-process, create span
|
|
96
97
|
* @returns {SpanEvent} The constructed event.
|
|
97
98
|
*/
|
|
98
|
-
static fromSegment(segment, transaction, parentId = null, isRoot = false) {
|
|
99
|
+
static fromSegment({ segment, transaction, parentId = null, isRoot = false, inProcessSpans }) {
|
|
100
|
+
const entryPoint = isEntryPointSpan({ segment, transaction })
|
|
101
|
+
if (!inProcessSpans && !shouldCreateSpan({ entryPoint, segment, transaction })) {
|
|
102
|
+
return null
|
|
103
|
+
}
|
|
104
|
+
|
|
99
105
|
const spanContext = segment.getSpanContext()
|
|
100
106
|
|
|
101
107
|
// Since segments already hold span agent attributes and we want to leverage
|
|
@@ -128,7 +134,7 @@ class SpanEvent {
|
|
|
128
134
|
|
|
129
135
|
span.intrinsics.traceId = transaction.traceId
|
|
130
136
|
span.intrinsics.guid = segment.id
|
|
131
|
-
span.intrinsics.parentId = parentId
|
|
137
|
+
span.intrinsics.parentId = reparentSpan({ inProcessSpans, isRoot, segment, transaction, parentId })
|
|
132
138
|
span.intrinsics.transactionId = transaction.id
|
|
133
139
|
span.intrinsics.sampled = transaction.sampled
|
|
134
140
|
span.intrinsics.priority = transaction.priority
|
|
@@ -142,7 +148,7 @@ class SpanEvent {
|
|
|
142
148
|
}
|
|
143
149
|
|
|
144
150
|
// Only set this if it will be `true`. Must be `null` otherwise.
|
|
145
|
-
if (
|
|
151
|
+
if (entryPoint) {
|
|
146
152
|
span.intrinsics['nr.entryPoint'] = true
|
|
147
153
|
}
|
|
148
154
|
|
|
@@ -44,6 +44,7 @@ class StreamingSpanEventAggregator extends Aggregator {
|
|
|
44
44
|
this.metrics = metrics
|
|
45
45
|
this.started = false
|
|
46
46
|
this.isStream = true
|
|
47
|
+
this.inProcessSpans = agent.config.distributed_tracing.in_process_spans.enabled
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
/**
|
|
@@ -112,8 +113,11 @@ class StreamingSpanEventAggregator extends Aggregator {
|
|
|
112
113
|
return
|
|
113
114
|
}
|
|
114
115
|
|
|
115
|
-
const span = StreamingSpanEvent.fromSegment(segment, transaction, parentId, isRoot)
|
|
116
|
-
|
|
116
|
+
const span = StreamingSpanEvent.fromSegment({ segment, transaction, parentId, isRoot, inProcessSpans: this.inProcessSpans })
|
|
117
|
+
|
|
118
|
+
if (span) {
|
|
119
|
+
this.stream.write(span)
|
|
120
|
+
}
|
|
117
121
|
}
|
|
118
122
|
|
|
119
123
|
reconfigure(config) {
|
|
@@ -10,7 +10,7 @@ const { truncate } = require('../util/byte-limit')
|
|
|
10
10
|
const Config = require('../config')
|
|
11
11
|
|
|
12
12
|
const { DESTINATIONS } = require('../config/attribute-filter')
|
|
13
|
-
const { addSpanKind, HTTP_LIBRARY, REGEXS, SPAN_KIND, CATEGORIES } = require('./helpers')
|
|
13
|
+
const { addSpanKind, isEntryPointSpan, reparentSpan, shouldCreateSpan, HTTP_LIBRARY, REGEXS, SPAN_KIND, CATEGORIES } = require('./helpers')
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Specialized span event class for use with infinite streaming.
|
|
@@ -108,7 +108,12 @@ class StreamingSpanEvent {
|
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
static fromSegment(segment, transaction, parentId = null, isRoot = false) {
|
|
111
|
+
static fromSegment({ segment, transaction, parentId = null, isRoot = false, inProcessSpans }) {
|
|
112
|
+
const entryPoint = isEntryPointSpan({ segment, transaction })
|
|
113
|
+
if (!inProcessSpans && !shouldCreateSpan({ entryPoint, segment, transaction })) {
|
|
114
|
+
return null
|
|
115
|
+
}
|
|
116
|
+
|
|
112
117
|
const spanContext = segment.getSpanContext()
|
|
113
118
|
|
|
114
119
|
// Since segments already hold span agent attributes and we want to leverage
|
|
@@ -141,8 +146,9 @@ class StreamingSpanEvent {
|
|
|
141
146
|
span.addIntrinsicAttribute(key, value)
|
|
142
147
|
}
|
|
143
148
|
|
|
149
|
+
const newParentId = reparentSpan({ inProcessSpans, isRoot, segment, transaction, parentId })
|
|
144
150
|
span.addIntrinsicAttribute('guid', segment.id)
|
|
145
|
-
span.addIntrinsicAttribute('parentId',
|
|
151
|
+
span.addIntrinsicAttribute('parentId', newParentId)
|
|
146
152
|
span.addIntrinsicAttribute('transactionId', transaction.id)
|
|
147
153
|
span.addIntrinsicAttribute('sampled', transaction.sampled)
|
|
148
154
|
span.addIntrinsicAttribute('priority', transaction.priority)
|
|
@@ -156,7 +162,7 @@ class StreamingSpanEvent {
|
|
|
156
162
|
}
|
|
157
163
|
|
|
158
164
|
// Only set this if it will be `true`. Must be `null` otherwise.
|
|
159
|
-
if (
|
|
165
|
+
if (entryPoint) {
|
|
160
166
|
span.addIntrinsicAttribute('nr.entryPoint', true)
|
|
161
167
|
}
|
|
162
168
|
|
|
@@ -52,7 +52,7 @@ clmUtils.addCLMAttributes = function addCLMAttributes(fn, segment) {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
try {
|
|
55
|
-
const { funcInfo } = require('@
|
|
55
|
+
const { funcInfo } = require('@newrelic/fn-inspect')
|
|
56
56
|
const { lineNumber, method, file: filePath, column } = funcInfo(fn)
|
|
57
57
|
const fnName = setFunctionName(method)
|
|
58
58
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "newrelic",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.23.0",
|
|
4
4
|
"author": "New Relic Node.js agent team <nodejs@newrelic.com>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"contributors": [
|
|
@@ -223,8 +223,8 @@
|
|
|
223
223
|
"winston-transport": "^4.5.0"
|
|
224
224
|
},
|
|
225
225
|
"optionalDependencies": {
|
|
226
|
-
"@
|
|
227
|
-
"@newrelic/native-metrics": "^11.
|
|
226
|
+
"@newrelic/fn-inspect": "^4.4.0",
|
|
227
|
+
"@newrelic/native-metrics": "^11.1.0",
|
|
228
228
|
"@prisma/prisma-fmt-wasm": "^4.17.0-16.27eb2449f178cd9fe1a4b892d732cc4795f75085"
|
|
229
229
|
},
|
|
230
230
|
"devDependencies": {
|