newrelic 13.8.0 → 13.9.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 +124 -69
- package/THIRD_PARTY_NOTICES.md +7 -7
- package/lib/config/default.js +0 -13
- package/lib/health-reporter.js +6 -1
- package/lib/instrumentations.js +0 -1
- package/lib/metrics/names.js +39 -12
- package/lib/otel/traces/segment-synthesis.js +6 -30
- package/lib/otel/traces/span-processor.js +80 -18
- package/lib/samplers/adaptive-sampler.js +12 -6
- package/lib/samplers/index.js +37 -1
- package/lib/samplers/ratio-based-sampler.js +1 -2
- package/lib/samplers/sampler.js +4 -2
- package/lib/serverless/aws-lambda.js +18 -12
- package/lib/spans/helpers.js +1 -63
- package/lib/spans/span-event-aggregator.js +10 -13
- package/lib/spans/span-event.js +210 -61
- package/lib/spans/streaming-span-event-aggregator.js +4 -10
- package/lib/spans/streaming-span-event.js +4 -10
- package/lib/spans/timed-event.js +77 -0
- package/lib/subscriber-configs.js +2 -0
- package/lib/subscribers/base.js +9 -2
- package/lib/subscribers/ioredis/index.js +2 -2
- package/lib/subscribers/iovalkey/config.js +21 -0
- package/lib/subscribers/iovalkey/index.js +15 -0
- package/lib/subscribers/langchain/base.js +161 -0
- package/lib/subscribers/langchain/chain-callback-manager.js +14 -0
- package/lib/subscribers/langchain/config.js +163 -0
- package/lib/subscribers/langchain/runnable-stream.js +149 -0
- package/lib/subscribers/langchain/runnable.js +56 -0
- package/lib/subscribers/langchain/tool-callback-manager.js +24 -0
- package/lib/subscribers/langchain/tool.js +115 -0
- package/lib/subscribers/langchain/vectorstore.js +133 -0
- package/lib/subscribers/openai/base.js +1 -1
- package/lib/subscribers/openai/chat.js +8 -0
- package/lib/subscribers/openai/embeddings.js +8 -0
- package/lib/subscribers/undici/index.js +11 -14
- package/lib/symbols.js +2 -0
- package/lib/tracking-packages.js +9 -1
- package/lib/transaction/index.js +18 -2
- package/lib/transaction/trace/index.js +4 -79
- package/lib/transaction/trace/partial-trace.js +243 -0
- package/lib/transaction/trace/segment.js +18 -1
- package/package.json +2 -2
- package/lib/instrumentation/langchain/callback-manager.js +0 -25
- package/lib/instrumentation/langchain/common.js +0 -69
- package/lib/instrumentation/langchain/nr-hooks.js +0 -42
- package/lib/instrumentation/langchain/runnable.js +0 -310
- package/lib/instrumentation/langchain/tools.js +0 -78
- package/lib/instrumentation/langchain/vectorstore.js +0 -141
|
@@ -11,8 +11,17 @@ const urltils = require('#agentlib/util/urltils.js')
|
|
|
11
11
|
|
|
12
12
|
const AttributeReconciler = require('./attr-reconciler.js')
|
|
13
13
|
const SegmentSynthesizer = require('./segment-synthesis.js')
|
|
14
|
+
const SpanLink = require('#agentlib/spans/span-link.js')
|
|
15
|
+
const TimedEvent = require('#agentlib/spans/timed-event.js')
|
|
16
|
+
const normalizeTimestamp = require('../normalize-timestamp.js')
|
|
14
17
|
const { otelSynthesis } = require('#agentlib/symbols.js')
|
|
15
|
-
const {
|
|
18
|
+
const {
|
|
19
|
+
assignToTarget,
|
|
20
|
+
buildRuleMappings,
|
|
21
|
+
extractAttributeValue,
|
|
22
|
+
processRegex,
|
|
23
|
+
transformTemplate
|
|
24
|
+
} = require('./utils.js')
|
|
16
25
|
const defaultLogger = require('#agentlib/logger.js').child({ component: 'span-processor' })
|
|
17
26
|
|
|
18
27
|
const {
|
|
@@ -44,15 +53,30 @@ module.exports = class NrSpanProcessor {
|
|
|
44
53
|
}
|
|
45
54
|
|
|
46
55
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
56
|
+
* Finalize the mapping of the OTEL span to the NR `TraceSegment`
|
|
57
|
+
* by copying final attributes over, updating the duration, handling
|
|
58
|
+
* any errors, and ending the transaction if necessary.
|
|
59
|
+
*
|
|
60
|
+
* @param {object} span source otel span
|
|
50
61
|
*/
|
|
51
62
|
onEnd(span) {
|
|
52
63
|
if (span[otelSynthesis] && span[otelSynthesis].segment) {
|
|
53
64
|
const { segment, transaction, rule } = span[otelSynthesis]
|
|
54
65
|
const { instrumentationScope } = span
|
|
55
66
|
|
|
67
|
+
// OTEL spans have a status attribute. We copy this information over
|
|
68
|
+
// to our agent attributes as informational metadata.
|
|
69
|
+
let code
|
|
70
|
+
switch (span.status.code) {
|
|
71
|
+
case 0: { code = 'unset'; break }
|
|
72
|
+
case 1: { code = 'ok'; break }
|
|
73
|
+
case 2: { code = 'error'; break }
|
|
74
|
+
}
|
|
75
|
+
segment.addAttribute('status.code', code)
|
|
76
|
+
if (code === 'error') {
|
|
77
|
+
segment.addAttribute('status.description', span.status.message)
|
|
78
|
+
}
|
|
79
|
+
|
|
56
80
|
// We always attach the instrumentation scope data as agent attributes
|
|
57
81
|
// if the OTEL span has them set.
|
|
58
82
|
// See https://opentelemetry.io/docs/specs/otel/common/mapping-to-non-otlp/#instrumentationscope
|
|
@@ -67,8 +91,14 @@ module.exports = class NrSpanProcessor {
|
|
|
67
91
|
|
|
68
92
|
this.updateDuration(segment, span)
|
|
69
93
|
this.handleError({ segment, transaction, span })
|
|
94
|
+
this.reconcileLinks({ otelSpan: span, segment })
|
|
95
|
+
this.reconcileEvents({ segment, span })
|
|
70
96
|
this.reconcileAttributes({ segment, span, transaction, rule })
|
|
71
97
|
delete span[otelSynthesis]
|
|
98
|
+
|
|
99
|
+
if (span.kind === SpanKind.SERVER || span.kind === SpanKind.CONSUMER) {
|
|
100
|
+
this.finalizeTransaction({ segment, span, transaction, rule, config: this.agent.config })
|
|
101
|
+
}
|
|
72
102
|
}
|
|
73
103
|
}
|
|
74
104
|
|
|
@@ -106,20 +136,52 @@ module.exports = class NrSpanProcessor {
|
|
|
106
136
|
}
|
|
107
137
|
|
|
108
138
|
/**
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
* @param {object} params
|
|
114
|
-
* @param {object} params.span
|
|
115
|
-
* @param {object} params.
|
|
116
|
-
* @param {object} params.rule - The transformation rule to use.
|
|
139
|
+
* Iterates the span events that have been added to the span and attaches
|
|
140
|
+
* them to the `TraceSegment` in the format expected by the New Relic
|
|
141
|
+
* collector.
|
|
142
|
+
*
|
|
143
|
+
* @param {object} params Function parameters
|
|
144
|
+
* @param {object} params.span The OTEL span that may contain events.
|
|
145
|
+
* @param {object} params.segment The target segment to attach the events to.
|
|
117
146
|
*/
|
|
118
|
-
|
|
119
|
-
|
|
147
|
+
reconcileEvents({ segment, span }) {
|
|
148
|
+
if (span.events.length < 1) {
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const spanContext = span.spanContext()
|
|
153
|
+
for (let i = 0; i < span.events.length; i++) {
|
|
154
|
+
const event = new TimedEvent({
|
|
155
|
+
event: span.events[i],
|
|
156
|
+
spanContext
|
|
157
|
+
})
|
|
158
|
+
segment.addTimedEvent(event)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Iterates the span links that have been added to the span and attaches
|
|
164
|
+
* them to the `TraceSegment` in the format expected by the New Relic
|
|
165
|
+
* collector.
|
|
166
|
+
*
|
|
167
|
+
* @param {object} params Function parameters
|
|
168
|
+
* @param {object} params.otelSpan The OTEL span that may contain links.
|
|
169
|
+
* @param {object} params.segment The target segment to attach the links to.
|
|
170
|
+
*/
|
|
171
|
+
reconcileLinks({ otelSpan, segment }) {
|
|
172
|
+
if (otelSpan.links.length < 1) {
|
|
173
|
+
return
|
|
174
|
+
}
|
|
120
175
|
|
|
121
|
-
|
|
122
|
-
|
|
176
|
+
const spanContext = otelSpan.spanContext()
|
|
177
|
+
const timestamp = normalizeTimestamp(otelSpan.startTime)
|
|
178
|
+
for (let i = 0; i < otelSpan.links.length; i += 1) {
|
|
179
|
+
const link = new SpanLink({
|
|
180
|
+
link: otelSpan.links.at(i),
|
|
181
|
+
spanContext,
|
|
182
|
+
timestamp
|
|
183
|
+
})
|
|
184
|
+
segment.addSpanLink(link)
|
|
123
185
|
}
|
|
124
186
|
}
|
|
125
187
|
|
|
@@ -130,9 +192,9 @@ module.exports = class NrSpanProcessor {
|
|
|
130
192
|
* @param {object} params.segment - The segment to add attributes to.
|
|
131
193
|
* @param {object} params.span - The span to add attributes from.
|
|
132
194
|
* @param {object} params.transaction - The transaction to add attributes to.
|
|
133
|
-
* @param {object} params.rule - The transformation rule to use.
|
|
195
|
+
* @param {object} [params.rule] - The transformation rule to use.
|
|
134
196
|
*/
|
|
135
|
-
|
|
197
|
+
reconcileAttributes({ segment, span, transaction, rule = {} }) {
|
|
136
198
|
const excludeAttributes = new Set()
|
|
137
199
|
for (const attribute of rule.attributes) {
|
|
138
200
|
const { key, target, name, highSecurity, regex } = attribute
|
|
@@ -108,19 +108,25 @@ class AdaptiveSampler extends Sampler {
|
|
|
108
108
|
applySamplingDecision({ transaction, tracestate, partialType }) {
|
|
109
109
|
if (!transaction) return
|
|
110
110
|
transaction.partialType = partialType
|
|
111
|
-
if (tracestate) {
|
|
111
|
+
if (tracestate?.intrinsics) {
|
|
112
112
|
// Explicitly set sampled and priority from tracestate intrinsics if available
|
|
113
|
-
transaction.sampled = tracestate
|
|
114
|
-
|
|
113
|
+
transaction.sampled = tracestate.isSampled
|
|
114
|
+
let initPriority = tracestate.priority
|
|
115
|
+
// If tracestate has intrinsics but lacks a priority we must generate a random priority
|
|
116
|
+
// if sampled, we also have to increment accordingly based on full/partial traces
|
|
117
|
+
if (!initPriority && tracestate.isSampled) {
|
|
118
|
+
initPriority = Sampler.generatePriority()
|
|
119
|
+
initPriority = Sampler.incrementPriority(initPriority, partialType)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
transaction.priority = initPriority
|
|
115
123
|
return
|
|
116
124
|
}
|
|
117
125
|
|
|
118
126
|
// If a tracestate is not defined, then do our normal priority calculation.
|
|
119
|
-
|
|
120
127
|
const initPriority = Sampler.generatePriority()
|
|
121
128
|
transaction.sampled = this.shouldSample(initPriority)
|
|
122
|
-
|
|
123
|
-
transaction.priority = transaction.sampled && !partialType ? Sampler.incrementPriority(initPriority, 1) : initPriority
|
|
129
|
+
transaction.priority = transaction.sampled ? Sampler.incrementPriority(initPriority, partialType) : initPriority
|
|
124
130
|
}
|
|
125
131
|
|
|
126
132
|
/**
|
package/lib/samplers/index.js
CHANGED
|
@@ -11,6 +11,7 @@ const AlwaysOnSampler = require('./always-on-sampler')
|
|
|
11
11
|
const TraceIdRatioBasedSampler = require('./ratio-based-sampler')
|
|
12
12
|
const logger = require('../logger').child({ component: 'samplers' })
|
|
13
13
|
const { PARTIAL_TYPES } = require('../transaction')
|
|
14
|
+
const { SAMPLERS } = require('#agentlib/metrics/names.js')
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Manages the different samplers used for distributed tracing sampling decisions.
|
|
@@ -19,7 +20,8 @@ const { PARTIAL_TYPES } = require('../transaction')
|
|
|
19
20
|
* @typedef {object} Samplers
|
|
20
21
|
* @property {boolean} fullEnabled Whether full granularity sampling is enabled.
|
|
21
22
|
* @property {boolean} partialEnabled Whether partial granularity sampling is enabled.
|
|
22
|
-
* @property {AdaptiveSampler|null} adaptiveSampler The global adaptive sampler instance
|
|
23
|
+
* @property {AdaptiveSampler|null} adaptiveSampler The global adaptive sampler instance;
|
|
24
|
+
* this is shared if `sampling_target` is not defined for a sampler type of `adaptive`.
|
|
23
25
|
* @property {Sampler} root The root sampler for traces originating in application.
|
|
24
26
|
* @property {Sampler} remoteParentSampled The sampler for traces with a remote parent that is sampled.
|
|
25
27
|
* @property {Sampler} remoteParentNotSampled The sampler for traces with a remote parent that is not sampled.
|
|
@@ -39,6 +41,40 @@ class Samplers {
|
|
|
39
41
|
this.partialRoot = this.determineSampler({ agent, sampler: 'root', isPartial: true })
|
|
40
42
|
this.partialRemoteParentSampled = this.determineSampler({ agent, sampler: 'remote_parent_sampled', isPartial: true })
|
|
41
43
|
this.partialRemoteParentNotSampled = this.determineSampler({ agent, sampler: 'remote_parent_not_sampled', isPartial: true })
|
|
44
|
+
this.#sendCoreTracingMetrics(agent)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Sends relevant Core Tracing metrics on startup in the form:
|
|
49
|
+
* `Supportability/Nodejs/<granularity type>/<sampler section>/<sampler type>`
|
|
50
|
+
* @param {Agent} agent agent instance with these `Samplers`
|
|
51
|
+
*/
|
|
52
|
+
#sendCoreTracingMetrics(agent) {
|
|
53
|
+
const metrics = agent.metrics
|
|
54
|
+
if (this.partialEnabled) {
|
|
55
|
+
// Supportability/Nodejs/PartialGranularity/<sampler section>/<sampler type>
|
|
56
|
+
metrics.getOrCreateMetric(`${SAMPLERS.PARTIAL.ROOT}/${this.#determineSamplerType(this.partialRoot)}`)
|
|
57
|
+
metrics.getOrCreateMetric(`${SAMPLERS.PARTIAL.PARENT_SAMPLED}/${this.#determineSamplerType(this.partialRemoteParentSampled)}`)
|
|
58
|
+
metrics.getOrCreateMetric(`${SAMPLERS.PARTIAL.PARENT_NOT_SAMPLED}/${this.#determineSamplerType(this.partialRemoteParentNotSampled)}`)
|
|
59
|
+
}
|
|
60
|
+
if (this.fullEnabled) {
|
|
61
|
+
// Supportability/Nodejs/PartialGranularity/<sampler section>/<sampler type>
|
|
62
|
+
metrics.getOrCreateMetric(`${SAMPLERS.FULL.ROOT}/${this.#determineSamplerType(this.root)}`)
|
|
63
|
+
metrics.getOrCreateMetric(`${SAMPLERS.FULL.PARENT_SAMPLED}/${this.#determineSamplerType(this.remoteParentSampled)}`)
|
|
64
|
+
metrics.getOrCreateMetric(`${SAMPLERS.FULL.PARENT_NOT_SAMPLED}/${this.#determineSamplerType(this.remoteParentNotSampled)}`)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
*
|
|
70
|
+
* @param {Sampler} sampler an instance of a Sampler
|
|
71
|
+
* @returns {string} 'Adaptive/Shared', 'Adaptive', 'AlwaysOn', 'AlwaysOff', or 'TraceIdRatioBased'
|
|
72
|
+
*/
|
|
73
|
+
#determineSamplerType(sampler) {
|
|
74
|
+
if (sampler === this.adaptiveSampler) {
|
|
75
|
+
return 'Adaptive/Shared'
|
|
76
|
+
}
|
|
77
|
+
return sampler.toString().replace('Sampler', '')
|
|
42
78
|
}
|
|
43
79
|
|
|
44
80
|
/**
|
|
@@ -26,8 +26,7 @@ class TraceIdRatioBasedSampler extends Sampler {
|
|
|
26
26
|
transaction.partialType = partialType
|
|
27
27
|
const initPriority = Sampler.generatePriority()
|
|
28
28
|
transaction.sampled = this.shouldSample(transaction.traceId)
|
|
29
|
-
|
|
30
|
-
transaction.priority = transaction.sampled && !partialType ? Sampler.incrementPriority(initPriority, 1) : initPriority
|
|
29
|
+
transaction.priority = transaction.sampled ? Sampler.incrementPriority(initPriority, partialType) : initPriority
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
/**
|
package/lib/samplers/sampler.js
CHANGED
|
@@ -45,11 +45,13 @@ class Sampler {
|
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
47
|
* Used to increment priority and truncate to 6 decimal places.
|
|
48
|
+
* Full traces are incremented by 2 and partial traces are incremented by 1
|
|
48
49
|
* @param {number} priority the current priority
|
|
49
|
-
* @param {
|
|
50
|
+
* @param {string|null} partialType if a partial trace
|
|
50
51
|
* @returns {number} the incremented priority
|
|
51
52
|
*/
|
|
52
|
-
static incrementPriority(priority,
|
|
53
|
+
static incrementPriority(priority, partialType) {
|
|
54
|
+
const increment = partialType ? 1 : 2
|
|
53
55
|
const newPriority = priority + increment
|
|
54
56
|
return ((newPriority * 1e6) | 0) / 1e6
|
|
55
57
|
}
|
|
@@ -200,14 +200,13 @@ class AwsLambda {
|
|
|
200
200
|
return handler.apply(this, args)
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
-
const event = args
|
|
204
|
-
const context = args[2]
|
|
203
|
+
const [event, responseStream, context] = args
|
|
205
204
|
logger.trace('In stream handler, lambda function name', context?.functionName)
|
|
206
205
|
const { segment, txnEnder } = awsLambda.createSegment({ context, event, transaction, recorder: recordBackground })
|
|
207
206
|
args[1] = awsLambda.wrapStreamAndCaptureError(
|
|
208
207
|
transaction,
|
|
209
208
|
txnEnder,
|
|
210
|
-
|
|
209
|
+
responseStream
|
|
211
210
|
)
|
|
212
211
|
|
|
213
212
|
let res
|
|
@@ -238,8 +237,7 @@ class AwsLambda {
|
|
|
238
237
|
return handler.apply(this, args)
|
|
239
238
|
}
|
|
240
239
|
|
|
241
|
-
const event = args
|
|
242
|
-
const context = args[1]
|
|
240
|
+
const [event, context, callback] = args
|
|
243
241
|
logger.trace('Lambda function name', context?.functionName)
|
|
244
242
|
const isApiGatewayLambdaProxy = apiGateway.isLambdaProxyEvent(event)
|
|
245
243
|
logger.trace('Is this Lambda event an API Gateway or ALB web proxy?', isApiGatewayLambdaProxy)
|
|
@@ -256,16 +254,24 @@ class AwsLambda {
|
|
|
256
254
|
setWebRequest(transaction, webRequest)
|
|
257
255
|
resultProcessor = getApiGatewayLambdaProxyResultProcessor(transaction)
|
|
258
256
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
args[cbIndex]
|
|
264
|
-
|
|
265
|
-
|
|
257
|
+
|
|
258
|
+
if (typeof callback === 'function') {
|
|
259
|
+
logger.trace('Wrapping Lambda handler callback')
|
|
260
|
+
const cbIndex = args.length - 1
|
|
261
|
+
args[cbIndex] = awsLambda.wrapCallbackAndCaptureError(
|
|
262
|
+
transaction,
|
|
263
|
+
txnEnder,
|
|
264
|
+
callback,
|
|
265
|
+
resultProcessor
|
|
266
|
+
)
|
|
267
|
+
} else {
|
|
268
|
+
logger.trace('Lambda handler callback not present, skip wrapping')
|
|
269
|
+
}
|
|
266
270
|
|
|
267
271
|
// context.{done,fail,succeed} are all considered deprecated by
|
|
268
272
|
// AWS, but are considered functional.
|
|
273
|
+
// TODO: Remove when we drop Node.js 22
|
|
274
|
+
// see: https://aws.amazon.com/blogs/compute/node-js-24-runtime-now-available-in-aws-lambda/
|
|
269
275
|
context.done = awsLambda.wrapCallbackAndCaptureError(transaction, txnEnder, context.done)
|
|
270
276
|
context.fail = awsLambda.wrapCallbackAndCaptureError(transaction, txnEnder, context.fail)
|
|
271
277
|
shim.wrap(context, 'succeed', function wrapSucceed(shim, original) {
|
package/lib/spans/helpers.js
CHANGED
|
@@ -60,72 +60,10 @@ 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
|
-
|
|
122
63
|
module.exports = {
|
|
123
64
|
HTTP_LIBRARY,
|
|
124
65
|
CATEGORIES,
|
|
125
66
|
SPAN_KIND,
|
|
126
67
|
REGEXS,
|
|
127
|
-
addSpanKind
|
|
128
|
-
isEntryPointSpan,
|
|
129
|
-
reparentSpan,
|
|
130
|
-
shouldCreateSpan
|
|
68
|
+
addSpanKind
|
|
131
69
|
}
|
|
@@ -21,7 +21,6 @@ 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
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
_toPayloadSync() {
|
|
@@ -45,6 +44,11 @@ class SpanEventAggregator extends EventAggregator {
|
|
|
45
44
|
Array.prototype.push.apply(eventsPayload, event.spanLinks)
|
|
46
45
|
delete event.spanLinks
|
|
47
46
|
}
|
|
47
|
+
|
|
48
|
+
if (event.timedEvents.length > 0) {
|
|
49
|
+
Array.prototype.push.apply(eventsPayload, event.timedEvents)
|
|
50
|
+
delete event.timedEvents
|
|
51
|
+
}
|
|
48
52
|
}
|
|
49
53
|
|
|
50
54
|
return [this.runId, metrics, eventsPayload]
|
|
@@ -80,8 +84,9 @@ class SpanEventAggregator extends EventAggregator {
|
|
|
80
84
|
* @param {Transaction} params.transaction active transaction
|
|
81
85
|
* @param {string} [params.parentId] GUID of the parent span.
|
|
82
86
|
* @param {boolean} params.isRoot if segment is root segment
|
|
87
|
+
* @param {boolean} params.isEntry if segment is entry point
|
|
83
88
|
*/
|
|
84
|
-
addSegment({ segment, transaction, parentId, isRoot }) {
|
|
89
|
+
addSegment({ segment, transaction, parentId, isRoot, isEntry }) {
|
|
85
90
|
// Check if the priority would be accepted before creating the event object.
|
|
86
91
|
|
|
87
92
|
if (transaction.priority < this._items.getMinimumPriority()) {
|
|
@@ -91,19 +96,11 @@ class SpanEventAggregator extends EventAggregator {
|
|
|
91
96
|
return false
|
|
92
97
|
}
|
|
93
98
|
|
|
94
|
-
const span = SpanEvent.fromSegment({ segment, transaction, parentId, isRoot,
|
|
99
|
+
const span = SpanEvent.fromSegment({ segment, transaction, parentId, isRoot, isEntry })
|
|
95
100
|
|
|
96
101
|
// Do not add span to aggregator if it is part of a partial trace
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if (transaction.partialType) {
|
|
100
|
-
const prefix = `${this._metricNames.PARTIAL_PREFIX}/${transaction.partialType}`
|
|
101
|
-
this._metrics.getOrCreateMetric(prefix).incrementCallCount()
|
|
102
|
-
this._metrics.getOrCreateMetric(`${prefix}${this._metricNames.INSTRUMENTED}`).incrementCallCount()
|
|
103
|
-
transaction.trace.addSpan({ span, id: segment.id, parentId })
|
|
104
|
-
if (span) {
|
|
105
|
-
this._metrics.getOrCreateMetric(`${prefix}${this._metricNames.KEPT}`).incrementCallCount()
|
|
106
|
-
}
|
|
102
|
+
if (transaction.partialTrace) {
|
|
103
|
+
transaction.partialTrace.addSpan({ span, isEntry })
|
|
107
104
|
} else if (span) {
|
|
108
105
|
this.add(span, transaction.priority)
|
|
109
106
|
}
|