sentry-uniapp
Version:
用于Uniapp/小程序/快应用等平台的 Sentry SDK
236 lines • 8.73 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.keypressEventHandler = exports.breadcrumbEventHandler = exports.wrap = exports.ignoreNextOnError = exports.shouldIgnoreOnError = void 0;
var tslib_1 = require("tslib");
var core_1 = require("@sentry/core");
var utils_1 = require("@sentry/utils");
var debounceDuration = 1000;
var keypressTimeout;
var lastCapturedEvent;
var ignoreOnError = 0;
/**
* @hidden
*/
function shouldIgnoreOnError() {
return ignoreOnError > 0;
}
exports.shouldIgnoreOnError = shouldIgnoreOnError;
/**
* @hidden
*/
function ignoreNextOnError() {
// onerror should trigger before setTimeout
ignoreOnError += 1;
setTimeout(function () {
ignoreOnError -= 1;
});
}
exports.ignoreNextOnError = ignoreNextOnError;
/**
* Instruments the given function and sends an event to Sentry every time the
* function throws an exception.
*
* @param fn A function to wrap.
* @returns The wrapped function.
* @hidden
*/
function wrap(fn, options, before) {
if (options === void 0) { options = {}; }
// tslint:disable-next-line:strict-type-predicates
if (typeof fn !== 'function') {
return fn;
}
try {
// We don't wanna wrap it twice
if (fn.__sentry__) {
return fn;
}
// If this has already been wrapped in the past, return that wrapped function
if (fn.__sentry_wrapped__) {
return fn.__sentry_wrapped__;
}
}
catch (e) {
// Just accessing custom props in some Selenium environments
// can cause a "Permission denied" exception (see raven-js#495).
// Bail on wrapping and return the function as-is (defers to window.onerror).
return fn;
}
var sentryWrapped = function () {
// tslint:disable-next-line:strict-type-predicates
if (before && typeof before === 'function') {
before.apply(this, arguments);
}
var args = Array.prototype.slice.call(arguments);
// tslint:disable:no-unsafe-any
try {
var wrappedArguments = args.map(function (arg) { return wrap(arg, options); });
if (fn.handleEvent) {
// Attempt to invoke user-land function
// 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.
return fn.handleEvent.apply(this, wrappedArguments);
}
// Attempt to invoke user-land function
// 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.
return fn.apply(this, wrappedArguments);
// tslint:enable:no-unsafe-any
}
catch (ex) {
ignoreNextOnError();
core_1.withScope(function (scope) {
scope.addEventProcessor(function (event) {
var processedEvent = tslib_1.__assign({}, event);
if (options.mechanism) {
utils_1.addExceptionTypeValue(processedEvent, undefined, undefined);
utils_1.addExceptionMechanism(processedEvent, options.mechanism);
}
processedEvent.extra = tslib_1.__assign(tslib_1.__assign({}, processedEvent.extra), { arguments: utils_1.normalize(args, 3) });
return processedEvent;
});
core_1.captureException(ex);
});
throw ex;
}
};
// Accessing some objects may throw
// ref: https://github.com/getsentry/sentry-javascript/issues/1168
try {
// tslint:disable-next-line: no-for-in
for (var property in fn) {
if (Object.prototype.hasOwnProperty.call(fn, property)) {
sentryWrapped[property] = fn[property];
}
}
}
catch (_oO) { } // tslint:disable-line:no-empty
fn.prototype = fn.prototype || {};
sentryWrapped.prototype = fn.prototype;
Object.defineProperty(fn, '__sentry_wrapped__', {
enumerable: false,
value: sentryWrapped,
});
// Signal that this function has been wrapped/filled already
// for both debugging and to prevent it to being wrapped/filled twice
Object.defineProperties(sentryWrapped, {
__sentry__: {
enumerable: false,
value: true,
},
__sentry_original__: {
enumerable: false,
value: fn,
},
});
// Restore original function name (not all browsers allow that)
try {
var descriptor = Object.getOwnPropertyDescriptor(sentryWrapped, 'name');
if (descriptor.configurable) {
Object.defineProperty(sentryWrapped, 'name', {
get: function () {
return fn.name;
},
});
}
}
catch (_oO) {
/*no-empty*/
}
return sentryWrapped;
}
exports.wrap = wrap;
var debounceTimer = 0;
/**
* Wraps addEventListener to capture UI breadcrumbs
* @param eventName the event name (e.g. "click")
* @returns wrapped breadcrumb events handler
* @hidden
*/
function breadcrumbEventHandler(eventName, debounce) {
if (debounce === void 0) { debounce = false; }
return function (event) {
// reset keypress timeout; e.g. triggering a 'click' after
// a 'keypress' will reset the keypress debounce so that a new
// set of keypresses can be recorded
keypressTimeout = undefined;
// 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 the event.
// tslint:disable-next-line: strict-comparisons
if (!event || lastCapturedEvent === event) {
return;
}
lastCapturedEvent = event;
var captureBreadcrumb = function () {
var target;
// Accessing event.target can throw (see getsentry/raven-js#838, #768)
try {
target = event.target ? utils_1.htmlTreeAsString(event.target) : utils_1.htmlTreeAsString(event);
}
catch (e) {
target = '<unknown>';
}
if (target.length === 0) {
return;
}
core_1.getCurrentHub().addBreadcrumb({
category: "ui." + eventName,
message: target,
}, {
event: event,
name: eventName,
});
};
if (debounceTimer) {
clearTimeout(debounceTimer);
}
if (debounce) {
debounceTimer = setTimeout(captureBreadcrumb);
}
else {
captureBreadcrumb();
}
};
}
exports.breadcrumbEventHandler = breadcrumbEventHandler;
/**
* Wraps addEventListener to capture keypress UI events
* @returns wrapped keypress events handler
* @hidden
*/
function keypressEventHandler() {
// TODO: if somehow user switches keypress target before
// debounce timeout is triggered, we will only capture
// a single breadcrumb from the FIRST target (acceptable?)
return function (event) {
var target;
try {
target = event.target;
}
catch (e) {
// just accessing event properties can throw an exception in some rare circumstances
// see: https://github.com/getsentry/raven-js/issues/838
return;
}
var tagName = target && target.tagName;
// only consider keypress events on actual input elements
// this will disregard keypresses targeting body (e.g. tabbing
// through elements, hotkeys, etc)
if (!tagName || (tagName !== 'INPUT' && tagName !== 'TEXTAREA' && !target.isContentEditable)) {
return;
}
// record first keypress in a series, but ignore subsequent
// keypresses until debounce clears
if (!keypressTimeout) {
breadcrumbEventHandler('input')(event);
}
clearTimeout(keypressTimeout);
keypressTimeout = setTimeout(function () {
keypressTimeout = undefined;
}, debounceDuration);
};
}
exports.keypressEventHandler = keypressEventHandler;
//# sourceMappingURL=helpers.js.map