|
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