Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
1 line
12 KiB
Plaintext
1 line
12 KiB
Plaintext
{"version":3,"file":"utils.js","sources":["../../../src/metrics/utils.ts"],"sourcesContent":["import type {\n Client,\n Integration,\n SentrySpan,\n Span,\n SpanAttributes,\n SpanTimeInput,\n StartSpanOptions,\n} from '@sentry/core';\nimport { getClient, getCurrentScope, spanToJSON, startInactiveSpan, withActiveSpan } from '@sentry/core';\nimport { WINDOW } from '../types';\nimport { onHidden } from './web-vitals/lib/onHidden';\n\nexport type WebVitalReportEvent = 'pagehide' | 'navigation';\n\n/**\n * Checks if a given value is a valid measurement value.\n */\nexport function isMeasurementValue(value: unknown): value is number {\n return typeof value === 'number' && isFinite(value);\n}\n\n/**\n * Helper function to start child on transactions. This function will make sure that the transaction will\n * use the start timestamp of the created child span if it is earlier than the transactions actual\n * start timestamp.\n */\nexport function startAndEndSpan(\n parentSpan: Span,\n startTimeInSeconds: number,\n endTime: SpanTimeInput,\n { ...ctx }: StartSpanOptions,\n): Span | undefined {\n const parentStartTime = spanToJSON(parentSpan).start_timestamp;\n if (parentStartTime && parentStartTime > startTimeInSeconds) {\n // We can only do this for SentrySpans...\n if (typeof (parentSpan as Partial<SentrySpan>).updateStartTime === 'function') {\n (parentSpan as SentrySpan).updateStartTime(startTimeInSeconds);\n }\n }\n\n // The return value only exists for tests\n return withActiveSpan(parentSpan, () => {\n const span = startInactiveSpan({\n startTime: startTimeInSeconds,\n ...ctx,\n });\n\n if (span) {\n span.end(endTime);\n }\n\n return span;\n });\n}\n\ninterface StandaloneWebVitalSpanOptions {\n name: string;\n transaction?: string;\n attributes: SpanAttributes;\n startTime: number;\n}\n\n/**\n * Starts an inactive, standalone span used to send web vital values to Sentry.\n * DO NOT use this for arbitrary spans, as these spans require special handling\n * during ingestion to extract metrics.\n *\n * This function adds a bunch of attributes and data to the span that's shared\n * by all web vital standalone spans. However, you need to take care of adding\n * the actual web vital value as an event to the span. Also, you need to assign\n * a transaction name and some other values that are specific to the web vital.\n *\n * Ultimately, you also need to take care of ending the span to send it off.\n *\n * @param options\n *\n * @returns an inactive, standalone and NOT YET ended span\n */\nexport function startStandaloneWebVitalSpan(options: StandaloneWebVitalSpanOptions): Span | undefined {\n const client = getClient();\n if (!client) {\n return;\n }\n\n const { name, transaction, attributes: passedAttributes, startTime } = options;\n\n const { release, environment, sendDefaultPii } = client.getOptions();\n // We need to get the replay, user, and activeTransaction from the current scope\n // so that we can associate replay id, profile id, and a user display to the span\n const replay = client.getIntegrationByName<Integration & { getReplayId: () => string }>('Replay');\n const replayId = replay?.getReplayId();\n\n const scope = getCurrentScope();\n\n const user = scope.getUser();\n const userDisplay = user !== undefined ? user.email || user.id || user.ip_address : undefined;\n\n let profileId: string | undefined;\n try {\n // @ts-expect-error skip optional chaining to save bundle size with try catch\n profileId = scope.getScopeData().contexts.profile.profile_id;\n } catch {\n // do nothing\n }\n\n const attributes: SpanAttributes = {\n release,\n environment,\n\n user: userDisplay || undefined,\n profile_id: profileId || undefined,\n replay_id: replayId || undefined,\n\n transaction,\n\n // Web vital score calculation relies on the user agent to account for different\n // browsers setting different thresholds for what is considered a good/meh/bad value.\n // For example: Chrome vs. Chrome Mobile\n 'user_agent.original': WINDOW.navigator?.userAgent,\n\n // This tells Sentry to infer the IP address from the request\n 'client.address': sendDefaultPii ? '{{auto}}' : undefined,\n\n ...passedAttributes,\n };\n\n return startInactiveSpan({\n name,\n attributes,\n startTime,\n experimental: {\n standalone: true,\n },\n });\n}\n\n/** Get the browser performance API. */\nexport function getBrowserPerformanceAPI(): Performance | undefined {\n // @ts-expect-error we want to make sure all of these are available, even if TS is sure they are\n return WINDOW.addEventListener && WINDOW.performance;\n}\n\n/**\n * Converts from milliseconds to seconds\n * @param time time in ms\n */\nexport function msToSec(time: number): number {\n return time / 1000;\n}\n\n/**\n * Converts ALPN protocol ids to name and version.\n *\n * (https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids)\n * @param nextHopProtocol PerformanceResourceTiming.nextHopProtocol\n */\nexport function extractNetworkProtocol(nextHopProtocol: string): { name: string; version: string } {\n let name = 'unknown';\n let version = 'unknown';\n let _name = '';\n for (const char of nextHopProtocol) {\n // http/1.1 etc.\n if (char === '/') {\n [name, version] = nextHopProtocol.split('/') as [string, string];\n break;\n }\n // h2, h3 etc.\n if (!isNaN(Number(char))) {\n name = _name === 'h' ? 'http' : _name;\n version = nextHopProtocol.split(_name)[1] as string;\n break;\n }\n _name += char;\n }\n if (_name === nextHopProtocol) {\n // webrtc, ftp, etc.\n name = _name;\n }\n return { name, version };\n}\n\n/**\n * Generic support check for web vitals\n */\nexport function supportsWebVital(entryType: 'layout-shift' | 'largest-contentful-paint'): boolean {\n try {\n return PerformanceObserver.supportedEntryTypes.includes(entryType);\n } catch {\n return false;\n }\n}\n\n/**\n * Listens for events on which we want to collect a previously accumulated web vital value.\n * Currently, this includes:\n *\n * - pagehide (i.e. user minimizes browser window, hides tab, etc)\n * - soft navigation (we only care about the vital of the initially loaded route)\n *\n * As a \"side-effect\", this function will also collect the span id of the pageload span.\n *\n * @param collectorCallback the callback to be called when the first of these events is triggered. Parameters:\n * - event: the event that triggered the reporting of the web vital value.\n * - pageloadSpanId: the span id of the pageload span. This is used to link the web vital span to the pageload span.\n */\nexport function listenForWebVitalReportEvents(\n client: Client,\n collectorCallback: (event: WebVitalReportEvent, pageloadSpanId: string) => void,\n) {\n let pageloadSpanId: string | undefined;\n\n let collected = false;\n function _runCollectorCallbackOnce(event: WebVitalReportEvent) {\n if (!collected && pageloadSpanId) {\n collectorCallback(event, pageloadSpanId);\n }\n collected = true;\n }\n\n // eslint-disable-next-line deprecation/deprecation\n onHidden(() => {\n _runCollectorCallbackOnce('pagehide');\n });\n\n const unsubscribeStartNavigation = client.on('beforeStartNavigationSpan', (_, options) => {\n // we only want to collect LCP if we actually navigate. Redirects should be ignored.\n if (!options?.isRedirect) {\n _runCollectorCallbackOnce('navigation');\n unsubscribeStartNavigation();\n unsubscribeAfterStartPageLoadSpan();\n }\n });\n\n const unsubscribeAfterStartPageLoadSpan = client.on('afterStartPageLoadSpan', span => {\n pageloadSpanId = span.spanContext().spanId;\n unsubscribeAfterStartPageLoadSpan();\n });\n}\n"],"names":[],"mappings":"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"} |