@sentry/browser 11.0.0-alpha.0 → 11.0.0-alpha.1
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/index.js +1 -0
- package/build/npm/cjs/dev/index.js.map +1 -1
- package/build/npm/cjs/dev/integrations/graphqlClient.js +3 -3
- package/build/npm/cjs/dev/integrations/graphqlClient.js.map +1 -1
- package/build/npm/cjs/dev/profiling/index.js.map +1 -1
- package/build/npm/cjs/dev/profiling/integration.js +21 -91
- package/build/npm/cjs/dev/profiling/integration.js.map +1 -1
- package/build/npm/cjs/dev/profiling/utils.js +0 -283
- package/build/npm/cjs/dev/profiling/utils.js.map +1 -1
- package/build/npm/cjs/dev/tracing/backgroundtab.js +5 -1
- package/build/npm/cjs/dev/tracing/backgroundtab.js.map +1 -1
- package/build/npm/cjs/dev/tracing/browserTracingIntegration.js +5 -9
- package/build/npm/cjs/dev/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/cjs/dev/tracing/linkedTraces.js +3 -2
- package/build/npm/cjs/dev/tracing/linkedTraces.js.map +1 -1
- package/build/npm/cjs/dev/tracing/request.js +2 -4
- package/build/npm/cjs/dev/tracing/request.js.map +1 -1
- package/build/npm/cjs/prod/index.js +1 -0
- package/build/npm/cjs/prod/index.js.map +1 -1
- package/build/npm/cjs/prod/integrations/graphqlClient.js +3 -3
- package/build/npm/cjs/prod/integrations/graphqlClient.js.map +1 -1
- package/build/npm/cjs/prod/profiling/index.js.map +1 -1
- package/build/npm/cjs/prod/profiling/integration.js +21 -91
- package/build/npm/cjs/prod/profiling/integration.js.map +1 -1
- package/build/npm/cjs/prod/profiling/utils.js +0 -283
- package/build/npm/cjs/prod/profiling/utils.js.map +1 -1
- package/build/npm/cjs/prod/tracing/backgroundtab.js +5 -1
- package/build/npm/cjs/prod/tracing/backgroundtab.js.map +1 -1
- package/build/npm/cjs/prod/tracing/browserTracingIntegration.js +5 -9
- package/build/npm/cjs/prod/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/cjs/prod/tracing/linkedTraces.js +3 -2
- package/build/npm/cjs/prod/tracing/linkedTraces.js.map +1 -1
- package/build/npm/cjs/prod/tracing/request.js +2 -4
- package/build/npm/cjs/prod/tracing/request.js.map +1 -1
- package/build/npm/esm/dev/index.js +1 -1
- package/build/npm/esm/dev/integrations/graphqlClient.js +5 -5
- package/build/npm/esm/dev/integrations/graphqlClient.js.map +1 -1
- package/build/npm/esm/dev/package.json +1 -1
- package/build/npm/esm/dev/profiling/index.js.map +1 -1
- package/build/npm/esm/dev/profiling/integration.js +22 -92
- package/build/npm/esm/dev/profiling/integration.js.map +1 -1
- package/build/npm/esm/dev/profiling/utils.js +2 -272
- package/build/npm/esm/dev/profiling/utils.js.map +1 -1
- package/build/npm/esm/dev/tracing/backgroundtab.js +5 -1
- package/build/npm/esm/dev/tracing/backgroundtab.js.map +1 -1
- package/build/npm/esm/dev/tracing/browserTracingIntegration.js +6 -10
- package/build/npm/esm/dev/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/esm/dev/tracing/linkedTraces.js +3 -2
- package/build/npm/esm/dev/tracing/linkedTraces.js.map +1 -1
- package/build/npm/esm/dev/tracing/request.js +2 -4
- package/build/npm/esm/dev/tracing/request.js.map +1 -1
- package/build/npm/esm/prod/index.js +1 -1
- package/build/npm/esm/prod/integrations/graphqlClient.js +5 -5
- package/build/npm/esm/prod/integrations/graphqlClient.js.map +1 -1
- package/build/npm/esm/prod/package.json +1 -1
- package/build/npm/esm/prod/profiling/index.js.map +1 -1
- package/build/npm/esm/prod/profiling/integration.js +22 -92
- package/build/npm/esm/prod/profiling/integration.js.map +1 -1
- package/build/npm/esm/prod/profiling/utils.js +2 -272
- package/build/npm/esm/prod/profiling/utils.js.map +1 -1
- package/build/npm/esm/prod/tracing/backgroundtab.js +5 -1
- package/build/npm/esm/prod/tracing/backgroundtab.js.map +1 -1
- package/build/npm/esm/prod/tracing/browserTracingIntegration.js +6 -10
- package/build/npm/esm/prod/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/esm/prod/tracing/linkedTraces.js +3 -2
- package/build/npm/esm/prod/tracing/linkedTraces.js.map +1 -1
- package/build/npm/esm/prod/tracing/request.js +2 -4
- package/build/npm/esm/prod/tracing/request.js.map +1 -1
- package/build/npm/types/exports.d.ts +1 -1
- package/build/npm/types/exports.d.ts.map +1 -1
- package/build/npm/types/index.bundle.d.ts +2 -2
- package/build/npm/types/index.bundle.d.ts.map +1 -1
- package/build/npm/types/index.bundle.feedback.d.ts +2 -2
- package/build/npm/types/index.bundle.feedback.d.ts.map +1 -1
- package/build/npm/types/index.bundle.logs.metrics.d.ts +1 -1
- package/build/npm/types/index.bundle.logs.metrics.d.ts.map +1 -1
- package/build/npm/types/index.bundle.replay.d.ts +2 -2
- package/build/npm/types/index.bundle.replay.d.ts.map +1 -1
- package/build/npm/types/index.bundle.replay.feedback.d.ts +2 -2
- package/build/npm/types/index.bundle.replay.feedback.d.ts.map +1 -1
- package/build/npm/types/index.bundle.replay.logs.metrics.d.ts +1 -1
- package/build/npm/types/index.bundle.replay.logs.metrics.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.d.ts +2 -2
- package/build/npm/types/index.bundle.tracing.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.logs.metrics.d.ts +1 -1
- package/build/npm/types/index.bundle.tracing.logs.metrics.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.replay.d.ts +2 -2
- package/build/npm/types/index.bundle.tracing.replay.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.replay.feedback.d.ts +2 -2
- 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 -1
- 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 -1
- package/build/npm/types/index.bundle.tracing.replay.logs.metrics.d.ts.map +1 -1
- package/build/npm/types/index.d.ts +1 -2
- package/build/npm/types/index.d.ts.map +1 -1
- package/build/npm/types/integrations/graphqlClient.d.ts.map +1 -1
- package/build/npm/types/profiling/index.d.ts.map +1 -1
- package/build/npm/types/profiling/integration.d.ts.map +1 -1
- package/build/npm/types/profiling/utils.d.ts +1 -74
- package/build/npm/types/profiling/utils.d.ts.map +1 -1
- package/build/npm/types/tracing/backgroundtab.d.ts.map +1 -1
- package/build/npm/types/tracing/browserTracingIntegration.d.ts +0 -10
- 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/tracing/request.d.ts +0 -13
- package/build/npm/types/tracing/request.d.ts.map +1 -1
- package/package.json +8 -8
- package/build/npm/cjs/dev/profiling/startProfileForSpan.js +0 -91
- package/build/npm/cjs/dev/profiling/startProfileForSpan.js.map +0 -1
- package/build/npm/cjs/prod/profiling/startProfileForSpan.js +0 -91
- package/build/npm/cjs/prod/profiling/startProfileForSpan.js.map +0 -1
- package/build/npm/esm/dev/profiling/startProfileForSpan.js +0 -89
- package/build/npm/esm/dev/profiling/startProfileForSpan.js.map +0 -1
- package/build/npm/esm/prod/profiling/startProfileForSpan.js +0 -89
- package/build/npm/esm/prod/profiling/startProfileForSpan.js.map +0 -1
- package/build/npm/types/profiling/startProfileForSpan.d.ts +0 -8
- package/build/npm/types/profiling/startProfileForSpan.d.ts.map +0 -1
|
@@ -116,6 +116,7 @@ exports.setTags = browser.setTags;
|
|
|
116
116
|
exports.setUser = browser.setUser;
|
|
117
117
|
exports.spanToBaggageHeader = browser.spanToBaggageHeader;
|
|
118
118
|
exports.spanToJSON = browser.spanToJSON;
|
|
119
|
+
exports.spanToStaticSpanJSON = browser.spanToStaticSpanJSON;
|
|
119
120
|
exports.spanToTraceHeader = browser.spanToTraceHeader;
|
|
120
121
|
exports.startInactiveSpan = browser.startInactiveSpan;
|
|
121
122
|
exports.startNewTrace = browser.startNewTrace;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -17,14 +17,14 @@ const _graphqlClientIntegration = ((options) => {
|
|
|
17
17
|
function _updateSpanWithGraphQLData(client, options) {
|
|
18
18
|
client.on("beforeOutgoingRequestSpan", (span, hint) => {
|
|
19
19
|
const spanJSON = browser.spanToJSON(span);
|
|
20
|
-
const spanAttributes = spanJSON.
|
|
21
|
-
const spanOp = spanAttributes[
|
|
20
|
+
const spanAttributes = spanJSON.attributes;
|
|
21
|
+
const spanOp = spanAttributes[attributes.SENTRY_OP];
|
|
22
22
|
const isHttpClientSpan = spanOp === "http.client";
|
|
23
23
|
if (!isHttpClientSpan) {
|
|
24
24
|
return;
|
|
25
25
|
}
|
|
26
26
|
const httpUrl = spanAttributes[attributes.URL_FULL];
|
|
27
|
-
const httpMethod = spanAttributes[browser.SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD] || spanAttributes[
|
|
27
|
+
const httpMethod = spanAttributes[browser.SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD] || spanAttributes[attributes.HTTP_METHOD];
|
|
28
28
|
if (!browser.isString(httpUrl) || !browser.isString(httpMethod)) {
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphqlClient.js","sources":["../../../../../src/integrations/graphqlClient.ts"],"sourcesContent":["import type { Client, IntegrationFn } from '@sentry/core/browser';\nimport {\n defineIntegration,\n isObjectLike,\n isString,\n SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n spanToJSON,\n stringMatchesSomePattern,\n} from '@sentry/core/browser';\nimport type { FetchHint, XhrHint } from '@sentry/browser-utils';\nimport { getBodyString, getFetchRequestArgBody, SENTRY_XHR_DATA_KEY } from '@sentry/browser-utils';\nimport { GRAPHQL_DOCUMENT, URL_FULL } from '@sentry/conventions/attributes';\n\ninterface GraphQLClientOptions {\n endpoints: Array<string | RegExp>;\n}\n\n/** Standard graphql request shape: https://graphql.org/learn/serving-over-http/#post-request-and-body */\ninterface GraphQLStandardRequest {\n query: string;\n operationName?: string;\n variables?: Record<string, unknown>;\n extensions?: Record<string, unknown>;\n}\n\n/** Persisted operation request */\ninterface GraphQLPersistedRequest {\n operationName: string;\n variables?: Record<string, unknown>;\n extensions: {\n persistedQuery: {\n version: number;\n sha256Hash: string;\n };\n } & Record<string, unknown>;\n}\n\ntype GraphQLRequestPayload = GraphQLStandardRequest | GraphQLPersistedRequest;\n\ninterface GraphQLOperation {\n operationType?: string;\n operationName?: string;\n}\n\nconst INTEGRATION_NAME = 'GraphQLClient' as const;\n\nconst _graphqlClientIntegration = ((options: GraphQLClientOptions) => {\n return {\n name: INTEGRATION_NAME,\n setup(client: Client) {\n _updateSpanWithGraphQLData(client, options);\n _updateBreadcrumbWithGraphQLData(client, options);\n },\n };\n}) satisfies IntegrationFn;\n\nfunction _updateSpanWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestSpan', (span, hint) => {\n const spanJSON = spanToJSON(span);\n\n const spanAttributes = spanJSON.data || {};\n const spanOp = spanAttributes[SEMANTIC_ATTRIBUTE_SENTRY_OP];\n\n const isHttpClientSpan = spanOp === 'http.client';\n\n if (!isHttpClientSpan) {\n return;\n }\n\n const httpUrl = spanAttributes[URL_FULL];\n const httpMethod = spanAttributes[SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD] || spanAttributes['http.method'];\n\n if (!isString(httpUrl) || !isString(httpMethod)) {\n return;\n }\n\n const { endpoints } = options;\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(hint as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n span.updateName(`${httpMethod} ${httpUrl} (${operationInfo})`);\n\n // Handle standard requests - capture the query document when enabled via dataCollection (default true)\n if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) {\n span.setAttribute(GRAPHQL_DOCUMENT, graphqlBody.query);\n }\n\n // Handle persisted operations - capture hash for debugging\n if (isPersistedRequest(graphqlBody)) {\n span.setAttribute('graphql.persisted_query.hash.sha256', graphqlBody.extensions.persistedQuery.sha256Hash);\n span.setAttribute('graphql.persisted_query.version', graphqlBody.extensions.persistedQuery.version);\n }\n }\n }\n });\n}\n\nfunction _updateBreadcrumbWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestBreadcrumb', (breadcrumb, handlerData) => {\n const { category, type, data } = breadcrumb;\n\n const isFetch = category === 'fetch';\n const isXhr = category === 'xhr';\n const isHttpBreadcrumb = type === 'http';\n\n if (isHttpBreadcrumb && (isFetch || isXhr)) {\n const httpUrl = data?.url;\n const { endpoints } = options;\n\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(handlerData as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && data && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (!data.graphql && graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n\n data['graphql.operation'] = operationInfo;\n\n if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) {\n data[GRAPHQL_DOCUMENT] = graphqlBody.query;\n }\n\n if (isPersistedRequest(graphqlBody)) {\n data['graphql.persisted_query.hash.sha256'] = graphqlBody.extensions.persistedQuery.sha256Hash;\n data['graphql.persisted_query.version'] = graphqlBody.extensions.persistedQuery.version;\n }\n }\n }\n }\n });\n}\n\n/**\n * @param requestBody - GraphQL request\n * @returns A formatted version of the request: 'TYPE NAME' or 'TYPE' or 'persisted NAME'\n */\nexport function _getGraphQLOperation(requestBody: GraphQLRequestPayload): string {\n // Handle persisted operations\n if (isPersistedRequest(requestBody)) {\n return `persisted ${requestBody.operationName}`;\n }\n\n // Handle standard GraphQL requests\n if (isStandardRequest(requestBody)) {\n const { query: graphqlQuery, operationName: graphqlOperationName } = requestBody;\n const { operationName = graphqlOperationName, operationType } = parseGraphQLQuery(graphqlQuery);\n const operationInfo = operationName ? `${operationType} ${operationName}` : `${operationType}`;\n return operationInfo;\n }\n\n // Fallback for unknown request types\n return 'unknown';\n}\n\n/**\n * Get the request body/payload based on the shape of the hint.\n *\n * Exported for tests only.\n */\nexport function getRequestPayloadXhrOrFetch(hint: XhrHint | FetchHint): string | undefined {\n const isXhr = 'xhr' in hint;\n\n let body: string | undefined;\n\n if (isXhr) {\n const sentryXhrData = hint.xhr[SENTRY_XHR_DATA_KEY];\n body = sentryXhrData && getBodyString(sentryXhrData.body)[0];\n } else {\n const sentryFetchData = getFetchRequestArgBody(hint.input);\n body = getBodyString(sentryFetchData)[0];\n }\n\n return body;\n}\n\n/**\n * Extract the name and type of the operation from the GraphQL query.\n *\n * Exported for tests only.\n */\nexport function parseGraphQLQuery(query: string): GraphQLOperation {\n const namedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)(\\w+)(?:\\s*)[{(]/;\n const unnamedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)[{(]/;\n\n const namedMatch = query.match(namedQueryRe);\n if (namedMatch) {\n return {\n operationType: namedMatch[1],\n operationName: namedMatch[2],\n };\n }\n\n const unnamedMatch = query.match(unnamedQueryRe);\n if (unnamedMatch) {\n return {\n operationType: unnamedMatch[1],\n operationName: undefined,\n };\n }\n return {\n operationType: undefined,\n operationName: undefined,\n };\n}\n\n/**\n * Helper to safely check if a value is a non-null object\n */\n\n/**\n * Type guard to check if a request is a standard GraphQL request\n */\nfunction isStandardRequest(payload: unknown): payload is GraphQLStandardRequest {\n return isObjectLike(payload) && typeof payload.query === 'string';\n}\n\n/**\n * Type guard to check if a request is a persisted operation request\n */\nfunction isPersistedRequest(payload: unknown): payload is GraphQLPersistedRequest {\n return (\n isObjectLike(payload) &&\n typeof payload.operationName === 'string' &&\n isObjectLike(payload.extensions) &&\n isObjectLike(payload.extensions.persistedQuery) &&\n typeof payload.extensions.persistedQuery.sha256Hash === 'string' &&\n typeof payload.extensions.persistedQuery.version === 'number'\n );\n}\n\n/**\n * Extract the payload of a request if it's GraphQL.\n * Exported for tests only.\n * @param payload - A valid JSON string\n * @returns A POJO or undefined\n */\nexport function getGraphQLRequestPayload(payload: string): GraphQLRequestPayload | undefined {\n try {\n const requestBody = JSON.parse(payload);\n\n // Return any valid GraphQL request (standard, persisted, or APQ retry with both)\n if (isStandardRequest(requestBody) || isPersistedRequest(requestBody)) {\n return requestBody;\n }\n\n // Not a GraphQL request\n return undefined;\n } catch {\n // Invalid JSON\n return undefined;\n }\n}\n\n/**\n * This integration ensures that GraphQL requests made in the browser\n * have their GraphQL-specific data captured and attached to spans and breadcrumbs.\n */\nexport const graphqlClientIntegration = defineIntegration(_graphqlClientIntegration);\n"],"names":["spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_OP","URL_FULL","SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD","isString","stringMatchesSomePattern","GRAPHQL_DOCUMENT","SENTRY_XHR_DATA_KEY","getBodyString","getFetchRequestArgBody","isObjectLike","defineIntegration"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"graphqlClient.js","sources":["../../../../../src/integrations/graphqlClient.ts"],"sourcesContent":["import type { Client, IntegrationFn } from '@sentry/core/browser';\nimport {\n defineIntegration,\n isObjectLike,\n isString,\n SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD,\n spanToJSON,\n stringMatchesSomePattern,\n} from '@sentry/core/browser';\nimport type { FetchHint, XhrHint } from '@sentry/browser-utils';\nimport { getBodyString, getFetchRequestArgBody, SENTRY_XHR_DATA_KEY } from '@sentry/browser-utils';\nimport { GRAPHQL_DOCUMENT, HTTP_METHOD, SENTRY_OP, URL_FULL } from '@sentry/conventions/attributes';\n\ninterface GraphQLClientOptions {\n endpoints: Array<string | RegExp>;\n}\n\n/** Standard graphql request shape: https://graphql.org/learn/serving-over-http/#post-request-and-body */\ninterface GraphQLStandardRequest {\n query: string;\n operationName?: string;\n variables?: Record<string, unknown>;\n extensions?: Record<string, unknown>;\n}\n\n/** Persisted operation request */\ninterface GraphQLPersistedRequest {\n operationName: string;\n variables?: Record<string, unknown>;\n extensions: {\n persistedQuery: {\n version: number;\n sha256Hash: string;\n };\n } & Record<string, unknown>;\n}\n\ntype GraphQLRequestPayload = GraphQLStandardRequest | GraphQLPersistedRequest;\n\ninterface GraphQLOperation {\n operationType?: string;\n operationName?: string;\n}\n\nconst INTEGRATION_NAME = 'GraphQLClient' as const;\n\nconst _graphqlClientIntegration = ((options: GraphQLClientOptions) => {\n return {\n name: INTEGRATION_NAME,\n setup(client: Client) {\n _updateSpanWithGraphQLData(client, options);\n _updateBreadcrumbWithGraphQLData(client, options);\n },\n };\n}) satisfies IntegrationFn;\n\nfunction _updateSpanWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestSpan', (span, hint) => {\n const spanJSON = spanToJSON(span);\n\n const spanAttributes = spanJSON.attributes;\n const spanOp = spanAttributes[SENTRY_OP];\n\n const isHttpClientSpan = spanOp === 'http.client';\n\n if (!isHttpClientSpan) {\n return;\n }\n\n const httpUrl = spanAttributes[URL_FULL];\n // oxlint-disable-next-line typescript/no-deprecated\n const httpMethod = spanAttributes[SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD] || spanAttributes[HTTP_METHOD];\n\n if (!isString(httpUrl) || !isString(httpMethod)) {\n return;\n }\n\n const { endpoints } = options;\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(hint as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n span.updateName(`${httpMethod} ${httpUrl} (${operationInfo})`);\n\n // Handle standard requests - capture the query document when enabled via dataCollection (default true)\n if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) {\n span.setAttribute(GRAPHQL_DOCUMENT, graphqlBody.query);\n }\n\n // Handle persisted operations - capture hash for debugging\n if (isPersistedRequest(graphqlBody)) {\n span.setAttribute('graphql.persisted_query.hash.sha256', graphqlBody.extensions.persistedQuery.sha256Hash);\n span.setAttribute('graphql.persisted_query.version', graphqlBody.extensions.persistedQuery.version);\n }\n }\n }\n });\n}\n\nfunction _updateBreadcrumbWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestBreadcrumb', (breadcrumb, handlerData) => {\n const { category, type, data } = breadcrumb;\n\n const isFetch = category === 'fetch';\n const isXhr = category === 'xhr';\n const isHttpBreadcrumb = type === 'http';\n\n if (isHttpBreadcrumb && (isFetch || isXhr)) {\n const httpUrl = data?.url;\n const { endpoints } = options;\n\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(handlerData as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && data && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (!data.graphql && graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n\n data['graphql.operation'] = operationInfo;\n\n if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) {\n data[GRAPHQL_DOCUMENT] = graphqlBody.query;\n }\n\n if (isPersistedRequest(graphqlBody)) {\n data['graphql.persisted_query.hash.sha256'] = graphqlBody.extensions.persistedQuery.sha256Hash;\n data['graphql.persisted_query.version'] = graphqlBody.extensions.persistedQuery.version;\n }\n }\n }\n }\n });\n}\n\n/**\n * @param requestBody - GraphQL request\n * @returns A formatted version of the request: 'TYPE NAME' or 'TYPE' or 'persisted NAME'\n */\nexport function _getGraphQLOperation(requestBody: GraphQLRequestPayload): string {\n // Handle persisted operations\n if (isPersistedRequest(requestBody)) {\n return `persisted ${requestBody.operationName}`;\n }\n\n // Handle standard GraphQL requests\n if (isStandardRequest(requestBody)) {\n const { query: graphqlQuery, operationName: graphqlOperationName } = requestBody;\n const { operationName = graphqlOperationName, operationType } = parseGraphQLQuery(graphqlQuery);\n const operationInfo = operationName ? `${operationType} ${operationName}` : `${operationType}`;\n return operationInfo;\n }\n\n // Fallback for unknown request types\n return 'unknown';\n}\n\n/**\n * Get the request body/payload based on the shape of the hint.\n *\n * Exported for tests only.\n */\nexport function getRequestPayloadXhrOrFetch(hint: XhrHint | FetchHint): string | undefined {\n const isXhr = 'xhr' in hint;\n\n let body: string | undefined;\n\n if (isXhr) {\n const sentryXhrData = hint.xhr[SENTRY_XHR_DATA_KEY];\n body = sentryXhrData && getBodyString(sentryXhrData.body)[0];\n } else {\n const sentryFetchData = getFetchRequestArgBody(hint.input);\n body = getBodyString(sentryFetchData)[0];\n }\n\n return body;\n}\n\n/**\n * Extract the name and type of the operation from the GraphQL query.\n *\n * Exported for tests only.\n */\nexport function parseGraphQLQuery(query: string): GraphQLOperation {\n const namedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)(\\w+)(?:\\s*)[{(]/;\n const unnamedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)[{(]/;\n\n const namedMatch = query.match(namedQueryRe);\n if (namedMatch) {\n return {\n operationType: namedMatch[1],\n operationName: namedMatch[2],\n };\n }\n\n const unnamedMatch = query.match(unnamedQueryRe);\n if (unnamedMatch) {\n return {\n operationType: unnamedMatch[1],\n operationName: undefined,\n };\n }\n return {\n operationType: undefined,\n operationName: undefined,\n };\n}\n\n/**\n * Helper to safely check if a value is a non-null object\n */\n\n/**\n * Type guard to check if a request is a standard GraphQL request\n */\nfunction isStandardRequest(payload: unknown): payload is GraphQLStandardRequest {\n return isObjectLike(payload) && typeof payload.query === 'string';\n}\n\n/**\n * Type guard to check if a request is a persisted operation request\n */\nfunction isPersistedRequest(payload: unknown): payload is GraphQLPersistedRequest {\n return (\n isObjectLike(payload) &&\n typeof payload.operationName === 'string' &&\n isObjectLike(payload.extensions) &&\n isObjectLike(payload.extensions.persistedQuery) &&\n typeof payload.extensions.persistedQuery.sha256Hash === 'string' &&\n typeof payload.extensions.persistedQuery.version === 'number'\n );\n}\n\n/**\n * Extract the payload of a request if it's GraphQL.\n * Exported for tests only.\n * @param payload - A valid JSON string\n * @returns A POJO or undefined\n */\nexport function getGraphQLRequestPayload(payload: string): GraphQLRequestPayload | undefined {\n try {\n const requestBody = JSON.parse(payload);\n\n // Return any valid GraphQL request (standard, persisted, or APQ retry with both)\n if (isStandardRequest(requestBody) || isPersistedRequest(requestBody)) {\n return requestBody;\n }\n\n // Not a GraphQL request\n return undefined;\n } catch {\n // Invalid JSON\n return undefined;\n }\n}\n\n/**\n * This integration ensures that GraphQL requests made in the browser\n * have their GraphQL-specific data captured and attached to spans and breadcrumbs.\n */\nexport const graphqlClientIntegration = defineIntegration(_graphqlClientIntegration);\n"],"names":["spanToJSON","SENTRY_OP","URL_FULL","SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD","HTTP_METHOD","isString","stringMatchesSomePattern","GRAPHQL_DOCUMENT","SENTRY_XHR_DATA_KEY","getBodyString","getFetchRequestArgBody","isObjectLike","defineIntegration"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../../src/profiling/index.ts"],"sourcesContent":["import type { Profiler } from '@sentry/core/browser';\nimport { debug, getClient } from '@sentry/core/browser';\nimport { DEBUG_BUILD } from '../debug-build';\n\n/**\n * Starts
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../../src/profiling/index.ts"],"sourcesContent":["import type { Profiler } from '@sentry/core/browser';\nimport { debug, getClient } from '@sentry/core/browser';\nimport { DEBUG_BUILD } from '../debug-build';\n\n/**\n * Starts a manually controlled Sentry UI profiling session.\n *\n * Profiling starts only when the integration sampled the current session and `profileLifecycle` is `manual`.\n * While running, the profiler periodically sends profile chunks to Sentry until `stopProfiler()` is called.\n */\nfunction startProfiler(): void {\n const client = getClient();\n if (!client) {\n DEBUG_BUILD && debug.warn('No Sentry client available, profiling is not started');\n return;\n }\n\n const integration = client.getIntegrationByName('BrowserProfiling');\n\n if (!integration) {\n DEBUG_BUILD && debug.warn('BrowserProfiling integration is not available');\n return;\n }\n\n client.emit('startUIProfiler');\n}\n\n/**\n * Stops a manually controlled Sentry UI profiling session.\n *\n * Calls to stop will stop the profiler and flush the currently collected profile data to Sentry.\n */\nfunction stopProfiler(): void {\n const client = getClient();\n if (!client) {\n DEBUG_BUILD && debug.warn('No Sentry client available, profiling is not started');\n return;\n }\n\n const integration = client.getIntegrationByName('BrowserProfiling');\n if (!integration) {\n DEBUG_BUILD && debug.warn('ProfilingIntegration is not available');\n return;\n }\n\n client.emit('stopUIProfiler');\n}\n\n/**\n * Profiler namespace for controlling the JS profiler in 'manual' mode.\n *\n * Requires the `browserProfilingIntegration` from the `@sentry/browser` package.\n */\nexport const uiProfiler: Profiler = {\n startProfiler,\n stopProfiler,\n};\n"],"names":["getClient","DEBUG_BUILD","debug"],"mappings":";;;;;AAUA,SAAS,aAAA,GAAsB;AAC7B,EAAA,MAAM,SAASA,iBAAA,EAAU;AACzB,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAAC,sBAAA,IAAeC,aAAA,CAAM,KAAK,sDAAsD,CAAA;AAChF,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,oBAAA,CAAqB,kBAAkB,CAAA;AAElE,EAAA,IAAI,CAAC,WAAA,EAAa;AAChB,IAAAD,sBAAA,IAAeC,aAAA,CAAM,KAAK,+CAA+C,CAAA;AACzE,IAAA;AAAA,EACF;AAEA,EAAA,MAAA,CAAO,KAAK,iBAAiB,CAAA;AAC/B;AAOA,SAAS,YAAA,GAAqB;AAC5B,EAAA,MAAM,SAASF,iBAAA,EAAU;AACzB,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAAC,sBAAA,IAAeC,aAAA,CAAM,KAAK,sDAAsD,CAAA;AAChF,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,oBAAA,CAAqB,kBAAkB,CAAA;AAClE,EAAA,IAAI,CAAC,WAAA,EAAa;AAChB,IAAAD,sBAAA,IAAeC,aAAA,CAAM,KAAK,uCAAuC,CAAA;AACjE,IAAA;AAAA,EACF;AAEA,EAAA,MAAA,CAAO,KAAK,gBAAgB,CAAA;AAC9B;AAOO,MAAM,UAAA,GAAuB;AAAA,EAClC,aAAA;AAAA,EACA;AACF;;;;"}
|
|
@@ -3,9 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
3
3
|
const browser = require('@sentry/core/browser');
|
|
4
4
|
const debugBuild = require('../debug-build.js');
|
|
5
5
|
const helpers = require('../helpers.js');
|
|
6
|
-
const startProfileForSpan = require('./startProfileForSpan.js');
|
|
7
6
|
const UIProfiler = require('./UIProfiler.js');
|
|
8
|
-
const utils = require('./utils.js');
|
|
9
7
|
|
|
10
8
|
const INTEGRATION_NAME = "BrowserProfiling";
|
|
11
9
|
const _browserProfilingIntegration = (() => {
|
|
@@ -14,102 +12,34 @@ const _browserProfilingIntegration = (() => {
|
|
|
14
12
|
setup(client) {
|
|
15
13
|
const options = client.getOptions();
|
|
16
14
|
const profiler = new UIProfiler.UIProfiler();
|
|
17
|
-
if (!
|
|
15
|
+
if (!options.profileLifecycle) {
|
|
18
16
|
options.profileLifecycle = "manual";
|
|
19
17
|
}
|
|
20
|
-
if (utils.hasLegacyProfiling(options) && !options.profilesSampleRate) {
|
|
21
|
-
debugBuild.DEBUG_BUILD && browser.debug.log("[Profiling] Profiling disabled, no profiling options found.");
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
18
|
const activeSpan = browser.getActiveSpan();
|
|
25
19
|
const rootSpan = activeSpan && browser.getRootSpan(activeSpan);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
} else if (lifecycleMode === "trace") {
|
|
38
|
-
if (!browser.hasSpansEnabled(options)) {
|
|
39
|
-
debugBuild.DEBUG_BUILD && browser.debug.warn(
|
|
40
|
-
"[Profiling] `profileLifecycle` is 'trace' but tracing is disabled. Set a `tracesSampleRate` or `tracesSampler` to enable span tracing."
|
|
41
|
-
);
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
profiler.initialize(client);
|
|
45
|
-
if (rootSpan) {
|
|
46
|
-
profiler.notifyRootSpanActive(rootSpan);
|
|
47
|
-
}
|
|
48
|
-
helpers.WINDOW.setTimeout(() => {
|
|
49
|
-
const laterActiveSpan = browser.getActiveSpan();
|
|
50
|
-
const laterRootSpan = laterActiveSpan && browser.getRootSpan(laterActiveSpan);
|
|
51
|
-
if (laterRootSpan) {
|
|
52
|
-
profiler.notifyRootSpanActive(laterRootSpan);
|
|
53
|
-
}
|
|
54
|
-
}, 0);
|
|
20
|
+
const lifecycleMode = options.profileLifecycle;
|
|
21
|
+
client.on("startUIProfiler", () => profiler.start());
|
|
22
|
+
client.on("stopUIProfiler", () => profiler.stop());
|
|
23
|
+
if (lifecycleMode === "manual") {
|
|
24
|
+
profiler.initialize(client);
|
|
25
|
+
} else if (lifecycleMode === "trace") {
|
|
26
|
+
if (!browser.hasSpansEnabled(options)) {
|
|
27
|
+
debugBuild.DEBUG_BUILD && browser.debug.warn(
|
|
28
|
+
"[Profiling] `profileLifecycle` is 'trace' but tracing is disabled. Set a `tracesSampleRate` or `tracesSampler` to enable span tracing."
|
|
29
|
+
);
|
|
30
|
+
return;
|
|
55
31
|
}
|
|
56
|
-
|
|
57
|
-
if (rootSpan
|
|
58
|
-
|
|
59
|
-
startProfileForSpan.startProfileForSpan(rootSpan);
|
|
60
|
-
}
|
|
32
|
+
profiler.initialize(client);
|
|
33
|
+
if (rootSpan) {
|
|
34
|
+
profiler.notifyRootSpanActive(rootSpan);
|
|
61
35
|
}
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
} else if (utils.PROFILED_ROOT_SPANS.has(rootSpan2)) {
|
|
69
|
-
utils.setThreadAttributes(span);
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
client.on("beforeEnvelope", (envelope) => {
|
|
73
|
-
if (!utils.getActiveProfilesCount()) {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
const profiledTransactionEvents = utils.findProfiledTransactionsFromEnvelope(envelope);
|
|
77
|
-
if (!profiledTransactionEvents.length) {
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
const profilesToAddToEnvelope = [];
|
|
81
|
-
for (const profiledTransaction of profiledTransactionEvents) {
|
|
82
|
-
const context = profiledTransaction?.contexts;
|
|
83
|
-
const profile_id = context?.profile?.["profile_id"];
|
|
84
|
-
const start_timestamp = context?.profile?.["start_timestamp"];
|
|
85
|
-
if (typeof profile_id !== "string") {
|
|
86
|
-
debugBuild.DEBUG_BUILD && browser.debug.log("[Profiling] cannot find profile for a span without a profile context");
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
if (!profile_id) {
|
|
90
|
-
debugBuild.DEBUG_BUILD && browser.debug.log("[Profiling] cannot find profile for a span without a profile context");
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
if (context?.profile) {
|
|
94
|
-
delete context.profile;
|
|
95
|
-
}
|
|
96
|
-
const profile = utils.takeProfileFromGlobalCache(profile_id);
|
|
97
|
-
if (!profile) {
|
|
98
|
-
debugBuild.DEBUG_BUILD && browser.debug.log(`[Profiling] Could not retrieve profile for span: ${profile_id}`);
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
101
|
-
const profileEvent = utils.createProfilingEvent(
|
|
102
|
-
profile_id,
|
|
103
|
-
start_timestamp,
|
|
104
|
-
profile,
|
|
105
|
-
profiledTransaction
|
|
106
|
-
);
|
|
107
|
-
if (profileEvent) {
|
|
108
|
-
profilesToAddToEnvelope.push(profileEvent);
|
|
109
|
-
}
|
|
36
|
+
helpers.WINDOW.setTimeout(() => {
|
|
37
|
+
const laterActiveSpan = browser.getActiveSpan();
|
|
38
|
+
const laterRootSpan = laterActiveSpan && browser.getRootSpan(laterActiveSpan);
|
|
39
|
+
if (laterRootSpan) {
|
|
40
|
+
profiler.notifyRootSpanActive(laterRootSpan);
|
|
110
41
|
}
|
|
111
|
-
|
|
112
|
-
});
|
|
42
|
+
}, 0);
|
|
113
43
|
}
|
|
114
44
|
}
|
|
115
45
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration.js","sources":["../../../../../src/profiling/integration.ts"],"sourcesContent":["import type { EventEnvelope, IntegrationFn, Profile, Span } from '@sentry/core/browser';\nimport { debug, defineIntegration, getActiveSpan, getRootSpan, hasSpansEnabled } from '@sentry/core/browser';\nimport type { BrowserOptions } from '../client';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { WINDOW } from '../helpers';\nimport { startProfileForSpan } from './startProfileForSpan';\nimport { UIProfiler } from './UIProfiler';\nimport type { ProfiledEvent } from './utils';\nimport {\n addProfilesToEnvelope,\n createProfilingEvent,\n findProfiledTransactionsFromEnvelope,\n getActiveProfilesCount,\n hasLegacyProfiling,\n isAutomatedPageLoadSpan,\n PROFILED_ROOT_SPANS,\n setThreadAttributes,\n shouldProfileSpanLegacy,\n takeProfileFromGlobalCache,\n} from './utils';\n\nconst INTEGRATION_NAME = 'BrowserProfiling' as const;\n\nconst _browserProfilingIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setup(client) {\n const options = client.getOptions() as BrowserOptions;\n const profiler = new UIProfiler();\n\n if (!hasLegacyProfiling(options) && !options.profileLifecycle) {\n // Set default lifecycle mode\n options.profileLifecycle = 'manual';\n }\n\n // eslint-disable-next-line typescript/no-deprecated\n if (hasLegacyProfiling(options) && !options.profilesSampleRate) {\n DEBUG_BUILD && debug.log('[Profiling] Profiling disabled, no profiling options found.');\n return;\n }\n\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan && getRootSpan(activeSpan);\n\n if (hasLegacyProfiling(options) && options.profileSessionSampleRate !== undefined) {\n DEBUG_BUILD &&\n debug.warn(\n '[Profiling] Both legacy profiling (`profilesSampleRate`) and UI profiling settings are defined. `profileSessionSampleRate` has no effect when legacy profiling is enabled.',\n );\n }\n\n // UI PROFILING (Profiling V2)\n if (!hasLegacyProfiling(options)) {\n const lifecycleMode = options.profileLifecycle;\n\n // Registering hooks in all lifecycle modes to be able to notify users in case they want to start/stop the profiler manually in `trace` mode\n client.on('startUIProfiler', () => profiler.start());\n client.on('stopUIProfiler', () => profiler.stop());\n\n if (lifecycleMode === 'manual') {\n profiler.initialize(client);\n } else if (lifecycleMode === 'trace') {\n if (!hasSpansEnabled(options)) {\n DEBUG_BUILD &&\n debug.warn(\n \"[Profiling] `profileLifecycle` is 'trace' but tracing is disabled. Set a `tracesSampleRate` or `tracesSampler` to enable span tracing.\",\n );\n return;\n }\n\n profiler.initialize(client);\n\n // If there is an active, sampled root span already, notify the profiler\n if (rootSpan) {\n profiler.notifyRootSpanActive(rootSpan);\n }\n\n // In case rootSpan is created slightly after setup -> schedule microtask to re-check and notify.\n WINDOW.setTimeout(() => {\n const laterActiveSpan = getActiveSpan();\n const laterRootSpan = laterActiveSpan && getRootSpan(laterActiveSpan);\n if (laterRootSpan) {\n profiler.notifyRootSpanActive(laterRootSpan);\n }\n }, 0);\n }\n } else {\n // LEGACY PROFILING (v1)\n if (rootSpan && isAutomatedPageLoadSpan(rootSpan)) {\n if (shouldProfileSpanLegacy(rootSpan)) {\n startProfileForSpan(rootSpan);\n }\n }\n\n client.on('spanStart', (span: Span) => {\n const rootSpan = getRootSpan(span);\n if (span === rootSpan) {\n if (shouldProfileSpanLegacy(span)) {\n startProfileForSpan(span);\n }\n } else if (PROFILED_ROOT_SPANS.has(rootSpan)) {\n setThreadAttributes(span);\n }\n });\n\n client.on('beforeEnvelope', (envelope): void => {\n // if not profiles are in queue, there is nothing to add to the envelope.\n if (!getActiveProfilesCount()) {\n return;\n }\n\n const profiledTransactionEvents = findProfiledTransactionsFromEnvelope(envelope);\n if (!profiledTransactionEvents.length) {\n return;\n }\n\n const profilesToAddToEnvelope: Profile[] = [];\n\n for (const profiledTransaction of profiledTransactionEvents) {\n const context = profiledTransaction?.contexts;\n const profile_id = context?.profile?.['profile_id'];\n const start_timestamp = context?.profile?.['start_timestamp'];\n\n if (typeof profile_id !== 'string') {\n DEBUG_BUILD && debug.log('[Profiling] cannot find profile for a span without a profile context');\n continue;\n }\n\n if (!profile_id) {\n DEBUG_BUILD && debug.log('[Profiling] cannot find profile for a span without a profile context');\n continue;\n }\n\n // Remove the profile from the span context before sending, relay will take care of the rest.\n if (context?.profile) {\n delete context.profile;\n }\n\n const profile = takeProfileFromGlobalCache(profile_id);\n if (!profile) {\n DEBUG_BUILD && debug.log(`[Profiling] Could not retrieve profile for span: ${profile_id}`);\n continue;\n }\n\n const profileEvent = createProfilingEvent(\n profile_id,\n start_timestamp as number | undefined,\n profile,\n profiledTransaction as ProfiledEvent,\n );\n if (profileEvent) {\n profilesToAddToEnvelope.push(profileEvent);\n }\n }\n\n addProfilesToEnvelope(envelope as EventEnvelope, profilesToAddToEnvelope);\n });\n }\n },\n };\n}) satisfies IntegrationFn;\n\nexport const browserProfilingIntegration = defineIntegration(_browserProfilingIntegration);\n"],"names":["UIProfiler","hasLegacyProfiling","DEBUG_BUILD","debug","getActiveSpan","getRootSpan","hasSpansEnabled","WINDOW","isAutomatedPageLoadSpan","shouldProfileSpanLegacy","startProfileForSpan","rootSpan","PROFILED_ROOT_SPANS","setThreadAttributes","getActiveProfilesCount","findProfiledTransactionsFromEnvelope","takeProfileFromGlobalCache","createProfilingEvent","addProfilesToEnvelope","defineIntegration"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"integration.js","sources":["../../../../../src/profiling/integration.ts"],"sourcesContent":["import type { IntegrationFn } from '@sentry/core/browser';\nimport { debug, defineIntegration, getActiveSpan, getRootSpan, hasSpansEnabled } from '@sentry/core/browser';\nimport type { BrowserOptions } from '../client';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { WINDOW } from '../helpers';\nimport { UIProfiler } from './UIProfiler';\n\nconst INTEGRATION_NAME = 'BrowserProfiling' as const;\n\nconst _browserProfilingIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setup(client) {\n const options = client.getOptions() as BrowserOptions;\n const profiler = new UIProfiler();\n\n if (!options.profileLifecycle) {\n // Set default lifecycle mode\n options.profileLifecycle = 'manual';\n }\n\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan && getRootSpan(activeSpan);\n const lifecycleMode = options.profileLifecycle;\n\n // Registering hooks in all lifecycle modes to be able to notify users in case they want to start/stop the profiler manually in `trace` mode\n client.on('startUIProfiler', () => profiler.start());\n client.on('stopUIProfiler', () => profiler.stop());\n\n if (lifecycleMode === 'manual') {\n profiler.initialize(client);\n } else if (lifecycleMode === 'trace') {\n if (!hasSpansEnabled(options)) {\n DEBUG_BUILD &&\n debug.warn(\n \"[Profiling] `profileLifecycle` is 'trace' but tracing is disabled. Set a `tracesSampleRate` or `tracesSampler` to enable span tracing.\",\n );\n return;\n }\n\n profiler.initialize(client);\n\n // If there is an active, sampled root span already, notify the profiler\n if (rootSpan) {\n profiler.notifyRootSpanActive(rootSpan);\n }\n\n // In case rootSpan is created slightly after setup -> schedule microtask to re-check and notify.\n WINDOW.setTimeout(() => {\n const laterActiveSpan = getActiveSpan();\n const laterRootSpan = laterActiveSpan && getRootSpan(laterActiveSpan);\n if (laterRootSpan) {\n profiler.notifyRootSpanActive(laterRootSpan);\n }\n }, 0);\n }\n },\n };\n}) satisfies IntegrationFn;\n\nexport const browserProfilingIntegration = defineIntegration(_browserProfilingIntegration);\n"],"names":["UIProfiler","getActiveSpan","getRootSpan","hasSpansEnabled","DEBUG_BUILD","debug","WINDOW","defineIntegration"],"mappings":";;;;;;;AAOA,MAAM,gBAAA,GAAmB,kBAAA;AAEzB,MAAM,gCAAgC,MAAM;AAC1C,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,MAAM,MAAA,EAAQ;AACZ,MAAA,MAAM,OAAA,GAAU,OAAO,UAAA,EAAW;AAClC,MAAA,MAAM,QAAA,GAAW,IAAIA,qBAAA,EAAW;AAEhC,MAAA,IAAI,CAAC,QAAQ,gBAAA,EAAkB;AAE7B,QAAA,OAAA,CAAQ,gBAAA,GAAmB,QAAA;AAAA,MAC7B;AAEA,MAAA,MAAM,aAAaC,qBAAA,EAAc;AACjC,MAAA,MAAM,QAAA,GAAW,UAAA,IAAcC,mBAAA,CAAY,UAAU,CAAA;AACrD,MAAA,MAAM,gBAAgB,OAAA,CAAQ,gBAAA;AAG9B,MAAA,MAAA,CAAO,EAAA,CAAG,iBAAA,EAAmB,MAAM,QAAA,CAAS,OAAO,CAAA;AACnD,MAAA,MAAA,CAAO,EAAA,CAAG,gBAAA,EAAkB,MAAM,QAAA,CAAS,MAAM,CAAA;AAEjD,MAAA,IAAI,kBAAkB,QAAA,EAAU;AAC9B,QAAA,QAAA,CAAS,WAAW,MAAM,CAAA;AAAA,MAC5B,CAAA,MAAA,IAAW,kBAAkB,OAAA,EAAS;AACpC,QAAA,IAAI,CAACC,uBAAA,CAAgB,OAAO,CAAA,EAAG;AAC7B,UAAAC,sBAAA,IACEC,aAAA,CAAM,IAAA;AAAA,YACJ;AAAA,WACF;AACF,UAAA;AAAA,QACF;AAEA,QAAA,QAAA,CAAS,WAAW,MAAM,CAAA;AAG1B,QAAA,IAAI,QAAA,EAAU;AACZ,UAAA,QAAA,CAAS,qBAAqB,QAAQ,CAAA;AAAA,QACxC;AAGA,QAAAC,cAAA,CAAO,WAAW,MAAM;AACtB,UAAA,MAAM,kBAAkBL,qBAAA,EAAc;AACtC,UAAA,MAAM,aAAA,GAAgB,eAAA,IAAmBC,mBAAA,CAAY,eAAe,CAAA;AACpE,UAAA,IAAI,aAAA,EAAe;AACjB,YAAA,QAAA,CAAS,qBAAqB,aAAa,CAAA;AAAA,UAC7C;AAAA,QACF,GAAG,CAAC,CAAA;AAAA,MACN;AAAA,IACF;AAAA,GACF;AACF,CAAA,CAAA;AAEO,MAAM,2BAAA,GAA8BK,0BAAkB,4BAA4B;;;;"}
|
|
@@ -4,107 +4,9 @@ const browser = require('@sentry/core/browser');
|
|
|
4
4
|
const debugBuild = require('../debug-build.js');
|
|
5
5
|
const helpers = require('../helpers.js');
|
|
6
6
|
|
|
7
|
-
const MS_TO_NS = 1e6;
|
|
8
7
|
const isMainThread = "window" in browser.GLOBAL_OBJ && browser.GLOBAL_OBJ.window === browser.GLOBAL_OBJ && typeof importScripts === "undefined";
|
|
9
8
|
const PROFILER_THREAD_ID_STRING = String(0);
|
|
10
9
|
const PROFILER_THREAD_NAME = isMainThread ? "main" : "worker";
|
|
11
|
-
const navigator = helpers.WINDOW.navigator;
|
|
12
|
-
let OS_PLATFORM = "";
|
|
13
|
-
let OS_PLATFORM_VERSION = "";
|
|
14
|
-
let OS_ARCH = "";
|
|
15
|
-
let OS_BROWSER = navigator?.userAgent || "";
|
|
16
|
-
let OS_MODEL = "";
|
|
17
|
-
const OS_LOCALE = navigator?.language || navigator?.languages?.[0] || "";
|
|
18
|
-
function isUserAgentData(data) {
|
|
19
|
-
return typeof data === "object" && data !== null && "getHighEntropyValues" in data;
|
|
20
|
-
}
|
|
21
|
-
const userAgentData = navigator?.userAgentData;
|
|
22
|
-
if (isUserAgentData(userAgentData)) {
|
|
23
|
-
userAgentData.getHighEntropyValues(["architecture", "model", "platform", "platformVersion", "fullVersionList"]).then((ua) => {
|
|
24
|
-
OS_PLATFORM = ua.platform || "";
|
|
25
|
-
OS_ARCH = ua.architecture || "";
|
|
26
|
-
OS_MODEL = ua.model || "";
|
|
27
|
-
OS_PLATFORM_VERSION = ua.platformVersion || "";
|
|
28
|
-
if (ua.fullVersionList?.length) {
|
|
29
|
-
const firstUa = ua.fullVersionList[ua.fullVersionList.length - 1];
|
|
30
|
-
OS_BROWSER = `${firstUa.brand} ${firstUa.version}`;
|
|
31
|
-
}
|
|
32
|
-
}).catch((e) => void 0);
|
|
33
|
-
}
|
|
34
|
-
function isProcessedJSSelfProfile(profile) {
|
|
35
|
-
return !("thread_metadata" in profile);
|
|
36
|
-
}
|
|
37
|
-
function enrichWithThreadInformation(profile) {
|
|
38
|
-
if (!isProcessedJSSelfProfile(profile)) {
|
|
39
|
-
return profile;
|
|
40
|
-
}
|
|
41
|
-
return convertJSSelfProfileToSampledFormat(profile);
|
|
42
|
-
}
|
|
43
|
-
function getTraceId(event) {
|
|
44
|
-
const traceId = event.contexts?.trace?.trace_id;
|
|
45
|
-
if (typeof traceId === "string" && traceId.length !== 32) {
|
|
46
|
-
if (debugBuild.DEBUG_BUILD) {
|
|
47
|
-
browser.debug.log(`[Profiling] Invalid traceId: ${traceId} on profiled event`);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
if (typeof traceId !== "string") {
|
|
51
|
-
return "";
|
|
52
|
-
}
|
|
53
|
-
return traceId;
|
|
54
|
-
}
|
|
55
|
-
function createProfilePayload(profile_id, start_timestamp, processed_profile, event) {
|
|
56
|
-
if (event.type !== "transaction") {
|
|
57
|
-
throw new TypeError("Profiling events may only be attached to transactions, this should never occur.");
|
|
58
|
-
}
|
|
59
|
-
if (processed_profile === void 0 || processed_profile === null) {
|
|
60
|
-
throw new TypeError(
|
|
61
|
-
`Cannot construct profiling event envelope without a valid profile. Got ${processed_profile} instead.`
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
const traceId = getTraceId(event);
|
|
65
|
-
const enrichedThreadProfile = enrichWithThreadInformation(processed_profile);
|
|
66
|
-
const transactionStartMs = start_timestamp ? start_timestamp : typeof event.start_timestamp === "number" ? event.start_timestamp * 1e3 : browser.timestampInSeconds() * 1e3;
|
|
67
|
-
const transactionEndMs = typeof event.timestamp === "number" ? event.timestamp * 1e3 : browser.timestampInSeconds() * 1e3;
|
|
68
|
-
const profile = {
|
|
69
|
-
event_id: profile_id,
|
|
70
|
-
timestamp: new Date(transactionStartMs).toISOString(),
|
|
71
|
-
platform: "javascript",
|
|
72
|
-
version: "1",
|
|
73
|
-
release: event.release || "",
|
|
74
|
-
environment: event.environment || browser.DEFAULT_ENVIRONMENT,
|
|
75
|
-
runtime: {
|
|
76
|
-
name: "javascript",
|
|
77
|
-
version: helpers.WINDOW.navigator.userAgent
|
|
78
|
-
},
|
|
79
|
-
os: {
|
|
80
|
-
name: OS_PLATFORM,
|
|
81
|
-
version: OS_PLATFORM_VERSION,
|
|
82
|
-
build_number: OS_BROWSER
|
|
83
|
-
},
|
|
84
|
-
device: {
|
|
85
|
-
locale: OS_LOCALE,
|
|
86
|
-
model: OS_MODEL,
|
|
87
|
-
manufacturer: OS_BROWSER,
|
|
88
|
-
architecture: OS_ARCH,
|
|
89
|
-
is_emulator: false
|
|
90
|
-
},
|
|
91
|
-
debug_meta: {
|
|
92
|
-
images: applyDebugMetadata(processed_profile.resources)
|
|
93
|
-
},
|
|
94
|
-
profile: enrichedThreadProfile,
|
|
95
|
-
transactions: [
|
|
96
|
-
{
|
|
97
|
-
name: event.transaction || "",
|
|
98
|
-
id: event.event_id || browser.uuid4(),
|
|
99
|
-
trace_id: traceId,
|
|
100
|
-
active_thread_id: PROFILER_THREAD_ID_STRING,
|
|
101
|
-
relative_start_ns: "0",
|
|
102
|
-
relative_end_ns: ((transactionEndMs - transactionStartMs) * 1e6).toFixed(0)
|
|
103
|
-
}
|
|
104
|
-
]
|
|
105
|
-
};
|
|
106
|
-
return profile;
|
|
107
|
-
}
|
|
108
10
|
function createProfileChunkPayload(jsSelfProfile, client, profilerId) {
|
|
109
11
|
if (jsSelfProfile == null) {
|
|
110
12
|
throw new TypeError(
|
|
@@ -216,94 +118,6 @@ function convertToContinuousProfile(input) {
|
|
|
216
118
|
thread_metadata: { [PROFILER_THREAD_ID_STRING]: { name: PROFILER_THREAD_NAME } }
|
|
217
119
|
};
|
|
218
120
|
}
|
|
219
|
-
function isAutomatedPageLoadSpan(span) {
|
|
220
|
-
return browser.spanToJSON(span).op === "pageload";
|
|
221
|
-
}
|
|
222
|
-
function convertJSSelfProfileToSampledFormat(input) {
|
|
223
|
-
let EMPTY_STACK_ID = void 0;
|
|
224
|
-
let STACK_ID = 0;
|
|
225
|
-
const profile = {
|
|
226
|
-
samples: [],
|
|
227
|
-
stacks: [],
|
|
228
|
-
frames: [],
|
|
229
|
-
thread_metadata: {
|
|
230
|
-
[PROFILER_THREAD_ID_STRING]: { name: PROFILER_THREAD_NAME }
|
|
231
|
-
}
|
|
232
|
-
};
|
|
233
|
-
const firstSample = input.samples[0];
|
|
234
|
-
if (!firstSample) {
|
|
235
|
-
return profile;
|
|
236
|
-
}
|
|
237
|
-
const start = firstSample.timestamp;
|
|
238
|
-
const perfOrigin = browser.browserPerformanceTimeOrigin();
|
|
239
|
-
const origin = typeof performance.timeOrigin === "number" ? performance.timeOrigin : perfOrigin || 0;
|
|
240
|
-
const adjustForOriginChange = origin - (perfOrigin || origin);
|
|
241
|
-
input.samples.forEach((jsSample, i) => {
|
|
242
|
-
if (jsSample.stackId === void 0) {
|
|
243
|
-
if (EMPTY_STACK_ID === void 0) {
|
|
244
|
-
EMPTY_STACK_ID = STACK_ID;
|
|
245
|
-
profile.stacks[EMPTY_STACK_ID] = [];
|
|
246
|
-
STACK_ID++;
|
|
247
|
-
}
|
|
248
|
-
profile["samples"][i] = {
|
|
249
|
-
// convert ms timestamp to ns
|
|
250
|
-
elapsed_since_start_ns: ((jsSample.timestamp + adjustForOriginChange - start) * MS_TO_NS).toFixed(0),
|
|
251
|
-
stack_id: EMPTY_STACK_ID,
|
|
252
|
-
thread_id: PROFILER_THREAD_ID_STRING
|
|
253
|
-
};
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
let stackTop = input.stacks[jsSample.stackId];
|
|
257
|
-
const stack = [];
|
|
258
|
-
while (stackTop) {
|
|
259
|
-
stack.push(stackTop.frameId);
|
|
260
|
-
const frame = input.frames[stackTop.frameId];
|
|
261
|
-
if (frame && profile.frames[stackTop.frameId] === void 0) {
|
|
262
|
-
profile.frames[stackTop.frameId] = {
|
|
263
|
-
function: frame.name,
|
|
264
|
-
abs_path: typeof frame.resourceId === "number" ? input.resources[frame.resourceId] : void 0,
|
|
265
|
-
lineno: frame.line,
|
|
266
|
-
colno: frame.column
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
stackTop = stackTop.parentId === void 0 ? void 0 : input.stacks[stackTop.parentId];
|
|
270
|
-
}
|
|
271
|
-
const sample = {
|
|
272
|
-
// convert ms timestamp to ns
|
|
273
|
-
elapsed_since_start_ns: ((jsSample.timestamp + adjustForOriginChange - start) * MS_TO_NS).toFixed(0),
|
|
274
|
-
stack_id: STACK_ID,
|
|
275
|
-
thread_id: PROFILER_THREAD_ID_STRING
|
|
276
|
-
};
|
|
277
|
-
profile["stacks"][STACK_ID] = stack;
|
|
278
|
-
profile["samples"][i] = sample;
|
|
279
|
-
STACK_ID++;
|
|
280
|
-
});
|
|
281
|
-
return profile;
|
|
282
|
-
}
|
|
283
|
-
function addProfilesToEnvelope(envelope, profiles) {
|
|
284
|
-
if (!profiles.length) {
|
|
285
|
-
return envelope;
|
|
286
|
-
}
|
|
287
|
-
for (const profile of profiles) {
|
|
288
|
-
envelope[1].push([{ type: "profile" }, profile]);
|
|
289
|
-
}
|
|
290
|
-
return envelope;
|
|
291
|
-
}
|
|
292
|
-
function findProfiledTransactionsFromEnvelope(envelope) {
|
|
293
|
-
const events = [];
|
|
294
|
-
browser.forEachEnvelopeItem(envelope, (item, type) => {
|
|
295
|
-
if (type !== "transaction") {
|
|
296
|
-
return;
|
|
297
|
-
}
|
|
298
|
-
for (let j = 1; j < item.length; j++) {
|
|
299
|
-
const event = item[j];
|
|
300
|
-
if (event?.contexts?.profile?.profile_id) {
|
|
301
|
-
events.push(item[j]);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
});
|
|
305
|
-
return events;
|
|
306
|
-
}
|
|
307
121
|
function applyDebugMetadata(resource_paths) {
|
|
308
122
|
const client = browser.getClient();
|
|
309
123
|
const options = client?.getOptions();
|
|
@@ -331,21 +145,6 @@ function isValidSampleRate(rate) {
|
|
|
331
145
|
}
|
|
332
146
|
return true;
|
|
333
147
|
}
|
|
334
|
-
function isValidProfile(profile) {
|
|
335
|
-
if (profile.samples.length < 2) {
|
|
336
|
-
if (debugBuild.DEBUG_BUILD) {
|
|
337
|
-
browser.debug.log("[Profiling] Discarding profile because it contains less than 2 samples");
|
|
338
|
-
}
|
|
339
|
-
return false;
|
|
340
|
-
}
|
|
341
|
-
if (!profile.frames.length) {
|
|
342
|
-
if (debugBuild.DEBUG_BUILD) {
|
|
343
|
-
browser.debug.log("[Profiling] Discarding profile because it contains no frames");
|
|
344
|
-
}
|
|
345
|
-
return false;
|
|
346
|
-
}
|
|
347
|
-
return true;
|
|
348
|
-
}
|
|
349
148
|
let PROFILING_CONSTRUCTOR_FAILED = false;
|
|
350
149
|
const MAX_PROFILE_DURATION_MS = 3e4;
|
|
351
150
|
function isJSProfilerSupported(maybeProfiler) {
|
|
@@ -374,45 +173,6 @@ function startJSSelfProfile() {
|
|
|
374
173
|
}
|
|
375
174
|
return;
|
|
376
175
|
}
|
|
377
|
-
function shouldProfileSpanLegacy(span) {
|
|
378
|
-
if (PROFILING_CONSTRUCTOR_FAILED) {
|
|
379
|
-
if (debugBuild.DEBUG_BUILD) {
|
|
380
|
-
browser.debug.log("[Profiling] Profiling has been disabled for the duration of the current user session.");
|
|
381
|
-
}
|
|
382
|
-
return false;
|
|
383
|
-
}
|
|
384
|
-
if (!span.isRecording()) {
|
|
385
|
-
debugBuild.DEBUG_BUILD && browser.debug.log("[Profiling] Discarding profile because root span was not sampled.");
|
|
386
|
-
return false;
|
|
387
|
-
}
|
|
388
|
-
const client = browser.getClient();
|
|
389
|
-
const options = client?.getOptions();
|
|
390
|
-
if (!options) {
|
|
391
|
-
debugBuild.DEBUG_BUILD && browser.debug.log("[Profiling] Profiling disabled, no options found.");
|
|
392
|
-
return false;
|
|
393
|
-
}
|
|
394
|
-
const profilesSampleRate = options.profilesSampleRate;
|
|
395
|
-
if (!isValidSampleRate(profilesSampleRate)) {
|
|
396
|
-
debugBuild.DEBUG_BUILD && browser.debug.warn("[Profiling] Discarding profile because of invalid sample rate.");
|
|
397
|
-
return false;
|
|
398
|
-
}
|
|
399
|
-
if (!profilesSampleRate) {
|
|
400
|
-
debugBuild.DEBUG_BUILD && browser.debug.log(
|
|
401
|
-
"[Profiling] Discarding profile because a negative sampling decision was inherited or profileSampleRate is set to 0"
|
|
402
|
-
);
|
|
403
|
-
return false;
|
|
404
|
-
}
|
|
405
|
-
const sampled = profilesSampleRate === true ? true : Math.random() < profilesSampleRate;
|
|
406
|
-
if (!sampled) {
|
|
407
|
-
debugBuild.DEBUG_BUILD && browser.debug.log(
|
|
408
|
-
`[Profiling] Discarding profile because it's not included in the random sample (sampling rate = ${Number(
|
|
409
|
-
profilesSampleRate
|
|
410
|
-
)})`
|
|
411
|
-
);
|
|
412
|
-
return false;
|
|
413
|
-
}
|
|
414
|
-
return true;
|
|
415
|
-
}
|
|
416
176
|
function shouldProfileSession(options) {
|
|
417
177
|
if (PROFILING_CONSTRUCTOR_FAILED) {
|
|
418
178
|
if (debugBuild.DEBUG_BUILD) {
|
|
@@ -437,62 +197,19 @@ function shouldProfileSession(options) {
|
|
|
437
197
|
}
|
|
438
198
|
return Math.random() <= profileSessionSampleRate;
|
|
439
199
|
}
|
|
440
|
-
function hasLegacyProfiling(options) {
|
|
441
|
-
return typeof options.profilesSampleRate !== "undefined";
|
|
442
|
-
}
|
|
443
|
-
function createProfilingEvent(profile_id, start_timestamp, profile, event) {
|
|
444
|
-
if (!isValidProfile(profile)) {
|
|
445
|
-
return null;
|
|
446
|
-
}
|
|
447
|
-
return createProfilePayload(profile_id, start_timestamp, profile, event);
|
|
448
|
-
}
|
|
449
|
-
const PROFILE_MAP = /* @__PURE__ */ new Map();
|
|
450
|
-
function getActiveProfilesCount() {
|
|
451
|
-
return PROFILE_MAP.size;
|
|
452
|
-
}
|
|
453
|
-
function takeProfileFromGlobalCache(profile_id) {
|
|
454
|
-
const profile = PROFILE_MAP.get(profile_id);
|
|
455
|
-
if (profile) {
|
|
456
|
-
PROFILE_MAP.delete(profile_id);
|
|
457
|
-
}
|
|
458
|
-
return profile;
|
|
459
|
-
}
|
|
460
|
-
function addProfileToGlobalCache(profile_id, profile) {
|
|
461
|
-
PROFILE_MAP.set(profile_id, profile);
|
|
462
|
-
if (PROFILE_MAP.size > 30) {
|
|
463
|
-
const last = PROFILE_MAP.keys().next().value;
|
|
464
|
-
if (last !== void 0) {
|
|
465
|
-
PROFILE_MAP.delete(last);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
const PROFILED_ROOT_SPANS = /* @__PURE__ */ new WeakSet();
|
|
470
200
|
function setThreadAttributes(span) {
|
|
471
201
|
span.setAttribute("thread.id", PROFILER_THREAD_ID_STRING);
|
|
472
202
|
span.setAttribute("thread.name", PROFILER_THREAD_NAME);
|
|
473
203
|
}
|
|
474
204
|
|
|
475
205
|
exports.MAX_PROFILE_DURATION_MS = MAX_PROFILE_DURATION_MS;
|
|
476
|
-
exports.PROFILED_ROOT_SPANS = PROFILED_ROOT_SPANS;
|
|
477
206
|
exports.PROFILER_THREAD_ID_STRING = PROFILER_THREAD_ID_STRING;
|
|
478
207
|
exports.PROFILER_THREAD_NAME = PROFILER_THREAD_NAME;
|
|
479
|
-
exports.addProfileToGlobalCache = addProfileToGlobalCache;
|
|
480
|
-
exports.addProfilesToEnvelope = addProfilesToEnvelope;
|
|
481
208
|
exports.applyDebugMetadata = applyDebugMetadata;
|
|
482
|
-
exports.convertJSSelfProfileToSampledFormat = convertJSSelfProfileToSampledFormat;
|
|
483
209
|
exports.createProfileChunkPayload = createProfileChunkPayload;
|
|
484
|
-
exports.createProfilePayload = createProfilePayload;
|
|
485
|
-
exports.createProfilingEvent = createProfilingEvent;
|
|
486
|
-
exports.enrichWithThreadInformation = enrichWithThreadInformation;
|
|
487
|
-
exports.findProfiledTransactionsFromEnvelope = findProfiledTransactionsFromEnvelope;
|
|
488
|
-
exports.getActiveProfilesCount = getActiveProfilesCount;
|
|
489
|
-
exports.hasLegacyProfiling = hasLegacyProfiling;
|
|
490
|
-
exports.isAutomatedPageLoadSpan = isAutomatedPageLoadSpan;
|
|
491
210
|
exports.isValidSampleRate = isValidSampleRate;
|
|
492
211
|
exports.setThreadAttributes = setThreadAttributes;
|
|
493
212
|
exports.shouldProfileSession = shouldProfileSession;
|
|
494
|
-
exports.shouldProfileSpanLegacy = shouldProfileSpanLegacy;
|
|
495
213
|
exports.startJSSelfProfile = startJSSelfProfile;
|
|
496
|
-
exports.takeProfileFromGlobalCache = takeProfileFromGlobalCache;
|
|
497
214
|
exports.validateProfileChunk = validateProfileChunk;
|
|
498
215
|
//# sourceMappingURL=utils.js.map
|