@sentry/browser 9.39.0 → 10.0.0-alpha.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/client.js +1 -2
- package/build/npm/cjs/client.js.map +1 -1
- package/build/npm/cjs/eventbuilder.js +2 -2
- package/build/npm/cjs/eventbuilder.js.map +1 -1
- package/build/npm/cjs/helpers.js +1 -1
- package/build/npm/cjs/helpers.js.map +1 -1
- package/build/npm/cjs/index.js +3 -0
- package/build/npm/cjs/index.js.map +1 -1
- package/build/npm/cjs/integrations/breadcrumbs.js +2 -2
- package/build/npm/cjs/integrations/breadcrumbs.js.map +1 -1
- package/build/npm/cjs/integrations/browserapierrors.js +1 -1
- package/build/npm/cjs/integrations/browserapierrors.js.map +1 -1
- package/build/npm/cjs/integrations/browsersession.js +1 -1
- package/build/npm/cjs/integrations/browsersession.js.map +1 -1
- package/build/npm/cjs/integrations/featureFlags/unleash/integration.js +1 -1
- package/build/npm/cjs/integrations/featureFlags/unleash/integration.js.map +1 -1
- package/build/npm/cjs/integrations/globalhandlers.js +1 -1
- package/build/npm/cjs/integrations/globalhandlers.js.map +1 -1
- package/build/npm/cjs/integrations/httpclient.js +1 -1
- package/build/npm/cjs/integrations/httpclient.js.map +1 -1
- package/build/npm/cjs/integrations/spotlight.js +4 -5
- package/build/npm/cjs/integrations/spotlight.js.map +1 -1
- package/build/npm/cjs/integrations/webWorker.js +139 -0
- package/build/npm/cjs/integrations/webWorker.js.map +1 -0
- package/build/npm/cjs/log.js +6 -6
- package/build/npm/cjs/log.js.map +1 -1
- package/build/npm/cjs/profiling/integration.js +3 -3
- package/build/npm/cjs/profiling/integration.js.map +1 -1
- package/build/npm/cjs/profiling/startProfileForSpan.js +5 -5
- package/build/npm/cjs/profiling/startProfileForSpan.js.map +1 -1
- package/build/npm/cjs/profiling/utils.js +16 -18
- package/build/npm/cjs/profiling/utils.js.map +1 -1
- package/build/npm/cjs/report-dialog.js +2 -2
- package/build/npm/cjs/report-dialog.js.map +1 -1
- package/build/npm/cjs/tracing/backgroundtab.js +2 -2
- package/build/npm/cjs/tracing/backgroundtab.js.map +1 -1
- package/build/npm/cjs/tracing/browserTracingIntegration.js +4 -4
- package/build/npm/cjs/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/cjs/tracing/linkedTraces.js +3 -3
- package/build/npm/cjs/tracing/linkedTraces.js.map +1 -1
- package/build/npm/cjs/tracing/request.js +2 -2
- package/build/npm/cjs/tracing/request.js.map +1 -1
- package/build/npm/cjs/transports/offline.js +3 -3
- package/build/npm/cjs/transports/offline.js.map +1 -1
- package/build/npm/esm/client.js +1 -2
- package/build/npm/esm/client.js.map +1 -1
- package/build/npm/esm/eventbuilder.js +2 -2
- package/build/npm/esm/eventbuilder.js.map +1 -1
- package/build/npm/esm/helpers.js +1 -1
- package/build/npm/esm/helpers.js.map +1 -1
- package/build/npm/esm/index.js +1 -0
- package/build/npm/esm/index.js.map +1 -1
- package/build/npm/esm/integrations/breadcrumbs.js +3 -3
- package/build/npm/esm/integrations/breadcrumbs.js.map +1 -1
- package/build/npm/esm/integrations/browserapierrors.js +1 -1
- package/build/npm/esm/integrations/browserapierrors.js.map +1 -1
- package/build/npm/esm/integrations/browsersession.js +2 -2
- package/build/npm/esm/integrations/browsersession.js.map +1 -1
- package/build/npm/esm/integrations/featureFlags/unleash/integration.js +2 -2
- package/build/npm/esm/integrations/featureFlags/unleash/integration.js.map +1 -1
- package/build/npm/esm/integrations/globalhandlers.js +2 -2
- package/build/npm/esm/integrations/globalhandlers.js.map +1 -1
- package/build/npm/esm/integrations/httpclient.js +2 -2
- package/build/npm/esm/integrations/httpclient.js.map +1 -1
- package/build/npm/esm/integrations/spotlight.js +5 -6
- package/build/npm/esm/integrations/spotlight.js.map +1 -1
- package/build/npm/esm/integrations/webWorker.js +135 -0
- package/build/npm/esm/integrations/webWorker.js.map +1 -0
- package/build/npm/esm/log.js +6 -6
- package/build/npm/esm/log.js.map +1 -1
- package/build/npm/esm/package.json +1 -1
- package/build/npm/esm/profiling/integration.js +4 -4
- package/build/npm/esm/profiling/integration.js.map +1 -1
- package/build/npm/esm/profiling/startProfileForSpan.js +6 -6
- package/build/npm/esm/profiling/startProfileForSpan.js.map +1 -1
- package/build/npm/esm/profiling/utils.js +17 -19
- package/build/npm/esm/profiling/utils.js.map +1 -1
- package/build/npm/esm/report-dialog.js +3 -3
- package/build/npm/esm/report-dialog.js.map +1 -1
- package/build/npm/esm/tracing/backgroundtab.js +3 -3
- package/build/npm/esm/tracing/backgroundtab.js.map +1 -1
- package/build/npm/esm/tracing/browserTracingIntegration.js +5 -5
- package/build/npm/esm/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/esm/tracing/linkedTraces.js +4 -4
- package/build/npm/esm/tracing/linkedTraces.js.map +1 -1
- package/build/npm/esm/tracing/request.js +2 -2
- package/build/npm/esm/tracing/request.js.map +1 -1
- package/build/npm/esm/transports/offline.js +3 -3
- package/build/npm/esm/transports/offline.js.map +1 -1
- package/build/npm/types/client.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/spotlight.d.ts.map +1 -1
- package/build/npm/types/integrations/webWorker.d.ts +103 -0
- package/build/npm/types/integrations/webWorker.d.ts.map +1 -0
- package/build/npm/types/log.d.ts +6 -6
- package/build/npm/types/profiling/utils.d.ts.map +1 -1
- package/build/npm/types-ts3.8/index.d.ts +1 -0
- package/build/npm/types-ts3.8/integrations/webWorker.d.ts +103 -0
- package/build/npm/types-ts3.8/log.d.ts +6 -6
- package/package.json +7 -7
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { defineIntegration, debug, isPlainObject } from '@sentry/core';
|
|
2
|
+
import { DEBUG_BUILD } from '../debug-build.js';
|
|
3
|
+
import { WINDOW } from '../helpers.js';
|
|
4
|
+
|
|
5
|
+
const INTEGRATION_NAME = 'WebWorker';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Use this integration to set up Sentry with web workers.
|
|
9
|
+
*
|
|
10
|
+
* IMPORTANT: This integration must be added **before** you start listening to
|
|
11
|
+
* any messages from the worker. Otherwise, your message handlers will receive
|
|
12
|
+
* messages from the Sentry SDK which you need to ignore.
|
|
13
|
+
*
|
|
14
|
+
* This integration only has an effect, if you call `Sentry.registerWorker(self)`
|
|
15
|
+
* from within the worker(s) you're adding to the integration.
|
|
16
|
+
*
|
|
17
|
+
* Given that you want to initialize the SDK as early as possible, you most likely
|
|
18
|
+
* want to add this integration **after** initializing the SDK:
|
|
19
|
+
*
|
|
20
|
+
* @example:
|
|
21
|
+
* ```ts filename={main.js}
|
|
22
|
+
* import * as Sentry from '@sentry/<your-sdk>';
|
|
23
|
+
*
|
|
24
|
+
* // some time earlier:
|
|
25
|
+
* Sentry.init(...)
|
|
26
|
+
*
|
|
27
|
+
* // 1. Initialize the worker
|
|
28
|
+
* const worker = new Worker(new URL('./worker.ts', import.meta.url));
|
|
29
|
+
*
|
|
30
|
+
* // 2. Add the integration
|
|
31
|
+
* const webWorkerIntegration = Sentry.webWorkerIntegration({ worker });
|
|
32
|
+
* Sentry.addIntegration(webWorkerIntegration);
|
|
33
|
+
*
|
|
34
|
+
* // 3. Register message listeners on the worker
|
|
35
|
+
* worker.addEventListener('message', event => {
|
|
36
|
+
* // ...
|
|
37
|
+
* });
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* If you initialize multiple workers at the same time, you can also pass an array of workers
|
|
41
|
+
* to the integration:
|
|
42
|
+
*
|
|
43
|
+
* ```ts filename={main.js}
|
|
44
|
+
* const webWorkerIntegration = Sentry.webWorkerIntegration({ worker: [worker1, worker2] });
|
|
45
|
+
* Sentry.addIntegration(webWorkerIntegration);
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* If you have any additional workers that you initialize at a later point,
|
|
49
|
+
* you can add them to the integration as follows:
|
|
50
|
+
*
|
|
51
|
+
* ```ts filename={main.js}
|
|
52
|
+
* const webWorkerIntegration = Sentry.webWorkerIntegration({ worker: worker1 });
|
|
53
|
+
* Sentry.addIntegration(webWorkerIntegration);
|
|
54
|
+
*
|
|
55
|
+
* // sometime later:
|
|
56
|
+
* webWorkerIntegration.addWorker(worker2);
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* Of course, you can also directly add the integration in Sentry.init:
|
|
60
|
+
* ```ts filename={main.js}
|
|
61
|
+
* import * as Sentry from '@sentry/<your-sdk>';
|
|
62
|
+
*
|
|
63
|
+
* // 1. Initialize the worker
|
|
64
|
+
* const worker = new Worker(new URL('./worker.ts', import.meta.url));
|
|
65
|
+
*
|
|
66
|
+
* // 2. Initialize the SDK
|
|
67
|
+
* Sentry.init({
|
|
68
|
+
* integrations: [Sentry.webWorkerIntegration({ worker })]
|
|
69
|
+
* });
|
|
70
|
+
*
|
|
71
|
+
* // 3. Register message listeners on the worker
|
|
72
|
+
* worker.addEventListener('message', event => {
|
|
73
|
+
* // ...
|
|
74
|
+
* });
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* @param options {WebWorkerIntegrationOptions} Integration options:
|
|
78
|
+
* - `worker`: The worker instance.
|
|
79
|
+
*/
|
|
80
|
+
const webWorkerIntegration = defineIntegration(({ worker }) => ({
|
|
81
|
+
name: INTEGRATION_NAME,
|
|
82
|
+
setupOnce: () => {
|
|
83
|
+
(Array.isArray(worker) ? worker : [worker]).forEach(w => listenForSentryDebugIdMessages(w));
|
|
84
|
+
},
|
|
85
|
+
addWorker: (worker) => listenForSentryDebugIdMessages(worker),
|
|
86
|
+
})) ;
|
|
87
|
+
|
|
88
|
+
function listenForSentryDebugIdMessages(worker) {
|
|
89
|
+
worker.addEventListener('message', event => {
|
|
90
|
+
if (isSentryDebugIdMessage(event.data)) {
|
|
91
|
+
event.stopImmediatePropagation(); // other listeners should not receive this message
|
|
92
|
+
DEBUG_BUILD && debug.log('Sentry debugId web worker message received', event.data);
|
|
93
|
+
WINDOW._sentryDebugIds = {
|
|
94
|
+
...event.data._sentryDebugIds,
|
|
95
|
+
// debugIds of the main thread have precedence over the worker's in case of a collision.
|
|
96
|
+
...WINDOW._sentryDebugIds,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Use this function to register the worker with the Sentry SDK.
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```ts filename={worker.js}
|
|
107
|
+
* import * as Sentry from '@sentry/<your-sdk>';
|
|
108
|
+
*
|
|
109
|
+
* // Do this as early as possible in your worker.
|
|
110
|
+
* Sentry.registerWorker({ self });
|
|
111
|
+
*
|
|
112
|
+
* // continue setting up your worker
|
|
113
|
+
* self.postMessage(...)
|
|
114
|
+
* ```
|
|
115
|
+
* @param options {RegisterWebWorkerOptions} Integration options:
|
|
116
|
+
* - `self`: The worker instance you're calling this function from (self).
|
|
117
|
+
*/
|
|
118
|
+
function registerWebWorker({ self }) {
|
|
119
|
+
self.postMessage({
|
|
120
|
+
_sentryMessage: true,
|
|
121
|
+
_sentryDebugIds: self._sentryDebugIds ?? undefined,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function isSentryDebugIdMessage(eventData) {
|
|
126
|
+
return (
|
|
127
|
+
isPlainObject(eventData) &&
|
|
128
|
+
eventData._sentryMessage === true &&
|
|
129
|
+
'_sentryDebugIds' in eventData &&
|
|
130
|
+
(isPlainObject(eventData._sentryDebugIds) || eventData._sentryDebugIds === undefined)
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export { INTEGRATION_NAME, registerWebWorker, webWorkerIntegration };
|
|
135
|
+
//# sourceMappingURL=webWorker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webWorker.js","sources":["../../../../src/integrations/webWorker.ts"],"sourcesContent":["import type { Integration, IntegrationFn } from '@sentry/core';\nimport { debug, defineIntegration, isPlainObject } from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { WINDOW } from '../helpers';\n\nexport const INTEGRATION_NAME = 'WebWorker';\n\ninterface WebWorkerMessage {\n _sentryMessage: boolean;\n _sentryDebugIds?: Record<string, string>;\n}\n\ninterface WebWorkerIntegrationOptions {\n worker: Worker | Array<Worker>;\n}\n\ninterface WebWorkerIntegration extends Integration {\n addWorker: (worker: Worker) => void;\n}\n\n/**\n * Use this integration to set up Sentry with web workers.\n *\n * IMPORTANT: This integration must be added **before** you start listening to\n * any messages from the worker. Otherwise, your message handlers will receive\n * messages from the Sentry SDK which you need to ignore.\n *\n * This integration only has an effect, if you call `Sentry.registerWorker(self)`\n * from within the worker(s) you're adding to the integration.\n *\n * Given that you want to initialize the SDK as early as possible, you most likely\n * want to add this integration **after** initializing the SDK:\n *\n * @example:\n * ```ts filename={main.js}\n * import * as Sentry from '@sentry/<your-sdk>';\n *\n * // some time earlier:\n * Sentry.init(...)\n *\n * // 1. Initialize the worker\n * const worker = new Worker(new URL('./worker.ts', import.meta.url));\n *\n * // 2. Add the integration\n * const webWorkerIntegration = Sentry.webWorkerIntegration({ worker });\n * Sentry.addIntegration(webWorkerIntegration);\n *\n * // 3. Register message listeners on the worker\n * worker.addEventListener('message', event => {\n * // ...\n * });\n * ```\n *\n * If you initialize multiple workers at the same time, you can also pass an array of workers\n * to the integration:\n *\n * ```ts filename={main.js}\n * const webWorkerIntegration = Sentry.webWorkerIntegration({ worker: [worker1, worker2] });\n * Sentry.addIntegration(webWorkerIntegration);\n * ```\n *\n * If you have any additional workers that you initialize at a later point,\n * you can add them to the integration as follows:\n *\n * ```ts filename={main.js}\n * const webWorkerIntegration = Sentry.webWorkerIntegration({ worker: worker1 });\n * Sentry.addIntegration(webWorkerIntegration);\n *\n * // sometime later:\n * webWorkerIntegration.addWorker(worker2);\n * ```\n *\n * Of course, you can also directly add the integration in Sentry.init:\n * ```ts filename={main.js}\n * import * as Sentry from '@sentry/<your-sdk>';\n *\n * // 1. Initialize the worker\n * const worker = new Worker(new URL('./worker.ts', import.meta.url));\n *\n * // 2. Initialize the SDK\n * Sentry.init({\n * integrations: [Sentry.webWorkerIntegration({ worker })]\n * });\n *\n * // 3. Register message listeners on the worker\n * worker.addEventListener('message', event => {\n * // ...\n * });\n * ```\n *\n * @param options {WebWorkerIntegrationOptions} Integration options:\n * - `worker`: The worker instance.\n */\nexport const webWorkerIntegration = defineIntegration(({ worker }: WebWorkerIntegrationOptions) => ({\n name: INTEGRATION_NAME,\n setupOnce: () => {\n (Array.isArray(worker) ? worker : [worker]).forEach(w => listenForSentryDebugIdMessages(w));\n },\n addWorker: (worker: Worker) => listenForSentryDebugIdMessages(worker),\n})) as IntegrationFn<WebWorkerIntegration>;\n\nfunction listenForSentryDebugIdMessages(worker: Worker): void {\n worker.addEventListener('message', event => {\n if (isSentryDebugIdMessage(event.data)) {\n event.stopImmediatePropagation(); // other listeners should not receive this message\n DEBUG_BUILD && debug.log('Sentry debugId web worker message received', event.data);\n WINDOW._sentryDebugIds = {\n ...event.data._sentryDebugIds,\n // debugIds of the main thread have precedence over the worker's in case of a collision.\n ...WINDOW._sentryDebugIds,\n };\n }\n });\n}\n\ninterface RegisterWebWorkerOptions {\n self: Worker & { _sentryDebugIds?: Record<string, string> };\n}\n\n/**\n * Use this function to register the worker with the Sentry SDK.\n *\n * @example\n * ```ts filename={worker.js}\n * import * as Sentry from '@sentry/<your-sdk>';\n *\n * // Do this as early as possible in your worker.\n * Sentry.registerWorker({ self });\n *\n * // continue setting up your worker\n * self.postMessage(...)\n * ```\n * @param options {RegisterWebWorkerOptions} Integration options:\n * - `self`: The worker instance you're calling this function from (self).\n */\nexport function registerWebWorker({ self }: RegisterWebWorkerOptions): void {\n self.postMessage({\n _sentryMessage: true,\n _sentryDebugIds: self._sentryDebugIds ?? undefined,\n });\n}\n\nfunction isSentryDebugIdMessage(eventData: unknown): eventData is WebWorkerMessage {\n return (\n isPlainObject(eventData) &&\n eventData._sentryMessage === true &&\n '_sentryDebugIds' in eventData &&\n (isPlainObject(eventData._sentryDebugIds) || eventData._sentryDebugIds === undefined)\n );\n}\n"],"names":[],"mappings":";;;;AAKO,MAAM,gBAAA,GAAmB;;AAehC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,oBAAA,GAAuB,iBAAiB,CAAC,CAAC,EAAE,MAAA,EAAQ,MAAmC;AACpG,EAAE,IAAI,EAAE,gBAAgB;AACxB,EAAE,SAAS,EAAE,MAAM;AACnB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAA,GAAI,MAAA,GAAS,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAA,IAAK,8BAA8B,CAAC,CAAC,CAAC,CAAC;AAC/F,GAAG;AACH,EAAE,SAAS,EAAE,CAAC,MAAM,KAAa,8BAA8B,CAAC,MAAM,CAAC;AACvE,CAAC,CAAC,CAAA;;AAEF,SAAS,8BAA8B,CAAC,MAAM,EAAgB;AAC9D,EAAE,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,SAAS;AAC9C,IAAI,IAAI,sBAAsB,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;AAC5C,MAAM,KAAK,CAAC,wBAAwB,EAAE,CAAA;AACtC,MAAM,WAAA,IAAe,KAAK,CAAC,GAAG,CAAC,4CAA4C,EAAE,KAAK,CAAC,IAAI,CAAC;AACxF,MAAM,MAAM,CAAC,eAAA,GAAkB;AAC/B,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,eAAe;AACrC;AACA,QAAQ,GAAG,MAAM,CAAC,eAAe;AACjC,OAAO;AACP;AACA,GAAG,CAAC;AACJ;;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,iBAAiB,CAAC,EAAE,IAAA,EAAM,EAAkC;AAC5E,EAAE,IAAI,CAAC,WAAW,CAAC;AACnB,IAAI,cAAc,EAAE,IAAI;AACxB,IAAI,eAAe,EAAE,IAAI,CAAC,eAAA,IAAmB,SAAS;AACtD,GAAG,CAAC;AACJ;;AAEA,SAAS,sBAAsB,CAAC,SAAS,EAA0C;AACnF,EAAE;AACF,IAAI,aAAa,CAAC,SAAS,CAAA;AAC3B,IAAI,SAAS,CAAC,cAAA,KAAmB,IAAA;AACjC,IAAI,iBAAA,IAAqB,SAAA;AACzB,KAAK,aAAa,CAAC,SAAS,CAAC,eAAe,CAAA,IAAK,SAAS,CAAC,eAAA,KAAoB,SAAS;AACxF;AACA;;;;"}
|
package/build/npm/esm/log.js
CHANGED
|
@@ -19,7 +19,7 @@ function captureLog(
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* @summary Capture a log with the `trace` level. Requires `
|
|
22
|
+
* @summary Capture a log with the `trace` level. Requires the `enableLogs` option to be enabled.
|
|
23
23
|
*
|
|
24
24
|
* @param message - The message to log.
|
|
25
25
|
* @param attributes - Arbitrary structured data that stores information about the log - e.g., { userId: 100, route: '/dashboard' }.
|
|
@@ -48,7 +48,7 @@ function trace(message, attributes) {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
|
-
* @summary Capture a log with the `debug` level. Requires `
|
|
51
|
+
* @summary Capture a log with the `debug` level. Requires the `enableLogs` option to be enabled.
|
|
52
52
|
*
|
|
53
53
|
* @param message - The message to log.
|
|
54
54
|
* @param attributes - Arbitrary structured data that stores information about the log - e.g., { component: 'Header', state: 'loading' }.
|
|
@@ -78,7 +78,7 @@ function debug(message, attributes) {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
/**
|
|
81
|
-
* @summary Capture a log with the `info` level. Requires `
|
|
81
|
+
* @summary Capture a log with the `info` level. Requires the `enableLogs` option to be enabled.
|
|
82
82
|
*
|
|
83
83
|
* @param message - The message to log.
|
|
84
84
|
* @param attributes - Arbitrary structured data that stores information about the log - e.g., { feature: 'checkout', status: 'completed' }.
|
|
@@ -108,7 +108,7 @@ function info(message, attributes) {
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
/**
|
|
111
|
-
* @summary Capture a log with the `warn` level. Requires `
|
|
111
|
+
* @summary Capture a log with the `warn` level. Requires the `enableLogs` option to be enabled.
|
|
112
112
|
*
|
|
113
113
|
* @param message - The message to log.
|
|
114
114
|
* @param attributes - Arbitrary structured data that stores information about the log - e.g., { browser: 'Chrome', version: '91.0' }.
|
|
@@ -139,7 +139,7 @@ function warn(message, attributes) {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
/**
|
|
142
|
-
* @summary Capture a log with the `error` level. Requires `
|
|
142
|
+
* @summary Capture a log with the `error` level. Requires the `enableLogs` option to be enabled.
|
|
143
143
|
*
|
|
144
144
|
* @param message - The message to log.
|
|
145
145
|
* @param attributes - Arbitrary structured data that stores information about the log - e.g., { error: 'NetworkError', url: '/api/data' }.
|
|
@@ -171,7 +171,7 @@ function error(message, attributes) {
|
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
/**
|
|
174
|
-
* @summary Capture a log with the `fatal` level. Requires `
|
|
174
|
+
* @summary Capture a log with the `fatal` level. Requires the `enableLogs` option to be enabled.
|
|
175
175
|
*
|
|
176
176
|
* @param message - The message to log.
|
|
177
177
|
* @param attributes - Arbitrary structured data that stores information about the log - e.g., { appState: 'corrupted', sessionId: 'abc-123' }.
|
package/build/npm/esm/log.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log.js","sources":["../../../src/log.ts"],"sourcesContent":["import type { Log, LogSeverityLevel, ParameterizedString } from '@sentry/core';\nimport { _INTERNAL_captureLog } from '@sentry/core';\n\n/**\n * Capture a log with the given level.\n *\n * @param level - The level of the log.\n * @param message - The message to log.\n * @param attributes - Arbitrary structured data that stores information about the log - e.g., userId: 100.\n * @param severityNumber - The severity number of the log.\n */\nfunction captureLog(\n level: LogSeverityLevel,\n message: ParameterizedString,\n attributes?: Log['attributes'],\n severityNumber?: Log['severityNumber'],\n): void {\n _INTERNAL_captureLog({ level, message, attributes, severityNumber });\n}\n\n/**\n * @summary Capture a log with the `trace` level. Requires `
|
|
1
|
+
{"version":3,"file":"log.js","sources":["../../../src/log.ts"],"sourcesContent":["import type { Log, LogSeverityLevel, ParameterizedString } from '@sentry/core';\nimport { _INTERNAL_captureLog } from '@sentry/core';\n\n/**\n * Capture a log with the given level.\n *\n * @param level - The level of the log.\n * @param message - The message to log.\n * @param attributes - Arbitrary structured data that stores information about the log - e.g., userId: 100.\n * @param severityNumber - The severity number of the log.\n */\nfunction captureLog(\n level: LogSeverityLevel,\n message: ParameterizedString,\n attributes?: Log['attributes'],\n severityNumber?: Log['severityNumber'],\n): void {\n _INTERNAL_captureLog({ level, message, attributes, severityNumber });\n}\n\n/**\n * @summary Capture a log with the `trace` level. Requires the `enableLogs` option to be enabled.\n *\n * @param message - The message to log.\n * @param attributes - Arbitrary structured data that stores information about the log - e.g., { userId: 100, route: '/dashboard' }.\n *\n * @example\n *\n * ```\n * Sentry.logger.trace('User clicked submit button', {\n * buttonId: 'submit-form',\n * formId: 'user-profile',\n * timestamp: Date.now()\n * });\n * ```\n *\n * @example With template strings\n *\n * ```\n * Sentry.logger.trace(Sentry.logger.fmt`User ${user} navigated to ${page}`, {\n * userId: '123',\n * sessionId: 'abc-xyz'\n * });\n * ```\n */\nexport function trace(message: ParameterizedString, attributes?: Log['attributes']): void {\n captureLog('trace', message, attributes);\n}\n\n/**\n * @summary Capture a log with the `debug` level. Requires the `enableLogs` option to be enabled.\n *\n * @param message - The message to log.\n * @param attributes - Arbitrary structured data that stores information about the log - e.g., { component: 'Header', state: 'loading' }.\n *\n * @example\n *\n * ```\n * Sentry.logger.debug('Component mounted', {\n * component: 'UserProfile',\n * props: { userId: 123 },\n * renderTime: 150\n * });\n * ```\n *\n * @example With template strings\n *\n * ```\n * Sentry.logger.debug(Sentry.logger.fmt`API request to ${endpoint} failed`, {\n * statusCode: 404,\n * requestId: 'req-123',\n * duration: 250\n * });\n * ```\n */\nexport function debug(message: ParameterizedString, attributes?: Log['attributes']): void {\n captureLog('debug', message, attributes);\n}\n\n/**\n * @summary Capture a log with the `info` level. Requires the `enableLogs` option to be enabled.\n *\n * @param message - The message to log.\n * @param attributes - Arbitrary structured data that stores information about the log - e.g., { feature: 'checkout', status: 'completed' }.\n *\n * @example\n *\n * ```\n * Sentry.logger.info('User completed checkout', {\n * orderId: 'order-123',\n * amount: 99.99,\n * paymentMethod: 'credit_card'\n * });\n * ```\n *\n * @example With template strings\n *\n * ```\n * Sentry.logger.info(Sentry.logger.fmt`User ${user} updated profile picture`, {\n * userId: 'user-123',\n * imageSize: '2.5MB',\n * timestamp: Date.now()\n * });\n * ```\n */\nexport function info(message: ParameterizedString, attributes?: Log['attributes']): void {\n captureLog('info', message, attributes);\n}\n\n/**\n * @summary Capture a log with the `warn` level. Requires the `enableLogs` option to be enabled.\n *\n * @param message - The message to log.\n * @param attributes - Arbitrary structured data that stores information about the log - e.g., { browser: 'Chrome', version: '91.0' }.\n *\n * @example\n *\n * ```\n * Sentry.logger.warn('Browser compatibility issue detected', {\n * browser: 'Safari',\n * version: '14.0',\n * feature: 'WebRTC',\n * fallback: 'enabled'\n * });\n * ```\n *\n * @example With template strings\n *\n * ```\n * Sentry.logger.warn(Sentry.logger.fmt`API endpoint ${endpoint} is deprecated`, {\n * recommendedEndpoint: '/api/v2/users',\n * sunsetDate: '2024-12-31',\n * clientVersion: '1.2.3'\n * });\n * ```\n */\nexport function warn(message: ParameterizedString, attributes?: Log['attributes']): void {\n captureLog('warn', message, attributes);\n}\n\n/**\n * @summary Capture a log with the `error` level. Requires the `enableLogs` option to be enabled.\n *\n * @param message - The message to log.\n * @param attributes - Arbitrary structured data that stores information about the log - e.g., { error: 'NetworkError', url: '/api/data' }.\n *\n * @example\n *\n * ```\n * Sentry.logger.error('Failed to load user data', {\n * error: 'NetworkError',\n * url: '/api/users/123',\n * statusCode: 500,\n * retryCount: 3\n * });\n * ```\n *\n * @example With template strings\n *\n * ```\n * Sentry.logger.error(Sentry.logger.fmt`Payment processing failed for order ${orderId}`, {\n * error: 'InsufficientFunds',\n * amount: 100.00,\n * currency: 'USD',\n * userId: 'user-456'\n * });\n * ```\n */\nexport function error(message: ParameterizedString, attributes?: Log['attributes']): void {\n captureLog('error', message, attributes);\n}\n\n/**\n * @summary Capture a log with the `fatal` level. Requires the `enableLogs` option to be enabled.\n *\n * @param message - The message to log.\n * @param attributes - Arbitrary structured data that stores information about the log - e.g., { appState: 'corrupted', sessionId: 'abc-123' }.\n *\n * @example\n *\n * ```\n * Sentry.logger.fatal('Application state corrupted', {\n * lastKnownState: 'authenticated',\n * sessionId: 'session-123',\n * timestamp: Date.now(),\n * recoveryAttempted: true\n * });\n * ```\n *\n * @example With template strings\n *\n * ```\n * Sentry.logger.fatal(Sentry.logger.fmt`Critical system failure in ${service}`, {\n * service: 'payment-processor',\n * errorCode: 'CRITICAL_FAILURE',\n * affectedUsers: 150,\n * timestamp: Date.now()\n * });\n * ```\n */\nexport function fatal(message: ParameterizedString, attributes?: Log['attributes']): void {\n captureLog('fatal', message, attributes);\n}\n\nexport { fmt } from '@sentry/core';\n"],"names":[],"mappings":";;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,UAAU;AACnB,EAAE,KAAK;AACP,EAAE,OAAO;AACT,EAAE,UAAU;AACZ,EAAE,cAAc;AAChB,EAAQ;AACR,EAAE,oBAAoB,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,cAAA,EAAgB,CAAC;AACtE;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,KAAK,CAAC,OAAO,EAAuB,UAAU,EAA4B;AAC1F,EAAE,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC;AAC1C;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,KAAK,CAAC,OAAO,EAAuB,UAAU,EAA4B;AAC1F,EAAE,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC;AAC1C;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,IAAI,CAAC,OAAO,EAAuB,UAAU,EAA4B;AACzF,EAAE,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC;AACzC;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,IAAI,CAAC,OAAO,EAAuB,UAAU,EAA4B;AACzF,EAAE,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC;AACzC;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,KAAK,CAAC,OAAO,EAAuB,UAAU,EAA4B;AAC1F,EAAE,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC;AAC1C;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,KAAK,CAAC,OAAO,EAAuB,UAAU,EAA4B;AAC1F,EAAE,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC;AAC1C;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"module","version":"
|
|
1
|
+
{"type":"module","version":"10.0.0-alpha.0","sideEffects":false}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineIntegration, getActiveSpan, getRootSpan,
|
|
1
|
+
import { defineIntegration, getActiveSpan, getRootSpan, debug } from '@sentry/core';
|
|
2
2
|
import { DEBUG_BUILD } from '../debug-build.js';
|
|
3
3
|
import { startProfileForSpan } from './startProfileForSpan.js';
|
|
4
4
|
import { isAutomatedPageLoadSpan, shouldProfileSpan, getActiveProfilesCount, findProfiledTransactionsFromEnvelope, takeProfileFromGlobalCache, createProfilingEvent, addProfilesToEnvelope } from './utils.js';
|
|
@@ -43,12 +43,12 @@ const _browserProfilingIntegration = (() => {
|
|
|
43
43
|
const start_timestamp = context?.profile?.['start_timestamp'];
|
|
44
44
|
|
|
45
45
|
if (typeof profile_id !== 'string') {
|
|
46
|
-
DEBUG_BUILD &&
|
|
46
|
+
DEBUG_BUILD && debug.log('[Profiling] cannot find profile for a span without a profile context');
|
|
47
47
|
continue;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
if (!profile_id) {
|
|
51
|
-
DEBUG_BUILD &&
|
|
51
|
+
DEBUG_BUILD && debug.log('[Profiling] cannot find profile for a span without a profile context');
|
|
52
52
|
continue;
|
|
53
53
|
}
|
|
54
54
|
|
|
@@ -59,7 +59,7 @@ const _browserProfilingIntegration = (() => {
|
|
|
59
59
|
|
|
60
60
|
const profile = takeProfileFromGlobalCache(profile_id);
|
|
61
61
|
if (!profile) {
|
|
62
|
-
DEBUG_BUILD &&
|
|
62
|
+
DEBUG_BUILD && debug.log(`[Profiling] Could not retrieve profile for span: ${profile_id}`);
|
|
63
63
|
continue;
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration.js","sources":["../../../../src/profiling/integration.ts"],"sourcesContent":["import type { EventEnvelope, IntegrationFn, Profile, Span } from '@sentry/core';\nimport { defineIntegration, getActiveSpan, getRootSpan
|
|
1
|
+
{"version":3,"file":"integration.js","sources":["../../../../src/profiling/integration.ts"],"sourcesContent":["import type { EventEnvelope, IntegrationFn, Profile, Span } from '@sentry/core';\nimport { debug, defineIntegration, getActiveSpan, getRootSpan } from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { startProfileForSpan } from './startProfileForSpan';\nimport type { ProfiledEvent } from './utils';\nimport {\n addProfilesToEnvelope,\n createProfilingEvent,\n findProfiledTransactionsFromEnvelope,\n getActiveProfilesCount,\n isAutomatedPageLoadSpan,\n shouldProfileSpan,\n takeProfileFromGlobalCache,\n} from './utils';\n\nconst INTEGRATION_NAME = 'BrowserProfiling';\n\nconst _browserProfilingIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setup(client) {\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan && getRootSpan(activeSpan);\n\n if (rootSpan && isAutomatedPageLoadSpan(rootSpan)) {\n if (shouldProfileSpan(rootSpan)) {\n startProfileForSpan(rootSpan);\n }\n }\n\n client.on('spanStart', (span: Span) => {\n if (span === getRootSpan(span) && shouldProfileSpan(span)) {\n startProfileForSpan(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}) satisfies IntegrationFn;\n\nexport const browserProfilingIntegration = defineIntegration(_browserProfilingIntegration);\n"],"names":[],"mappings":";;;;;AAeA,MAAM,gBAAA,GAAmB,kBAAkB;;AAE3C,MAAM,4BAAA,IAAgC,MAAM;AAC5C,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,gBAAgB;AAC1B,IAAI,KAAK,CAAC,MAAM,EAAE;AAClB,MAAM,MAAM,UAAA,GAAa,aAAa,EAAE;AACxC,MAAM,MAAM,WAAW,UAAA,IAAc,WAAW,CAAC,UAAU,CAAC;;AAE5D,MAAM,IAAI,QAAA,IAAY,uBAAuB,CAAC,QAAQ,CAAC,EAAE;AACzD,QAAQ,IAAI,iBAAiB,CAAC,QAAQ,CAAC,EAAE;AACzC,UAAU,mBAAmB,CAAC,QAAQ,CAAC;AACvC;AACA;;AAEA,MAAM,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,IAAI,KAAW;AAC7C,QAAQ,IAAI,IAAA,KAAS,WAAW,CAAC,IAAI,CAAA,IAAK,iBAAiB,CAAC,IAAI,CAAC,EAAE;AACnE,UAAU,mBAAmB,CAAC,IAAI,CAAC;AACnC;AACA,OAAO,CAAC;;AAER,MAAM,MAAM,CAAC,EAAE,CAAC,gBAAgB,EAAE,CAAC,QAAQ,KAAW;AACtD;AACA,QAAQ,IAAI,CAAC,sBAAsB,EAAE,EAAE;AACvC,UAAU;AACV;;AAEA,QAAQ,MAAM,yBAAA,GAA4B,oCAAoC,CAAC,QAAQ,CAAC;AACxF,QAAQ,IAAI,CAAC,yBAAyB,CAAC,MAAM,EAAE;AAC/C,UAAU;AACV;;AAEA,QAAQ,MAAM,uBAAuB,GAAc,EAAE;;AAErD,QAAQ,KAAK,MAAM,mBAAA,IAAuB,yBAAyB,EAAE;AACrE,UAAU,MAAM,OAAA,GAAU,mBAAmB,EAAE,QAAQ;AACvD,UAAU,MAAM,aAAa,OAAO,EAAE,OAAO,GAAG,YAAY,CAAC;AAC7D,UAAU,MAAM,kBAAkB,OAAO,EAAE,OAAO,GAAG,iBAAiB,CAAC;;AAEvE,UAAU,IAAI,OAAO,UAAA,KAAe,QAAQ,EAAE;AAC9C,YAAY,eAAe,KAAK,CAAC,GAAG,CAAC,sEAAsE,CAAC;AAC5G,YAAY;AACZ;;AAEA,UAAU,IAAI,CAAC,UAAU,EAAE;AAC3B,YAAY,eAAe,KAAK,CAAC,GAAG,CAAC,sEAAsE,CAAC;AAC5G,YAAY;AACZ;;AAEA;AACA,UAAU,IAAI,OAAO,EAAE,OAAO,EAAE;AAChC,YAAY,OAAO,OAAO,CAAC,OAAO;AAClC;;AAEA,UAAU,MAAM,OAAA,GAAU,0BAA0B,CAAC,UAAU,CAAC;AAChE,UAAU,IAAI,CAAC,OAAO,EAAE;AACxB,YAAY,WAAA,IAAe,KAAK,CAAC,GAAG,CAAC,CAAC,iDAAiD,EAAE,UAAU,CAAC,CAAA,CAAA;AACA,YAAA;AACA;;AAEA,UAAA,MAAA,YAAA,GAAA,oBAAA;AACA,YAAA,UAAA;AACA,YAAA,eAAA;AACA,YAAA,OAAA;AACA,YAAA,mBAAA;AACA,WAAA;AACA,UAAA,IAAA,YAAA,EAAA;AACA,YAAA,uBAAA,CAAA,IAAA,CAAA,YAAA,CAAA;AACA;AACA;;AAEA,QAAA,qBAAA,CAAA,QAAA,GAAA,uBAAA,CAAA;AACA,OAAA,CAAA;AACA,KAAA;AACA,GAAA;AACA,CAAA,CAAA;;AAEA,MAAA,2BAAA,GAAA,iBAAA,CAAA,4BAAA;;;;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { timestampInSeconds,
|
|
1
|
+
import { timestampInSeconds, debug, spanToJSON, uuid4, getCurrentScope } from '@sentry/core';
|
|
2
2
|
import { DEBUG_BUILD } from '../debug-build.js';
|
|
3
3
|
import { WINDOW } from '../helpers.js';
|
|
4
4
|
import { isAutomatedPageLoadSpan, startJSSelfProfile, MAX_PROFILE_DURATION_MS, addProfileToGlobalCache } from './utils.js';
|
|
@@ -24,7 +24,7 @@ function startProfileForSpan(span) {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
if (DEBUG_BUILD) {
|
|
27
|
-
|
|
27
|
+
debug.log(`[Profiling] started profiling span: ${spanToJSON(span).description}`);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
// We create "unique" span names to avoid concurrent spans with same names
|
|
@@ -59,13 +59,13 @@ function startProfileForSpan(span) {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
if (DEBUG_BUILD) {
|
|
62
|
-
|
|
62
|
+
debug.log(`[Profiling] stopped profiling of span: ${spanToJSON(span).description}`);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
// In case of an overlapping span, stopProfiling may return null and silently ignore the overlapping profile.
|
|
66
66
|
if (!profile) {
|
|
67
67
|
if (DEBUG_BUILD) {
|
|
68
|
-
|
|
68
|
+
debug.log(
|
|
69
69
|
`[Profiling] profiler returned null profile for: ${spanToJSON(span).description}`,
|
|
70
70
|
'this may indicate an overlapping span or a call to stopProfiling with a profile title that was never started',
|
|
71
71
|
);
|
|
@@ -77,7 +77,7 @@ function startProfileForSpan(span) {
|
|
|
77
77
|
})
|
|
78
78
|
.catch(error => {
|
|
79
79
|
if (DEBUG_BUILD) {
|
|
80
|
-
|
|
80
|
+
debug.log('[Profiling] error while stopping profiler:', error);
|
|
81
81
|
}
|
|
82
82
|
});
|
|
83
83
|
}
|
|
@@ -85,7 +85,7 @@ function startProfileForSpan(span) {
|
|
|
85
85
|
// Enqueue a timeout to prevent profiles from running over max duration.
|
|
86
86
|
let maxDurationTimeoutID = WINDOW.setTimeout(() => {
|
|
87
87
|
if (DEBUG_BUILD) {
|
|
88
|
-
|
|
88
|
+
debug.log('[Profiling] max profile duration elapsed, stopping profiling for:', spanToJSON(span).description);
|
|
89
89
|
}
|
|
90
90
|
// If the timeout exceeds, we want to stop profiling, but not finish the span
|
|
91
91
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"startProfileForSpan.js","sources":["../../../../src/profiling/startProfileForSpan.ts"],"sourcesContent":["import type { Span } from '@sentry/core';\nimport {
|
|
1
|
+
{"version":3,"file":"startProfileForSpan.js","sources":["../../../../src/profiling/startProfileForSpan.ts"],"sourcesContent":["import type { Span } from '@sentry/core';\nimport { debug, getCurrentScope, spanToJSON, timestampInSeconds, uuid4 } from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { WINDOW } from '../helpers';\nimport type { JSSelfProfile } from './jsSelfProfiling';\nimport { addProfileToGlobalCache, isAutomatedPageLoadSpan, MAX_PROFILE_DURATION_MS, startJSSelfProfile } from './utils';\n\n/**\n * Wraps startTransaction and stopTransaction with profiling related logic.\n * startProfileForTransaction is called after the call to startTransaction in order to avoid our own code from\n * being profiled. Because of that same reason, stopProfiling is called before the call to stopTransaction.\n */\nexport function startProfileForSpan(span: Span): void {\n // Start the profiler and get the profiler instance.\n let startTimestamp: number | undefined;\n if (isAutomatedPageLoadSpan(span)) {\n startTimestamp = timestampInSeconds() * 1000;\n }\n\n const profiler = startJSSelfProfile();\n\n // We failed to construct the profiler, so we skip.\n // No need to log anything as this has already been logged in startProfile.\n if (!profiler) {\n return;\n }\n\n if (DEBUG_BUILD) {\n debug.log(`[Profiling] started profiling span: ${spanToJSON(span).description}`);\n }\n\n // We create \"unique\" span names to avoid concurrent spans with same names\n // from being ignored by the profiler. From here on, only this span name should be used when\n // calling the profiler methods. Note: we log the original name to the user to avoid confusion.\n const profileId = uuid4();\n\n // A couple of important things to note here:\n // `CpuProfilerBindings.stopProfiling` will be scheduled to run in 30seconds in order to exceed max profile duration.\n // Whichever of the two (span.finish/timeout) is first to run, the profiling will be stopped and the gathered profile\n // will be processed when the original span is finished. Since onProfileHandler can be invoked multiple times in the\n // event of an error or user mistake (calling span.finish multiple times), it is important that the behavior of onProfileHandler\n // is idempotent as we do not want any timings or profiles to be overridden by the last call to onProfileHandler.\n // After the original finish method is called, the event will be reported through the integration and delegated to transport.\n const processedProfile: JSSelfProfile | null = null;\n\n getCurrentScope().setContext('profile', {\n profile_id: profileId,\n start_timestamp: startTimestamp,\n });\n\n /**\n * Idempotent handler for profile stop\n */\n async function onProfileHandler(): Promise<void> {\n // Check if the profile exists and return it the behavior has to be idempotent as users may call span.finish multiple times.\n if (!span) {\n return;\n }\n // Satisfy the type checker, but profiler will always be defined here.\n if (!profiler) {\n return;\n }\n if (processedProfile) {\n if (DEBUG_BUILD) {\n debug.log('[Profiling] profile for:', spanToJSON(span).description, 'already exists, returning early');\n }\n return;\n }\n\n return profiler\n .stop()\n .then((profile: JSSelfProfile): void => {\n if (maxDurationTimeoutID) {\n WINDOW.clearTimeout(maxDurationTimeoutID);\n maxDurationTimeoutID = undefined;\n }\n\n if (DEBUG_BUILD) {\n debug.log(`[Profiling] stopped profiling of span: ${spanToJSON(span).description}`);\n }\n\n // In case of an overlapping span, stopProfiling may return null and silently ignore the overlapping profile.\n if (!profile) {\n if (DEBUG_BUILD) {\n debug.log(\n `[Profiling] profiler returned null profile for: ${spanToJSON(span).description}`,\n 'this may indicate an overlapping span or a call to stopProfiling with a profile title that was never started',\n );\n }\n return;\n }\n\n addProfileToGlobalCache(profileId, profile);\n })\n .catch(error => {\n if (DEBUG_BUILD) {\n debug.log('[Profiling] error while stopping profiler:', error);\n }\n });\n }\n\n // Enqueue a timeout to prevent profiles from running over max duration.\n let maxDurationTimeoutID: number | undefined = WINDOW.setTimeout(() => {\n if (DEBUG_BUILD) {\n debug.log('[Profiling] max profile duration elapsed, stopping profiling for:', spanToJSON(span).description);\n }\n // If the timeout exceeds, we want to stop profiling, but not finish the span\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n onProfileHandler();\n }, MAX_PROFILE_DURATION_MS);\n\n // We need to reference the original end call to avoid creating an infinite loop\n const originalEnd = span.end.bind(span);\n\n /**\n * Wraps span `end()` with profiling related logic.\n * startProfiling is called after the call to spanStart in order to avoid our own code from\n * being profiled. Because of that same reason, stopProfiling is called before the call to spanEnd.\n */\n function profilingWrappedSpanEnd(): Span {\n if (!span) {\n return originalEnd();\n }\n // onProfileHandler should always return the same profile even if this is called multiple times.\n // Always call onProfileHandler to ensure stopProfiling is called and the timeout is cleared.\n void onProfileHandler().then(\n () => {\n originalEnd();\n },\n () => {\n // If onProfileHandler fails, we still want to call the original finish method.\n originalEnd();\n },\n );\n\n return span;\n }\n\n span.end = profilingWrappedSpanEnd;\n}\n"],"names":[],"mappings":";;;;;AAOA;AACA;AACA;AACA;AACA;AACO,SAAS,mBAAmB,CAAC,IAAI,EAAc;AACtD;AACA,EAAE,IAAI,cAAc;AACpB,EAAE,IAAI,uBAAuB,CAAC,IAAI,CAAC,EAAE;AACrC,IAAI,iBAAiB,kBAAkB,EAAC,GAAI,IAAI;AAChD;;AAEA,EAAE,MAAM,QAAA,GAAW,kBAAkB,EAAE;;AAEvC;AACA;AACA,EAAE,IAAI,CAAC,QAAQ,EAAE;AACjB,IAAI;AACJ;;AAEA,EAAE,IAAI,WAAW,EAAE;AACnB,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,oCAAoC,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,CAAA,CAAA;AACA;;AAEA;AACA;AACA;AACA,EAAA,MAAA,SAAA,GAAA,KAAA,EAAA;;AAWA,EAAA,eAAA,EAAA,CAAA,UAAA,CAAA,SAAA,EAAA;AACA,IAAA,UAAA,EAAA,SAAA;AACA,IAAA,eAAA,EAAA,cAAA;AACA,GAAA,CAAA;;AAEA;AACA;AACA;AACA,EAAA,eAAA,gBAAA,GAAA;AACA;AACA,IAAA,IAAA,CAAA,IAAA,EAAA;AACA,MAAA;AACA;AACA;AACA,IAAA,IAAA,CAAA,QAAA,EAAA;AACA,MAAA;AACA;;AAQA,IAAA,OAAA;AACA,OAAA,IAAA;AACA,OAAA,IAAA,CAAA,CAAA,OAAA,KAAA;AACA,QAAA,IAAA,oBAAA,EAAA;AACA,UAAA,MAAA,CAAA,YAAA,CAAA,oBAAA,CAAA;AACA,UAAA,oBAAA,GAAA,SAAA;AACA;;AAEA,QAAA,IAAA,WAAA,EAAA;AACA,UAAA,KAAA,CAAA,GAAA,CAAA,CAAA,uCAAA,EAAA,UAAA,CAAA,IAAA,CAAA,CAAA,WAAA,CAAA,CAAA,CAAA;AACA;;AAEA;AACA,QAAA,IAAA,CAAA,OAAA,EAAA;AACA,UAAA,IAAA,WAAA,EAAA;AACA,YAAA,KAAA,CAAA,GAAA;AACA,cAAA,CAAA,gDAAA,EAAA,UAAA,CAAA,IAAA,CAAA,CAAA,WAAA,CAAA,CAAA;AACA,cAAA,8GAAA;AACA,aAAA;AACA;AACA,UAAA;AACA;;AAEA,QAAA,uBAAA,CAAA,SAAA,EAAA,OAAA,CAAA;AACA,OAAA;AACA,OAAA,KAAA,CAAA,KAAA,IAAA;AACA,QAAA,IAAA,WAAA,EAAA;AACA,UAAA,KAAA,CAAA,GAAA,CAAA,4CAAA,EAAA,KAAA,CAAA;AACA;AACA,OAAA,CAAA;AACA;;AAEA;AACA,EAAA,IAAA,oBAAA,GAAA,MAAA,CAAA,UAAA,CAAA,MAAA;AACA,IAAA,IAAA,WAAA,EAAA;AACA,MAAA,KAAA,CAAA,GAAA,CAAA,mEAAA,EAAA,UAAA,CAAA,IAAA,CAAA,CAAA,WAAA,CAAA;AACA;AACA;AACA;AACA,IAAA,gBAAA,EAAA;AACA,GAAA,EAAA,uBAAA,CAAA;;AAEA;AACA,EAAA,MAAA,WAAA,GAAA,IAAA,CAAA,GAAA,CAAA,IAAA,CAAA,IAAA,CAAA;;AAEA;AACA;AACA;AACA;AACA;AACA,EAAA,SAAA,uBAAA,GAAA;AACA,IAAA,IAAA,CAAA,IAAA,EAAA;AACA,MAAA,OAAA,WAAA,EAAA;AACA;AACA;AACA;AACA,IAAA,KAAA,gBAAA,EAAA,CAAA,IAAA;AACA,MAAA,MAAA;AACA,QAAA,WAAA,EAAA;AACA,OAAA;AACA,MAAA,MAAA;AACA;AACA,QAAA,WAAA,EAAA;AACA,OAAA;AACA,KAAA;;AAEA,IAAA,OAAA,IAAA;AACA;;AAEA,EAAA,IAAA,CAAA,GAAA,GAAA,uBAAA;AACA;;;;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { spanToJSON,
|
|
1
|
+
import { spanToJSON, debug, getClient, forEachEnvelopeItem, timestampInSeconds, uuid4, DEFAULT_ENVIRONMENT, getDebugImagesForResources, browserPerformanceTimeOrigin } from '@sentry/core';
|
|
2
2
|
import { DEBUG_BUILD } from '../debug-build.js';
|
|
3
3
|
import { WINDOW } from '../helpers.js';
|
|
4
4
|
|
|
@@ -65,13 +65,13 @@ function enrichWithThreadInformation(profile) {
|
|
|
65
65
|
// by the integration before the event is processed by other integrations.
|
|
66
66
|
|
|
67
67
|
function getTraceId(event) {
|
|
68
|
-
const traceId = event.contexts?.trace?.
|
|
68
|
+
const traceId = event.contexts?.trace?.trace_id;
|
|
69
69
|
// Log a warning if the profile has an invalid traceId (should be uuidv4).
|
|
70
70
|
// All profiles and transactions are rejected if this is the case and we want to
|
|
71
71
|
// warn users that this is happening if they enable debug flag
|
|
72
72
|
if (typeof traceId === 'string' && traceId.length !== 32) {
|
|
73
73
|
if (DEBUG_BUILD) {
|
|
74
|
-
|
|
74
|
+
debug.log(`[Profiling] Invalid traceId: ${traceId} on profiled event`);
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
if (typeof traceId !== 'string') {
|
|
@@ -293,7 +293,7 @@ function findProfiledTransactionsFromEnvelope(envelope) {
|
|
|
293
293
|
for (let j = 1; j < item.length; j++) {
|
|
294
294
|
const event = item[j] ;
|
|
295
295
|
|
|
296
|
-
if (event?.contexts
|
|
296
|
+
if (event?.contexts?.profile?.profile_id) {
|
|
297
297
|
events.push(item[j] );
|
|
298
298
|
}
|
|
299
299
|
}
|
|
@@ -324,7 +324,7 @@ function isValidSampleRate(rate) {
|
|
|
324
324
|
// we need to check NaN explicitly because it's of type 'number' and therefore wouldn't get caught by this typecheck
|
|
325
325
|
if ((typeof rate !== 'number' && typeof rate !== 'boolean') || (typeof rate === 'number' && isNaN(rate))) {
|
|
326
326
|
DEBUG_BUILD &&
|
|
327
|
-
|
|
327
|
+
debug.warn(
|
|
328
328
|
`[Profiling] Invalid sample rate. Sample rate must be a boolean or a number between 0 and 1. Got ${JSON.stringify(
|
|
329
329
|
rate,
|
|
330
330
|
)} of type ${JSON.stringify(typeof rate)}.`,
|
|
@@ -339,7 +339,7 @@ function isValidSampleRate(rate) {
|
|
|
339
339
|
|
|
340
340
|
// in case sampleRate is a boolean, it will get automatically cast to 1 if it's true and 0 if it's false
|
|
341
341
|
if (rate < 0 || rate > 1) {
|
|
342
|
-
DEBUG_BUILD &&
|
|
342
|
+
DEBUG_BUILD && debug.warn(`[Profiling] Invalid sample rate. Sample rate must be between 0 and 1. Got ${rate}.`);
|
|
343
343
|
return false;
|
|
344
344
|
}
|
|
345
345
|
return true;
|
|
@@ -351,14 +351,14 @@ function isValidProfile(profile) {
|
|
|
351
351
|
// Log a warning if the profile has less than 2 samples so users can know why
|
|
352
352
|
// they are not seeing any profiling data and we cant avoid the back and forth
|
|
353
353
|
// of asking them to provide us with a dump of the profile data.
|
|
354
|
-
|
|
354
|
+
debug.log('[Profiling] Discarding profile because it contains less than 2 samples');
|
|
355
355
|
}
|
|
356
356
|
return false;
|
|
357
357
|
}
|
|
358
358
|
|
|
359
359
|
if (!profile.frames.length) {
|
|
360
360
|
if (DEBUG_BUILD) {
|
|
361
|
-
|
|
361
|
+
debug.log('[Profiling] Discarding profile because it contains no frames');
|
|
362
362
|
}
|
|
363
363
|
return false;
|
|
364
364
|
}
|
|
@@ -388,9 +388,7 @@ function startJSSelfProfile() {
|
|
|
388
388
|
|
|
389
389
|
if (!isJSProfilerSupported(JSProfilerConstructor)) {
|
|
390
390
|
if (DEBUG_BUILD) {
|
|
391
|
-
|
|
392
|
-
'[Profiling] Profiling is not supported by this browser, Profiler interface missing on window object.',
|
|
393
|
-
);
|
|
391
|
+
debug.log('[Profiling] Profiling is not supported by this browser, Profiler interface missing on window object.');
|
|
394
392
|
}
|
|
395
393
|
return;
|
|
396
394
|
}
|
|
@@ -407,10 +405,10 @@ function startJSSelfProfile() {
|
|
|
407
405
|
return new JSProfilerConstructor({ sampleInterval: samplingIntervalMS, maxBufferSize: maxSamples });
|
|
408
406
|
} catch (e) {
|
|
409
407
|
if (DEBUG_BUILD) {
|
|
410
|
-
|
|
408
|
+
debug.log(
|
|
411
409
|
"[Profiling] Failed to initialize the Profiling constructor, this is likely due to a missing 'Document-Policy': 'js-profiling' header.",
|
|
412
410
|
);
|
|
413
|
-
|
|
411
|
+
debug.log('[Profiling] Disabling profiling for current user session.');
|
|
414
412
|
}
|
|
415
413
|
PROFILING_CONSTRUCTOR_FAILED = true;
|
|
416
414
|
}
|
|
@@ -425,14 +423,14 @@ function shouldProfileSpan(span) {
|
|
|
425
423
|
// If constructor failed once, it will always fail, so we can early return.
|
|
426
424
|
if (PROFILING_CONSTRUCTOR_FAILED) {
|
|
427
425
|
if (DEBUG_BUILD) {
|
|
428
|
-
|
|
426
|
+
debug.log('[Profiling] Profiling has been disabled for the duration of the current user session.');
|
|
429
427
|
}
|
|
430
428
|
return false;
|
|
431
429
|
}
|
|
432
430
|
|
|
433
431
|
if (!span.isRecording()) {
|
|
434
432
|
if (DEBUG_BUILD) {
|
|
435
|
-
|
|
433
|
+
debug.log('[Profiling] Discarding profile because transaction was not sampled.');
|
|
436
434
|
}
|
|
437
435
|
return false;
|
|
438
436
|
}
|
|
@@ -440,7 +438,7 @@ function shouldProfileSpan(span) {
|
|
|
440
438
|
const client = getClient();
|
|
441
439
|
const options = client?.getOptions();
|
|
442
440
|
if (!options) {
|
|
443
|
-
DEBUG_BUILD &&
|
|
441
|
+
DEBUG_BUILD && debug.log('[Profiling] Profiling disabled, no options found.');
|
|
444
442
|
return false;
|
|
445
443
|
}
|
|
446
444
|
|
|
@@ -450,14 +448,14 @@ function shouldProfileSpan(span) {
|
|
|
450
448
|
// Since this is coming from the user (or from a function provided by the user), who knows what we might get. (The
|
|
451
449
|
// only valid values are booleans or numbers between 0 and 1.)
|
|
452
450
|
if (!isValidSampleRate(profilesSampleRate)) {
|
|
453
|
-
DEBUG_BUILD &&
|
|
451
|
+
DEBUG_BUILD && debug.warn('[Profiling] Discarding profile because of invalid sample rate.');
|
|
454
452
|
return false;
|
|
455
453
|
}
|
|
456
454
|
|
|
457
455
|
// if the function returned 0 (or false), or if `profileSampleRate` is 0, it's a sign the profile should be dropped
|
|
458
456
|
if (!profilesSampleRate) {
|
|
459
457
|
DEBUG_BUILD &&
|
|
460
|
-
|
|
458
|
+
debug.log(
|
|
461
459
|
'[Profiling] Discarding profile because a negative sampling decision was inherited or profileSampleRate is set to 0',
|
|
462
460
|
);
|
|
463
461
|
return false;
|
|
@@ -469,7 +467,7 @@ function shouldProfileSpan(span) {
|
|
|
469
467
|
// Check if we should sample this profile
|
|
470
468
|
if (!sampled) {
|
|
471
469
|
DEBUG_BUILD &&
|
|
472
|
-
|
|
470
|
+
debug.log(
|
|
473
471
|
`[Profiling] Discarding profile because it's not included in the random sample (sampling rate = ${Number(
|
|
474
472
|
profilesSampleRate,
|
|
475
473
|
)})`,
|