|
|
|
@ -1,4 +1,4 @@
|
|
|
|
|
/*! Raven.js 1.1.18 (8ad15bc) | github.com/getsentry/raven-js */
|
|
|
|
|
/*! Raven.js 1.3.0 (768fdca) | github.com/getsentry/raven-js */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Includes TraceKit
|
|
|
|
@ -21,7 +21,8 @@ var TraceKit = {
|
|
|
|
|
remoteFetching: false,
|
|
|
|
|
collectWindowErrors: true,
|
|
|
|
|
// 3 lines before, the offending line, 3 lines after
|
|
|
|
|
linesOfContext: 7
|
|
|
|
|
linesOfContext: 7,
|
|
|
|
|
debug: false
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// global reference to slice
|
|
|
|
@ -29,23 +30,11 @@ var _slice = [].slice;
|
|
|
|
|
var UNKNOWN_FUNCTION = '?';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* TraceKit.wrap: Wrap any function in a TraceKit reporter
|
|
|
|
|
* Example: func = TraceKit.wrap(func);
|
|
|
|
|
*
|
|
|
|
|
* @param {Function} func Function to be wrapped
|
|
|
|
|
* @return {Function} The wrapped func
|
|
|
|
|
*/
|
|
|
|
|
TraceKit.wrap = function traceKitWrapper(func) {
|
|
|
|
|
function wrapped() {
|
|
|
|
|
try {
|
|
|
|
|
return func.apply(this, arguments);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
TraceKit.report(e);
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return wrapped;
|
|
|
|
|
function getLocationHref() {
|
|
|
|
|
if (typeof document === 'undefined')
|
|
|
|
|
return '';
|
|
|
|
|
|
|
|
|
|
return document.location.href;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -181,7 +170,7 @@ TraceKit.report = (function reportModuleWrapper() {
|
|
|
|
|
location.context = TraceKit.computeStackTrace.gatherContext(location.url, location.line);
|
|
|
|
|
stack = {
|
|
|
|
|
'message': message,
|
|
|
|
|
'url': document.location.href,
|
|
|
|
|
'url': getLocationHref(),
|
|
|
|
|
'stack': [location]
|
|
|
|
|
};
|
|
|
|
|
notifyHandlers(stack, true);
|
|
|
|
@ -319,8 +308,7 @@ TraceKit.report = (function reportModuleWrapper() {
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
|
|
|
|
var debug = false,
|
|
|
|
|
sourceCache = {};
|
|
|
|
|
var sourceCache = {};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Attempts to retrieve source code via XMLHttpRequest, which is used
|
|
|
|
@ -362,7 +350,9 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
|
|
|
|
// URL needs to be able to fetched within the acceptable domain. Otherwise,
|
|
|
|
|
// cross-domain errors will be triggered.
|
|
|
|
|
var source = '';
|
|
|
|
|
if (url.indexOf(document.domain) !== -1) {
|
|
|
|
|
var domain = '';
|
|
|
|
|
try { domain = document.domain; } catch (e) {}
|
|
|
|
|
if (url.indexOf(domain) !== -1) {
|
|
|
|
|
source = loadSource(url);
|
|
|
|
|
}
|
|
|
|
|
sourceCache[url] = source ? source.split('\n') : [];
|
|
|
|
@ -524,6 +514,9 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
|
|
|
|
* the url, line, and column number of the defined function.
|
|
|
|
|
*/
|
|
|
|
|
function findSourceByFunctionBody(func) {
|
|
|
|
|
if (typeof document === 'undefined')
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var urls = [window.location.href],
|
|
|
|
|
scripts = document.getElementsByTagName('script'),
|
|
|
|
|
body,
|
|
|
|
@ -627,12 +620,11 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
|
|
|
|
* @return {?Object.<string, *>} Stack trace information.
|
|
|
|
|
*/
|
|
|
|
|
function computeStackTraceFromStackProp(ex) {
|
|
|
|
|
if (!ex.stack) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
if (isUndefined(ex.stack) || !ex.stack) return;
|
|
|
|
|
|
|
|
|
|
var chrome = /^\s*at (.*?) ?\(?((?:file|https?|chrome-extension):.*?):(\d+)(?::(\d+))?\)?\s*$/i,
|
|
|
|
|
var chrome = /^\s*at (.*?) ?\(?((?:(?:file|https?|chrome-extension):.*?)|<anonymous>):(\d+)(?::(\d+))?\)?\s*$/i,
|
|
|
|
|
gecko = /^\s*(.*?)(?:\((.*?)\))?@((?:file|https?|chrome).*?):(\d+)(?::(\d+))?\s*$/i,
|
|
|
|
|
winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:ms-appx|http|https):.*?):(\d+)(?::(\d+))?\)?\s*$/i,
|
|
|
|
|
lines = ex.stack.split('\n'),
|
|
|
|
|
stack = [],
|
|
|
|
|
parts,
|
|
|
|
@ -655,6 +647,13 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
|
|
|
|
'line': +parts[3],
|
|
|
|
|
'column': parts[4] ? +parts[4] : null
|
|
|
|
|
};
|
|
|
|
|
} else if ((parts = winjs.exec(lines[i]))) {
|
|
|
|
|
element = {
|
|
|
|
|
'url': parts[2],
|
|
|
|
|
'func': parts[1] || UNKNOWN_FUNCTION,
|
|
|
|
|
'line': +parts[3],
|
|
|
|
|
'column': parts[4] ? +parts[4] : null
|
|
|
|
|
};
|
|
|
|
|
} else {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
@ -686,7 +685,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
|
|
|
|
return {
|
|
|
|
|
'name': ex.name,
|
|
|
|
|
'message': ex.message,
|
|
|
|
|
'url': document.location.href,
|
|
|
|
|
'url': getLocationHref(),
|
|
|
|
|
'stack': stack
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
@ -702,6 +701,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
|
|
|
|
// else to it because Opera is not very good at providing it
|
|
|
|
|
// reliably in other circumstances.
|
|
|
|
|
var stacktrace = ex.stacktrace;
|
|
|
|
|
if (isUndefined(ex.stacktrace) || !ex.stacktrace) return;
|
|
|
|
|
|
|
|
|
|
var testRE = / line (\d+), column (\d+) in (?:<anonymous function: ([^>]+)>|([^\)]+))\((.*)\) in (.*):\s*$/i,
|
|
|
|
|
lines = stacktrace.split('\n'),
|
|
|
|
@ -742,7 +742,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
|
|
|
|
return {
|
|
|
|
|
'name': ex.name,
|
|
|
|
|
'message': ex.message,
|
|
|
|
|
'url': document.location.href,
|
|
|
|
|
'url': getLocationHref(),
|
|
|
|
|
'stack': stack
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
@ -852,7 +852,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
|
|
|
|
return {
|
|
|
|
|
'name': ex.name,
|
|
|
|
|
'message': lines[0],
|
|
|
|
|
'url': document.location.href,
|
|
|
|
|
'url': getLocationHref(),
|
|
|
|
|
'stack': stack
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
@ -951,6 +951,12 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
|
|
|
|
item.func = parts[1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (typeof item.func === 'undefined') {
|
|
|
|
|
try {
|
|
|
|
|
item.func = parts.input.substring(0, parts.input.indexOf('{'));
|
|
|
|
|
} catch (e) { }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((source = findSourceByFunctionBody(curr))) {
|
|
|
|
|
item.url = source.url;
|
|
|
|
|
item.line = source.line;
|
|
|
|
@ -983,7 +989,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
|
|
|
|
var result = {
|
|
|
|
|
'name': ex.name,
|
|
|
|
|
'message': ex.message,
|
|
|
|
|
'url': document.location.href,
|
|
|
|
|
'url': getLocationHref(),
|
|
|
|
|
'stack': stack
|
|
|
|
|
};
|
|
|
|
|
augmentStackTraceWithInitialElement(result, ex.sourceURL || ex.fileName, ex.line || ex.lineNumber, ex.message || ex.description);
|
|
|
|
@ -1008,7 +1014,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
|
|
|
|
return stack;
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
if (debug) {
|
|
|
|
|
if (TraceKit.debug) {
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1019,7 +1025,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
|
|
|
|
return stack;
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
if (debug) {
|
|
|
|
|
if (TraceKit.debug) {
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1030,7 +1036,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
|
|
|
|
return stack;
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
if (debug) {
|
|
|
|
|
if (TraceKit.debug) {
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1041,12 +1047,16 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
|
|
|
|
return stack;
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
if (debug) {
|
|
|
|
|
if (TraceKit.debug) {
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
return {
|
|
|
|
|
'name': ex.name,
|
|
|
|
|
'message': ex.message,
|
|
|
|
|
'url': getLocationHref()
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
computeStackTrace.augmentStackTraceWithInitialElement = augmentStackTraceWithInitialElement;
|
|
|
|
@ -1064,38 +1074,45 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
|
|
|
|
|
// since JSON is required to encode the payload
|
|
|
|
|
var _Raven = window.Raven,
|
|
|
|
|
hasJSON = !!(typeof JSON === 'object' && JSON.stringify),
|
|
|
|
|
// Raven can run in contexts where there's no document (react-native)
|
|
|
|
|
hasDocument = typeof document !== 'undefined',
|
|
|
|
|
lastCapturedException,
|
|
|
|
|
lastEventId,
|
|
|
|
|
globalServer,
|
|
|
|
|
globalUser,
|
|
|
|
|
globalKey,
|
|
|
|
|
globalProject,
|
|
|
|
|
globalContext = {},
|
|
|
|
|
globalOptions = {
|
|
|
|
|
logger: 'javascript',
|
|
|
|
|
ignoreErrors: [],
|
|
|
|
|
ignoreUrls: [],
|
|
|
|
|
whitelistUrls: [],
|
|
|
|
|
includePaths: [],
|
|
|
|
|
crossOrigin: 'anonymous',
|
|
|
|
|
collectWindowErrors: true,
|
|
|
|
|
tags: {},
|
|
|
|
|
maxMessageLength: 100,
|
|
|
|
|
extra: {}
|
|
|
|
|
maxMessageLength: 100
|
|
|
|
|
},
|
|
|
|
|
authQueryString,
|
|
|
|
|
isRavenInstalled = false,
|
|
|
|
|
|
|
|
|
|
objectPrototype = Object.prototype,
|
|
|
|
|
// capture references to window.console *and* all its methods first
|
|
|
|
|
// before the console plugin has a chance to monkey patch
|
|
|
|
|
originalConsole = window.console || {},
|
|
|
|
|
originalConsoleMethods = {},
|
|
|
|
|
plugins = [],
|
|
|
|
|
startTime = now();
|
|
|
|
|
|
|
|
|
|
for (var method in originalConsole) {
|
|
|
|
|
originalConsoleMethods[method] = originalConsole[method];
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* The core Raven singleton
|
|
|
|
|
*
|
|
|
|
|
* @this {Raven}
|
|
|
|
|
*/
|
|
|
|
|
var Raven = {
|
|
|
|
|
VERSION: '1.1.18',
|
|
|
|
|
VERSION: '1.3.0',
|
|
|
|
|
|
|
|
|
|
debug: true,
|
|
|
|
|
debug: false,
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Allow multiple versions of Raven to be installed.
|
|
|
|
@ -1129,7 +1146,12 @@ var Raven = {
|
|
|
|
|
// merge in options
|
|
|
|
|
if (options) {
|
|
|
|
|
each(options, function(key, value){
|
|
|
|
|
globalOptions[key] = value;
|
|
|
|
|
// tags and extra are special and need to be put into context
|
|
|
|
|
if (key == 'tags' || key == 'extra') {
|
|
|
|
|
globalContext[key] = value;
|
|
|
|
|
} else {
|
|
|
|
|
globalOptions[key] = value;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1166,8 +1188,6 @@ var Raven = {
|
|
|
|
|
|
|
|
|
|
TraceKit.collectWindowErrors = !!globalOptions.collectWindowErrors;
|
|
|
|
|
|
|
|
|
|
setAuthQueryString();
|
|
|
|
|
|
|
|
|
|
// return for chaining
|
|
|
|
|
return Raven;
|
|
|
|
|
},
|
|
|
|
@ -1183,6 +1203,12 @@ var Raven = {
|
|
|
|
|
install: function() {
|
|
|
|
|
if (isSetup() && !isRavenInstalled) {
|
|
|
|
|
TraceKit.report.subscribe(handleStackInfo);
|
|
|
|
|
|
|
|
|
|
// Install all of the plugins
|
|
|
|
|
each(plugins, function(_, plugin) {
|
|
|
|
|
plugin();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
isRavenInstalled = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1261,6 +1287,7 @@ var Raven = {
|
|
|
|
|
wrapped[property] = func[property];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
wrapped.prototype = func.prototype;
|
|
|
|
|
|
|
|
|
|
// Signal that this function has been wrapped already
|
|
|
|
|
// for both debugging and to prevent it to being wrapped twice
|
|
|
|
@ -1302,7 +1329,8 @@ var Raven = {
|
|
|
|
|
// raises an exception different from the one we asked to
|
|
|
|
|
// report on.
|
|
|
|
|
try {
|
|
|
|
|
TraceKit.report(ex, options);
|
|
|
|
|
var stack = TraceKit.computeStackTrace(ex);
|
|
|
|
|
handleStackInfo(stack, options);
|
|
|
|
|
} catch(ex1) {
|
|
|
|
|
if(ex !== ex1) {
|
|
|
|
|
throw ex1;
|
|
|
|
@ -1337,6 +1365,12 @@ var Raven = {
|
|
|
|
|
return Raven;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
addPlugin: function(plugin) {
|
|
|
|
|
plugins.push(plugin);
|
|
|
|
|
if (isRavenInstalled) plugin();
|
|
|
|
|
return Raven;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set/clear a user to be sent along with the payload.
|
|
|
|
|
*
|
|
|
|
@ -1344,47 +1378,110 @@ var Raven = {
|
|
|
|
|
* @return {Raven}
|
|
|
|
|
*/
|
|
|
|
|
setUserContext: function(user) {
|
|
|
|
|
globalUser = user;
|
|
|
|
|
// Intentionally do not merge here since that's an unexpected behavior.
|
|
|
|
|
globalContext.user = user;
|
|
|
|
|
|
|
|
|
|
return Raven;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set extra attributes to be sent along with the payload.
|
|
|
|
|
* Merge extra attributes to be sent along with the payload.
|
|
|
|
|
*
|
|
|
|
|
* @param {object} extra An object representing extra data [optional]
|
|
|
|
|
* @return {Raven}
|
|
|
|
|
*/
|
|
|
|
|
setExtraContext: function(extra) {
|
|
|
|
|
globalOptions.extra = extra || {};
|
|
|
|
|
mergeContext('extra', extra);
|
|
|
|
|
|
|
|
|
|
return Raven;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set tags to be sent along with the payload.
|
|
|
|
|
* Merge tags to be sent along with the payload.
|
|
|
|
|
*
|
|
|
|
|
* @param {object} tags An object representing tags [optional]
|
|
|
|
|
* @return {Raven}
|
|
|
|
|
*/
|
|
|
|
|
setTagsContext: function(tags) {
|
|
|
|
|
globalOptions.tags = tags || {};
|
|
|
|
|
mergeContext('tags', tags);
|
|
|
|
|
|
|
|
|
|
return Raven;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Clear all of the context.
|
|
|
|
|
*
|
|
|
|
|
* @return {Raven}
|
|
|
|
|
*/
|
|
|
|
|
clearContext: function() {
|
|
|
|
|
globalContext = {};
|
|
|
|
|
|
|
|
|
|
return Raven;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get a copy of the current context. This cannot be mutated.
|
|
|
|
|
*
|
|
|
|
|
* @return {object} copy of context
|
|
|
|
|
*/
|
|
|
|
|
getContext: function() {
|
|
|
|
|
// lol javascript
|
|
|
|
|
return JSON.parse(JSON.stringify(globalContext));
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set release version of application
|
|
|
|
|
*
|
|
|
|
|
* @param {string} release Typically something like a git SHA to identify version
|
|
|
|
|
* @return {Raven}
|
|
|
|
|
*/
|
|
|
|
|
setReleaseContext: function(release) {
|
|
|
|
|
setRelease: function(release) {
|
|
|
|
|
globalOptions.release = release;
|
|
|
|
|
|
|
|
|
|
return Raven;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set the dataCallback option
|
|
|
|
|
*
|
|
|
|
|
* @param {function} callback The callback to run which allows the
|
|
|
|
|
* data blob to be mutated before sending
|
|
|
|
|
* @return {Raven}
|
|
|
|
|
*/
|
|
|
|
|
setDataCallback: function(callback) {
|
|
|
|
|
globalOptions.dataCallback = callback;
|
|
|
|
|
|
|
|
|
|
return Raven;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set the shouldSendCallback option
|
|
|
|
|
*
|
|
|
|
|
* @param {function} callback The callback to run which allows
|
|
|
|
|
* introspecting the blob before sending
|
|
|
|
|
* @return {Raven}
|
|
|
|
|
*/
|
|
|
|
|
setShouldSendCallback: function(callback) {
|
|
|
|
|
globalOptions.shouldSendCallback = callback;
|
|
|
|
|
|
|
|
|
|
return Raven;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Override the default HTTP transport mechanism that transmits data
|
|
|
|
|
* to the Sentry server.
|
|
|
|
|
*
|
|
|
|
|
* @param {function} transport Function invoked instead of the default
|
|
|
|
|
* `makeRequest` handler.
|
|
|
|
|
*
|
|
|
|
|
* @return {Raven}
|
|
|
|
|
*/
|
|
|
|
|
setTransport: function(transport) {
|
|
|
|
|
globalOptions.transport = transport;
|
|
|
|
|
|
|
|
|
|
return Raven;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get the latest raw exception that was captured by Raven.
|
|
|
|
|
*
|
|
|
|
@ -1413,41 +1510,47 @@ var Raven = {
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Raven.setUser = Raven.setUserContext; // To be deprecated
|
|
|
|
|
// Deprecations
|
|
|
|
|
Raven.setUser = Raven.setUserContext;
|
|
|
|
|
Raven.setReleaseContext = Raven.setRelease;
|
|
|
|
|
|
|
|
|
|
function triggerEvent(eventType, options) {
|
|
|
|
|
var event, key;
|
|
|
|
|
// NOTE: `event` is a native browser thing, so let's avoid conflicting wiht it
|
|
|
|
|
var evt, key;
|
|
|
|
|
|
|
|
|
|
if (!hasDocument)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
options = options || {};
|
|
|
|
|
|
|
|
|
|
eventType = 'raven' + eventType.substr(0,1).toUpperCase() + eventType.substr(1);
|
|
|
|
|
|
|
|
|
|
if (document.createEvent) {
|
|
|
|
|
event = document.createEvent('HTMLEvents');
|
|
|
|
|
event.initEvent(eventType, true, true);
|
|
|
|
|
evt = document.createEvent('HTMLEvents');
|
|
|
|
|
evt.initEvent(eventType, true, true);
|
|
|
|
|
} else {
|
|
|
|
|
event = document.createEventObject();
|
|
|
|
|
event.eventType = eventType;
|
|
|
|
|
evt = document.createEventObject();
|
|
|
|
|
evt.eventType = eventType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (key in options) if (hasKey(options, key)) {
|
|
|
|
|
event[key] = options[key];
|
|
|
|
|
evt[key] = options[key];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (document.createEvent) {
|
|
|
|
|
// IE9 if standards
|
|
|
|
|
document.dispatchEvent(event);
|
|
|
|
|
document.dispatchEvent(evt);
|
|
|
|
|
} else {
|
|
|
|
|
// IE8 regardless of Quirks or Standards
|
|
|
|
|
// IE9 if quirks
|
|
|
|
|
try {
|
|
|
|
|
document.fireEvent('on' + event.eventType.toLowerCase(), event);
|
|
|
|
|
document.fireEvent('on' + evt.eventType.toLowerCase(), evt);
|
|
|
|
|
} catch(e) {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var dsnKeys = 'source protocol user pass host port path'.split(' '),
|
|
|
|
|
dsnPattern = /^(?:(\w+):)?\/\/(\w+)(:\w+)?@([\w\.-]+)(?::(\d+))?(\/.*)/;
|
|
|
|
|
dsnPattern = /^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/;
|
|
|
|
|
|
|
|
|
|
function RavenConfigError(message) {
|
|
|
|
|
this.name = 'RavenConfigError';
|
|
|
|
@ -1475,7 +1578,7 @@ function parseDSN(str) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isUndefined(what) {
|
|
|
|
|
return typeof what === 'undefined';
|
|
|
|
|
return what === void 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isFunction(what) {
|
|
|
|
@ -1483,7 +1586,7 @@ function isFunction(what) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isString(what) {
|
|
|
|
|
return typeof what === 'string';
|
|
|
|
|
return objectPrototype.toString.call(what) === '[object String]';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isObject(what) {
|
|
|
|
@ -1533,15 +1636,6 @@ function each(obj, callback) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function setAuthQueryString() {
|
|
|
|
|
authQueryString =
|
|
|
|
|
'?sentry_version=4' +
|
|
|
|
|
'&sentry_client=raven-js/' + Raven.VERSION +
|
|
|
|
|
'&sentry_key=' + globalKey;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function handleStackInfo(stackInfo, options) {
|
|
|
|
|
var frames = [];
|
|
|
|
|
|
|
|
|
@ -1588,7 +1682,7 @@ function normalizeFrame(frame) {
|
|
|
|
|
|
|
|
|
|
normalized.in_app = !( // determine if an exception came from outside of our app
|
|
|
|
|
// first we check the global includePaths list.
|
|
|
|
|
!globalOptions.includePaths.test(normalized.filename) ||
|
|
|
|
|
(!!globalOptions.includePaths.test && !globalOptions.includePaths.test(normalized.filename)) ||
|
|
|
|
|
// Now we check for fun, if the function name is Raven or TraceKit
|
|
|
|
|
/(Raven|TraceKit)\./.test(normalized['function']) ||
|
|
|
|
|
// finally, we do a last ditch effort and check for raven.min.js
|
|
|
|
@ -1638,20 +1732,12 @@ function extractContextFromFrame(frame) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function processException(type, message, fileurl, lineno, frames, options) {
|
|
|
|
|
var stacktrace, label, i;
|
|
|
|
|
var stacktrace, i, fullMessage;
|
|
|
|
|
|
|
|
|
|
// In some instances message is not actually a string, no idea why,
|
|
|
|
|
// so we want to always coerce it to one.
|
|
|
|
|
message += '';
|
|
|
|
|
|
|
|
|
|
// Sometimes an exception is getting logged in Sentry as
|
|
|
|
|
// <no message value>
|
|
|
|
|
// This can only mean that the message was falsey since this value
|
|
|
|
|
// is hardcoded into Sentry itself.
|
|
|
|
|
// At this point, if the message is falsey, we bail since it's useless
|
|
|
|
|
if (type === 'Error' && !message) return;
|
|
|
|
|
if (!!globalOptions.ignoreErrors.test && globalOptions.ignoreErrors.test(message)) return;
|
|
|
|
|
|
|
|
|
|
if (globalOptions.ignoreErrors.test(message)) return;
|
|
|
|
|
message += '';
|
|
|
|
|
fullMessage = type + ': ' + message;
|
|
|
|
|
|
|
|
|
|
if (frames && frames.length) {
|
|
|
|
|
fileurl = frames[0].filename || fileurl;
|
|
|
|
@ -1669,26 +1755,22 @@ function processException(type, message, fileurl, lineno, frames, options) {
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Truncate the message to a max of characters
|
|
|
|
|
message = truncate(message, globalOptions.maxMessageLength);
|
|
|
|
|
|
|
|
|
|
if (globalOptions.ignoreUrls && globalOptions.ignoreUrls.test(fileurl)) return;
|
|
|
|
|
if (globalOptions.whitelistUrls && !globalOptions.whitelistUrls.test(fileurl)) return;
|
|
|
|
|
|
|
|
|
|
label = lineno ? message + ' at ' + lineno : message;
|
|
|
|
|
if (!!globalOptions.ignoreUrls.test && globalOptions.ignoreUrls.test(fileurl)) return;
|
|
|
|
|
if (!!globalOptions.whitelistUrls.test && !globalOptions.whitelistUrls.test(fileurl)) return;
|
|
|
|
|
|
|
|
|
|
// Fire away!
|
|
|
|
|
send(
|
|
|
|
|
objectMerge({
|
|
|
|
|
// sentry.interfaces.Exception
|
|
|
|
|
exception: {
|
|
|
|
|
type: type,
|
|
|
|
|
value: message
|
|
|
|
|
values: [{
|
|
|
|
|
type: type,
|
|
|
|
|
value: message,
|
|
|
|
|
stacktrace: stacktrace
|
|
|
|
|
}]
|
|
|
|
|
},
|
|
|
|
|
// sentry.interfaces.Stacktrace
|
|
|
|
|
stacktrace: stacktrace,
|
|
|
|
|
culprit: fileurl,
|
|
|
|
|
message: label
|
|
|
|
|
message: fullMessage
|
|
|
|
|
}, options)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
@ -1707,58 +1789,83 @@ function truncate(str, max) {
|
|
|
|
|
return str.length <= max ? str : str.substr(0, max) + '\u2026';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function trimPacket(data) {
|
|
|
|
|
// For now, we only want to truncate the two different messages
|
|
|
|
|
// but this could/should be expanded to just trim everything
|
|
|
|
|
var max = globalOptions.maxMessageLength;
|
|
|
|
|
data.message = truncate(data.message, max);
|
|
|
|
|
if (data.exception) {
|
|
|
|
|
var exception = data.exception.values[0];
|
|
|
|
|
exception.value = truncate(exception.value, max);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function now() {
|
|
|
|
|
return +new Date();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getHttpData() {
|
|
|
|
|
var http = {
|
|
|
|
|
url: document.location.href,
|
|
|
|
|
if (!hasDocument || !document.location || !document.location.href) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var httpData = {
|
|
|
|
|
headers: {
|
|
|
|
|
'User-Agent': navigator.userAgent
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
httpData.url = document.location.href;
|
|
|
|
|
|
|
|
|
|
if (document.referrer) {
|
|
|
|
|
http.headers.Referer = document.referrer;
|
|
|
|
|
httpData.headers.Referer = document.referrer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return http;
|
|
|
|
|
return httpData;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function send(data) {
|
|
|
|
|
if (!isSetup()) return;
|
|
|
|
|
|
|
|
|
|
data = objectMerge({
|
|
|
|
|
var baseData = {
|
|
|
|
|
project: globalProject,
|
|
|
|
|
logger: globalOptions.logger,
|
|
|
|
|
platform: 'javascript',
|
|
|
|
|
// sentry.interfaces.Http
|
|
|
|
|
request: getHttpData()
|
|
|
|
|
}, data);
|
|
|
|
|
platform: 'javascript'
|
|
|
|
|
}, httpData = getHttpData();
|
|
|
|
|
|
|
|
|
|
if (httpData) {
|
|
|
|
|
baseData.request = httpData;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data = objectMerge(baseData, data);
|
|
|
|
|
|
|
|
|
|
// Merge in the tags and extra separately since objectMerge doesn't handle a deep merge
|
|
|
|
|
data.tags = objectMerge(objectMerge({}, globalOptions.tags), data.tags);
|
|
|
|
|
data.extra = objectMerge(objectMerge({}, globalOptions.extra), data.extra);
|
|
|
|
|
data.tags = objectMerge(objectMerge({}, globalContext.tags), data.tags);
|
|
|
|
|
data.extra = objectMerge(objectMerge({}, globalContext.extra), data.extra);
|
|
|
|
|
|
|
|
|
|
// Send along our own collected metadata with extra
|
|
|
|
|
data.extra = objectMerge({
|
|
|
|
|
'session:duration': now() - startTime
|
|
|
|
|
}, data.extra);
|
|
|
|
|
data.extra['session:duration'] = now() - startTime;
|
|
|
|
|
|
|
|
|
|
// If there are no tags/extra, strip the key from the payload alltogther.
|
|
|
|
|
if (isEmptyObject(data.tags)) delete data.tags;
|
|
|
|
|
|
|
|
|
|
if (globalUser) {
|
|
|
|
|
if (globalContext.user) {
|
|
|
|
|
// sentry.interfaces.User
|
|
|
|
|
data.user = globalUser;
|
|
|
|
|
data.user = globalContext.user;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Include the release iff it's defined in globalOptions
|
|
|
|
|
// Include the release if it's defined in globalOptions
|
|
|
|
|
if (globalOptions.release) data.release = globalOptions.release;
|
|
|
|
|
// Include server_name if it's defined in globalOptions
|
|
|
|
|
if (globalOptions.serverName) data.server_name = globalOptions.serverName;
|
|
|
|
|
|
|
|
|
|
if (isFunction(globalOptions.dataCallback)) {
|
|
|
|
|
data = globalOptions.dataCallback(data);
|
|
|
|
|
data = globalOptions.dataCallback(data) || data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Why??????????
|
|
|
|
|
if (!data || isEmptyObject(data)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if the request should be filtered or not
|
|
|
|
@ -1771,34 +1878,68 @@ function send(data) {
|
|
|
|
|
// Set lastEventId after we know the error should actually be sent
|
|
|
|
|
lastEventId = data.event_id || (data.event_id = uuid4());
|
|
|
|
|
|
|
|
|
|
makeRequest(data);
|
|
|
|
|
// Try and clean up the packet before sending by truncating long values
|
|
|
|
|
data = trimPacket(data);
|
|
|
|
|
|
|
|
|
|
logDebug('debug', 'Raven about to send:', data);
|
|
|
|
|
|
|
|
|
|
if (!isSetup()) return;
|
|
|
|
|
|
|
|
|
|
(globalOptions.transport || makeRequest)({
|
|
|
|
|
url: globalServer,
|
|
|
|
|
auth: {
|
|
|
|
|
sentry_version: '7',
|
|
|
|
|
sentry_client: 'raven-js/' + Raven.VERSION,
|
|
|
|
|
sentry_key: globalKey
|
|
|
|
|
},
|
|
|
|
|
data: data,
|
|
|
|
|
options: globalOptions,
|
|
|
|
|
onSuccess: function success() {
|
|
|
|
|
triggerEvent('success', {
|
|
|
|
|
data: data,
|
|
|
|
|
src: globalServer
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
onError: function failure() {
|
|
|
|
|
triggerEvent('failure', {
|
|
|
|
|
data: data,
|
|
|
|
|
src: globalServer
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function makeRequest(opts) {
|
|
|
|
|
// Tack on sentry_data to auth options, which get urlencoded
|
|
|
|
|
opts.auth.sentry_data = JSON.stringify(opts.data);
|
|
|
|
|
|
|
|
|
|
function makeRequest(data) {
|
|
|
|
|
var img = new Image(),
|
|
|
|
|
src = globalServer + authQueryString + '&sentry_data=' + encodeURIComponent(JSON.stringify(data));
|
|
|
|
|
var img = newImage(),
|
|
|
|
|
src = opts.url + '?' + urlencode(opts.auth),
|
|
|
|
|
crossOrigin = opts.options.crossOrigin;
|
|
|
|
|
|
|
|
|
|
img.crossOrigin = 'anonymous';
|
|
|
|
|
img.onload = function success() {
|
|
|
|
|
triggerEvent('success', {
|
|
|
|
|
data: data,
|
|
|
|
|
src: src
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
img.onerror = img.onabort = function failure() {
|
|
|
|
|
triggerEvent('failure', {
|
|
|
|
|
data: data,
|
|
|
|
|
src: src
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
if (crossOrigin || crossOrigin === '') {
|
|
|
|
|
img.crossOrigin = crossOrigin;
|
|
|
|
|
}
|
|
|
|
|
img.onload = opts.onSuccess;
|
|
|
|
|
img.onerror = img.onabort = opts.onError;
|
|
|
|
|
img.src = src;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Note: this is shitty, but I can't figure out how to get
|
|
|
|
|
// sinon to stub document.createElement without breaking everything
|
|
|
|
|
// so this wrapper is just so I can stub it for tests.
|
|
|
|
|
function newImage() {
|
|
|
|
|
return document.createElement('img');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var ravenNotConfiguredError;
|
|
|
|
|
|
|
|
|
|
function isSetup() {
|
|
|
|
|
if (!hasJSON) return false; // needs JSON support
|
|
|
|
|
if (!globalServer) {
|
|
|
|
|
logDebug('error', 'Error: Raven has not been configured.');
|
|
|
|
|
if (!ravenNotConfiguredError)
|
|
|
|
|
logDebug('error', 'Error: Raven has not been configured.');
|
|
|
|
|
ravenNotConfiguredError = true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
@ -1826,18 +1967,44 @@ function joinRegExp(patterns) {
|
|
|
|
|
return new RegExp(sources.join('|'), 'i');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
|
|
|
|
|
function uuid4() {
|
|
|
|
|
return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
|
|
|
var r = Math.random()*16|0,
|
|
|
|
|
v = c == 'x' ? r : (r&0x3|0x8);
|
|
|
|
|
return v.toString(16);
|
|
|
|
|
});
|
|
|
|
|
var crypto = window.crypto || window.msCrypto;
|
|
|
|
|
|
|
|
|
|
if (!isUndefined(crypto) && crypto.getRandomValues) {
|
|
|
|
|
// Use window.crypto API if available
|
|
|
|
|
var arr = new Uint16Array(8);
|
|
|
|
|
crypto.getRandomValues(arr);
|
|
|
|
|
|
|
|
|
|
// set 4 in byte 7
|
|
|
|
|
arr[3] = arr[3] & 0xFFF | 0x4000;
|
|
|
|
|
// set 2 most significant bits of byte 9 to '10'
|
|
|
|
|
arr[4] = arr[4] & 0x3FFF | 0x8000;
|
|
|
|
|
|
|
|
|
|
var pad = function(num) {
|
|
|
|
|
var v = num.toString(16);
|
|
|
|
|
while (v.length < 4) {
|
|
|
|
|
v = '0' + v;
|
|
|
|
|
}
|
|
|
|
|
return v;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (pad(arr[0]) + pad(arr[1]) + pad(arr[2]) + pad(arr[3]) + pad(arr[4]) +
|
|
|
|
|
pad(arr[5]) + pad(arr[6]) + pad(arr[7]));
|
|
|
|
|
} else {
|
|
|
|
|
// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
|
|
|
|
|
return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
|
|
|
var r = Math.random()*16|0,
|
|
|
|
|
v = c == 'x' ? r : (r&0x3|0x8);
|
|
|
|
|
return v.toString(16);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function logDebug(level, message) {
|
|
|
|
|
if (window.console && console[level] && Raven.debug) {
|
|
|
|
|
console[level](message);
|
|
|
|
|
function logDebug(level) {
|
|
|
|
|
if (originalConsoleMethods[level] && Raven.debug) {
|
|
|
|
|
// _slice is coming from vendor/TraceKit/tracekit.js
|
|
|
|
|
// so it's accessible globally
|
|
|
|
|
originalConsoleMethods[level].apply(originalConsole, _slice.call(arguments, 1));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1848,12 +2015,32 @@ function afterLoad() {
|
|
|
|
|
Raven.config(RavenConfig.dsn, RavenConfig.config).install();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function urlencode(o) {
|
|
|
|
|
var pairs = [];
|
|
|
|
|
each(o, function(key, value) {
|
|
|
|
|
pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
|
|
|
|
|
});
|
|
|
|
|
return pairs.join('&');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function mergeContext(key, context) {
|
|
|
|
|
if (isUndefined(context)) {
|
|
|
|
|
delete globalContext[key];
|
|
|
|
|
} else {
|
|
|
|
|
globalContext[key] = objectMerge(globalContext[key] || {}, context);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
afterLoad();
|
|
|
|
|
|
|
|
|
|
// This is being exposed no matter what because there are too many weird
|
|
|
|
|
// usecases for how people use Raven. If this is really a problem, I'm sorry.
|
|
|
|
|
window.Raven = Raven;
|
|
|
|
|
|
|
|
|
|
// Expose Raven to the world
|
|
|
|
|
if (typeof define === 'function' && define.amd) {
|
|
|
|
|
// AMD
|
|
|
|
|
window.Raven = Raven;
|
|
|
|
|
define('raven', [], function() {
|
|
|
|
|
return Raven;
|
|
|
|
|
});
|
|
|
|
@ -1863,9 +2050,6 @@ if (typeof define === 'function' && define.amd) {
|
|
|
|
|
} else if (typeof exports === 'object') {
|
|
|
|
|
// CommonJS
|
|
|
|
|
exports = Raven;
|
|
|
|
|
} else {
|
|
|
|
|
// Everything else
|
|
|
|
|
window.Raven = Raven;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
})(window);
|
|
|
|
|
})(typeof window !== 'undefined' ? window : this);
|
|
|
|
|