@sentry/browser 10.55.0 → 10.57.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/build/npm/cjs/dev/client.js +6 -10
- package/build/npm/cjs/dev/client.js.map +1 -1
- package/build/npm/cjs/dev/index.js +2 -0
- package/build/npm/cjs/dev/index.js.map +1 -1
- package/build/npm/cjs/dev/integrations/contextlines.js +2 -2
- package/build/npm/cjs/dev/integrations/contextlines.js.map +1 -1
- package/build/npm/cjs/dev/integrations/httpclient.js +45 -30
- package/build/npm/cjs/dev/integrations/httpclient.js.map +1 -1
- package/build/npm/cjs/dev/integrations/webVitals.js +62 -0
- package/build/npm/cjs/dev/integrations/webVitals.js.map +1 -0
- package/build/npm/cjs/dev/tracing/browserTracingIntegration.js +13 -24
- package/build/npm/cjs/dev/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/cjs/dev/tracing/linkedTraces.js +4 -1
- package/build/npm/cjs/dev/tracing/linkedTraces.js.map +1 -1
- package/build/npm/cjs/prod/client.js +6 -10
- package/build/npm/cjs/prod/client.js.map +1 -1
- package/build/npm/cjs/prod/index.js +2 -0
- package/build/npm/cjs/prod/index.js.map +1 -1
- package/build/npm/cjs/prod/integrations/contextlines.js +2 -2
- package/build/npm/cjs/prod/integrations/contextlines.js.map +1 -1
- package/build/npm/cjs/prod/integrations/httpclient.js +45 -30
- package/build/npm/cjs/prod/integrations/httpclient.js.map +1 -1
- package/build/npm/cjs/prod/integrations/webVitals.js +62 -0
- package/build/npm/cjs/prod/integrations/webVitals.js.map +1 -0
- package/build/npm/cjs/prod/tracing/browserTracingIntegration.js +13 -24
- package/build/npm/cjs/prod/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/cjs/prod/tracing/linkedTraces.js +4 -1
- package/build/npm/cjs/prod/tracing/linkedTraces.js.map +1 -1
- package/build/npm/esm/dev/client.js +6 -10
- package/build/npm/esm/dev/client.js.map +1 -1
- package/build/npm/esm/dev/index.js +1 -0
- package/build/npm/esm/dev/index.js.map +1 -1
- package/build/npm/esm/dev/integrations/contextlines.js +2 -2
- package/build/npm/esm/dev/integrations/contextlines.js.map +1 -1
- package/build/npm/esm/dev/integrations/httpclient.js +46 -31
- package/build/npm/esm/dev/integrations/httpclient.js.map +1 -1
- package/build/npm/esm/dev/integrations/webVitals.js +59 -0
- package/build/npm/esm/dev/integrations/webVitals.js.map +1 -0
- package/build/npm/esm/dev/package.json +1 -1
- package/build/npm/esm/dev/tracing/browserTracingIntegration.js +15 -26
- package/build/npm/esm/dev/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/esm/dev/tracing/linkedTraces.js +4 -1
- package/build/npm/esm/dev/tracing/linkedTraces.js.map +1 -1
- package/build/npm/esm/prod/client.js +6 -10
- package/build/npm/esm/prod/client.js.map +1 -1
- package/build/npm/esm/prod/index.js +1 -0
- package/build/npm/esm/prod/index.js.map +1 -1
- package/build/npm/esm/prod/integrations/contextlines.js +2 -2
- package/build/npm/esm/prod/integrations/contextlines.js.map +1 -1
- package/build/npm/esm/prod/integrations/httpclient.js +46 -31
- package/build/npm/esm/prod/integrations/httpclient.js.map +1 -1
- package/build/npm/esm/prod/integrations/webVitals.js +59 -0
- package/build/npm/esm/prod/integrations/webVitals.js.map +1 -0
- package/build/npm/esm/prod/package.json +1 -1
- package/build/npm/esm/prod/tracing/browserTracingIntegration.js +15 -26
- package/build/npm/esm/prod/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/esm/prod/tracing/linkedTraces.js +4 -1
- package/build/npm/esm/prod/tracing/linkedTraces.js.map +1 -1
- package/build/npm/types/client.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.d.ts +1 -0
- package/build/npm/types/index.bundle.tracing.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.logs.metrics.d.ts +1 -0
- package/build/npm/types/index.bundle.tracing.logs.metrics.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.replay.d.ts +1 -0
- package/build/npm/types/index.bundle.tracing.replay.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.replay.feedback.d.ts +1 -0
- package/build/npm/types/index.bundle.tracing.replay.feedback.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.replay.feedback.logs.metrics.d.ts +1 -0
- package/build/npm/types/index.bundle.tracing.replay.feedback.logs.metrics.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.replay.logs.metrics.d.ts +1 -0
- package/build/npm/types/index.bundle.tracing.replay.logs.metrics.d.ts.map +1 -1
- package/build/npm/types/index.d.ts +1 -0
- package/build/npm/types/index.d.ts.map +1 -1
- package/build/npm/types/integrations/contextlines.d.ts +2 -0
- package/build/npm/types/integrations/contextlines.d.ts.map +1 -1
- package/build/npm/types/integrations/httpclient.d.ts.map +1 -1
- package/build/npm/types/integrations/webVitals.d.ts +24 -0
- package/build/npm/types/integrations/webVitals.d.ts.map +1 -0
- package/build/npm/types/tracing/browserTracingIntegration.d.ts.map +1 -1
- package/build/npm/types/tracing/linkedTraces.d.ts.map +1 -1
- package/build/npm/types-ts3.8/index.bundle.tracing.d.ts +1 -0
- package/build/npm/types-ts3.8/index.bundle.tracing.logs.metrics.d.ts +1 -0
- package/build/npm/types-ts3.8/index.bundle.tracing.replay.d.ts +1 -0
- package/build/npm/types-ts3.8/index.bundle.tracing.replay.feedback.d.ts +1 -0
- package/build/npm/types-ts3.8/index.bundle.tracing.replay.feedback.logs.metrics.d.ts +1 -0
- package/build/npm/types-ts3.8/index.bundle.tracing.replay.logs.metrics.d.ts +1 -0
- package/build/npm/types-ts3.8/index.d.ts +1 -0
- package/build/npm/types-ts3.8/integrations/contextlines.d.ts +2 -0
- package/build/npm/types-ts3.8/integrations/webVitals.d.ts +24 -0
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"httpclient.js","sources":["../../../../../src/integrations/httpclient.ts"],"sourcesContent":["import type { Client, Event as SentryEvent, IntegrationFn, SentryWrappedXMLHttpRequest } from '@sentry/core/browser';\nimport {\n addExceptionMechanism,\n addFetchInstrumentationHandler,\n captureEvent,\n debug,\n defineIntegration,\n getClient,\n GLOBAL_OBJ,\n isSentryRequestUrl,\n supportsNativeFetch,\n} from '@sentry/core/browser';\nimport { addXhrInstrumentationHandler, SENTRY_XHR_DATA_KEY } from '@sentry-internal/browser-utils';\nimport { DEBUG_BUILD } from '../debug-build';\n\nexport type HttpStatusCodeRange = [number, number] | number;\nexport type HttpRequestTarget = string | RegExp;\n\nconst INTEGRATION_NAME = 'HttpClient';\n\ninterface HttpClientOptions {\n /**\n * HTTP status codes that should be considered failed.\n * This array can contain tuples of `[begin, end]` (both inclusive),\n * single status codes, or a combinations of both\n *\n * Example: [[500, 505], 507]\n * Default: [[500, 599]]\n */\n failedRequestStatusCodes: HttpStatusCodeRange[];\n\n /**\n * Targets to track for failed requests.\n * This array can contain strings or regular expressions.\n *\n * Example: ['http://localhost', /api\\/.*\\/]\n * Default: [/.*\\/]\n */\n failedRequestTargets: HttpRequestTarget[];\n}\n\nconst _httpClientIntegration = ((options: Partial<HttpClientOptions> = {}) => {\n const _options: HttpClientOptions = {\n failedRequestStatusCodes: [[500, 599]],\n failedRequestTargets: [/.*/],\n ...options,\n };\n\n return {\n name: INTEGRATION_NAME,\n setup(client): void {\n _wrapFetch(client, _options);\n _wrapXHR(client, _options);\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Create events for failed client side HTTP requests.\n */\nexport const httpClientIntegration = defineIntegration(_httpClientIntegration);\n\n/**\n * Interceptor function for fetch requests\n *\n * @param requestInfo The Fetch API request info\n * @param response The Fetch API response\n * @param requestInit The request init object\n */\nfunction _fetchResponseHandler(\n options: HttpClientOptions,\n requestInfo: RequestInfo,\n response: Response,\n requestInit?: RequestInit,\n error?: unknown,\n): void {\n if (_shouldCaptureResponse(options, response.status, response.url)) {\n const request = _getRequest(requestInfo, requestInit);\n\n let requestHeaders, responseHeaders, requestCookies, responseCookies;\n\n if (_shouldSendDefaultPii()) {\n [requestHeaders, requestCookies] = _parseCookieHeaders('Cookie', request);\n [responseHeaders, responseCookies] = _parseCookieHeaders('Set-Cookie', response);\n }\n\n const event = _createEvent({\n url: request.url,\n method: request.method,\n status: response.status,\n requestHeaders,\n responseHeaders,\n requestCookies,\n responseCookies,\n error,\n type: 'fetch',\n });\n\n captureEvent(event);\n }\n}\n\nfunction _parseCookieHeaders(\n cookieHeader: string,\n obj: Request | Response,\n): [Record<string, string>, Record<string, string> | undefined] {\n const headers = _extractFetchHeaders(obj.headers);\n let cookies;\n\n try {\n const cookieString = headers[cookieHeader] || headers[cookieHeader.toLowerCase()] || undefined;\n\n if (cookieString) {\n cookies = _parseCookieString(cookieString);\n }\n } catch {\n // ignore it if parsing fails\n }\n\n return [headers, cookies];\n}\n\n/**\n * Interceptor function for XHR requests\n *\n * @param xhr The XHR request\n * @param method The HTTP method\n * @param headers The HTTP headers\n */\nfunction _xhrResponseHandler(\n options: HttpClientOptions,\n xhr: XMLHttpRequest,\n method: string,\n headers: Record<string, string>,\n error?: unknown,\n): void {\n if (_shouldCaptureResponse(options, xhr.status, xhr.responseURL)) {\n let requestHeaders, responseCookies, responseHeaders;\n\n if (_shouldSendDefaultPii()) {\n try {\n const cookieString = xhr.getResponseHeader('Set-Cookie') || xhr.getResponseHeader('set-cookie') || undefined;\n\n if (cookieString) {\n responseCookies = _parseCookieString(cookieString);\n }\n } catch {\n // ignore it if parsing fails\n }\n\n try {\n responseHeaders = _getXHRResponseHeaders(xhr);\n } catch {\n // ignore it if parsing fails\n }\n\n requestHeaders = headers;\n }\n\n const event = _createEvent({\n url: xhr.responseURL,\n method,\n status: xhr.status,\n requestHeaders,\n // Can't access request cookies from XHR\n responseHeaders,\n responseCookies,\n error,\n type: 'xhr',\n });\n\n captureEvent(event);\n }\n}\n\n/**\n * Extracts response size from `Content-Length` header when possible\n *\n * @param headers\n * @returns The response size in bytes or undefined\n */\nfunction _getResponseSizeFromHeaders(headers?: Record<string, string>): number | undefined {\n if (headers) {\n const contentLength = headers['Content-Length'] || headers['content-length'];\n\n if (contentLength) {\n return parseInt(contentLength, 10);\n }\n }\n\n return undefined;\n}\n\n/**\n * Creates an object containing cookies from the given cookie string\n *\n * @param cookieString The cookie string to parse\n * @returns The parsed cookies\n */\nfunction _parseCookieString(cookieString: string): Record<string, string> {\n return cookieString.split('; ').reduce((acc: Record<string, string>, cookie: string) => {\n const [key, value] = cookie.split('=');\n if (key && value) {\n acc[key] = value;\n }\n return acc;\n }, {});\n}\n\n/**\n * Extracts the headers as an object from the given Fetch API request or response object\n *\n * @param headers The headers to extract\n * @returns The extracted headers as an object\n */\nfunction _extractFetchHeaders(headers: Headers): Record<string, string> {\n const result: Record<string, string> = {};\n\n headers.forEach((value, key) => {\n result[key] = value;\n });\n\n return result;\n}\n\n/**\n * Extracts the response headers as an object from the given XHR object\n *\n * @param xhr The XHR object to extract the response headers from\n * @returns The response headers as an object\n */\nfunction _getXHRResponseHeaders(xhr: XMLHttpRequest): Record<string, string> {\n const headers = xhr.getAllResponseHeaders();\n\n if (!headers) {\n return {};\n }\n\n return headers.split('\\r\\n').reduce((acc: Record<string, string>, line: string) => {\n const [key, value] = line.split(': ');\n if (key && value) {\n acc[key] = value;\n }\n return acc;\n }, {});\n}\n\n/**\n * Checks if the given target url is in the given list of targets\n *\n * @param target The target url to check\n * @returns true if the target url is in the given list of targets, false otherwise\n */\nfunction _isInGivenRequestTargets(\n failedRequestTargets: HttpClientOptions['failedRequestTargets'],\n target: string,\n): boolean {\n return failedRequestTargets.some((givenRequestTarget: HttpRequestTarget) => {\n if (typeof givenRequestTarget === 'string') {\n return target.includes(givenRequestTarget);\n }\n\n return givenRequestTarget.test(target);\n });\n}\n\n/**\n * Checks if the given status code is in the given range\n *\n * @param status The status code to check\n * @returns true if the status code is in the given range, false otherwise\n */\nfunction _isInGivenStatusRanges(\n failedRequestStatusCodes: HttpClientOptions['failedRequestStatusCodes'],\n status: number,\n): boolean {\n return failedRequestStatusCodes.some((range: HttpStatusCodeRange) => {\n if (typeof range === 'number') {\n return range === status;\n }\n\n return status >= range[0] && status <= range[1];\n });\n}\n\n/**\n * Wraps `fetch` function to capture request and response data\n */\nfunction _wrapFetch(client: Client, options: HttpClientOptions): void {\n if (!supportsNativeFetch()) {\n return;\n }\n\n addFetchInstrumentationHandler(handlerData => {\n if (getClient() !== client) {\n return;\n }\n\n const { response, args, error, virtualError } = handlerData;\n const [requestInfo, requestInit] = args as [RequestInfo, RequestInit | undefined];\n\n if (!response) {\n return;\n }\n\n _fetchResponseHandler(options, requestInfo, response as Response, requestInit, error || virtualError);\n }, false);\n}\n\n/**\n * Wraps XMLHttpRequest to capture request and response data\n */\nfunction _wrapXHR(client: Client, options: HttpClientOptions): void {\n if (!('XMLHttpRequest' in GLOBAL_OBJ)) {\n return;\n }\n\n addXhrInstrumentationHandler(handlerData => {\n if (getClient() !== client) {\n return;\n }\n\n const { error, virtualError } = handlerData;\n\n const xhr = handlerData.xhr as SentryWrappedXMLHttpRequest & XMLHttpRequest;\n\n const sentryXhrData = xhr[SENTRY_XHR_DATA_KEY];\n\n if (!sentryXhrData) {\n return;\n }\n\n const { method, request_headers: headers } = sentryXhrData;\n\n try {\n _xhrResponseHandler(options, xhr, method, headers, error || virtualError);\n } catch (e) {\n DEBUG_BUILD && debug.warn('Error while extracting response event form XHR response', e);\n }\n });\n}\n\n/**\n * Checks whether to capture given response as an event\n *\n * @param status response status code\n * @param url response url\n */\nfunction _shouldCaptureResponse(options: HttpClientOptions, status: number, url: string): boolean {\n return (\n _isInGivenStatusRanges(options.failedRequestStatusCodes, status) &&\n _isInGivenRequestTargets(options.failedRequestTargets, url) &&\n !isSentryRequestUrl(url, getClient())\n );\n}\n\n/**\n * Creates a synthetic Sentry event from given response data\n *\n * @param data response data\n * @returns event\n */\nfunction _createEvent(data: {\n url: string;\n method: string;\n status: number;\n type: 'fetch' | 'xhr';\n responseHeaders?: Record<string, string>;\n responseCookies?: Record<string, string>;\n requestHeaders?: Record<string, string>;\n requestCookies?: Record<string, string>;\n error?: unknown;\n}): SentryEvent {\n const client = getClient();\n const virtualStackTrace = client && data.error && data.error instanceof Error ? data.error.stack : undefined;\n // Remove the first frame from the stack as it's the HttpClient call\n const stack = virtualStackTrace && client ? client.getOptions().stackParser(virtualStackTrace, 0, 1) : undefined;\n const message = `HTTP Client Error with status code: ${data.status}`;\n\n const event: SentryEvent = {\n message,\n exception: {\n values: [\n {\n type: 'Error',\n value: message,\n stacktrace: stack ? { frames: stack } : undefined,\n },\n ],\n },\n request: {\n url: data.url,\n method: data.method,\n headers: data.requestHeaders,\n cookies: data.requestCookies,\n },\n contexts: {\n response: {\n status_code: data.status,\n headers: data.responseHeaders,\n cookies: data.responseCookies,\n body_size: _getResponseSizeFromHeaders(data.responseHeaders),\n },\n },\n };\n\n addExceptionMechanism(event, {\n type: `auto.http.client.${data.type}`,\n handled: false,\n });\n\n return event;\n}\n\nfunction _getRequest(requestInfo: RequestInfo, requestInit?: RequestInit): Request {\n if (!requestInit && requestInfo instanceof Request) {\n return requestInfo;\n }\n\n // If both are set, we try to construct a new Request with the given arguments\n // However, if e.g. the original request has a `body`, this will throw an error because it was already accessed\n // In this case, as a fallback, we just use the original request - using both is rather an edge case\n if (requestInfo instanceof Request && requestInfo.bodyUsed) {\n return requestInfo;\n }\n\n return new Request(requestInfo, requestInit);\n}\n\nfunction _shouldSendDefaultPii(): boolean {\n const client = getClient();\n return client ? Boolean(client.getOptions().sendDefaultPii) : false;\n}\n"],"names":["defineIntegration","captureEvent","supportsNativeFetch","addFetchInstrumentationHandler","getClient","GLOBAL_OBJ","addXhrInstrumentationHandler","SENTRY_XHR_DATA_KEY","DEBUG_BUILD","debug","isSentryRequestUrl","addExceptionMechanism"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"httpclient.js","sources":["../../../../../src/integrations/httpclient.ts"],"sourcesContent":["import type { Client, Event as SentryEvent, IntegrationFn, SentryWrappedXMLHttpRequest } from '@sentry/core/browser';\nimport {\n _INTERNAL_filterCookies,\n _INTERNAL_filterKeyValueData,\n addExceptionMechanism,\n addFetchInstrumentationHandler,\n captureEvent,\n debug,\n defineIntegration,\n getClient,\n GLOBAL_OBJ,\n isSentryRequestUrl,\n supportsNativeFetch,\n} from '@sentry/core/browser';\nimport { addXhrInstrumentationHandler, SENTRY_XHR_DATA_KEY } from '@sentry-internal/browser-utils';\nimport { DEBUG_BUILD } from '../debug-build';\n\nexport type HttpStatusCodeRange = [number, number] | number;\nexport type HttpRequestTarget = string | RegExp;\n\nconst INTEGRATION_NAME = 'HttpClient';\n\ninterface HttpClientOptions {\n /**\n * HTTP status codes that should be considered failed.\n * This array can contain tuples of `[begin, end]` (both inclusive),\n * single status codes, or a combinations of both\n *\n * Example: [[500, 505], 507]\n * Default: [[500, 599]]\n */\n failedRequestStatusCodes: HttpStatusCodeRange[];\n\n /**\n * Targets to track for failed requests.\n * This array can contain strings or regular expressions.\n *\n * Example: ['http://localhost', /api\\/.*\\/]\n * Default: [/.*\\/]\n */\n failedRequestTargets: HttpRequestTarget[];\n}\n\nconst _httpClientIntegration = ((options: Partial<HttpClientOptions> = {}) => {\n const _options: HttpClientOptions = {\n failedRequestStatusCodes: [[500, 599]],\n failedRequestTargets: [/.*/],\n ...options,\n };\n\n return {\n name: INTEGRATION_NAME,\n setup(client): void {\n _wrapFetch(client, _options);\n _wrapXHR(client, _options);\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Create events for failed client side HTTP requests.\n */\nexport const httpClientIntegration = defineIntegration(_httpClientIntegration);\n\n/**\n * Interceptor function for fetch requests\n *\n * @param requestInfo The Fetch API request info\n * @param response The Fetch API response\n * @param requestInit The request init object\n */\nfunction _fetchResponseHandler(\n options: HttpClientOptions,\n requestInfo: RequestInfo,\n response: Response,\n requestInit?: RequestInit,\n error?: unknown,\n): void {\n if (_shouldCaptureResponse(options, response.status, response.url)) {\n const request = _getRequest(requestInfo, requestInit);\n\n let requestHeaders, responseHeaders, requestCookies, responseCookies;\n\n const dc = _getDataCollectionSettings();\n\n if (dc.requestHeaders !== false) {\n requestHeaders = _INTERNAL_filterKeyValueData(_extractFetchHeaders(request.headers), dc.requestHeaders);\n }\n if (dc.responseHeaders !== false) {\n responseHeaders = _INTERNAL_filterKeyValueData(_extractFetchHeaders(response.headers), dc.responseHeaders);\n }\n if (dc.cookies !== false) {\n const reqCookieStr = request.headers.get('Cookie') || undefined;\n if (reqCookieStr) {\n const filtered = _INTERNAL_filterCookies(reqCookieStr, dc.cookies);\n if (typeof filtered === 'object') {\n requestCookies = filtered;\n }\n }\n const resCookieStr = response.headers.get('Set-Cookie') || undefined;\n if (resCookieStr) {\n const filtered = _INTERNAL_filterCookies(resCookieStr, dc.cookies);\n if (typeof filtered === 'object') {\n responseCookies = filtered;\n }\n }\n }\n\n const event = _createEvent({\n url: request.url,\n method: request.method,\n status: response.status,\n requestHeaders,\n responseHeaders,\n requestCookies,\n responseCookies,\n error,\n type: 'fetch',\n });\n\n captureEvent(event);\n }\n}\n\n/**\n * Interceptor function for XHR requests\n *\n * @param xhr The XHR request\n * @param method The HTTP method\n * @param headers The HTTP headers\n */\nfunction _xhrResponseHandler(\n options: HttpClientOptions,\n xhr: XMLHttpRequest,\n method: string,\n headers: Record<string, string>,\n error?: unknown,\n): void {\n if (_shouldCaptureResponse(options, xhr.status, xhr.responseURL)) {\n let requestHeaders, responseCookies, responseHeaders;\n\n const dc = _getDataCollectionSettings();\n\n if (dc.cookies !== false) {\n try {\n const cookieString = xhr.getResponseHeader('Set-Cookie') || xhr.getResponseHeader('set-cookie') || undefined;\n if (cookieString) {\n const filtered = _INTERNAL_filterCookies(cookieString, dc.cookies);\n if (typeof filtered === 'object') {\n responseCookies = filtered;\n }\n }\n } catch {\n // ignore it if parsing fails\n }\n }\n\n if (dc.responseHeaders !== false) {\n try {\n responseHeaders = _INTERNAL_filterKeyValueData(_getXHRResponseHeaders(xhr), dc.responseHeaders);\n } catch {\n // ignore it if parsing fails\n }\n }\n\n if (dc.requestHeaders !== false) {\n requestHeaders = _INTERNAL_filterKeyValueData(headers, dc.requestHeaders);\n }\n\n const event = _createEvent({\n url: xhr.responseURL,\n method,\n status: xhr.status,\n requestHeaders,\n // Can't access request cookies from XHR\n responseHeaders,\n responseCookies,\n error,\n type: 'xhr',\n });\n\n captureEvent(event);\n }\n}\n\n/**\n * Extracts response size from `Content-Length` header when possible\n *\n * @param headers\n * @returns The response size in bytes or undefined\n */\nfunction _getResponseSizeFromHeaders(headers?: Record<string, string>): number | undefined {\n if (headers) {\n const contentLength = headers['Content-Length'] || headers['content-length'];\n\n if (contentLength) {\n return parseInt(contentLength, 10);\n }\n }\n\n return undefined;\n}\n\n/**\n * Extracts the headers as an object from the given Fetch API request or response object\n *\n * @param headers The headers to extract\n * @returns The extracted headers as an object\n */\nfunction _extractFetchHeaders(headers: Headers): Record<string, string> {\n const result: Record<string, string> = {};\n\n headers.forEach((value, key) => {\n result[key] = value;\n });\n\n return result;\n}\n\n/**\n * Extracts the response headers as an object from the given XHR object\n *\n * @param xhr The XHR object to extract the response headers from\n * @returns The response headers as an object\n */\nfunction _getXHRResponseHeaders(xhr: XMLHttpRequest): Record<string, string> {\n const headers = xhr.getAllResponseHeaders();\n\n if (!headers) {\n return {};\n }\n\n return headers.split('\\r\\n').reduce((acc: Record<string, string>, line: string) => {\n const [key, value] = line.split(': ');\n if (key && value) {\n acc[key] = value;\n }\n return acc;\n }, {});\n}\n\n/**\n * Checks if the given target url is in the given list of targets\n *\n * @param target The target url to check\n * @returns true if the target url is in the given list of targets, false otherwise\n */\nfunction _isInGivenRequestTargets(\n failedRequestTargets: HttpClientOptions['failedRequestTargets'],\n target: string,\n): boolean {\n return failedRequestTargets.some((givenRequestTarget: HttpRequestTarget) => {\n if (typeof givenRequestTarget === 'string') {\n return target.includes(givenRequestTarget);\n }\n\n return givenRequestTarget.test(target);\n });\n}\n\n/**\n * Checks if the given status code is in the given range\n *\n * @param status The status code to check\n * @returns true if the status code is in the given range, false otherwise\n */\nfunction _isInGivenStatusRanges(\n failedRequestStatusCodes: HttpClientOptions['failedRequestStatusCodes'],\n status: number,\n): boolean {\n return failedRequestStatusCodes.some((range: HttpStatusCodeRange) => {\n if (typeof range === 'number') {\n return range === status;\n }\n\n return status >= range[0] && status <= range[1];\n });\n}\n\n/**\n * Wraps `fetch` function to capture request and response data\n */\nfunction _wrapFetch(client: Client, options: HttpClientOptions): void {\n if (!supportsNativeFetch()) {\n return;\n }\n\n addFetchInstrumentationHandler(handlerData => {\n if (getClient() !== client) {\n return;\n }\n\n const { response, args, error, virtualError } = handlerData;\n const [requestInfo, requestInit] = args as [RequestInfo, RequestInit | undefined];\n\n if (!response) {\n return;\n }\n\n _fetchResponseHandler(options, requestInfo, response as Response, requestInit, error || virtualError);\n }, false);\n}\n\n/**\n * Wraps XMLHttpRequest to capture request and response data\n */\nfunction _wrapXHR(client: Client, options: HttpClientOptions): void {\n if (!('XMLHttpRequest' in GLOBAL_OBJ)) {\n return;\n }\n\n addXhrInstrumentationHandler(handlerData => {\n if (getClient() !== client) {\n return;\n }\n\n const { error, virtualError } = handlerData;\n\n const xhr = handlerData.xhr as SentryWrappedXMLHttpRequest & XMLHttpRequest;\n\n const sentryXhrData = xhr[SENTRY_XHR_DATA_KEY];\n\n if (!sentryXhrData) {\n return;\n }\n\n const { method, request_headers: headers } = sentryXhrData;\n\n try {\n _xhrResponseHandler(options, xhr, method, headers, error || virtualError);\n } catch (e) {\n DEBUG_BUILD && debug.warn('Error while extracting response event form XHR response', e);\n }\n });\n}\n\n/**\n * Checks whether to capture given response as an event\n *\n * @param status response status code\n * @param url response url\n */\nfunction _shouldCaptureResponse(options: HttpClientOptions, status: number, url: string): boolean {\n return (\n _isInGivenStatusRanges(options.failedRequestStatusCodes, status) &&\n _isInGivenRequestTargets(options.failedRequestTargets, url) &&\n !isSentryRequestUrl(url, getClient())\n );\n}\n\n/**\n * Creates a synthetic Sentry event from given response data\n *\n * @param data response data\n * @returns event\n */\nfunction _createEvent(data: {\n url: string;\n method: string;\n status: number;\n type: 'fetch' | 'xhr';\n responseHeaders?: Record<string, string>;\n responseCookies?: Record<string, string>;\n requestHeaders?: Record<string, string>;\n requestCookies?: Record<string, string>;\n error?: unknown;\n}): SentryEvent {\n const client = getClient();\n const virtualStackTrace = client && data.error && data.error instanceof Error ? data.error.stack : undefined;\n // Remove the first frame from the stack as it's the HttpClient call\n const stack = virtualStackTrace && client ? client.getOptions().stackParser(virtualStackTrace, 0, 1) : undefined;\n const message = `HTTP Client Error with status code: ${data.status}`;\n\n const event: SentryEvent = {\n message,\n exception: {\n values: [\n {\n type: 'Error',\n value: message,\n stacktrace: stack ? { frames: stack } : undefined,\n },\n ],\n },\n request: {\n url: data.url,\n method: data.method,\n headers: data.requestHeaders,\n cookies: data.requestCookies,\n },\n contexts: {\n response: {\n status_code: data.status,\n headers: data.responseHeaders,\n cookies: data.responseCookies,\n body_size: _getResponseSizeFromHeaders(data.responseHeaders),\n },\n },\n };\n\n addExceptionMechanism(event, {\n type: `auto.http.client.${data.type}`,\n handled: false,\n });\n\n return event;\n}\n\nfunction _getRequest(requestInfo: RequestInfo, requestInit?: RequestInit): Request {\n if (!requestInit && requestInfo instanceof Request) {\n return requestInfo;\n }\n\n // If both are set, we try to construct a new Request with the given arguments\n // However, if e.g. the original request has a `body`, this will throw an error because it was already accessed\n // In this case, as a fallback, we just use the original request - using both is rather an edge case\n if (requestInfo instanceof Request && requestInfo.bodyUsed) {\n return requestInfo;\n }\n\n return new Request(requestInfo, requestInit);\n}\n\nfunction _getDataCollectionSettings() {\n const client = getClient();\n if (!client) {\n return { cookies: false, requestHeaders: false, responseHeaders: false };\n }\n\n // todo(v11): Always use granular dataCollection settings and remove this legacy guard.\n // Currently, when dataCollection is not explicitly set, we gate all collection on\n // sendDefaultPii to avoid sending more data than before (the spec defaults would\n // collect headers/cookies with deny-list filtering even without sendDefaultPii).\n const options = client.getOptions();\n if (options.dataCollection == null) {\n // eslint-disable-next-line deprecation/deprecation\n const enabled = Boolean(options.sendDefaultPii);\n return { cookies: enabled, requestHeaders: enabled, responseHeaders: enabled };\n }\n\n const { cookies, httpHeaders } = client.getDataCollectionOptions();\n return { cookies, requestHeaders: httpHeaders.request, responseHeaders: httpHeaders.response };\n}\n"],"names":["defineIntegration","_INTERNAL_filterKeyValueData","_INTERNAL_filterCookies","captureEvent","supportsNativeFetch","addFetchInstrumentationHandler","getClient","GLOBAL_OBJ","addXhrInstrumentationHandler","SENTRY_XHR_DATA_KEY","DEBUG_BUILD","debug","isSentryRequestUrl","addExceptionMechanism"],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const browser = require('@sentry/core/browser');
|
|
4
|
+
const browserUtils = require('@sentry-internal/browser-utils');
|
|
5
|
+
|
|
6
|
+
const WEB_VITALS_INTEGRATION_NAME = "WebVitals";
|
|
7
|
+
const webVitalsIntegration = browser.defineIntegration((options = {}) => {
|
|
8
|
+
const ignored = new Set(options.ignore ?? []);
|
|
9
|
+
return {
|
|
10
|
+
name: WEB_VITALS_INTEGRATION_NAME,
|
|
11
|
+
setup(client) {
|
|
12
|
+
const spanStreamingEnabled = browser.hasSpanStreamingEnabled(client);
|
|
13
|
+
const { enableStandaloneClsSpans, enableStandaloneLcpSpans } = options._experiments ?? {};
|
|
14
|
+
const recordClsStandaloneSpans = spanStreamingEnabled || ignored.has("cls") ? void 0 : enableStandaloneClsSpans || false;
|
|
15
|
+
const recordLcpStandaloneSpans = spanStreamingEnabled || ignored.has("lcp") ? void 0 : enableStandaloneLcpSpans || false;
|
|
16
|
+
const finalizeWebVitals = browserUtils.startTrackingWebVitals({
|
|
17
|
+
recordClsStandaloneSpans,
|
|
18
|
+
recordLcpStandaloneSpans,
|
|
19
|
+
client
|
|
20
|
+
});
|
|
21
|
+
const pageloadSpans = /* @__PURE__ */ new WeakSet();
|
|
22
|
+
client.on("afterStartPageLoadSpan", (span) => {
|
|
23
|
+
pageloadSpans.add(span);
|
|
24
|
+
});
|
|
25
|
+
client.on("spanEnd", (span) => {
|
|
26
|
+
if (!pageloadSpans.delete(span)) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
finalizeWebVitals();
|
|
30
|
+
browserUtils.addWebVitalsToSpan(span, {
|
|
31
|
+
// CLS/LCP are recorded as pageload span measurements only when they're neither
|
|
32
|
+
// tracked as standalone spans nor handled by span streaming (and not ignored).
|
|
33
|
+
recordClsOnPageloadSpan: recordClsStandaloneSpans === false,
|
|
34
|
+
recordLcpOnPageloadSpan: recordLcpStandaloneSpans === false,
|
|
35
|
+
spanStreamingEnabled
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
if (spanStreamingEnabled) {
|
|
39
|
+
if (!ignored.has("lcp")) {
|
|
40
|
+
browserUtils.trackLcpAsSpan(client);
|
|
41
|
+
}
|
|
42
|
+
if (!ignored.has("cls")) {
|
|
43
|
+
browserUtils.trackClsAsSpan(client);
|
|
44
|
+
}
|
|
45
|
+
if (!ignored.has("inp")) {
|
|
46
|
+
browserUtils.trackInpAsSpan();
|
|
47
|
+
}
|
|
48
|
+
} else if (!ignored.has("inp")) {
|
|
49
|
+
browserUtils.startTrackingINP();
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
afterAllSetup() {
|
|
53
|
+
if (!ignored.has("inp")) {
|
|
54
|
+
browserUtils.registerInpInteractionListener();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
exports.WEB_VITALS_INTEGRATION_NAME = WEB_VITALS_INTEGRATION_NAME;
|
|
61
|
+
exports.webVitalsIntegration = webVitalsIntegration;
|
|
62
|
+
//# sourceMappingURL=webVitals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webVitals.js","sources":["../../../../../src/integrations/webVitals.ts"],"sourcesContent":["import type { IntegrationFn, Span } from '@sentry/core/browser';\nimport { defineIntegration, hasSpanStreamingEnabled } from '@sentry/core/browser';\nimport {\n addWebVitalsToSpan,\n registerInpInteractionListener,\n startTrackingINP,\n startTrackingWebVitals,\n trackClsAsSpan,\n trackInpAsSpan,\n trackLcpAsSpan,\n} from '@sentry-internal/browser-utils';\n\nexport const WEB_VITALS_INTEGRATION_NAME = 'WebVitals';\n\nexport type WebVitalName = 'cls' | 'inp' | 'lcp';\n\nexport interface WebVitalsOptions {\n /**\n * Web vitals to skip.\n */\n ignore?: WebVitalName[];\n\n /**\n * @experimental\n */\n _experiments?: Partial<{\n enableStandaloneClsSpans: boolean;\n enableStandaloneLcpSpans: boolean;\n }>;\n}\n\n/**\n * Captures Core Web Vitals (LCP, CLS, INP) and related pageload vitals.\n *\n * `browserTracingIntegration` auto-registers this integration if no\n * `webVitalsIntegration` is already present, so explicit registration is only\n * needed to customize options or to use it without `browserTracingIntegration`.\n */\nexport const webVitalsIntegration = defineIntegration((options: WebVitalsOptions = {}) => {\n const ignored = new Set(options.ignore ?? []);\n\n return {\n name: WEB_VITALS_INTEGRATION_NAME,\n setup(client) {\n const spanStreamingEnabled = hasSpanStreamingEnabled(client);\n const { enableStandaloneClsSpans, enableStandaloneLcpSpans } = options._experiments ?? {};\n\n const recordClsStandaloneSpans =\n spanStreamingEnabled || ignored.has('cls') ? undefined : enableStandaloneClsSpans || false;\n const recordLcpStandaloneSpans =\n spanStreamingEnabled || ignored.has('lcp') ? undefined : enableStandaloneLcpSpans || false;\n\n const finalizeWebVitals = startTrackingWebVitals({\n recordClsStandaloneSpans,\n recordLcpStandaloneSpans,\n client,\n });\n\n const pageloadSpans = new WeakSet<Span>();\n\n client.on('afterStartPageLoadSpan', span => {\n pageloadSpans.add(span);\n });\n\n client.on('spanEnd', span => {\n if (!pageloadSpans.delete(span)) {\n return;\n }\n\n finalizeWebVitals();\n addWebVitalsToSpan(span, {\n // CLS/LCP are recorded as pageload span measurements only when they're neither\n // tracked as standalone spans nor handled by span streaming (and not ignored).\n recordClsOnPageloadSpan: recordClsStandaloneSpans === false,\n recordLcpOnPageloadSpan: recordLcpStandaloneSpans === false,\n spanStreamingEnabled,\n });\n });\n\n if (spanStreamingEnabled) {\n if (!ignored.has('lcp')) {\n trackLcpAsSpan(client);\n }\n if (!ignored.has('cls')) {\n trackClsAsSpan(client);\n }\n if (!ignored.has('inp')) {\n trackInpAsSpan();\n }\n } else if (!ignored.has('inp')) {\n startTrackingINP();\n }\n },\n afterAllSetup() {\n if (!ignored.has('inp')) {\n registerInpInteractionListener();\n }\n },\n };\n}) satisfies IntegrationFn;\n"],"names":["defineIntegration","hasSpanStreamingEnabled","startTrackingWebVitals","addWebVitalsToSpan","trackLcpAsSpan","trackClsAsSpan","trackInpAsSpan","startTrackingINP","registerInpInteractionListener"],"mappings":";;;;;AAYO,MAAM,2BAAA,GAA8B;AA0BpC,MAAM,oBAAA,GAAuBA,yBAAA,CAAkB,CAAC,OAAA,GAA4B,EAAC,KAAM;AACxF,EAAA,MAAM,UAAU,IAAI,GAAA,CAAI,OAAA,CAAQ,MAAA,IAAU,EAAE,CAAA;AAE5C,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,2BAAA;AAAA,IACN,MAAM,MAAA,EAAQ;AACZ,MAAA,MAAM,oBAAA,GAAuBC,gCAAwB,MAAM,CAAA;AAC3D,MAAA,MAAM,EAAE,wBAAA,EAA0B,wBAAA,EAAyB,GAAI,OAAA,CAAQ,gBAAgB,EAAC;AAExF,MAAA,MAAM,2BACJ,oBAAA,IAAwB,OAAA,CAAQ,IAAI,KAAK,CAAA,GAAI,SAAY,wBAAA,IAA4B,KAAA;AACvF,MAAA,MAAM,2BACJ,oBAAA,IAAwB,OAAA,CAAQ,IAAI,KAAK,CAAA,GAAI,SAAY,wBAAA,IAA4B,KAAA;AAEvF,MAAA,MAAM,oBAAoBC,mCAAA,CAAuB;AAAA,QAC/C,wBAAA;AAAA,QACA,wBAAA;AAAA,QACA;AAAA,OACD,CAAA;AAED,MAAA,MAAM,aAAA,uBAAoB,OAAA,EAAc;AAExC,MAAA,MAAA,CAAO,EAAA,CAAG,0BAA0B,CAAA,IAAA,KAAQ;AAC1C,QAAA,aAAA,CAAc,IAAI,IAAI,CAAA;AAAA,MACxB,CAAC,CAAA;AAED,MAAA,MAAA,CAAO,EAAA,CAAG,WAAW,CAAA,IAAA,KAAQ;AAC3B,QAAA,IAAI,CAAC,aAAA,CAAc,MAAA,CAAO,IAAI,CAAA,EAAG;AAC/B,UAAA;AAAA,QACF;AAEA,QAAA,iBAAA,EAAkB;AAClB,QAAAC,+BAAA,CAAmB,IAAA,EAAM;AAAA;AAAA;AAAA,UAGvB,yBAAyB,wBAAA,KAA6B,KAAA;AAAA,UACtD,yBAAyB,wBAAA,KAA6B,KAAA;AAAA,UACtD;AAAA,SACD,CAAA;AAAA,MACH,CAAC,CAAA;AAED,MAAA,IAAI,oBAAA,EAAsB;AACxB,QAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA,EAAG;AACvB,UAAAC,2BAAA,CAAe,MAAM,CAAA;AAAA,QACvB;AACA,QAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA,EAAG;AACvB,UAAAC,2BAAA,CAAe,MAAM,CAAA;AAAA,QACvB;AACA,QAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA,EAAG;AACvB,UAAAC,2BAAA,EAAe;AAAA,QACjB;AAAA,MACF,CAAA,MAAA,IAAW,CAAC,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA,EAAG;AAC9B,QAAAC,6BAAA,EAAiB;AAAA,MACnB;AAAA,IACF,CAAA;AAAA,IACA,aAAA,GAAgB;AACd,MAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA,EAAG;AACvB,QAAAC,2CAAA,EAA+B;AAAA,MACjC;AAAA,IACF;AAAA,GACF;AACF,CAAC;;;;;"}
|
|
@@ -5,6 +5,7 @@ const browserUtils = require('@sentry-internal/browser-utils');
|
|
|
5
5
|
const debugBuild = require('../debug-build.js');
|
|
6
6
|
const helpers = require('../helpers.js');
|
|
7
7
|
const fetchStreamPerformance = require('../integrations/fetchStreamPerformance.js');
|
|
8
|
+
const webVitals = require('../integrations/webVitals.js');
|
|
8
9
|
const backgroundtab = require('./backgroundtab.js');
|
|
9
10
|
const linkedTraces = require('./linkedTraces.js');
|
|
10
11
|
const request = require('./request.js');
|
|
@@ -78,7 +79,6 @@ const browserTracingIntegration = ((options = {}) => {
|
|
|
78
79
|
...options
|
|
79
80
|
};
|
|
80
81
|
const _isBot = isBotUserAgent();
|
|
81
|
-
let _collectWebVitals;
|
|
82
82
|
let lastInteractionTimestamp;
|
|
83
83
|
let _pageloadSpan;
|
|
84
84
|
function _createRouteSpan(client, startSpanOptions, makeActive = true) {
|
|
@@ -107,14 +107,10 @@ const browserTracingIntegration = ((options = {}) => {
|
|
|
107
107
|
// should wait for finish signal if it's a pageload transaction
|
|
108
108
|
disableAutoFinish: isPageloadSpan,
|
|
109
109
|
beforeSpanEnd: (span) => {
|
|
110
|
-
_collectWebVitals?.();
|
|
111
|
-
const spanStreamingEnabled = browser.hasSpanStreamingEnabled(client);
|
|
112
110
|
browserUtils.addPerformanceEntries(span, {
|
|
113
|
-
recordClsOnPageloadSpan: !spanStreamingEnabled && !enableStandaloneClsSpans,
|
|
114
|
-
recordLcpOnPageloadSpan: !spanStreamingEnabled && !enableStandaloneLcpSpans,
|
|
115
111
|
ignoreResourceSpans,
|
|
116
112
|
ignorePerformanceApiSpans,
|
|
117
|
-
spanStreamingEnabled
|
|
113
|
+
spanStreamingEnabled: browser.hasSpanStreamingEnabled(client)
|
|
118
114
|
});
|
|
119
115
|
setActiveIdleSpan(client, void 0);
|
|
120
116
|
const scope = browser.getCurrentScope();
|
|
@@ -155,21 +151,6 @@ const browserTracingIntegration = ((options = {}) => {
|
|
|
155
151
|
return;
|
|
156
152
|
}
|
|
157
153
|
browser.registerSpanErrorInstrumentation();
|
|
158
|
-
const spanStreamingEnabled = browser.hasSpanStreamingEnabled(client);
|
|
159
|
-
_collectWebVitals = browserUtils.startTrackingWebVitals({
|
|
160
|
-
recordClsStandaloneSpans: spanStreamingEnabled ? void 0 : enableStandaloneClsSpans || false,
|
|
161
|
-
recordLcpStandaloneSpans: spanStreamingEnabled ? void 0 : enableStandaloneLcpSpans || false,
|
|
162
|
-
client
|
|
163
|
-
});
|
|
164
|
-
if (spanStreamingEnabled) {
|
|
165
|
-
browserUtils.trackLcpAsSpan(client);
|
|
166
|
-
browserUtils.trackClsAsSpan(client);
|
|
167
|
-
if (enableInp) {
|
|
168
|
-
browserUtils.trackInpAsSpan();
|
|
169
|
-
}
|
|
170
|
-
} else if (enableInp) {
|
|
171
|
-
browserUtils.startTrackingINP();
|
|
172
|
-
}
|
|
173
154
|
if (enableLongAnimationFrame && browser.GLOBAL_OBJ.PerformanceObserver && PerformanceObserver.supportedEntryTypes?.includes("long-animation-frame")) {
|
|
174
155
|
browserUtils.startTrackingLongAnimationFrames();
|
|
175
156
|
} else if (enableLongTask) {
|
|
@@ -265,6 +246,17 @@ const browserTracingIntegration = ((options = {}) => {
|
|
|
265
246
|
if (_isBot) {
|
|
266
247
|
return;
|
|
267
248
|
}
|
|
249
|
+
if (client.addIntegration && !client.getIntegrationByName?.(webVitals.WEB_VITALS_INTEGRATION_NAME)) {
|
|
250
|
+
client.addIntegration(
|
|
251
|
+
webVitals.webVitalsIntegration({
|
|
252
|
+
ignore: enableInp ? [] : ["inp"],
|
|
253
|
+
_experiments: {
|
|
254
|
+
enableStandaloneClsSpans,
|
|
255
|
+
enableStandaloneLcpSpans
|
|
256
|
+
}
|
|
257
|
+
})
|
|
258
|
+
);
|
|
259
|
+
}
|
|
268
260
|
let startingUrl = browser.getLocationHref();
|
|
269
261
|
if (linkPreviousTrace !== "off") {
|
|
270
262
|
linkedTraces.linkTraces(client, { linkPreviousTrace, consistentTraceSampling });
|
|
@@ -312,9 +304,6 @@ const browserTracingIntegration = ((options = {}) => {
|
|
|
312
304
|
if (enableInteractions) {
|
|
313
305
|
registerInteractionListener(client, idleTimeout, finalTimeout, childSpanTimeout, latestRoute);
|
|
314
306
|
}
|
|
315
|
-
if (enableInp) {
|
|
316
|
-
browserUtils.registerInpInteractionListener();
|
|
317
|
-
}
|
|
318
307
|
request.instrumentOutgoingRequests(client, {
|
|
319
308
|
traceFetch,
|
|
320
309
|
traceXHR,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browserTracingIntegration.js","sources":["../../../../../src/tracing/browserTracingIntegration.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport type {\n Client,\n IntegrationFn,\n RequestHookInfo,\n ResponseHookInfo,\n Span,\n StartSpanOptions,\n TransactionSource,\n} from '@sentry/core/browser';\nimport {\n addNonEnumerableProperty,\n browserPerformanceTimeOrigin,\n consoleSandbox,\n dateTimestampInSeconds,\n debug,\n generateSpanId,\n generateTraceId,\n getClient,\n getCurrentScope,\n getDynamicSamplingContextFromSpan,\n getIsolationScope,\n getLocationHref,\n GLOBAL_OBJ,\n hasSpansEnabled,\n hasSpanStreamingEnabled,\n parseStringToURLObject,\n propagationContextFromHeaders,\n registerSpanErrorInstrumentation,\n SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n spanIsSampled,\n spanToJSON,\n startIdleSpan,\n startInactiveSpan,\n timestampInSeconds,\n TRACING_DEFAULTS,\n} from '@sentry/core/browser';\nimport {\n addHistoryInstrumentationHandler,\n addPerformanceEntries,\n registerInpInteractionListener,\n startTrackingINP,\n startTrackingInteractions,\n startTrackingLongAnimationFrames,\n startTrackingLongTasks,\n startTrackingWebVitals,\n trackClsAsSpan,\n trackInpAsSpan,\n trackLcpAsSpan,\n} from '@sentry-internal/browser-utils';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { getHttpRequestData, WINDOW } from '../helpers';\nimport { fetchStreamPerformanceIntegration } from '../integrations/fetchStreamPerformance';\nimport { registerBackgroundTabDetection } from './backgroundtab';\nimport { linkTraces } from './linkedTraces';\nimport { defaultRequestInstrumentationOptions, instrumentOutgoingRequests } from './request';\n\nexport const BROWSER_TRACING_INTEGRATION_ID = 'BrowserTracing';\n\n/**\n * We don't want to start a bunch of idle timers and PerformanceObservers\n * for web crawlers, as they may prevent the page from being seen as \"idle\"\n * by the crawler's rendering engine (e.g. Googlebot's headless Chromium).\n */\nconst BOT_USER_AGENT_RE =\n /Googlebot|Google-InspectionTool|Storebot-Google|Bingbot|Slurp|DuckDuckBot|Baiduspider|YandexBot|Facebot|facebookexternalhit|LinkedInBot|Twitterbot|Applebot/i;\n\nexport function isBotUserAgent(): boolean {\n const nav = WINDOW.navigator as Navigator | undefined;\n if (!nav?.userAgent) {\n return false;\n }\n return BOT_USER_AGENT_RE.test(nav.userAgent);\n}\n\ninterface RouteInfo {\n name: string | undefined;\n source: TransactionSource | undefined;\n}\n\n/** Options for Browser Tracing integration */\nexport interface BrowserTracingOptions {\n /**\n * The time that has to pass without any span being created.\n * If this time is exceeded, the idle span will finish.\n *\n * Default: 1000 (ms)\n */\n idleTimeout: number;\n\n /**\n * The max. time an idle span may run.\n * If this time is exceeded, the idle span will finish no matter what.\n *\n * Default: 30000 (ms)\n */\n finalTimeout: number;\n\n /**\n The max. time an idle span may run.\n * If this time is exceeded, the idle span will finish no matter what.\n *\n * Default: 15000 (ms)\n */\n childSpanTimeout: number;\n\n /**\n * If a span should be created on page load.\n * If this is set to `false`, this integration will not start the default page load span.\n * Default: true\n */\n instrumentPageLoad: boolean;\n\n /**\n * If a span should be created on navigation (history change).\n * If this is set to `false`, this integration will not start the default navigation spans.\n * Default: true\n */\n instrumentNavigation: boolean;\n\n /**\n * Flag spans where tabs moved to background with \"cancelled\". Browser background tab timing is\n * not suited towards doing precise measurements of operations. By default, we recommend that this option\n * be enabled as background transactions can mess up your statistics in nondeterministic ways.\n *\n * Default: true\n */\n markBackgroundSpan: boolean;\n\n /**\n * If true, Sentry will capture long tasks and add them to the corresponding transaction.\n *\n * Default: true\n */\n enableLongTask: boolean;\n\n /**\n * If true, Sentry will capture long animation frames and add them to the corresponding transaction.\n *\n * Default: false\n */\n enableLongAnimationFrame: boolean;\n\n /**\n * If true, Sentry will capture first input delay and add it to the corresponding transaction.\n *\n * Default: true\n */\n enableInp: boolean;\n\n /**\n * @deprecated This option is no longer used. Element timing is now tracked via the standalone\n * `elementTimingIntegration`. Add it to your `integrations` array to collect element timing metrics.\n */\n enableElementTiming?: boolean;\n\n /**\n * Flag to disable patching all together for fetch requests.\n *\n * Default: true\n */\n traceFetch: boolean;\n\n /**\n * Flag to disable patching all together for xhr requests.\n *\n * Default: true\n */\n traceXHR: boolean;\n\n /**\n * Flag to disable tracking of long-lived streams, like server-sent events (SSE) via fetch.\n * Do not enable this in case you have live streams or very long running streams.\n *\n * Default: false\n *\n * @deprecated Use `fetchStreamPerformanceIntegration()` instead. Add it to your `integrations` array\n * to track the duration of streamed fetch response bodies.\n */\n trackFetchStreamPerformance: boolean;\n\n /**\n * If true, Sentry will capture http timings and add them to the corresponding http spans.\n *\n * Default: true\n */\n enableHTTPTimings: boolean;\n\n /**\n * Resource spans with `op`s matching strings in the array will not be emitted.\n *\n * Default: []\n */\n ignoreResourceSpans: Array<'resouce.script' | 'resource.css' | 'resource.img' | 'resource.other' | string>;\n\n /**\n * Spans created from the following browser Performance APIs,\n *\n * - [`performance.mark(...)`](https://developer.mozilla.org/en-US/docs/Web/API/Performance/mark)\n * - [`performance.measure(...)`](https://developer.mozilla.org/en-US/docs/Web/API/Performance/measure)\n *\n * will not be emitted if their names match strings in this array.\n *\n * This is useful, if you come across `mark` or `measure` spans in your Sentry traces\n * that you want to ignore. For example, sometimes, browser extensions or libraries\n * emit these entries on their own, which might not be relevant to your application.\n *\n * * @example\n * ```ts\n * Sentry.init({\n * integrations: [\n * Sentry.browserTracingIntegration({\n * ignorePerformanceApiSpans: ['myMeasurement', /myMark/],\n * }),\n * ],\n * });\n *\n * // no spans will be created for these:\n * performance.mark('myMark');\n * performance.measure('myMeasurement');\n *\n * // spans will be created for these:\n * performance.mark('authenticated');\n * performance.measure('input-duration', ...);\n * ```\n *\n * Default: [] - By default, all `mark` and `measure` entries are sent as spans.\n */\n ignorePerformanceApiSpans: Array<string | RegExp>;\n\n /**\n * By default, the SDK will try to detect redirects and avoid creating separate spans for them.\n * If you want to opt-out of this behavior, you can set this option to `false`.\n *\n * Default: true\n */\n detectRedirects: boolean;\n\n /**\n * Link the currently started trace to a previous trace (e.g. a prior pageload, navigation or\n * manually started span). When enabled, this option will allow you to navigate between traces\n * in the Sentry UI.\n *\n * You can set this option to the following values:\n *\n * - `'in-memory'`: The previous trace data will be stored in memory.\n * This is useful for single-page applications and enabled by default.\n *\n * - `'session-storage'`: The previous trace data will be stored in the `sessionStorage`.\n * This is useful for multi-page applications or static sites but it means that the\n * Sentry SDK writes to the browser's `sessionStorage`.\n *\n * - `'off'`: The previous trace data will not be stored or linked.\n *\n * You can also use {@link BrowserTracingOptions.consistentTraceSampling} to get\n * consistent trace sampling of subsequent traces. Otherwise, by default, your\n * `tracesSampleRate` or `tracesSampler` config significantly influences how often\n * traces will be linked.\n *\n * @default 'in-memory' - see explanation above\n */\n linkPreviousTrace: 'in-memory' | 'session-storage' | 'off';\n\n /**\n * If true, Sentry will consistently sample subsequent traces based on the\n * sampling decision of the initial trace. For example, if the initial page\n * load trace was sampled positively, all subsequent traces (e.g. navigations)\n * are also sampled positively. In case the initial trace was sampled negatively,\n * all subsequent traces are also sampled negatively.\n *\n * This option allows you to get consistent, linked traces within a user journey\n * while maintaining an overall quota based on your trace sampling settings.\n *\n * This option is only effective if {@link BrowserTracingOptions.linkPreviousTrace}\n * is enabled (i.e. not set to `'off'`).\n *\n * @default `false` - this is an opt-in feature.\n */\n consistentTraceSampling: boolean;\n\n /**\n * If set to `true`, the pageload span will not end itself automatically, unless it\n * runs until the {@link BrowserTracingOptions.finalTimeout} (30 seconds by default) is reached.\n *\n * Set this option to `true`, if you want full control over the pageload span duration.\n * You can use `Sentry.reportPageLoaded()` to manually end the pageload span whenever convenient.\n * Be aware that you have to ensure that this is always called, regardless of the chosen route\n * or path in the application.\n *\n * @default `false`. By default, the pageload span will end itself automatically, based on\n * the {@link BrowserTracingOptions.finalTimeout}, {@link BrowserTracingOptions.idleTimeout}\n * and {@link BrowserTracingOptions.childSpanTimeout}. This is more convenient to use but means\n * that the pageload duration can be arbitrary and might not be fully representative of a perceived\n * page load time.\n */\n enableReportPageLoaded: boolean;\n\n /**\n * _experiments allows the user to send options to define how this integration works.\n *\n * Default: undefined\n */\n _experiments: Partial<{\n enableInteractions: boolean;\n enableStandaloneClsSpans: boolean;\n enableStandaloneLcpSpans: boolean;\n }>;\n\n /**\n * A callback which is called before a span for a pageload or navigation is started.\n * It receives the options passed to `startSpan`, and expects to return an updated options object.\n */\n beforeStartSpan?: (options: StartSpanOptions) => StartSpanOptions;\n\n /**\n * This function will be called before creating a span for a request with the given url.\n * Return false if you don't want a span for the given url.\n *\n * Default: (url: string) => true\n */\n shouldCreateSpanForRequest?(this: void, url: string): boolean;\n\n /**\n * This callback is invoked directly after a span is started for an outgoing fetch or XHR request.\n * You can use it to annotate the span with additional data or attributes, for example by setting\n * attributes based on the passed request headers.\n */\n onRequestSpanStart?(span: Span, requestInformation: RequestHookInfo): void;\n\n /**\n * Is called when spans end for outgoing requests, providing access to response headers.\n */\n onRequestSpanEnd?(span: Span, responseInformation: ResponseHookInfo): void;\n}\n\nconst DEFAULT_BROWSER_TRACING_OPTIONS: BrowserTracingOptions = {\n ...TRACING_DEFAULTS,\n instrumentNavigation: true,\n instrumentPageLoad: true,\n markBackgroundSpan: true,\n enableLongTask: true,\n enableLongAnimationFrame: true,\n enableInp: true,\n ignoreResourceSpans: [],\n ignorePerformanceApiSpans: [],\n detectRedirects: true,\n linkPreviousTrace: 'in-memory',\n consistentTraceSampling: false,\n enableReportPageLoaded: false,\n _experiments: {},\n ...defaultRequestInstrumentationOptions,\n};\n\n/**\n * The Browser Tracing integration automatically instruments browser pageload/navigation\n * actions as transactions, and captures requests, metrics and errors as spans.\n *\n * The integration can be configured with a variety of options, and can be extended to use\n * any routing library.\n *\n * We explicitly export the proper type here, as this has to be extended in some cases.\n */\nexport const browserTracingIntegration = ((options: Partial<BrowserTracingOptions> = {}) => {\n if ('enableElementTiming' in options) {\n consoleSandbox(() => {\n // oxlint-disable-next-line no-console\n console.warn(\n '[Sentry] `enableElementTiming` is deprecated and no longer has any effect. Use the standalone `elementTimingIntegration` instead.',\n );\n });\n }\n\n const latestRoute: RouteInfo = {\n name: undefined,\n source: undefined,\n };\n\n /**\n * This is just a small wrapper that makes `document` optional.\n * We want to be extra-safe and always check that this exists, to ensure weird environments do not blow up.\n */\n const optionalWindowDocument = WINDOW.document as (typeof WINDOW)['document'] | undefined;\n\n const {\n enableInp,\n enableLongTask,\n enableLongAnimationFrame,\n _experiments: { enableInteractions, enableStandaloneClsSpans, enableStandaloneLcpSpans },\n beforeStartSpan,\n idleTimeout,\n finalTimeout,\n childSpanTimeout,\n markBackgroundSpan,\n traceFetch,\n traceXHR,\n trackFetchStreamPerformance,\n shouldCreateSpanForRequest,\n enableHTTPTimings,\n ignoreResourceSpans,\n ignorePerformanceApiSpans,\n instrumentPageLoad,\n instrumentNavigation,\n detectRedirects,\n linkPreviousTrace,\n consistentTraceSampling,\n enableReportPageLoaded,\n onRequestSpanStart,\n onRequestSpanEnd,\n } = {\n ...DEFAULT_BROWSER_TRACING_OPTIONS,\n ...options,\n };\n\n const _isBot = isBotUserAgent();\n\n let _collectWebVitals: undefined | (() => void);\n let lastInteractionTimestamp: number | undefined;\n\n let _pageloadSpan: Span | undefined;\n\n /** Create routing idle transaction. */\n function _createRouteSpan(client: Client, startSpanOptions: StartSpanOptions, makeActive = true): void {\n const isPageloadSpan = startSpanOptions.op === 'pageload';\n\n const initialSpanName = startSpanOptions.name;\n const finalStartSpanOptions: StartSpanOptions = beforeStartSpan\n ? beforeStartSpan(startSpanOptions)\n : startSpanOptions;\n\n const attributes = finalStartSpanOptions.attributes || {};\n\n // If `finalStartSpanOptions.name` is different than `startSpanOptions.name`\n // it is because `beforeStartSpan` set a custom name. Therefore we set the source to 'custom'.\n if (initialSpanName !== finalStartSpanOptions.name) {\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] = 'custom';\n finalStartSpanOptions.attributes = attributes;\n }\n\n if (!makeActive) {\n // We want to ensure this has 0s duration\n const now = dateTimestampInSeconds();\n startInactiveSpan({\n ...finalStartSpanOptions,\n startTime: now,\n }).end(now);\n return;\n }\n\n latestRoute.name = finalStartSpanOptions.name;\n latestRoute.source = attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];\n\n const idleSpan = startIdleSpan(finalStartSpanOptions, {\n idleTimeout,\n finalTimeout,\n childSpanTimeout,\n // should wait for finish signal if it's a pageload transaction\n disableAutoFinish: isPageloadSpan,\n beforeSpanEnd: span => {\n // This will generally always be defined here, because it is set in `setup()` of the integration\n // but technically, it is optional, so we guard here to be extra safe\n _collectWebVitals?.();\n const spanStreamingEnabled = hasSpanStreamingEnabled(client);\n addPerformanceEntries(span, {\n recordClsOnPageloadSpan: !spanStreamingEnabled && !enableStandaloneClsSpans,\n recordLcpOnPageloadSpan: !spanStreamingEnabled && !enableStandaloneLcpSpans,\n ignoreResourceSpans,\n ignorePerformanceApiSpans,\n spanStreamingEnabled,\n });\n setActiveIdleSpan(client, undefined);\n\n // A trace should stay consistent over the entire timespan of one route - even after the pageload/navigation ended.\n // Only when another navigation happens, we want to create a new trace.\n // This way, e.g. errors that occur after the pageload span ended are still associated to the pageload trace.\n const scope = getCurrentScope();\n const oldPropagationContext = scope.getPropagationContext();\n\n scope.setPropagationContext({\n ...oldPropagationContext,\n traceId: idleSpan.spanContext().traceId,\n sampled: spanIsSampled(idleSpan),\n dsc: getDynamicSamplingContextFromSpan(span),\n });\n\n if (isPageloadSpan) {\n // clean up the stored pageload span on the intergration.\n _pageloadSpan = undefined;\n }\n },\n trimIdleSpanEndTimestamp: !enableReportPageLoaded,\n });\n\n if (isPageloadSpan && enableReportPageLoaded) {\n _pageloadSpan = idleSpan;\n }\n\n setActiveIdleSpan(client, idleSpan);\n\n function emitFinish(): void {\n if (optionalWindowDocument && ['interactive', 'complete'].includes(optionalWindowDocument.readyState)) {\n client.emit('idleSpanEnableAutoFinish', idleSpan);\n }\n }\n\n // Enable auto finish of the pageload span if users are not explicitly ending it\n if (isPageloadSpan && !enableReportPageLoaded && optionalWindowDocument) {\n optionalWindowDocument.addEventListener('readystatechange', () => {\n emitFinish();\n });\n\n emitFinish();\n }\n }\n\n return {\n name: BROWSER_TRACING_INTEGRATION_ID,\n setup(client) {\n if (_isBot) {\n DEBUG_BUILD && debug.log('[Tracing] Skipping browserTracingIntegration setup for bot user agent.');\n return;\n }\n\n registerSpanErrorInstrumentation();\n\n const spanStreamingEnabled = hasSpanStreamingEnabled(client);\n\n _collectWebVitals = startTrackingWebVitals({\n recordClsStandaloneSpans: spanStreamingEnabled ? undefined : enableStandaloneClsSpans || false,\n recordLcpStandaloneSpans: spanStreamingEnabled ? undefined : enableStandaloneLcpSpans || false,\n client,\n });\n\n if (spanStreamingEnabled) {\n trackLcpAsSpan(client);\n trackClsAsSpan(client);\n if (enableInp) {\n trackInpAsSpan();\n }\n } else if (enableInp) {\n startTrackingINP();\n }\n\n if (\n enableLongAnimationFrame &&\n GLOBAL_OBJ.PerformanceObserver &&\n PerformanceObserver.supportedEntryTypes?.includes('long-animation-frame')\n ) {\n startTrackingLongAnimationFrames();\n } else if (enableLongTask) {\n startTrackingLongTasks();\n }\n\n if (enableInteractions) {\n startTrackingInteractions();\n }\n\n if (detectRedirects && optionalWindowDocument) {\n const interactionHandler = (): void => {\n lastInteractionTimestamp = timestampInSeconds();\n };\n addEventListener('click', interactionHandler, { capture: true });\n addEventListener('keydown', interactionHandler, { capture: true, passive: true });\n }\n\n function maybeEndActiveSpan(): void {\n const activeSpan = getActiveIdleSpan(client);\n\n if (activeSpan && !spanToJSON(activeSpan).timestamp) {\n DEBUG_BUILD && debug.log(`[Tracing] Finishing current active span with op: ${spanToJSON(activeSpan).op}`);\n // If there's an open active span, we need to finish it before creating an new one.\n activeSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON, 'cancelled');\n activeSpan.end();\n }\n }\n\n client.on('startNavigationSpan', (startSpanOptions, navigationOptions) => {\n if (getClient() !== client) {\n return;\n }\n\n if (navigationOptions?.isRedirect) {\n DEBUG_BUILD &&\n debug.warn('[Tracing] Detected redirect, navigation span will not be the root span, but a child span.');\n _createRouteSpan(\n client,\n {\n op: 'navigation.redirect',\n ...startSpanOptions,\n },\n false,\n );\n return;\n }\n\n // Reset the last interaction timestamp since we now start a new navigation.\n // Any subsequent navigation span starts could again be a redirect, so we\n // should reset our heuristic detectors.\n lastInteractionTimestamp = undefined;\n\n maybeEndActiveSpan();\n\n getIsolationScope().setPropagationContext({\n traceId: generateTraceId(),\n sampleRand: Math.random(),\n propagationSpanId: hasSpansEnabled() ? undefined : generateSpanId(),\n });\n\n const scope = getCurrentScope();\n scope.setPropagationContext({\n traceId: generateTraceId(),\n sampleRand: Math.random(),\n propagationSpanId: hasSpansEnabled() ? undefined : generateSpanId(),\n });\n\n // We reset this to ensure we do not have lingering incorrect data here\n // places that call this hook may set this where appropriate - else, the URL at span sending time is used\n scope.setSDKProcessingMetadata({\n normalizedRequest: undefined,\n });\n\n _createRouteSpan(client, {\n op: 'navigation',\n ...startSpanOptions,\n // Navigation starts a new trace and is NOT parented under any active interaction (e.g. ui.action.click)\n parentSpan: null,\n forceTransaction: true,\n });\n });\n\n client.on('startPageLoadSpan', (startSpanOptions, traceOptions = {}) => {\n if (getClient() !== client) {\n return;\n }\n maybeEndActiveSpan();\n\n const sentryTrace =\n traceOptions.sentryTrace || getMetaContent('sentry-trace') || getServerTiming('sentry-trace');\n const baggage = traceOptions.baggage || getMetaContent('baggage') || getServerTiming('baggage');\n\n const propagationContext = propagationContextFromHeaders(sentryTrace, baggage);\n\n const scope = getCurrentScope();\n scope.setPropagationContext(propagationContext);\n if (!hasSpansEnabled()) {\n // for browser, we wanna keep the spanIds consistent during the entire lifetime of the trace\n // this works by setting the propagationSpanId to a random spanId so that we have a consistent\n // span id to propagate in TwP mode (!hasSpansEnabled())\n scope.getPropagationContext().propagationSpanId = generateSpanId();\n }\n\n // We store the normalized request data on the scope, so we get the request data at time of span creation\n // otherwise, the URL etc. may already be of the following navigation, and we'd report the wrong URL\n scope.setSDKProcessingMetadata({\n normalizedRequest: getHttpRequestData(),\n });\n\n _createRouteSpan(client, {\n op: 'pageload',\n ...startSpanOptions,\n });\n });\n\n client.on('endPageloadSpan', () => {\n if (enableReportPageLoaded && _pageloadSpan) {\n _pageloadSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON, 'reportPageLoaded');\n _pageloadSpan.end();\n }\n });\n },\n\n afterAllSetup(client) {\n if (_isBot) {\n return;\n }\n\n let startingUrl: string | undefined = getLocationHref();\n\n if (linkPreviousTrace !== 'off') {\n linkTraces(client, { linkPreviousTrace, consistentTraceSampling });\n }\n\n if (WINDOW.location) {\n if (instrumentPageLoad) {\n const origin = browserPerformanceTimeOrigin();\n startBrowserTracingPageLoadSpan(client, {\n name: WINDOW.location.pathname,\n // pageload should always start at timeOrigin (and needs to be in s, not ms)\n startTime: origin ? origin / 1000 : undefined,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.browser',\n },\n });\n }\n\n if (instrumentNavigation) {\n addHistoryInstrumentationHandler(({ to, from }) => {\n /**\n * This early return is there to account for some cases where a navigation transaction starts right after\n * long-running pageload. We make sure that if `from` is undefined and a valid `startingURL` exists, we don't\n * create an uneccessary navigation transaction.\n *\n * This was hard to duplicate, but this behavior stopped as soon as this fix was applied. This issue might also\n * only be caused in certain development environments where the usage of a hot module reloader is causing\n * errors.\n */\n if (from === undefined && startingUrl?.indexOf(to) !== -1) {\n startingUrl = undefined;\n return;\n }\n\n startingUrl = undefined;\n const parsed = parseStringToURLObject(to);\n const activeSpan = getActiveIdleSpan(client);\n const navigationIsRedirect =\n activeSpan && detectRedirects && isRedirect(activeSpan, lastInteractionTimestamp);\n\n startBrowserTracingNavigationSpan(\n client,\n {\n name: parsed?.pathname || WINDOW.location.pathname,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.browser',\n },\n },\n { url: to, isRedirect: navigationIsRedirect },\n );\n });\n }\n }\n\n if (markBackgroundSpan) {\n registerBackgroundTabDetection();\n }\n\n if (enableInteractions) {\n registerInteractionListener(client, idleTimeout, finalTimeout, childSpanTimeout, latestRoute);\n }\n\n if (enableInp) {\n registerInpInteractionListener();\n }\n\n instrumentOutgoingRequests(client, {\n traceFetch,\n traceXHR,\n tracePropagationTargets: client.getOptions().tracePropagationTargets,\n shouldCreateSpanForRequest,\n enableHTTPTimings,\n onRequestSpanStart,\n onRequestSpanEnd,\n });\n\n if (trackFetchStreamPerformance) {\n client.addIntegration(fetchStreamPerformanceIntegration());\n }\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Manually start a page load span.\n * This will only do something if a browser tracing integration integration has been setup.\n *\n * If you provide a custom `traceOptions` object, it will be used to continue the trace\n * instead of the default behavior, which is to look it up on the <meta> tags.\n */\nexport function startBrowserTracingPageLoadSpan(\n client: Client,\n spanOptions: StartSpanOptions,\n traceOptions?: { sentryTrace?: string | undefined; baggage?: string | undefined },\n): Span | undefined {\n client.emit('startPageLoadSpan', spanOptions, traceOptions);\n getCurrentScope().setTransactionName(spanOptions.name);\n\n const pageloadSpan = getActiveIdleSpan(client);\n\n if (pageloadSpan) {\n client.emit('afterStartPageLoadSpan', pageloadSpan);\n }\n\n return pageloadSpan;\n}\n\n/**\n * Manually start a navigation span.\n * This will only do something if a browser tracing integration has been setup.\n */\nexport function startBrowserTracingNavigationSpan(\n client: Client,\n spanOptions: StartSpanOptions,\n options?: { url?: string; isRedirect?: boolean },\n): Span | undefined {\n const { url, isRedirect } = options || {};\n client.emit('beforeStartNavigationSpan', spanOptions, { isRedirect });\n client.emit('startNavigationSpan', spanOptions, { isRedirect });\n\n const scope = getCurrentScope();\n scope.setTransactionName(spanOptions.name);\n\n // We store the normalized request data on the scope, so we get the request data at time of span creation\n // otherwise, the URL etc. may already be of the following navigation, and we'd report the wrong URL\n if (url && !isRedirect) {\n scope.setSDKProcessingMetadata({\n normalizedRequest: {\n ...getHttpRequestData(),\n url,\n },\n });\n }\n\n return getActiveIdleSpan(client);\n}\n\n/** Returns the value of a meta tag */\nexport function getMetaContent(metaName: string): string | undefined {\n /**\n * This is just a small wrapper that makes `document` optional.\n * We want to be extra-safe and always check that this exists, to ensure weird environments do not blow up.\n */\n const optionalWindowDocument = WINDOW.document as (typeof WINDOW)['document'] | undefined;\n\n const metaTag = optionalWindowDocument?.querySelector(`meta[name=${metaName}]`);\n return metaTag?.getAttribute('content') || undefined;\n}\n\n/** Returns the description of a server timing entry */\nexport function getServerTiming(name: string): string | undefined {\n const navigation = WINDOW.performance?.getEntriesByType?.('navigation')[0] as PerformanceNavigationTiming | undefined;\n const entry = navigation?.serverTiming?.find(entry => entry.name === name);\n return entry?.description;\n}\n\n/** Start listener for interaction transactions */\nfunction registerInteractionListener(\n client: Client,\n idleTimeout: BrowserTracingOptions['idleTimeout'],\n finalTimeout: BrowserTracingOptions['finalTimeout'],\n childSpanTimeout: BrowserTracingOptions['childSpanTimeout'],\n latestRoute: RouteInfo,\n): void {\n /**\n * This is just a small wrapper that makes `document` optional.\n * We want to be extra-safe and always check that this exists, to ensure weird environments do not blow up.\n */\n const optionalWindowDocument = WINDOW.document as (typeof WINDOW)['document'] | undefined;\n\n let inflightInteractionSpan: Span | undefined;\n const registerInteractionTransaction = (): void => {\n const op = 'ui.action.click';\n\n const activeIdleSpan = getActiveIdleSpan(client);\n if (activeIdleSpan) {\n const currentRootSpanOp = spanToJSON(activeIdleSpan).op;\n if (['navigation', 'pageload'].includes(currentRootSpanOp as string)) {\n DEBUG_BUILD &&\n debug.warn(`[Tracing] Did not create ${op} span because a pageload or navigation span is in progress.`);\n return undefined;\n }\n }\n\n if (inflightInteractionSpan) {\n inflightInteractionSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON, 'interactionInterrupted');\n inflightInteractionSpan.end();\n inflightInteractionSpan = undefined;\n }\n\n if (!latestRoute.name) {\n DEBUG_BUILD && debug.warn(`[Tracing] Did not create ${op} transaction because _latestRouteName is missing.`);\n return undefined;\n }\n\n inflightInteractionSpan = startIdleSpan(\n {\n name: latestRoute.name,\n op,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: latestRoute.source || 'url',\n },\n },\n {\n idleTimeout,\n finalTimeout,\n childSpanTimeout,\n },\n );\n };\n\n if (optionalWindowDocument) {\n addEventListener('click', registerInteractionTransaction, { capture: true });\n }\n}\n\n// We store the active idle span on the client object, so we can access it from exported functions\nconst ACTIVE_IDLE_SPAN_PROPERTY = '_sentry_idleSpan';\nfunction getActiveIdleSpan(client: Client): Span | undefined {\n return (client as { [ACTIVE_IDLE_SPAN_PROPERTY]?: Span })[ACTIVE_IDLE_SPAN_PROPERTY];\n}\n\nfunction setActiveIdleSpan(client: Client, span: Span | undefined): void {\n addNonEnumerableProperty(client, ACTIVE_IDLE_SPAN_PROPERTY, span);\n}\n\n// The max. time in seconds between two pageload/navigation spans that makes us consider the second one a redirect\nconst REDIRECT_THRESHOLD = 1.5;\n\nfunction isRedirect(activeSpan: Span, lastInteractionTimestamp: number | undefined): boolean {\n const spanData = spanToJSON(activeSpan);\n\n const now = dateTimestampInSeconds();\n\n // More than REDIRECT_THRESHOLD seconds since last navigation/pageload span?\n // --> never consider this a redirect\n const startTimestamp = spanData.start_timestamp;\n if (now - startTimestamp > REDIRECT_THRESHOLD) {\n return false;\n }\n\n // A click happened in the last REDIRECT_THRESHOLD seconds?\n // --> never consider this a redirect\n if (lastInteractionTimestamp && now - lastInteractionTimestamp <= REDIRECT_THRESHOLD) {\n return false;\n }\n\n return true;\n}\n"],"names":["WINDOW","TRACING_DEFAULTS","defaultRequestInstrumentationOptions","consoleSandbox","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","dateTimestampInSeconds","startInactiveSpan","startIdleSpan","hasSpanStreamingEnabled","addPerformanceEntries","getCurrentScope","spanIsSampled","getDynamicSamplingContextFromSpan","DEBUG_BUILD","debug","registerSpanErrorInstrumentation","startTrackingWebVitals","trackLcpAsSpan","trackClsAsSpan","trackInpAsSpan","startTrackingINP","GLOBAL_OBJ","startTrackingLongAnimationFrames","startTrackingLongTasks","startTrackingInteractions","timestampInSeconds","spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON","getClient","getIsolationScope","generateTraceId","hasSpansEnabled","generateSpanId","propagationContextFromHeaders","getHttpRequestData","getLocationHref","linkTraces","browserPerformanceTimeOrigin","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","addHistoryInstrumentationHandler","parseStringToURLObject","registerBackgroundTabDetection","registerInpInteractionListener","instrumentOutgoingRequests","fetchStreamPerformanceIntegration","isRedirect","entry","addNonEnumerableProperty"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"browserTracingIntegration.js","sources":["../../../../../src/tracing/browserTracingIntegration.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport type {\n Client,\n IntegrationFn,\n RequestHookInfo,\n ResponseHookInfo,\n Span,\n StartSpanOptions,\n TransactionSource,\n} from '@sentry/core/browser';\nimport {\n addNonEnumerableProperty,\n browserPerformanceTimeOrigin,\n consoleSandbox,\n dateTimestampInSeconds,\n debug,\n generateSpanId,\n generateTraceId,\n getClient,\n getCurrentScope,\n getDynamicSamplingContextFromSpan,\n getIsolationScope,\n getLocationHref,\n GLOBAL_OBJ,\n hasSpansEnabled,\n hasSpanStreamingEnabled,\n parseStringToURLObject,\n propagationContextFromHeaders,\n registerSpanErrorInstrumentation,\n SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n spanIsSampled,\n spanToJSON,\n startIdleSpan,\n startInactiveSpan,\n timestampInSeconds,\n TRACING_DEFAULTS,\n} from '@sentry/core/browser';\nimport {\n addHistoryInstrumentationHandler,\n addPerformanceEntries,\n startTrackingInteractions,\n startTrackingLongAnimationFrames,\n startTrackingLongTasks,\n} from '@sentry-internal/browser-utils';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { getHttpRequestData, WINDOW } from '../helpers';\nimport { fetchStreamPerformanceIntegration } from '../integrations/fetchStreamPerformance';\nimport { WEB_VITALS_INTEGRATION_NAME, webVitalsIntegration } from '../integrations/webVitals';\nimport { registerBackgroundTabDetection } from './backgroundtab';\nimport { linkTraces } from './linkedTraces';\nimport { defaultRequestInstrumentationOptions, instrumentOutgoingRequests } from './request';\n\nexport const BROWSER_TRACING_INTEGRATION_ID = 'BrowserTracing';\n\n/**\n * We don't want to start a bunch of idle timers and PerformanceObservers\n * for web crawlers, as they may prevent the page from being seen as \"idle\"\n * by the crawler's rendering engine (e.g. Googlebot's headless Chromium).\n */\nconst BOT_USER_AGENT_RE =\n /Googlebot|Google-InspectionTool|Storebot-Google|Bingbot|Slurp|DuckDuckBot|Baiduspider|YandexBot|Facebot|facebookexternalhit|LinkedInBot|Twitterbot|Applebot/i;\n\nexport function isBotUserAgent(): boolean {\n const nav = WINDOW.navigator as Navigator | undefined;\n if (!nav?.userAgent) {\n return false;\n }\n return BOT_USER_AGENT_RE.test(nav.userAgent);\n}\n\ninterface RouteInfo {\n name: string | undefined;\n source: TransactionSource | undefined;\n}\n\n/** Options for Browser Tracing integration */\nexport interface BrowserTracingOptions {\n /**\n * The time that has to pass without any span being created.\n * If this time is exceeded, the idle span will finish.\n *\n * Default: 1000 (ms)\n */\n idleTimeout: number;\n\n /**\n * The max. time an idle span may run.\n * If this time is exceeded, the idle span will finish no matter what.\n *\n * Default: 30000 (ms)\n */\n finalTimeout: number;\n\n /**\n The max. time an idle span may run.\n * If this time is exceeded, the idle span will finish no matter what.\n *\n * Default: 15000 (ms)\n */\n childSpanTimeout: number;\n\n /**\n * If a span should be created on page load.\n * If this is set to `false`, this integration will not start the default page load span.\n * Default: true\n */\n instrumentPageLoad: boolean;\n\n /**\n * If a span should be created on navigation (history change).\n * If this is set to `false`, this integration will not start the default navigation spans.\n * Default: true\n */\n instrumentNavigation: boolean;\n\n /**\n * Flag spans where tabs moved to background with \"cancelled\". Browser background tab timing is\n * not suited towards doing precise measurements of operations. By default, we recommend that this option\n * be enabled as background transactions can mess up your statistics in nondeterministic ways.\n *\n * Default: true\n */\n markBackgroundSpan: boolean;\n\n /**\n * If true, Sentry will capture long tasks and add them to the corresponding transaction.\n *\n * Default: true\n */\n enableLongTask: boolean;\n\n /**\n * If true, Sentry will capture long animation frames and add them to the corresponding transaction.\n *\n * Default: false\n */\n enableLongAnimationFrame: boolean;\n\n /**\n * If true, Sentry will capture first input delay and add it to the corresponding transaction.\n *\n * Default: true\n */\n enableInp: boolean;\n\n /**\n * @deprecated This option is no longer used. Element timing is now tracked via the standalone\n * `elementTimingIntegration`. Add it to your `integrations` array to collect element timing metrics.\n */\n enableElementTiming?: boolean;\n\n /**\n * Flag to disable patching all together for fetch requests.\n *\n * Default: true\n */\n traceFetch: boolean;\n\n /**\n * Flag to disable patching all together for xhr requests.\n *\n * Default: true\n */\n traceXHR: boolean;\n\n /**\n * Flag to disable tracking of long-lived streams, like server-sent events (SSE) via fetch.\n * Do not enable this in case you have live streams or very long running streams.\n *\n * Default: false\n *\n * @deprecated Use `fetchStreamPerformanceIntegration()` instead. Add it to your `integrations` array\n * to track the duration of streamed fetch response bodies.\n */\n trackFetchStreamPerformance: boolean;\n\n /**\n * If true, Sentry will capture http timings and add them to the corresponding http spans.\n *\n * Default: true\n */\n enableHTTPTimings: boolean;\n\n /**\n * Resource spans with `op`s matching strings in the array will not be emitted.\n *\n * Default: []\n */\n ignoreResourceSpans: Array<'resouce.script' | 'resource.css' | 'resource.img' | 'resource.other' | string>;\n\n /**\n * Spans created from the following browser Performance APIs,\n *\n * - [`performance.mark(...)`](https://developer.mozilla.org/en-US/docs/Web/API/Performance/mark)\n * - [`performance.measure(...)`](https://developer.mozilla.org/en-US/docs/Web/API/Performance/measure)\n *\n * will not be emitted if their names match strings in this array.\n *\n * This is useful, if you come across `mark` or `measure` spans in your Sentry traces\n * that you want to ignore. For example, sometimes, browser extensions or libraries\n * emit these entries on their own, which might not be relevant to your application.\n *\n * * @example\n * ```ts\n * Sentry.init({\n * integrations: [\n * Sentry.browserTracingIntegration({\n * ignorePerformanceApiSpans: ['myMeasurement', /myMark/],\n * }),\n * ],\n * });\n *\n * // no spans will be created for these:\n * performance.mark('myMark');\n * performance.measure('myMeasurement');\n *\n * // spans will be created for these:\n * performance.mark('authenticated');\n * performance.measure('input-duration', ...);\n * ```\n *\n * Default: [] - By default, all `mark` and `measure` entries are sent as spans.\n */\n ignorePerformanceApiSpans: Array<string | RegExp>;\n\n /**\n * By default, the SDK will try to detect redirects and avoid creating separate spans for them.\n * If you want to opt-out of this behavior, you can set this option to `false`.\n *\n * Default: true\n */\n detectRedirects: boolean;\n\n /**\n * Link the currently started trace to a previous trace (e.g. a prior pageload, navigation or\n * manually started span). When enabled, this option will allow you to navigate between traces\n * in the Sentry UI.\n *\n * You can set this option to the following values:\n *\n * - `'in-memory'`: The previous trace data will be stored in memory.\n * This is useful for single-page applications and enabled by default.\n *\n * - `'session-storage'`: The previous trace data will be stored in the `sessionStorage`.\n * This is useful for multi-page applications or static sites but it means that the\n * Sentry SDK writes to the browser's `sessionStorage`.\n *\n * - `'off'`: The previous trace data will not be stored or linked.\n *\n * You can also use {@link BrowserTracingOptions.consistentTraceSampling} to get\n * consistent trace sampling of subsequent traces. Otherwise, by default, your\n * `tracesSampleRate` or `tracesSampler` config significantly influences how often\n * traces will be linked.\n *\n * @default 'in-memory' - see explanation above\n */\n linkPreviousTrace: 'in-memory' | 'session-storage' | 'off';\n\n /**\n * If true, Sentry will consistently sample subsequent traces based on the\n * sampling decision of the initial trace. For example, if the initial page\n * load trace was sampled positively, all subsequent traces (e.g. navigations)\n * are also sampled positively. In case the initial trace was sampled negatively,\n * all subsequent traces are also sampled negatively.\n *\n * This option allows you to get consistent, linked traces within a user journey\n * while maintaining an overall quota based on your trace sampling settings.\n *\n * This option is only effective if {@link BrowserTracingOptions.linkPreviousTrace}\n * is enabled (i.e. not set to `'off'`).\n *\n * @default `false` - this is an opt-in feature.\n */\n consistentTraceSampling: boolean;\n\n /**\n * If set to `true`, the pageload span will not end itself automatically, unless it\n * runs until the {@link BrowserTracingOptions.finalTimeout} (30 seconds by default) is reached.\n *\n * Set this option to `true`, if you want full control over the pageload span duration.\n * You can use `Sentry.reportPageLoaded()` to manually end the pageload span whenever convenient.\n * Be aware that you have to ensure that this is always called, regardless of the chosen route\n * or path in the application.\n *\n * @default `false`. By default, the pageload span will end itself automatically, based on\n * the {@link BrowserTracingOptions.finalTimeout}, {@link BrowserTracingOptions.idleTimeout}\n * and {@link BrowserTracingOptions.childSpanTimeout}. This is more convenient to use but means\n * that the pageload duration can be arbitrary and might not be fully representative of a perceived\n * page load time.\n */\n enableReportPageLoaded: boolean;\n\n /**\n * _experiments allows the user to send options to define how this integration works.\n *\n * Default: undefined\n */\n _experiments: Partial<{\n enableInteractions: boolean;\n enableStandaloneClsSpans: boolean;\n enableStandaloneLcpSpans: boolean;\n }>;\n\n /**\n * A callback which is called before a span for a pageload or navigation is started.\n * It receives the options passed to `startSpan`, and expects to return an updated options object.\n */\n beforeStartSpan?: (options: StartSpanOptions) => StartSpanOptions;\n\n /**\n * This function will be called before creating a span for a request with the given url.\n * Return false if you don't want a span for the given url.\n *\n * Default: (url: string) => true\n */\n shouldCreateSpanForRequest?(this: void, url: string): boolean;\n\n /**\n * This callback is invoked directly after a span is started for an outgoing fetch or XHR request.\n * You can use it to annotate the span with additional data or attributes, for example by setting\n * attributes based on the passed request headers.\n */\n onRequestSpanStart?(span: Span, requestInformation: RequestHookInfo): void;\n\n /**\n * Is called when spans end for outgoing requests, providing access to response headers.\n */\n onRequestSpanEnd?(span: Span, responseInformation: ResponseHookInfo): void;\n}\n\nconst DEFAULT_BROWSER_TRACING_OPTIONS: BrowserTracingOptions = {\n ...TRACING_DEFAULTS,\n instrumentNavigation: true,\n instrumentPageLoad: true,\n markBackgroundSpan: true,\n enableLongTask: true,\n enableLongAnimationFrame: true,\n enableInp: true,\n ignoreResourceSpans: [],\n ignorePerformanceApiSpans: [],\n detectRedirects: true,\n linkPreviousTrace: 'in-memory',\n consistentTraceSampling: false,\n enableReportPageLoaded: false,\n _experiments: {},\n ...defaultRequestInstrumentationOptions,\n};\n\n/**\n * The Browser Tracing integration automatically instruments browser pageload/navigation\n * actions as transactions, and captures requests, metrics and errors as spans.\n *\n * The integration can be configured with a variety of options, and can be extended to use\n * any routing library.\n *\n * We explicitly export the proper type here, as this has to be extended in some cases.\n */\nexport const browserTracingIntegration = ((options: Partial<BrowserTracingOptions> = {}) => {\n if ('enableElementTiming' in options) {\n consoleSandbox(() => {\n // oxlint-disable-next-line no-console\n console.warn(\n '[Sentry] `enableElementTiming` is deprecated and no longer has any effect. Use the standalone `elementTimingIntegration` instead.',\n );\n });\n }\n\n const latestRoute: RouteInfo = {\n name: undefined,\n source: undefined,\n };\n\n /**\n * This is just a small wrapper that makes `document` optional.\n * We want to be extra-safe and always check that this exists, to ensure weird environments do not blow up.\n */\n const optionalWindowDocument = WINDOW.document as (typeof WINDOW)['document'] | undefined;\n\n const {\n enableInp,\n enableLongTask,\n enableLongAnimationFrame,\n _experiments: { enableInteractions, enableStandaloneClsSpans, enableStandaloneLcpSpans },\n beforeStartSpan,\n idleTimeout,\n finalTimeout,\n childSpanTimeout,\n markBackgroundSpan,\n traceFetch,\n traceXHR,\n trackFetchStreamPerformance,\n shouldCreateSpanForRequest,\n enableHTTPTimings,\n ignoreResourceSpans,\n ignorePerformanceApiSpans,\n instrumentPageLoad,\n instrumentNavigation,\n detectRedirects,\n linkPreviousTrace,\n consistentTraceSampling,\n enableReportPageLoaded,\n onRequestSpanStart,\n onRequestSpanEnd,\n } = {\n ...DEFAULT_BROWSER_TRACING_OPTIONS,\n ...options,\n };\n\n const _isBot = isBotUserAgent();\n\n let lastInteractionTimestamp: number | undefined;\n\n let _pageloadSpan: Span | undefined;\n\n /** Create routing idle transaction. */\n function _createRouteSpan(client: Client, startSpanOptions: StartSpanOptions, makeActive = true): void {\n const isPageloadSpan = startSpanOptions.op === 'pageload';\n\n const initialSpanName = startSpanOptions.name;\n const finalStartSpanOptions: StartSpanOptions = beforeStartSpan\n ? beforeStartSpan(startSpanOptions)\n : startSpanOptions;\n\n const attributes = finalStartSpanOptions.attributes || {};\n\n // If `finalStartSpanOptions.name` is different than `startSpanOptions.name`\n // it is because `beforeStartSpan` set a custom name. Therefore we set the source to 'custom'.\n if (initialSpanName !== finalStartSpanOptions.name) {\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] = 'custom';\n finalStartSpanOptions.attributes = attributes;\n }\n\n if (!makeActive) {\n // We want to ensure this has 0s duration\n const now = dateTimestampInSeconds();\n startInactiveSpan({\n ...finalStartSpanOptions,\n startTime: now,\n }).end(now);\n return;\n }\n\n latestRoute.name = finalStartSpanOptions.name;\n latestRoute.source = attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];\n\n const idleSpan = startIdleSpan(finalStartSpanOptions, {\n idleTimeout,\n finalTimeout,\n childSpanTimeout,\n // should wait for finish signal if it's a pageload transaction\n disableAutoFinish: isPageloadSpan,\n beforeSpanEnd: span => {\n addPerformanceEntries(span, {\n ignoreResourceSpans,\n ignorePerformanceApiSpans,\n spanStreamingEnabled: hasSpanStreamingEnabled(client),\n });\n setActiveIdleSpan(client, undefined);\n\n // A trace should stay consistent over the entire timespan of one route - even after the pageload/navigation ended.\n // Only when another navigation happens, we want to create a new trace.\n // This way, e.g. errors that occur after the pageload span ended are still associated to the pageload trace.\n const scope = getCurrentScope();\n const oldPropagationContext = scope.getPropagationContext();\n\n scope.setPropagationContext({\n ...oldPropagationContext,\n traceId: idleSpan.spanContext().traceId,\n sampled: spanIsSampled(idleSpan),\n dsc: getDynamicSamplingContextFromSpan(span),\n });\n\n if (isPageloadSpan) {\n // clean up the stored pageload span on the intergration.\n _pageloadSpan = undefined;\n }\n },\n trimIdleSpanEndTimestamp: !enableReportPageLoaded,\n });\n\n if (isPageloadSpan && enableReportPageLoaded) {\n _pageloadSpan = idleSpan;\n }\n\n setActiveIdleSpan(client, idleSpan);\n\n function emitFinish(): void {\n if (optionalWindowDocument && ['interactive', 'complete'].includes(optionalWindowDocument.readyState)) {\n client.emit('idleSpanEnableAutoFinish', idleSpan);\n }\n }\n\n // Enable auto finish of the pageload span if users are not explicitly ending it\n if (isPageloadSpan && !enableReportPageLoaded && optionalWindowDocument) {\n optionalWindowDocument.addEventListener('readystatechange', () => {\n emitFinish();\n });\n\n emitFinish();\n }\n }\n\n return {\n name: BROWSER_TRACING_INTEGRATION_ID,\n setup(client) {\n if (_isBot) {\n DEBUG_BUILD && debug.log('[Tracing] Skipping browserTracingIntegration setup for bot user agent.');\n return;\n }\n\n registerSpanErrorInstrumentation();\n\n if (\n enableLongAnimationFrame &&\n GLOBAL_OBJ.PerformanceObserver &&\n PerformanceObserver.supportedEntryTypes?.includes('long-animation-frame')\n ) {\n startTrackingLongAnimationFrames();\n } else if (enableLongTask) {\n startTrackingLongTasks();\n }\n\n if (enableInteractions) {\n startTrackingInteractions();\n }\n\n if (detectRedirects && optionalWindowDocument) {\n const interactionHandler = (): void => {\n lastInteractionTimestamp = timestampInSeconds();\n };\n addEventListener('click', interactionHandler, { capture: true });\n addEventListener('keydown', interactionHandler, { capture: true, passive: true });\n }\n\n function maybeEndActiveSpan(): void {\n const activeSpan = getActiveIdleSpan(client);\n\n if (activeSpan && !spanToJSON(activeSpan).timestamp) {\n DEBUG_BUILD && debug.log(`[Tracing] Finishing current active span with op: ${spanToJSON(activeSpan).op}`);\n // If there's an open active span, we need to finish it before creating an new one.\n activeSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON, 'cancelled');\n activeSpan.end();\n }\n }\n\n client.on('startNavigationSpan', (startSpanOptions, navigationOptions) => {\n if (getClient() !== client) {\n return;\n }\n\n if (navigationOptions?.isRedirect) {\n DEBUG_BUILD &&\n debug.warn('[Tracing] Detected redirect, navigation span will not be the root span, but a child span.');\n _createRouteSpan(\n client,\n {\n op: 'navigation.redirect',\n ...startSpanOptions,\n },\n false,\n );\n return;\n }\n\n // Reset the last interaction timestamp since we now start a new navigation.\n // Any subsequent navigation span starts could again be a redirect, so we\n // should reset our heuristic detectors.\n lastInteractionTimestamp = undefined;\n\n maybeEndActiveSpan();\n\n getIsolationScope().setPropagationContext({\n traceId: generateTraceId(),\n sampleRand: Math.random(),\n propagationSpanId: hasSpansEnabled() ? undefined : generateSpanId(),\n });\n\n const scope = getCurrentScope();\n scope.setPropagationContext({\n traceId: generateTraceId(),\n sampleRand: Math.random(),\n propagationSpanId: hasSpansEnabled() ? undefined : generateSpanId(),\n });\n\n // We reset this to ensure we do not have lingering incorrect data here\n // places that call this hook may set this where appropriate - else, the URL at span sending time is used\n scope.setSDKProcessingMetadata({\n normalizedRequest: undefined,\n });\n\n _createRouteSpan(client, {\n op: 'navigation',\n ...startSpanOptions,\n // Navigation starts a new trace and is NOT parented under any active interaction (e.g. ui.action.click)\n parentSpan: null,\n forceTransaction: true,\n });\n });\n\n client.on('startPageLoadSpan', (startSpanOptions, traceOptions = {}) => {\n if (getClient() !== client) {\n return;\n }\n maybeEndActiveSpan();\n\n const sentryTrace =\n traceOptions.sentryTrace || getMetaContent('sentry-trace') || getServerTiming('sentry-trace');\n const baggage = traceOptions.baggage || getMetaContent('baggage') || getServerTiming('baggage');\n\n const propagationContext = propagationContextFromHeaders(sentryTrace, baggage);\n\n const scope = getCurrentScope();\n scope.setPropagationContext(propagationContext);\n if (!hasSpansEnabled()) {\n // for browser, we wanna keep the spanIds consistent during the entire lifetime of the trace\n // this works by setting the propagationSpanId to a random spanId so that we have a consistent\n // span id to propagate in TwP mode (!hasSpansEnabled())\n scope.getPropagationContext().propagationSpanId = generateSpanId();\n }\n\n // We store the normalized request data on the scope, so we get the request data at time of span creation\n // otherwise, the URL etc. may already be of the following navigation, and we'd report the wrong URL\n scope.setSDKProcessingMetadata({\n normalizedRequest: getHttpRequestData(),\n });\n\n _createRouteSpan(client, {\n op: 'pageload',\n ...startSpanOptions,\n });\n });\n\n client.on('endPageloadSpan', () => {\n if (enableReportPageLoaded && _pageloadSpan) {\n _pageloadSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON, 'reportPageLoaded');\n _pageloadSpan.end();\n }\n });\n },\n\n afterAllSetup(client) {\n if (_isBot) {\n return;\n }\n\n // Auto-register webVitalsIntegration if the user hasn't added one. We do this in\n // afterAllSetup so that a user-provided webVitalsIntegration - which may be ordered after\n // browserTracingIntegration in the integrations array - has already been installed.\n if (client.addIntegration && !client.getIntegrationByName?.(WEB_VITALS_INTEGRATION_NAME)) {\n client.addIntegration(\n webVitalsIntegration({\n ignore: enableInp ? [] : ['inp'],\n _experiments: {\n enableStandaloneClsSpans,\n enableStandaloneLcpSpans,\n },\n }),\n );\n }\n\n let startingUrl: string | undefined = getLocationHref();\n\n if (linkPreviousTrace !== 'off') {\n linkTraces(client, { linkPreviousTrace, consistentTraceSampling });\n }\n\n if (WINDOW.location) {\n if (instrumentPageLoad) {\n const origin = browserPerformanceTimeOrigin();\n startBrowserTracingPageLoadSpan(client, {\n name: WINDOW.location.pathname,\n // pageload should always start at timeOrigin (and needs to be in s, not ms)\n startTime: origin ? origin / 1000 : undefined,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.browser',\n },\n });\n }\n\n if (instrumentNavigation) {\n addHistoryInstrumentationHandler(({ to, from }) => {\n /**\n * This early return is there to account for some cases where a navigation transaction starts right after\n * long-running pageload. We make sure that if `from` is undefined and a valid `startingURL` exists, we don't\n * create an uneccessary navigation transaction.\n *\n * This was hard to duplicate, but this behavior stopped as soon as this fix was applied. This issue might also\n * only be caused in certain development environments where the usage of a hot module reloader is causing\n * errors.\n */\n if (from === undefined && startingUrl?.indexOf(to) !== -1) {\n startingUrl = undefined;\n return;\n }\n\n startingUrl = undefined;\n const parsed = parseStringToURLObject(to);\n const activeSpan = getActiveIdleSpan(client);\n const navigationIsRedirect =\n activeSpan && detectRedirects && isRedirect(activeSpan, lastInteractionTimestamp);\n\n startBrowserTracingNavigationSpan(\n client,\n {\n name: parsed?.pathname || WINDOW.location.pathname,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.browser',\n },\n },\n { url: to, isRedirect: navigationIsRedirect },\n );\n });\n }\n }\n\n if (markBackgroundSpan) {\n registerBackgroundTabDetection();\n }\n\n if (enableInteractions) {\n registerInteractionListener(client, idleTimeout, finalTimeout, childSpanTimeout, latestRoute);\n }\n\n instrumentOutgoingRequests(client, {\n traceFetch,\n traceXHR,\n tracePropagationTargets: client.getOptions().tracePropagationTargets,\n shouldCreateSpanForRequest,\n enableHTTPTimings,\n onRequestSpanStart,\n onRequestSpanEnd,\n });\n\n if (trackFetchStreamPerformance) {\n client.addIntegration(fetchStreamPerformanceIntegration());\n }\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Manually start a page load span.\n * This will only do something if a browser tracing integration integration has been setup.\n *\n * If you provide a custom `traceOptions` object, it will be used to continue the trace\n * instead of the default behavior, which is to look it up on the <meta> tags.\n */\nexport function startBrowserTracingPageLoadSpan(\n client: Client,\n spanOptions: StartSpanOptions,\n traceOptions?: { sentryTrace?: string | undefined; baggage?: string | undefined },\n): Span | undefined {\n client.emit('startPageLoadSpan', spanOptions, traceOptions);\n getCurrentScope().setTransactionName(spanOptions.name);\n\n const pageloadSpan = getActiveIdleSpan(client);\n\n if (pageloadSpan) {\n client.emit('afterStartPageLoadSpan', pageloadSpan);\n }\n\n return pageloadSpan;\n}\n\n/**\n * Manually start a navigation span.\n * This will only do something if a browser tracing integration has been setup.\n */\nexport function startBrowserTracingNavigationSpan(\n client: Client,\n spanOptions: StartSpanOptions,\n options?: { url?: string; isRedirect?: boolean },\n): Span | undefined {\n const { url, isRedirect } = options || {};\n client.emit('beforeStartNavigationSpan', spanOptions, { isRedirect });\n client.emit('startNavigationSpan', spanOptions, { isRedirect });\n\n const scope = getCurrentScope();\n scope.setTransactionName(spanOptions.name);\n\n // We store the normalized request data on the scope, so we get the request data at time of span creation\n // otherwise, the URL etc. may already be of the following navigation, and we'd report the wrong URL\n if (url && !isRedirect) {\n scope.setSDKProcessingMetadata({\n normalizedRequest: {\n ...getHttpRequestData(),\n url,\n },\n });\n }\n\n return getActiveIdleSpan(client);\n}\n\n/** Returns the value of a meta tag */\nexport function getMetaContent(metaName: string): string | undefined {\n /**\n * This is just a small wrapper that makes `document` optional.\n * We want to be extra-safe and always check that this exists, to ensure weird environments do not blow up.\n */\n const optionalWindowDocument = WINDOW.document as (typeof WINDOW)['document'] | undefined;\n\n const metaTag = optionalWindowDocument?.querySelector(`meta[name=${metaName}]`);\n return metaTag?.getAttribute('content') || undefined;\n}\n\n/** Returns the description of a server timing entry */\nexport function getServerTiming(name: string): string | undefined {\n const navigation = WINDOW.performance?.getEntriesByType?.('navigation')[0] as PerformanceNavigationTiming | undefined;\n const entry = navigation?.serverTiming?.find(entry => entry.name === name);\n return entry?.description;\n}\n\n/** Start listener for interaction transactions */\nfunction registerInteractionListener(\n client: Client,\n idleTimeout: BrowserTracingOptions['idleTimeout'],\n finalTimeout: BrowserTracingOptions['finalTimeout'],\n childSpanTimeout: BrowserTracingOptions['childSpanTimeout'],\n latestRoute: RouteInfo,\n): void {\n /**\n * This is just a small wrapper that makes `document` optional.\n * We want to be extra-safe and always check that this exists, to ensure weird environments do not blow up.\n */\n const optionalWindowDocument = WINDOW.document as (typeof WINDOW)['document'] | undefined;\n\n let inflightInteractionSpan: Span | undefined;\n const registerInteractionTransaction = (): void => {\n const op = 'ui.action.click';\n\n const activeIdleSpan = getActiveIdleSpan(client);\n if (activeIdleSpan) {\n const currentRootSpanOp = spanToJSON(activeIdleSpan).op;\n if (['navigation', 'pageload'].includes(currentRootSpanOp as string)) {\n DEBUG_BUILD &&\n debug.warn(`[Tracing] Did not create ${op} span because a pageload or navigation span is in progress.`);\n return undefined;\n }\n }\n\n if (inflightInteractionSpan) {\n inflightInteractionSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON, 'interactionInterrupted');\n inflightInteractionSpan.end();\n inflightInteractionSpan = undefined;\n }\n\n if (!latestRoute.name) {\n DEBUG_BUILD && debug.warn(`[Tracing] Did not create ${op} transaction because _latestRouteName is missing.`);\n return undefined;\n }\n\n inflightInteractionSpan = startIdleSpan(\n {\n name: latestRoute.name,\n op,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: latestRoute.source || 'url',\n },\n },\n {\n idleTimeout,\n finalTimeout,\n childSpanTimeout,\n },\n );\n };\n\n if (optionalWindowDocument) {\n addEventListener('click', registerInteractionTransaction, { capture: true });\n }\n}\n\n// We store the active idle span on the client object, so we can access it from exported functions\nconst ACTIVE_IDLE_SPAN_PROPERTY = '_sentry_idleSpan';\nfunction getActiveIdleSpan(client: Client): Span | undefined {\n return (client as { [ACTIVE_IDLE_SPAN_PROPERTY]?: Span })[ACTIVE_IDLE_SPAN_PROPERTY];\n}\n\nfunction setActiveIdleSpan(client: Client, span: Span | undefined): void {\n addNonEnumerableProperty(client, ACTIVE_IDLE_SPAN_PROPERTY, span);\n}\n\n// The max. time in seconds between two pageload/navigation spans that makes us consider the second one a redirect\nconst REDIRECT_THRESHOLD = 1.5;\n\nfunction isRedirect(activeSpan: Span, lastInteractionTimestamp: number | undefined): boolean {\n const spanData = spanToJSON(activeSpan);\n\n const now = dateTimestampInSeconds();\n\n // More than REDIRECT_THRESHOLD seconds since last navigation/pageload span?\n // --> never consider this a redirect\n const startTimestamp = spanData.start_timestamp;\n if (now - startTimestamp > REDIRECT_THRESHOLD) {\n return false;\n }\n\n // A click happened in the last REDIRECT_THRESHOLD seconds?\n // --> never consider this a redirect\n if (lastInteractionTimestamp && now - lastInteractionTimestamp <= REDIRECT_THRESHOLD) {\n return false;\n }\n\n return true;\n}\n"],"names":["WINDOW","TRACING_DEFAULTS","defaultRequestInstrumentationOptions","consoleSandbox","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","dateTimestampInSeconds","startInactiveSpan","startIdleSpan","addPerformanceEntries","hasSpanStreamingEnabled","getCurrentScope","spanIsSampled","getDynamicSamplingContextFromSpan","DEBUG_BUILD","debug","registerSpanErrorInstrumentation","GLOBAL_OBJ","startTrackingLongAnimationFrames","startTrackingLongTasks","startTrackingInteractions","timestampInSeconds","spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_IDLE_SPAN_FINISH_REASON","getClient","getIsolationScope","generateTraceId","hasSpansEnabled","generateSpanId","propagationContextFromHeaders","getHttpRequestData","WEB_VITALS_INTEGRATION_NAME","webVitalsIntegration","getLocationHref","linkTraces","browserPerformanceTimeOrigin","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","addHistoryInstrumentationHandler","parseStringToURLObject","registerBackgroundTabDetection","instrumentOutgoingRequests","fetchStreamPerformanceIntegration","isRedirect","entry","addNonEnumerableProperty"],"mappings":"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"}
|
|
@@ -66,7 +66,10 @@ function addPreviousTraceSpanLink(previousTraceInfo, span, oldPropagationContext
|
|
|
66
66
|
const spanJson = browser.spanToJSON(span);
|
|
67
67
|
function getSampleRate() {
|
|
68
68
|
try {
|
|
69
|
-
|
|
69
|
+
const oldSampleRate = Number(
|
|
70
|
+
spanJson.data?.[browser.SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE] ?? oldPropagationContext.dsc?.sample_rate
|
|
71
|
+
);
|
|
72
|
+
return Number.isNaN(oldSampleRate) ? 0 : oldSampleRate;
|
|
70
73
|
} catch {
|
|
71
74
|
return 0;
|
|
72
75
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"linkedTraces.js","sources":["../../../../../src/tracing/linkedTraces.ts"],"sourcesContent":["import type { Client, PropagationContext, Span, SpanContextData } from '@sentry/core/browser';\nimport {\n debug,\n getCurrentScope,\n getRootSpan,\n SEMANTIC_ATTRIBUTE_SENTRY_PREVIOUS_TRACE_SAMPLE_RATE,\n SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE,\n SEMANTIC_LINK_ATTRIBUTE_LINK_TYPE,\n spanToJSON,\n} from '@sentry/core/browser';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { WINDOW } from '../exports';\n\nexport interface PreviousTraceInfo {\n /**\n * Span context of the previous trace's local root span\n */\n spanContext: SpanContextData;\n\n /**\n * Timestamp in seconds when the previous trace was started\n */\n startTimestamp: number;\n\n /**\n * sample rate of the previous trace\n */\n sampleRate: number;\n\n /**\n * The sample rand of the previous trace\n */\n sampleRand: number;\n}\n\n// 1h in seconds\nexport const PREVIOUS_TRACE_MAX_DURATION = 3600;\n\n// session storage key\nexport const PREVIOUS_TRACE_KEY = 'sentry_previous_trace';\n\nexport const PREVIOUS_TRACE_TMP_SPAN_ATTRIBUTE = 'sentry.previous_trace';\n\n/**\n * Takes care of linking traces and applying the (consistent) sampling behavoiour based on the passed options\n * @param options - options for linking traces and consistent trace sampling (@see BrowserTracingOptions)\n * @param client - Sentry client\n */\nexport function linkTraces(\n client: Client,\n {\n linkPreviousTrace,\n consistentTraceSampling,\n }: {\n linkPreviousTrace: 'session-storage' | 'in-memory';\n consistentTraceSampling: boolean;\n },\n): void {\n const useSessionStorage = linkPreviousTrace === 'session-storage';\n\n let inMemoryPreviousTraceInfo = useSessionStorage ? getPreviousTraceFromSessionStorage() : undefined;\n\n client.on('spanStart', span => {\n if (getRootSpan(span) !== span) {\n return;\n }\n\n const oldPropagationContext = getCurrentScope().getPropagationContext();\n inMemoryPreviousTraceInfo = addPreviousTraceSpanLink(inMemoryPreviousTraceInfo, span, oldPropagationContext);\n\n if (useSessionStorage) {\n storePreviousTraceInSessionStorage(inMemoryPreviousTraceInfo);\n }\n });\n\n let isFirstTraceOnPageload = true;\n if (consistentTraceSampling) {\n /*\n When users opt into `consistentTraceSampling`, we need to ensure that we propagate\n the previous trace's sample rate and rand to the current trace. This is necessary because otherwise, span\n metric extrapolation is inaccurate, as we'd propagate too high of a sample rate for the subsequent traces.\n\n So therefore, we pretend that the previous trace was the parent trace of the newly started trace. To do that,\n we mutate the propagation context of the current trace and set the sample rate and sample rand of the previous trace.\n Timing-wise, it is fine because it happens before we even sample the root span.\n\n @see https://github.com/getsentry/sentry-javascript/issues/15754\n */\n client.on('beforeSampling', mutableSamplingContextData => {\n if (!inMemoryPreviousTraceInfo) {\n return;\n }\n\n const scope = getCurrentScope();\n const currentPropagationContext = scope.getPropagationContext();\n\n // We do not want to force-continue the sampling decision if we continue a trace\n // that was started on the backend. Most prominently, this will happen in MPAs where\n // users hard-navigate between pages. In this case, the sampling decision of a potentially\n // started trace on the server takes precedence.\n // Why? We want to prioritize inter-trace consistency over intra-trace consistency.\n if (isFirstTraceOnPageload && currentPropagationContext.parentSpanId) {\n isFirstTraceOnPageload = false;\n return;\n }\n\n scope.setPropagationContext({\n ...currentPropagationContext,\n dsc: {\n ...currentPropagationContext.dsc,\n sample_rate: String(inMemoryPreviousTraceInfo.sampleRate),\n sampled: String(spanContextSampled(inMemoryPreviousTraceInfo.spanContext)),\n },\n sampleRand: inMemoryPreviousTraceInfo.sampleRand,\n });\n\n mutableSamplingContextData.parentSampled = spanContextSampled(inMemoryPreviousTraceInfo.spanContext);\n mutableSamplingContextData.parentSampleRate = inMemoryPreviousTraceInfo.sampleRate;\n\n mutableSamplingContextData.spanAttributes = {\n ...mutableSamplingContextData.spanAttributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_PREVIOUS_TRACE_SAMPLE_RATE]: inMemoryPreviousTraceInfo.sampleRate,\n };\n });\n }\n}\n\n/**\n * Adds a previous_trace span link to the passed span if the passed\n * previousTraceInfo is still valid.\n *\n * @returns the updated previous trace info (based on the current span/trace) to\n * be used on the next call\n */\nexport function addPreviousTraceSpanLink(\n previousTraceInfo: PreviousTraceInfo | undefined,\n span: Span,\n oldPropagationContext: PropagationContext,\n): PreviousTraceInfo {\n const spanJson = spanToJSON(span);\n\n function getSampleRate(): number {\n try {\n return (\n Number(oldPropagationContext.dsc?.sample_rate) ?? Number(spanJson.data?.[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE])\n );\n } catch {\n return 0;\n }\n }\n\n const updatedPreviousTraceInfo = {\n spanContext: span.spanContext(),\n startTimestamp: spanJson.start_timestamp,\n sampleRate: getSampleRate(),\n sampleRand: oldPropagationContext.sampleRand,\n };\n\n if (!previousTraceInfo) {\n return updatedPreviousTraceInfo;\n }\n\n const previousTraceSpanCtx = previousTraceInfo.spanContext;\n if (previousTraceSpanCtx.traceId === spanJson.trace_id) {\n // This means, we're still in the same trace so let's not update the previous trace info\n // or add a link to the current span.\n // Once we move away from the long-lived, route-based trace model, we can remove this cases\n return previousTraceInfo;\n }\n\n // Only add the link if the startTimeStamp of the previous trace's root span is within\n // PREVIOUS_TRACE_MAX_DURATION (1h) of the current root span's startTimestamp\n // This is done to\n // - avoid adding links to \"stale\" traces\n // - enable more efficient querying for previous/next traces in Sentry\n if (Date.now() / 1000 - previousTraceInfo.startTimestamp <= PREVIOUS_TRACE_MAX_DURATION) {\n if (DEBUG_BUILD) {\n debug.log(\n `Adding previous_trace \\`${JSON.stringify(previousTraceSpanCtx)}\\` link to span \\`${JSON.stringify({\n op: spanJson.op,\n ...span.spanContext(),\n })}\\``,\n );\n }\n\n span.addLink({\n context: previousTraceSpanCtx,\n attributes: {\n [SEMANTIC_LINK_ATTRIBUTE_LINK_TYPE]: 'previous_trace',\n },\n });\n\n // TODO: Remove this once EAP can store span links. We currently only set this attribute so that we\n // can obtain the previous trace information from the EAP store. Long-term, EAP will handle\n // span links and then we should remove this again. Also throwing in a TODO(v11), to remind us\n // to check this at v11 time :)\n span.setAttribute(\n PREVIOUS_TRACE_TMP_SPAN_ATTRIBUTE,\n `${previousTraceSpanCtx.traceId}-${previousTraceSpanCtx.spanId}-${\n spanContextSampled(previousTraceSpanCtx) ? 1 : 0\n }`,\n );\n }\n\n return updatedPreviousTraceInfo;\n}\n\n/**\n * Stores @param previousTraceInfo in sessionStorage.\n */\nexport function storePreviousTraceInSessionStorage(previousTraceInfo: PreviousTraceInfo): void {\n try {\n WINDOW.sessionStorage.setItem(PREVIOUS_TRACE_KEY, JSON.stringify(previousTraceInfo));\n } catch (e) {\n // Ignore potential errors (e.g. if sessionStorage is not available)\n DEBUG_BUILD && debug.warn('Could not store previous trace in sessionStorage', e);\n }\n}\n\n/**\n * Retrieves the previous trace from sessionStorage if available.\n */\nexport function getPreviousTraceFromSessionStorage(): PreviousTraceInfo | undefined {\n try {\n const previousTraceInfo = WINDOW.sessionStorage?.getItem(PREVIOUS_TRACE_KEY);\n // @ts-expect-error - intentionally risking JSON.parse throwing when previousTraceInfo is null to save bundle size\n return JSON.parse(previousTraceInfo);\n } catch {\n return undefined;\n }\n}\n\n/**\n * see {@link import('@sentry/core/browser').spanIsSampled}\n */\nexport function spanContextSampled(ctx: SpanContextData): boolean {\n return ctx.traceFlags === 0x1;\n}\n"],"names":["getRootSpan","getCurrentScope","SEMANTIC_ATTRIBUTE_SENTRY_PREVIOUS_TRACE_SAMPLE_RATE","spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE","DEBUG_BUILD","debug","SEMANTIC_LINK_ATTRIBUTE_LINK_TYPE","WINDOW"],"mappings":";;;;;;;;;;;;;;;AAoCO,MAAM,2BAAA,GAA8B;AAGpC,MAAM,kBAAA,GAAqB;AAE3B,MAAM,iCAAA,GAAoC;AAO1C,SAAS,WACd,MAAA,EACA;AAAA,EACE,iBAAA;AAAA,EACA;AACF,CAAA,EAIM;AACN,EAAA,MAAM,oBAAoB,iBAAA,KAAsB,iBAAA;AAEhD,EAAA,IAAI,yBAAA,GAA4B,iBAAA,GAAoB,kCAAA,EAAmC,GAAI,MAAA;AAE3F,EAAA,MAAA,CAAO,EAAA,CAAG,aAAa,CAAA,IAAA,KAAQ;AAC7B,IAAA,IAAIA,mBAAA,CAAY,IAAI,CAAA,KAAM,IAAA,EAAM;AAC9B,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,qBAAA,GAAwBC,uBAAA,EAAgB,CAAE,qBAAA,EAAsB;AACtE,IAAA,yBAAA,GAA4B,wBAAA,CAAyB,yBAAA,EAA2B,IAAA,EAAM,qBAAqB,CAAA;AAE3G,IAAA,IAAI,iBAAA,EAAmB;AACrB,MAAA,kCAAA,CAAmC,yBAAyB,CAAA;AAAA,IAC9D;AAAA,EACF,CAAC,CAAA;AAED,EAAA,IAAI,sBAAA,GAAyB,IAAA;AAC7B,EAAA,IAAI,uBAAA,EAAyB;AAY3B,IAAA,MAAA,CAAO,EAAA,CAAG,kBAAkB,CAAA,0BAAA,KAA8B;AACxD,MAAA,IAAI,CAAC,yBAAA,EAA2B;AAC9B,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,QAAQA,uBAAA,EAAgB;AAC9B,MAAA,MAAM,yBAAA,GAA4B,MAAM,qBAAA,EAAsB;AAO9D,MAAA,IAAI,sBAAA,IAA0B,0BAA0B,YAAA,EAAc;AACpE,QAAA,sBAAA,GAAyB,KAAA;AACzB,QAAA;AAAA,MACF;AAEA,MAAA,KAAA,CAAM,qBAAA,CAAsB;AAAA,QAC1B,GAAG,yBAAA;AAAA,QACH,GAAA,EAAK;AAAA,UACH,GAAG,yBAAA,CAA0B,GAAA;AAAA,UAC7B,WAAA,EAAa,MAAA,CAAO,yBAAA,CAA0B,UAAU,CAAA;AAAA,UACxD,OAAA,EAAS,MAAA,CAAO,kBAAA,CAAmB,yBAAA,CAA0B,WAAW,CAAC;AAAA,SAC3E;AAAA,QACA,YAAY,yBAAA,CAA0B;AAAA,OACvC,CAAA;AAED,MAAA,0BAAA,CAA2B,aAAA,GAAgB,kBAAA,CAAmB,yBAAA,CAA0B,WAAW,CAAA;AACnG,MAAA,0BAAA,CAA2B,mBAAmB,yBAAA,CAA0B,UAAA;AAExE,MAAA,0BAAA,CAA2B,cAAA,GAAiB;AAAA,QAC1C,GAAG,0BAAA,CAA2B,cAAA;AAAA,QAC9B,CAACC,4DAAoD,GAAG,yBAAA,CAA0B;AAAA,OACpF;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AACF;AASO,SAAS,wBAAA,CACd,iBAAA,EACA,IAAA,EACA,qBAAA,EACmB;AACnB,EAAA,MAAM,QAAA,GAAWC,mBAAW,IAAI,CAAA;AAEhC,EAAA,SAAS,aAAA,GAAwB;AAC/B,IAAA,IAAI;AACF,MAAA,OACE,MAAA,CAAO,sBAAsB,GAAA,EAAK,WAAW,KAAK,MAAA,CAAO,QAAA,CAAS,IAAA,GAAOC,6CAAqC,CAAC,CAAA;AAAA,IAEnH,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,CAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,MAAM,wBAAA,GAA2B;AAAA,IAC/B,WAAA,EAAa,KAAK,WAAA,EAAY;AAAA,IAC9B,gBAAgB,QAAA,CAAS,eAAA;AAAA,IACzB,YAAY,aAAA,EAAc;AAAA,IAC1B,YAAY,qBAAA,CAAsB;AAAA,GACpC;AAEA,EAAA,IAAI,CAAC,iBAAA,EAAmB;AACtB,IAAA,OAAO,wBAAA;AAAA,EACT;AAEA,EAAA,MAAM,uBAAuB,iBAAA,CAAkB,WAAA;AAC/C,EAAA,IAAI,oBAAA,CAAqB,OAAA,KAAY,QAAA,CAAS,QAAA,EAAU;AAItD,IAAA,OAAO,iBAAA;AAAA,EACT;AAOA,EAAA,IAAI,KAAK,GAAA,EAAI,GAAI,GAAA,GAAO,iBAAA,CAAkB,kBAAkB,2BAAA,EAA6B;AACvF,IAAA,IAAIC,sBAAA,EAAa;AACf,MAAAC,aAAA,CAAM,GAAA;AAAA,QACJ,2BAA2B,IAAA,CAAK,SAAA,CAAU,oBAAoB,CAAC,CAAA,kBAAA,EAAqB,KAAK,SAAA,CAAU;AAAA,UACjG,IAAI,QAAA,CAAS,EAAA;AAAA,UACb,GAAG,KAAK,WAAA;AAAY,SACrB,CAAC,CAAA,EAAA;AAAA,OACJ;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,OAAA,CAAQ;AAAA,MACX,OAAA,EAAS,oBAAA;AAAA,MACT,UAAA,EAAY;AAAA,QACV,CAACC,yCAAiC,GAAG;AAAA;AACvC,KACD,CAAA;AAMD,IAAA,IAAA,CAAK,YAAA;AAAA,MACH,iCAAA;AAAA,MACA,CAAA,EAAG,oBAAA,CAAqB,OAAO,CAAA,CAAA,EAAI,oBAAA,CAAqB,MAAM,CAAA,CAAA,EAC5D,kBAAA,CAAmB,oBAAoB,CAAA,GAAI,CAAA,GAAI,CACjD,CAAA;AAAA,KACF;AAAA,EACF;AAEA,EAAA,OAAO,wBAAA;AACT;AAKO,SAAS,mCAAmC,iBAAA,EAA4C;AAC7F,EAAA,IAAI;AACF,IAAAC,cAAA,CAAO,eAAe,OAAA,CAAQ,kBAAA,EAAoB,IAAA,CAAK,SAAA,CAAU,iBAAiB,CAAC,CAAA;AAAA,EACrF,SAAS,CAAA,EAAG;AAEV,IAAAH,sBAAA,IAAeC,aAAA,CAAM,IAAA,CAAK,kDAAA,EAAoD,CAAC,CAAA;AAAA,EACjF;AACF;AAKO,SAAS,kCAAA,GAAoE;AAClF,EAAA,IAAI;AACF,IAAA,MAAM,iBAAA,GAAoBE,cAAA,CAAO,cAAA,EAAgB,OAAA,CAAQ,kBAAkB,CAAA;AAE3E,IAAA,OAAO,IAAA,CAAK,MAAM,iBAAiB,CAAA;AAAA,EACrC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAKO,SAAS,mBAAmB,GAAA,EAA+B;AAChE,EAAA,OAAO,IAAI,UAAA,KAAe,CAAA;AAC5B;;;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"linkedTraces.js","sources":["../../../../../src/tracing/linkedTraces.ts"],"sourcesContent":["import type { Client, PropagationContext, Span, SpanContextData } from '@sentry/core/browser';\nimport {\n debug,\n getCurrentScope,\n getRootSpan,\n SEMANTIC_ATTRIBUTE_SENTRY_PREVIOUS_TRACE_SAMPLE_RATE,\n SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE,\n SEMANTIC_LINK_ATTRIBUTE_LINK_TYPE,\n spanToJSON,\n} from '@sentry/core/browser';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { WINDOW } from '../exports';\n\nexport interface PreviousTraceInfo {\n /**\n * Span context of the previous trace's local root span\n */\n spanContext: SpanContextData;\n\n /**\n * Timestamp in seconds when the previous trace was started\n */\n startTimestamp: number;\n\n /**\n * sample rate of the previous trace\n */\n sampleRate: number;\n\n /**\n * The sample rand of the previous trace\n */\n sampleRand: number;\n}\n\n// 1h in seconds\nexport const PREVIOUS_TRACE_MAX_DURATION = 3600;\n\n// session storage key\nexport const PREVIOUS_TRACE_KEY = 'sentry_previous_trace';\n\nexport const PREVIOUS_TRACE_TMP_SPAN_ATTRIBUTE = 'sentry.previous_trace';\n\n/**\n * Takes care of linking traces and applying the (consistent) sampling behavoiour based on the passed options\n * @param options - options for linking traces and consistent trace sampling (@see BrowserTracingOptions)\n * @param client - Sentry client\n */\nexport function linkTraces(\n client: Client,\n {\n linkPreviousTrace,\n consistentTraceSampling,\n }: {\n linkPreviousTrace: 'session-storage' | 'in-memory';\n consistentTraceSampling: boolean;\n },\n): void {\n const useSessionStorage = linkPreviousTrace === 'session-storage';\n\n let inMemoryPreviousTraceInfo = useSessionStorage ? getPreviousTraceFromSessionStorage() : undefined;\n\n client.on('spanStart', span => {\n if (getRootSpan(span) !== span) {\n return;\n }\n\n const oldPropagationContext = getCurrentScope().getPropagationContext();\n inMemoryPreviousTraceInfo = addPreviousTraceSpanLink(inMemoryPreviousTraceInfo, span, oldPropagationContext);\n\n if (useSessionStorage) {\n storePreviousTraceInSessionStorage(inMemoryPreviousTraceInfo);\n }\n });\n\n let isFirstTraceOnPageload = true;\n if (consistentTraceSampling) {\n /*\n When users opt into `consistentTraceSampling`, we need to ensure that we propagate\n the previous trace's sample rate and rand to the current trace. This is necessary because otherwise, span\n metric extrapolation is inaccurate, as we'd propagate too high of a sample rate for the subsequent traces.\n\n So therefore, we pretend that the previous trace was the parent trace of the newly started trace. To do that,\n we mutate the propagation context of the current trace and set the sample rate and sample rand of the previous trace.\n Timing-wise, it is fine because it happens before we even sample the root span.\n\n @see https://github.com/getsentry/sentry-javascript/issues/15754\n */\n client.on('beforeSampling', mutableSamplingContextData => {\n if (!inMemoryPreviousTraceInfo) {\n return;\n }\n\n const scope = getCurrentScope();\n const currentPropagationContext = scope.getPropagationContext();\n\n // We do not want to force-continue the sampling decision if we continue a trace\n // that was started on the backend. Most prominently, this will happen in MPAs where\n // users hard-navigate between pages. In this case, the sampling decision of a potentially\n // started trace on the server takes precedence.\n // Why? We want to prioritize inter-trace consistency over intra-trace consistency.\n if (isFirstTraceOnPageload && currentPropagationContext.parentSpanId) {\n isFirstTraceOnPageload = false;\n return;\n }\n\n scope.setPropagationContext({\n ...currentPropagationContext,\n dsc: {\n ...currentPropagationContext.dsc,\n sample_rate: String(inMemoryPreviousTraceInfo.sampleRate),\n sampled: String(spanContextSampled(inMemoryPreviousTraceInfo.spanContext)),\n },\n sampleRand: inMemoryPreviousTraceInfo.sampleRand,\n });\n\n mutableSamplingContextData.parentSampled = spanContextSampled(inMemoryPreviousTraceInfo.spanContext);\n mutableSamplingContextData.parentSampleRate = inMemoryPreviousTraceInfo.sampleRate;\n\n mutableSamplingContextData.spanAttributes = {\n ...mutableSamplingContextData.spanAttributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_PREVIOUS_TRACE_SAMPLE_RATE]: inMemoryPreviousTraceInfo.sampleRate,\n };\n });\n }\n}\n\n/**\n * Adds a previous_trace span link to the passed span if the passed\n * previousTraceInfo is still valid.\n *\n * @returns the updated previous trace info (based on the current span/trace) to\n * be used on the next call\n */\nexport function addPreviousTraceSpanLink(\n previousTraceInfo: PreviousTraceInfo | undefined,\n span: Span,\n oldPropagationContext: PropagationContext,\n): PreviousTraceInfo {\n const spanJson = spanToJSON(span);\n\n function getSampleRate(): number {\n try {\n const oldSampleRate = Number(\n spanJson.data?.[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE] ?? oldPropagationContext.dsc?.sample_rate,\n );\n return Number.isNaN(oldSampleRate) ? 0 : oldSampleRate;\n } catch {\n return 0;\n }\n }\n\n const updatedPreviousTraceInfo = {\n spanContext: span.spanContext(),\n startTimestamp: spanJson.start_timestamp,\n sampleRate: getSampleRate(),\n sampleRand: oldPropagationContext.sampleRand,\n };\n\n if (!previousTraceInfo) {\n return updatedPreviousTraceInfo;\n }\n\n const previousTraceSpanCtx = previousTraceInfo.spanContext;\n if (previousTraceSpanCtx.traceId === spanJson.trace_id) {\n // This means, we're still in the same trace so let's not update the previous trace info\n // or add a link to the current span.\n // Once we move away from the long-lived, route-based trace model, we can remove this cases\n return previousTraceInfo;\n }\n\n // Only add the link if the startTimeStamp of the previous trace's root span is within\n // PREVIOUS_TRACE_MAX_DURATION (1h) of the current root span's startTimestamp\n // This is done to\n // - avoid adding links to \"stale\" traces\n // - enable more efficient querying for previous/next traces in Sentry\n if (Date.now() / 1000 - previousTraceInfo.startTimestamp <= PREVIOUS_TRACE_MAX_DURATION) {\n if (DEBUG_BUILD) {\n debug.log(\n `Adding previous_trace \\`${JSON.stringify(previousTraceSpanCtx)}\\` link to span \\`${JSON.stringify({\n op: spanJson.op,\n ...span.spanContext(),\n })}\\``,\n );\n }\n\n span.addLink({\n context: previousTraceSpanCtx,\n attributes: {\n [SEMANTIC_LINK_ATTRIBUTE_LINK_TYPE]: 'previous_trace',\n },\n });\n\n // TODO: Remove this once EAP can store span links. We currently only set this attribute so that we\n // can obtain the previous trace information from the EAP store. Long-term, EAP will handle\n // span links and then we should remove this again. Also throwing in a TODO(v11), to remind us\n // to check this at v11 time :)\n span.setAttribute(\n PREVIOUS_TRACE_TMP_SPAN_ATTRIBUTE,\n `${previousTraceSpanCtx.traceId}-${previousTraceSpanCtx.spanId}-${\n spanContextSampled(previousTraceSpanCtx) ? 1 : 0\n }`,\n );\n }\n\n return updatedPreviousTraceInfo;\n}\n\n/**\n * Stores @param previousTraceInfo in sessionStorage.\n */\nexport function storePreviousTraceInSessionStorage(previousTraceInfo: PreviousTraceInfo): void {\n try {\n WINDOW.sessionStorage.setItem(PREVIOUS_TRACE_KEY, JSON.stringify(previousTraceInfo));\n } catch (e) {\n // Ignore potential errors (e.g. if sessionStorage is not available)\n DEBUG_BUILD && debug.warn('Could not store previous trace in sessionStorage', e);\n }\n}\n\n/**\n * Retrieves the previous trace from sessionStorage if available.\n */\nexport function getPreviousTraceFromSessionStorage(): PreviousTraceInfo | undefined {\n try {\n const previousTraceInfo = WINDOW.sessionStorage?.getItem(PREVIOUS_TRACE_KEY);\n // @ts-expect-error - intentionally risking JSON.parse throwing when previousTraceInfo is null to save bundle size\n return JSON.parse(previousTraceInfo);\n } catch {\n return undefined;\n }\n}\n\n/**\n * see {@link import('@sentry/core/browser').spanIsSampled}\n */\nexport function spanContextSampled(ctx: SpanContextData): boolean {\n return ctx.traceFlags === 0x1;\n}\n"],"names":["getRootSpan","getCurrentScope","SEMANTIC_ATTRIBUTE_SENTRY_PREVIOUS_TRACE_SAMPLE_RATE","spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE","DEBUG_BUILD","debug","SEMANTIC_LINK_ATTRIBUTE_LINK_TYPE","WINDOW"],"mappings":"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"}
|
|
@@ -12,21 +12,17 @@ class BrowserClient extends Client {
|
|
|
12
12
|
const opts = applyDefaultOptions(options);
|
|
13
13
|
const sdkSource = WINDOW.SENTRY_SDK_SOURCE || getSDKSource();
|
|
14
14
|
applySdkMetadata(opts, "browser", ["browser"], sdkSource);
|
|
15
|
+
super(opts);
|
|
16
|
+
const { userInfo } = this.getDataCollectionOptions();
|
|
15
17
|
if (opts._metadata?.sdk) {
|
|
16
18
|
opts._metadata.sdk.settings = {
|
|
17
|
-
|
|
19
|
+
// Only allow IP inferral by Relay if the user opted in via dataCollection
|
|
20
|
+
infer_ip: userInfo ? "auto" : "never",
|
|
18
21
|
// purposefully allowing already passed settings to override the default
|
|
19
22
|
...opts._metadata.sdk.settings
|
|
20
23
|
};
|
|
21
24
|
}
|
|
22
|
-
|
|
23
|
-
const {
|
|
24
|
-
sendDefaultPii,
|
|
25
|
-
sendClientReports,
|
|
26
|
-
enableLogs,
|
|
27
|
-
_experiments,
|
|
28
|
-
enableMetrics: enableMetricsOption
|
|
29
|
-
} = this._options;
|
|
25
|
+
const { sendClientReports, enableLogs, _experiments, enableMetrics: enableMetricsOption } = this._options;
|
|
30
26
|
const enableMetrics = enableMetricsOption ?? _experiments?.enableMetrics ?? true;
|
|
31
27
|
if (WINDOW.document && (sendClientReports || enableLogs || enableMetrics)) {
|
|
32
28
|
WINDOW.document.addEventListener("visibilitychange", () => {
|
|
@@ -43,7 +39,7 @@ class BrowserClient extends Client {
|
|
|
43
39
|
}
|
|
44
40
|
});
|
|
45
41
|
}
|
|
46
|
-
if (
|
|
42
|
+
if (userInfo) {
|
|
47
43
|
this.on("beforeSendSession", addAutoIpAddressToSession);
|
|
48
44
|
}
|
|
49
45
|
}
|