|
1 | 1 | /* eslint-disable max-lines */
|
2 | 2 | import type { IdleTransaction, Transaction } from '@sentry/core';
|
3 |
| -import { Span, getActiveTransaction, getClient, setMeasurement } from '@sentry/core'; |
4 |
| -import type { Measurements, SpanContext } from '@sentry/types'; |
| 3 | +import { |
| 4 | + Span, |
| 5 | + getActiveTransaction, |
| 6 | + getClient, |
| 7 | + hasTracingEnabled, |
| 8 | + isValidSampleRate, |
| 9 | + setMeasurement, |
| 10 | +} from '@sentry/core'; |
| 11 | +import type { ClientOptions, Measurements, SpanContext, TransactionContext } from '@sentry/types'; |
5 | 12 | import { browserPerformanceTimeOrigin, getComponentName, htmlTreeAsString, logger, parseUrl } from '@sentry/utils';
|
6 | 13 |
|
7 | 14 | import { spanToJSON } from '@sentry/core';
|
@@ -202,33 +209,57 @@ function _trackINP(interactionIdtoRouteNameMapping: InteractionRouteNameMapping)
|
202 | 209 | if (!entry || !client) {
|
203 | 210 | return;
|
204 | 211 | }
|
205 |
| - const { release, environment } = client.getOptions(); |
| 212 | + const options = client.getOptions(); |
206 | 213 | /** Build the INP span, create an envelope from the span, and then send the envelope */
|
207 | 214 | const startTime = msToSec((browserPerformanceTimeOrigin as number) + entry.startTime);
|
208 | 215 | const duration = msToSec(metric.value);
|
209 |
| - const routeName = |
210 |
| - entry.interactionId !== undefined ? interactionIdtoRouteNameMapping[entry.interactionId].routeName : undefined; |
| 216 | + const { routeName, parentContext, activeTransaction, user, replayId } = |
| 217 | + entry.interactionId !== undefined |
| 218 | + ? interactionIdtoRouteNameMapping[entry.interactionId] |
| 219 | + : { |
| 220 | + routeName: undefined, |
| 221 | + parentContext: undefined, |
| 222 | + activeTransaction: undefined, |
| 223 | + user: undefined, |
| 224 | + replayId: undefined, |
| 225 | + }; |
| 226 | + const userDisplay = user !== undefined ? user.email || user.id || user.ip_address : undefined; |
| 227 | + // eslint-disable-next-line deprecation/deprecation |
| 228 | + const profileId = activeTransaction !== undefined ? activeTransaction.getProfileId() : undefined; |
211 | 229 | const span = new Span({
|
212 | 230 | startTimestamp: startTime,
|
213 | 231 | endTimestamp: startTime + duration,
|
214 | 232 | op: 'ui.interaction.click',
|
215 | 233 | name: htmlTreeAsString(entry.target),
|
216 | 234 | attributes: {
|
217 |
| - release, |
218 |
| - environment, |
| 235 | + release: options.release, |
| 236 | + environment: options.environment, |
219 | 237 | transaction: routeName,
|
| 238 | + ...(userDisplay !== undefined && userDisplay !== '' ? { user: userDisplay } : {}), |
| 239 | + ...(profileId !== undefined ? { profile_id: profileId } : {}), |
| 240 | + ...(replayId !== undefined ? { replay_id: replayId } : {}), |
220 | 241 | },
|
221 | 242 | exclusiveTime: metric.value,
|
222 | 243 | measurements: {
|
223 | 244 | inp: { value: metric.value, unit: 'millisecond' },
|
224 | 245 | },
|
225 | 246 | });
|
226 |
| - const envelope = span ? createSpanEnvelope([span]) : undefined; |
227 |
| - const transport = client && client.getTransport(); |
228 |
| - if (transport && envelope) { |
229 |
| - transport.send(envelope).then(null, reason => { |
230 |
| - DEBUG_BUILD && logger.error('Error while sending interaction:', reason); |
231 |
| - }); |
| 247 | + |
| 248 | + /** Check to see if the span should be sampled */ |
| 249 | + const sampleRate = getSampleRate(parentContext, options); |
| 250 | + if (!sampleRate) { |
| 251 | + return; |
| 252 | + } |
| 253 | + |
| 254 | + if (Math.random() < (sampleRate as number | boolean)) { |
| 255 | + const envelope = span ? createSpanEnvelope([span]) : undefined; |
| 256 | + const transport = client && client.getTransport(); |
| 257 | + if (transport && envelope) { |
| 258 | + transport.send(envelope).then(null, reason => { |
| 259 | + DEBUG_BUILD && logger.error('Error while sending interaction:', reason); |
| 260 | + }); |
| 261 | + } |
| 262 | + return; |
232 | 263 | }
|
233 | 264 | });
|
234 | 265 | }
|
@@ -631,3 +662,35 @@ export function _addTtfbToMeasurements(
|
631 | 662 | }
|
632 | 663 | }
|
633 | 664 | }
|
| 665 | + |
| 666 | +/** Taken from @sentry/core sampling.ts */ |
| 667 | +function getSampleRate(transactionContext: TransactionContext | undefined, options: ClientOptions): number | boolean { |
| 668 | + if (!hasTracingEnabled(options)) { |
| 669 | + return false; |
| 670 | + } |
| 671 | + let sampleRate; |
| 672 | + if (transactionContext !== undefined && typeof options.tracesSampler === 'function') { |
| 673 | + sampleRate = options.tracesSampler({ |
| 674 | + transactionContext, |
| 675 | + name: transactionContext.name, |
| 676 | + parentSampled: transactionContext.parentSampled, |
| 677 | + attributes: { |
| 678 | + // eslint-disable-next-line deprecation/deprecation |
| 679 | + ...transactionContext.data, |
| 680 | + ...transactionContext.attributes, |
| 681 | + }, |
| 682 | + location: WINDOW.location, |
| 683 | + }); |
| 684 | + } else if (transactionContext !== undefined && transactionContext.sampled !== undefined) { |
| 685 | + sampleRate = transactionContext.sampled; |
| 686 | + } else if (typeof options.tracesSampleRate !== 'undefined') { |
| 687 | + sampleRate = options.tracesSampleRate; |
| 688 | + } else { |
| 689 | + sampleRate = 1; |
| 690 | + } |
| 691 | + if (!isValidSampleRate(sampleRate)) { |
| 692 | + DEBUG_BUILD && logger.warn('[Tracing] Discarding transaction because of invalid sample rate.'); |
| 693 | + return false; |
| 694 | + } |
| 695 | + return sampleRate; |
| 696 | +} |
0 commit comments