Newer
Older
236001
236002
236003
236004
236005
236006
236007
236008
236009
236010
236011
236012
236013
236014
236015
236016
236017
236018
236019
236020
236021
236022
236023
236024
236025
236026
236027
236028
236029
236030
236031
236032
236033
236034
236035
236036
236037
236038
236039
236040
236041
236042
236043
236044
236045
236046
236047
236048
236049
236050
236051
236052
236053
236054
236055
236056
236057
236058
236059
236060
236061
236062
236063
236064
236065
236066
236067
236068
236069
236070
236071
236072
236073
236074
236075
236076
236077
236078
236079
236080
236081
236082
236083
236084
236085
236086
236087
236088
236089
236090
236091
236092
236093
236094
236095
236096
236097
236098
236099
236100
236101
236102
236103
236104
236105
236106
236107
236108
236109
236110
236111
236112
236113
236114
236115
236116
236117
236118
236119
236120
236121
236122
236123
236124
236125
236126
236127
236128
236129
236130
236131
236132
236133
236134
236135
236136
toTraceparent() {
let sampledString = '';
if (this.sampled !== undefined) {
sampledString = this.sampled ? '-1' : '-0';
}
return `${this.traceId}-${this.spanId}${sampledString}`;
}
/**
* @inheritDoc
*/
toContext() {
return (0,_sentry_utils__WEBPACK_IMPORTED_MODULE_3__.dropUndefinedKeys)({
data: this.data,
description: this.description,
endTimestamp: this.endTimestamp,
op: this.op,
parentSpanId: this.parentSpanId,
sampled: this.sampled,
spanId: this.spanId,
startTimestamp: this.startTimestamp,
status: this.status,
tags: this.tags,
traceId: this.traceId,
});
}
/**
* @inheritDoc
*/
updateWithContext(spanContext) {
this.data = (0,_sentry_utils_esm_buildPolyfills__WEBPACK_IMPORTED_MODULE_4__._nullishCoalesce)(spanContext.data, () => ( {}));
this.description = spanContext.description;
this.endTimestamp = spanContext.endTimestamp;
this.op = spanContext.op;
this.parentSpanId = spanContext.parentSpanId;
this.sampled = spanContext.sampled;
this.spanId = (0,_sentry_utils_esm_buildPolyfills__WEBPACK_IMPORTED_MODULE_4__._nullishCoalesce)(spanContext.spanId, () => ( this.spanId));
this.startTimestamp = (0,_sentry_utils_esm_buildPolyfills__WEBPACK_IMPORTED_MODULE_4__._nullishCoalesce)(spanContext.startTimestamp, () => ( this.startTimestamp));
this.status = spanContext.status;
this.tags = (0,_sentry_utils_esm_buildPolyfills__WEBPACK_IMPORTED_MODULE_4__._nullishCoalesce)(spanContext.tags, () => ( {}));
this.traceId = (0,_sentry_utils_esm_buildPolyfills__WEBPACK_IMPORTED_MODULE_4__._nullishCoalesce)(spanContext.traceId, () => ( this.traceId));
return this;
}
/**
* @inheritDoc
*/
getTraceContext()
{
return (0,_sentry_utils__WEBPACK_IMPORTED_MODULE_3__.dropUndefinedKeys)({
data: Object.keys(this.data).length > 0 ? this.data : undefined,
description: this.description,
op: this.op,
parent_span_id: this.parentSpanId,
span_id: this.spanId,
status: this.status,
tags: Object.keys(this.tags).length > 0 ? this.tags : undefined,
trace_id: this.traceId,
});
}
/**
* @inheritDoc
*/
toJSON()
{
return (0,_sentry_utils__WEBPACK_IMPORTED_MODULE_3__.dropUndefinedKeys)({
data: Object.keys(this.data).length > 0 ? this.data : undefined,
description: this.description,
op: this.op,
parent_span_id: this.parentSpanId,
span_id: this.spanId,
start_timestamp: this.startTimestamp,
status: this.status,
tags: Object.keys(this.tags).length > 0 ? this.tags : undefined,
timestamp: this.endTimestamp,
trace_id: this.traceId,
});
}
}
/**
* Converts a HTTP status code into a {@link SpanStatusType}.
*
* @param httpStatus The HTTP response status code.
* @returns The span status or unknown_error.
*/
function spanStatusfromHttpCode(httpStatus) {
if (httpStatus < 400 && httpStatus >= 100) {
return 'ok';
}
if (httpStatus >= 400 && httpStatus < 500) {
switch (httpStatus) {
case 401:
return 'unauthenticated';
case 403:
return 'permission_denied';
case 404:
return 'not_found';
case 409:
return 'already_exists';
case 413:
return 'failed_precondition';
case 429:
return 'resource_exhausted';
default:
return 'invalid_argument';
}
}
if (httpStatus >= 500 && httpStatus < 600) {
switch (httpStatus) {
case 501:
return 'unimplemented';
case 503:
return 'unavailable';
case 504:
return 'deadline_exceeded';
default:
return 'internal_error';
}
}
return 'unknown_error';
}
//# sourceMappingURL=span.js.map
/***/ }),
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "DEFAULT_FINAL_TIMEOUT": () => (/* binding */ DEFAULT_FINAL_TIMEOUT),
/* harmony export */ "DEFAULT_HEARTBEAT_INTERVAL": () => (/* binding */ DEFAULT_HEARTBEAT_INTERVAL),
/* harmony export */ "DEFAULT_IDLE_TIMEOUT": () => (/* binding */ DEFAULT_IDLE_TIMEOUT),
/* harmony export */ "IdleTransaction": () => (/* binding */ IdleTransaction),
/* harmony export */ "IdleTransactionSpanRecorder": () => (/* binding */ IdleTransactionSpanRecorder)
/* harmony export */ });
/* harmony import */ var _sentry_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(1538);
/* harmony import */ var _sentry_utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(1548);
/* harmony import */ var _span_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1613);
/* harmony import */ var _transaction_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1612);
const DEFAULT_IDLE_TIMEOUT = 1000;
const DEFAULT_FINAL_TIMEOUT = 30000;
const DEFAULT_HEARTBEAT_INTERVAL = 5000;
/**
* @inheritDoc
*/
class IdleTransactionSpanRecorder extends _span_js__WEBPACK_IMPORTED_MODULE_0__.SpanRecorder {
236165
236166
236167
236168
236169
236170
236171
236172
236173
236174
236175
236176
236177
236178
236179
236180
236181
236182
constructor(
_pushActivity,
_popActivity,
transactionSpanId,
maxlen,
) {
super(maxlen);this._pushActivity = _pushActivity;this._popActivity = _popActivity;this.transactionSpanId = transactionSpanId;;
}
/**
* @inheritDoc
*/
add(span) {
// We should make sure we do not push and pop activities for
// the transaction that this span recorder belongs to.
if (span.spanId !== this.transactionSpanId) {
// We patch span.finish() to pop an activity after setting an endTimestamp.
span.finish = (endTimestamp) => {
span.endTimestamp = typeof endTimestamp === 'number' ? endTimestamp : (0,_sentry_utils__WEBPACK_IMPORTED_MODULE_1__.timestampWithMs)();
236184
236185
236186
236187
236188
236189
236190
236191
236192
236193
236194
236195
236196
236197
236198
236199
236200
236201
this._popActivity(span.spanId);
};
// We should only push new activities if the span does not have an end timestamp.
if (span.endTimestamp === undefined) {
this._pushActivity(span.spanId);
}
}
super.add(span);
}
}
/**
* An IdleTransaction is a transaction that automatically finishes. It does this by tracking child spans as activities.
* You can have multiple IdleTransactions active, but if the `onScope` option is specified, the idle transaction will
* put itself on the scope on creation.
*/
class IdleTransaction extends _transaction_js__WEBPACK_IMPORTED_MODULE_2__.Transaction {
236203
236204
236205
236206
236207
236208
236209
236210
236211
236212
236213
236214
236215
236216
236217
236218
236219
236220
236221
236222
236223
236224
236225
236226
236227
236228
236229
236230
236231
236232
236233
236234
236235
236236
236237
236238
236239
236240
236241
236242
236243
// Activities store a list of active spans
__init() {this.activities = {};}
// Track state of activities in previous heartbeat
// Amount of times heartbeat has counted. Will cause transaction to finish after 3 beats.
__init2() {this._heartbeatCounter = 0;}
// We should not use heartbeat if we finished a transaction
__init3() {this._finished = false;}
__init4() {this._beforeFinishCallbacks = [];}
/**
* Timer that tracks Transaction idleTimeout
*/
constructor(
transactionContext,
_idleHub,
/**
* The time to wait in ms until the idle transaction will be finished. This timer is started each time
* there are no active spans on this transaction.
*/
_idleTimeout = DEFAULT_IDLE_TIMEOUT,
/**
* The final value in ms that a transaction cannot exceed
*/
_finalTimeout = DEFAULT_FINAL_TIMEOUT,
_heartbeatInterval = DEFAULT_HEARTBEAT_INTERVAL,
// Whether or not the transaction should put itself on the scope when it starts and pop itself off when it ends
_onScope = false,
) {
super(transactionContext, _idleHub);this._idleHub = _idleHub;this._idleTimeout = _idleTimeout;this._finalTimeout = _finalTimeout;this._heartbeatInterval = _heartbeatInterval;this._onScope = _onScope;IdleTransaction.prototype.__init.call(this);IdleTransaction.prototype.__init2.call(this);IdleTransaction.prototype.__init3.call(this);IdleTransaction.prototype.__init4.call(this);;
if (_onScope) {
// There should only be one active transaction on the scope
clearActiveTransaction(_idleHub);
// We set the transaction here on the scope so error events pick up the trace
// context and attach it to the error.
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && _sentry_utils__WEBPACK_IMPORTED_MODULE_3__.logger.log(`Setting idle transaction on scope. Span ID: ${this.spanId}`);
_idleHub.configureScope(scope => scope.setSpan(this));
}
this._startIdleTimeout();
setTimeout(() => {
if (!this._finished) {
this.setStatus('deadline_exceeded');
this.finish();
}
}, this._finalTimeout);
}
/** {@inheritDoc} */
finish(endTimestamp = (0,_sentry_utils__WEBPACK_IMPORTED_MODULE_1__.timestampWithMs)()) {
this._finished = true;
this.activities = {};
if (this.spanRecorder) {
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
_sentry_utils__WEBPACK_IMPORTED_MODULE_3__.logger.log('[Tracing] finishing IdleTransaction', new Date(endTimestamp * 1000).toISOString(), this.op);
236265
236266
236267
236268
236269
236270
236271
236272
236273
236274
236275
236276
236277
236278
236279
236280
for (const callback of this._beforeFinishCallbacks) {
callback(this, endTimestamp);
}
this.spanRecorder.spans = this.spanRecorder.spans.filter((span) => {
// If we are dealing with the transaction itself, we just return it
if (span.spanId === this.spanId) {
return true;
}
// We cancel all pending spans with status "cancelled" to indicate the idle transaction was finished early
if (!span.endTimestamp) {
span.endTimestamp = endTimestamp;
span.setStatus('cancelled');
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
_sentry_utils__WEBPACK_IMPORTED_MODULE_3__.logger.log('[Tracing] cancelling span since transaction ended early', JSON.stringify(span, undefined, 2));
}
const keepSpan = span.startTimestamp < endTimestamp;
if (!keepSpan) {
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
_sentry_utils__WEBPACK_IMPORTED_MODULE_3__.logger.log(
'[Tracing] discarding Span since it happened after Transaction was finished',
JSON.stringify(span, undefined, 2),
);
}
return keepSpan;
});
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && _sentry_utils__WEBPACK_IMPORTED_MODULE_3__.logger.log('[Tracing] flushing IdleTransaction');
} else {
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && _sentry_utils__WEBPACK_IMPORTED_MODULE_3__.logger.log('[Tracing] No active IdleTransaction');
236298
236299
236300
236301
236302
236303
236304
236305
236306
236307
236308
236309
236310
236311
236312
236313
236314
236315
236316
236317
236318
236319
236320
236321
236322
236323
236324
236325
236326
236327
236328
236329
236330
236331
236332
236333
236334
236335
236336
236337
236338
236339
}
// if `this._onScope` is `true`, the transaction put itself on the scope when it started
if (this._onScope) {
clearActiveTransaction(this._idleHub);
}
return super.finish(endTimestamp);
}
/**
* Register a callback function that gets excecuted before the transaction finishes.
* Useful for cleanup or if you want to add any additional spans based on current context.
*
* This is exposed because users have no other way of running something before an idle transaction
* finishes.
*/
registerBeforeFinishCallback(callback) {
this._beforeFinishCallbacks.push(callback);
}
/**
* @inheritDoc
*/
initSpanRecorder(maxlen) {
if (!this.spanRecorder) {
const pushActivity = (id) => {
if (this._finished) {
return;
}
this._pushActivity(id);
};
const popActivity = (id) => {
if (this._finished) {
return;
}
this._popActivity(id);
};
this.spanRecorder = new IdleTransactionSpanRecorder(pushActivity, popActivity, this.spanId, maxlen);
// Start heartbeat so that transactions do not run forever.
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && _sentry_utils__WEBPACK_IMPORTED_MODULE_3__.logger.log('Starting heartbeat');
236341
236342
236343
236344
236345
236346
236347
236348
236349
236350
236351
236352
236353
236354
236355
236356
236357
236358
236359
236360
236361
236362
236363
236364
236365
236366
236367
236368
236369
236370
236371
236372
236373
this._pingHeartbeat();
}
this.spanRecorder.add(this);
}
/**
* Cancels the existing idletimeout, if there is one
*/
_cancelIdleTimeout() {
if (this._idleTimeoutID) {
clearTimeout(this._idleTimeoutID);
this._idleTimeoutID = undefined;
}
}
/**
* Creates an idletimeout
*/
_startIdleTimeout(endTimestamp) {
this._cancelIdleTimeout();
this._idleTimeoutID = setTimeout(() => {
if (!this._finished && Object.keys(this.activities).length === 0) {
this.finish(endTimestamp);
}
}, this._idleTimeout);
}
/**
* Start tracking a specific activity.
* @param spanId The span id that represents the activity
*/
_pushActivity(spanId) {
this._cancelIdleTimeout();
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && _sentry_utils__WEBPACK_IMPORTED_MODULE_3__.logger.log(`[Tracing] pushActivity: ${spanId}`);
this.activities[spanId] = true;
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && _sentry_utils__WEBPACK_IMPORTED_MODULE_3__.logger.log('[Tracing] new activities count', Object.keys(this.activities).length);
}
/**
* Remove an activity from usage
* @param spanId The span id that represents the activity
*/
_popActivity(spanId) {
if (this.activities[spanId]) {
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && _sentry_utils__WEBPACK_IMPORTED_MODULE_3__.logger.log(`[Tracing] popActivity ${spanId}`);
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete this.activities[spanId];
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && _sentry_utils__WEBPACK_IMPORTED_MODULE_3__.logger.log('[Tracing] new activities count', Object.keys(this.activities).length);
}
if (Object.keys(this.activities).length === 0) {
// We need to add the timeout here to have the real endtimestamp of the transaction
// Remember timestampWithMs is in seconds, timeout is in ms
const endTimestamp = (0,_sentry_utils__WEBPACK_IMPORTED_MODULE_1__.timestampWithMs)() + this._idleTimeout / 1000;
236395
236396
236397
236398
236399
236400
236401
236402
236403
236404
236405
236406
236407
236408
236409
236410
236411
236412
236413
236414
236415
236416
236417
236418
236419
this._startIdleTimeout(endTimestamp);
}
}
/**
* Checks when entries of this.activities are not changing for 3 beats.
* If this occurs we finish the transaction.
*/
_beat() {
// We should not be running heartbeat if the idle transaction is finished.
if (this._finished) {
return;
}
const heartbeatString = Object.keys(this.activities).join('');
if (heartbeatString === this._prevHeartbeatString) {
this._heartbeatCounter++;
} else {
this._heartbeatCounter = 1;
}
this._prevHeartbeatString = heartbeatString;
if (this._heartbeatCounter >= 3) {
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && _sentry_utils__WEBPACK_IMPORTED_MODULE_3__.logger.log('[Tracing] Transaction finished because of no change for 3 heart beats');
this.setStatus('deadline_exceeded');
this.finish();
} else {
this._pingHeartbeat();
}
}
/**
* Pings the heartbeat
*/
_pingHeartbeat() {
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && _sentry_utils__WEBPACK_IMPORTED_MODULE_3__.logger.log(`pinging Heartbeat -> current counter: ${this._heartbeatCounter}`);
236433
236434
236435
236436
236437
236438
236439
236440
236441
236442
236443
236444
236445
236446
236447
236448
236449
236450
236451
236452
236453
236454
236455
236456
setTimeout(() => {
this._beat();
}, this._heartbeatInterval);
}
}
/**
* Reset transaction on scope to `undefined`
*/
function clearActiveTransaction(hub) {
const scope = hub.getScope();
if (scope) {
const transaction = scope.getTransaction();
if (transaction) {
scope.setSpan(undefined);
}
}
}
//# sourceMappingURL=idletransaction.js.map
/***/ }),
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "registerErrorInstrumentation": () => (/* binding */ registerErrorInstrumentation)
/* harmony export */ });
/* harmony import */ var _sentry_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1616);
/* harmony import */ var _sentry_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1548);
/* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(1611);
/**
* Configures global error listeners
*/
function registerErrorInstrumentation() {
(0,_sentry_utils__WEBPACK_IMPORTED_MODULE_0__.addInstrumentationHandler)('error', errorCallback);
(0,_sentry_utils__WEBPACK_IMPORTED_MODULE_0__.addInstrumentationHandler)('unhandledrejection', errorCallback);
}
/**
* If an error or unhandled promise occurs, we mark the active transaction as failed
*/
function errorCallback() {
const activeTransaction = (0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.getActiveTransaction)();
if (activeTransaction) {
const status = 'internal_error';
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && _sentry_utils__WEBPACK_IMPORTED_MODULE_2__.logger.log(`[Tracing] Transaction: ${status} -> Global error occured`);
activeTransaction.setStatus(status);
//# sourceMappingURL=errors.js.map
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "addInstrumentationHandler": () => (/* binding */ addInstrumentationHandler)
/* harmony export */ });
/* harmony import */ var _is_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(1544);
/* harmony import */ var _logger_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(1548);
/* harmony import */ var _object_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(1545);
/* harmony import */ var _stacktrace_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1557);
/* harmony import */ var _supports_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(1617);
/* harmony import */ var _worldwide_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1539);
// eslint-disable-next-line deprecation/deprecation
const WINDOW = (0,_worldwide_js__WEBPACK_IMPORTED_MODULE_0__.getGlobalObject)();
236520
236521
236522
236523
236524
236525
236526
236527
236528
236529
236530
236531
236532
236533
236534
236535
236536
236537
/**
* Instrument native APIs to call handlers that can be used to create breadcrumbs, APM spans etc.
* - Console API
* - Fetch API
* - XHR API
* - History API
* - DOM API (click/typing)
* - Error API
* - UnhandledRejection API
*/
const handlers = {};
const instrumented = {};
/** Instruments given API */
function instrument(type) {
if (instrumented[type]) {
return;
}
236542
236543
236544
236545
236546
236547
236548
236549
236550
236551
236552
236553
236554
236555
236556
236557
236558
236559
236560
236561
236562
236563
236564
236565
236566
switch (type) {
case 'console':
instrumentConsole();
break;
case 'dom':
instrumentDOM();
break;
case 'xhr':
instrumentXHR();
break;
case 'fetch':
instrumentFetch();
break;
case 'history':
instrumentHistory();
break;
case 'error':
instrumentError();
break;
case 'unhandledrejection':
instrumentUnhandledRejection();
break;
default:
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && _logger_js__WEBPACK_IMPORTED_MODULE_1__.logger.warn('unknown instrumentation type:', type);
return;
}
}
/**
* Add handler that will be called when given type of instrumentation triggers.
* Use at your own risk, this might break without changelog notice, only used internally.
* @hidden
function addInstrumentationHandler(type, callback) {
handlers[type] = handlers[type] || [];
(handlers[type] ).push(callback);
instrument(type);
}
/** JSDoc */
function triggerHandlers(type, data) {
if (!type || !handlers[type]) {
return;
}
for (const handler of handlers[type] || []) {
try {
handler(data);
} catch (e) {
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
_logger_js__WEBPACK_IMPORTED_MODULE_1__.logger.error(
`Error while triggering instrumentation handler.\nType: ${type}\nName: ${(0,_stacktrace_js__WEBPACK_IMPORTED_MODULE_2__.getFunctionName)(handler)}\nError:`,
e,
);
}
}
}
/** JSDoc */
function instrumentConsole() {
if (!('console' in WINDOW)) {
return;
}
_logger_js__WEBPACK_IMPORTED_MODULE_1__.CONSOLE_LEVELS.forEach(function (level) {
if (!(level in WINDOW.console)) {
return;
}
(0,_object_js__WEBPACK_IMPORTED_MODULE_3__.fill)(WINDOW.console, level, function (originalConsoleMethod) {
return function (...args) {
triggerHandlers('console', { args, level });
// this fails for some browsers. :(
if (originalConsoleMethod) {
originalConsoleMethod.apply(WINDOW.console, args);
}
};
});
});
}
/** JSDoc */
function instrumentFetch() {
if (!(0,_supports_js__WEBPACK_IMPORTED_MODULE_4__.supportsNativeFetch)()) {
return;
}
(0,_object_js__WEBPACK_IMPORTED_MODULE_3__.fill)(WINDOW, 'fetch', function (originalFetch) {
return function (...args) {
const handlerData = {
args,
fetchData: {
method: getFetchMethod(args),
url: getFetchUrl(args),
},
startTimestamp: Date.now(),
};
triggerHandlers('fetch', {
...handlerData,
});
236645
236646
236647
236648
236649
236650
236651
236652
236653
236654
236655
236656
236657
236658
236659
236660
236661
236662
236663
236664
236665
236666
236667
236668
236669
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
return originalFetch.apply(WINDOW, args).then(
(response) => {
triggerHandlers('fetch', {
...handlerData,
endTimestamp: Date.now(),
response,
});
return response;
},
(error) => {
triggerHandlers('fetch', {
...handlerData,
endTimestamp: Date.now(),
error,
});
// NOTE: If you are a Sentry user, and you are seeing this stack frame,
// it means the sentry.javascript SDK caught an error invoking your application code.
// This is expected behavior and NOT indicative of a bug with sentry.javascript.
throw error;
},
);
};
});
}
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/** Extract `method` from fetch call arguments */
function getFetchMethod(fetchArgs = []) {
if ('Request' in WINDOW && (0,_is_js__WEBPACK_IMPORTED_MODULE_5__.isInstanceOf)(fetchArgs[0], Request) && fetchArgs[0].method) {
return String(fetchArgs[0].method).toUpperCase();
}
if (fetchArgs[1] && fetchArgs[1].method) {
return String(fetchArgs[1].method).toUpperCase();
}
return 'GET';
}
/** Extract `url` from fetch call arguments */
function getFetchUrl(fetchArgs = []) {
if (typeof fetchArgs[0] === 'string') {
return fetchArgs[0];
}
if ('Request' in WINDOW && (0,_is_js__WEBPACK_IMPORTED_MODULE_5__.isInstanceOf)(fetchArgs[0], Request)) {
return fetchArgs[0].url;
}
return String(fetchArgs[0]);
}
/* eslint-enable @typescript-eslint/no-unsafe-member-access */
/** JSDoc */
function instrumentXHR() {
if (!('XMLHttpRequest' in WINDOW)) {
return;
}
const xhrproto = XMLHttpRequest.prototype;
(0,_object_js__WEBPACK_IMPORTED_MODULE_3__.fill)(xhrproto, 'open', function (originalOpen) {
return function ( ...args) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const xhr = this;
const url = args[1];
const xhrInfo = (xhr.__sentry_xhr__ = {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
method: (0,_is_js__WEBPACK_IMPORTED_MODULE_5__.isString)(args[0]) ? args[0].toUpperCase() : args[0],
url: args[1],
});
// if Sentry key appears in URL, don't capture it as a request
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if ((0,_is_js__WEBPACK_IMPORTED_MODULE_5__.isString)(url) && xhrInfo.method === 'POST' && url.match(/sentry_key/)) {
xhr.__sentry_own_request__ = true;
}
const onreadystatechangeHandler = function () {
if (xhr.readyState === 4) {
try {
// touching statusCode in some platforms throws
// an exception
xhrInfo.status_code = xhr.status;
} catch (e) {
/* do nothing */
}
triggerHandlers('xhr', {
args,
endTimestamp: Date.now(),
startTimestamp: Date.now(),
xhr,
});
}
};
if ('onreadystatechange' in xhr && typeof xhr.onreadystatechange === 'function') {
(0,_object_js__WEBPACK_IMPORTED_MODULE_3__.fill)(xhr, 'onreadystatechange', function (original) {
return function (...readyStateArgs) {
onreadystatechangeHandler();
return original.apply(xhr, readyStateArgs);
};
});
} else {
xhr.addEventListener('readystatechange', onreadystatechangeHandler);
}
return originalOpen.apply(xhr, args);
};
});
(0,_object_js__WEBPACK_IMPORTED_MODULE_3__.fill)(xhrproto, 'send', function (originalSend) {
return function ( ...args) {
if (this.__sentry_xhr__ && args[0] !== undefined) {
this.__sentry_xhr__.body = args[0];
}
triggerHandlers('xhr', {
args,
startTimestamp: Date.now(),
xhr: this,
});
return originalSend.apply(this, args);
/** JSDoc */
function instrumentHistory() {
if (!(0,_supports_js__WEBPACK_IMPORTED_MODULE_4__.supportsHistory)()) {
return;
}
236779
236780
236781
236782
236783
236784
236785
236786
236787
236788
236789
236790
236791
236792
236793
236794
236795
236796
236797
const oldOnPopState = WINDOW.onpopstate;
WINDOW.onpopstate = function ( ...args) {
const to = WINDOW.location.href;
// keep track of the current URL state, as we always receive only the updated state
const from = lastHref;
lastHref = to;
triggerHandlers('history', {
from,
to,
});
if (oldOnPopState) {
// Apparently this can throw in Firefox when incorrectly implemented plugin is installed.
// https://github.com/getsentry/sentry-javascript/issues/3344
// https://github.com/bugsnag/bugsnag-js/issues/469
try {
return oldOnPopState.apply(this, args);
} catch (_oO) {
// no-empty
}
236799
236800
236801
236802
236803
236804
236805
236806
236807
236808
236809
236810
236811
236812
236813
236814
236815
236816
236817
};
/** @hidden */
function historyReplacementFunction(originalHistoryFunction) {
return function ( ...args) {
const url = args.length > 2 ? args[2] : undefined;
if (url) {
// coerce to string (this is what pushState does)
const from = lastHref;
const to = String(url);
// keep track of the current URL state, as we always receive only the updated state
lastHref = to;
triggerHandlers('history', {
from,
to,
});
}
return originalHistoryFunction.apply(this, args);
};
}
236820
236821
236822
236823
236824
236825
236826
236827
236828
236829
236830
236831
236832
236833
236834
236835
236836
(0,_object_js__WEBPACK_IMPORTED_MODULE_3__.fill)(WINDOW.history, 'pushState', historyReplacementFunction);
(0,_object_js__WEBPACK_IMPORTED_MODULE_3__.fill)(WINDOW.history, 'replaceState', historyReplacementFunction);
}
const debounceDuration = 1000;
let debounceTimerID;
let lastCapturedEvent;
/**
* Decide whether the current event should finish the debounce of previously captured one.
* @param previous previously captured event
* @param current event to be captured
*/
function shouldShortcircuitPreviousDebounce(previous, current) {
// If there was no previous event, it should always be swapped for the new one.
if (!previous) {
return true;
}
// If both events have different type, then user definitely performed two separate actions. e.g. click + keypress.
if (previous.type !== current.type) {
return true;
}
try {
// If both events have the same type, it's still possible that actions were performed on different targets.
// e.g. 2 clicks on different buttons.
if (previous.target !== current.target) {
return true;
} catch (e) {
// just accessing `target` property can throw an exception in some rare circumstances
// see: https://github.com/getsentry/sentry-javascript/issues/838
}
// If both events have the same type _and_ same `target` (an element which triggered an event, _not necessarily_
// to which an event listener was attached), we treat them as the same action, as we want to capture
// only one breadcrumb. e.g. multiple clicks on the same button, or typing inside a user input box.
return false;
}
/**
* Decide whether an event should be captured.
* @param event event to be captured
*/
function shouldSkipDOMEvent(event) {
// We are only interested in filtering `keypress` events for now.
if (event.type !== 'keypress') {
return false;
}
try {
const target = event.target ;
if (!target || !target.tagName) {
return true;
}
// Only consider keypress events on actual input elements. This will disregard keypresses targeting body
// e.g.tabbing through elements, hotkeys, etc.
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {
return false;
} catch (e) {
// just accessing `target` property can throw an exception in some rare circumstances
// see: https://github.com/getsentry/sentry-javascript/issues/838
}
236891
236892
236893
236894
236895
236896
236897
236898
236899
236900
236901
236902
236903
236904
236905
/**
* Wraps addEventListener to capture UI breadcrumbs
* @param handler function that will be triggered
* @param globalListener indicates whether event was captured by the global event listener
* @returns wrapped breadcrumb events handler
* @hidden
*/
function makeDOMEventHandler(handler, globalListener = false) {
return (event) => {
// It's possible this handler might trigger multiple times for the same
// event (e.g. event propagation through node ancestors).
// Ignore if we've already captured that event.
if (!event || lastCapturedEvent === event) {
return;
}
// We always want to skip _some_ events.
if (shouldSkipDOMEvent(event)) {
return;
}
236912
236913
236914
236915
236916
236917
236918
236919
236920
236921
236922
236923
236924
236925
236926
236927
236928
236929
236930
236931
const name = event.type === 'keypress' ? 'input' : event.type;
// If there is no debounce timer, it means that we can safely capture the new event and store it for future comparisons.
if (debounceTimerID === undefined) {
handler({
event: event,
name,
global: globalListener,
});
lastCapturedEvent = event;
}
// If there is a debounce awaiting, see if the new event is different enough to treat it as a unique one.
// If that's the case, emit the previous event and store locally the newly-captured DOM event.
else if (shouldShortcircuitPreviousDebounce(lastCapturedEvent, event)) {
handler({
event: event,
name,
global: globalListener,
});
lastCapturedEvent = event;
}
// Start a new debounce timer that will prevent us from capturing multiple events that should be grouped together.
clearTimeout(debounceTimerID);
debounceTimerID = WINDOW.setTimeout(() => {
debounceTimerID = undefined;
}, debounceDuration);
};
}
/** JSDoc */
function instrumentDOM() {
if (!('document' in WINDOW)) {
return;
}
// Make it so that any click or keypress that is unhandled / bubbled up all the way to the document triggers our dom
// handlers. (Normally we have only one, which captures a breadcrumb for each click or keypress.) Do this before
// we instrument `addEventListener` so that we don't end up attaching this handler twice.
const triggerDOMHandler = triggerHandlers.bind(null, 'dom');
const globalDOMEventHandler = makeDOMEventHandler(triggerDOMHandler, true);
WINDOW.document.addEventListener('click', globalDOMEventHandler, false);
WINDOW.document.addEventListener('keypress', globalDOMEventHandler, false);
// After hooking into click and keypress events bubbled up to `document`, we also hook into user-handled
// clicks & keypresses, by adding an event listener of our own to any element to which they add a listener. That
// way, whenever one of their handlers is triggered, ours will be, too. (This is needed because their handler
// could potentially prevent the event from bubbling up to our global listeners. This way, our handler are still
// guaranteed to fire at least once.)
['EventTarget', 'Node'].forEach((target) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const proto = (WINDOW )[target] && (WINDOW )[target].prototype;
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, no-prototype-builtins
if (!proto || !proto.hasOwnProperty || !proto.hasOwnProperty('addEventListener')) {
return;
}
(0,_object_js__WEBPACK_IMPORTED_MODULE_3__.fill)(proto, 'addEventListener', function (originalAddEventListener) {
return function (
236972
236973
236974
236975
236976
236977
236978
236979
236980
236981
236982
236983
236984
236985
236986
236987
236988
236989
236990
236991
236992
type,
listener,
options,
) {
if (type === 'click' || type == 'keypress') {
try {
const el = this ;
const handlers = (el.__sentry_instrumentation_handlers__ = el.__sentry_instrumentation_handlers__ || {});
const handlerForType = (handlers[type] = handlers[type] || { refCount: 0 });
if (!handlerForType.handler) {
const handler = makeDOMEventHandler(triggerDOMHandler);
handlerForType.handler = handler;
originalAddEventListener.call(this, type, handler, options);
}
handlerForType.refCount++;
} catch (e) {
// Accessing dom properties is always fragile.
// Also allows us to skip `addEventListenrs` calls with no proper `this` context.
}
}
return originalAddEventListener.call(this, type, listener, options);
};
});
(0,_object_js__WEBPACK_IMPORTED_MODULE_3__.fill)(
proto,