History

Update raven.js

Thibaut committed 10 years ago

Commit 3b68eb01 parent 5de8c371 file · +336 −152Browse files

Unified · Split

assets/javascripts/vendor/raven.js+336−152
@@ -1,4 +1,4 @@
1/*! Raven.js 1.1.18 (8ad15bc) | github.com/getsentry/raven-js */1/*! Raven.js 1.3.0 (768fdca) | github.com/getsentry/raven-js */
2 2
3/*3/*
4 * Includes TraceKit4 * Includes TraceKit
@@ -21,7 +21,8 @@ var TraceKit = { · 16 unmodified lines
21 remoteFetching: false,21 remoteFetching: false,
22 collectWindowErrors: true,22 collectWindowErrors: true,
23 // 3 lines before, the offending line, 3 lines after23 // 3 lines before, the offending line, 3 lines after
24 linesOfContext: 724 linesOfContext: 7,
25 debug: false
25};26};
26 27
27// global reference to slice28// global reference to slice
@@ -29,23 +30,11 @@ var _slice = [].slice; · 1 unmodified line
29var UNKNOWN_FUNCTION = '?';30var UNKNOWN_FUNCTION = '?';
30 31
31 32
32/**33function getLocationHref() {
33 * TraceKit.wrap: Wrap any function in a TraceKit reporter34 if (typeof document === 'undefined')
34 * Example: func = TraceKit.wrap(func);35 return '';
35 *36
36 * @param {Function} func Function to be wrapped37 return document.location.href;
37 * @return {Function} The wrapped func
38 */
39TraceKit.wrap = function traceKitWrapper(func) {
40 function wrapped() {
41 try {
42 return func.apply(this, arguments);
43 } catch (e) {
44 TraceKit.report(e);
45 throw e;
46 }
47 }
48 return wrapped;
49};38};
50 39
51/**40/**
@@ -181,7 +170,7 @@ TraceKit.report = (function reportModuleWrapper() { · 129 unmodified lines
181 location.context = TraceKit.computeStackTrace.gatherContext(location.url, location.line);170 location.context = TraceKit.computeStackTrace.gatherContext(location.url, location.line);
182 stack = {171 stack = {
183 'message': message,172 'message': message,
184 'url': document.location.href,173 'url': getLocationHref(),
185 'stack': [location]174 'stack': [location]
186 };175 };
187 notifyHandlers(stack, true);176 notifyHandlers(stack, true);
@@ -319,8 +308,7 @@ TraceKit.report = (function reportModuleWrapper() { · 131 unmodified lines
319 *308 *
320 */309 */
321TraceKit.computeStackTrace = (function computeStackTraceWrapper() {310TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
322 var debug = false,311 var sourceCache = {};
323 sourceCache = {};
324 312
325 /**313 /**
326 * Attempts to retrieve source code via XMLHttpRequest, which is used314 * Attempts to retrieve source code via XMLHttpRequest, which is used
@@ -362,7 +350,9 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 35 unmodified lines
362 // URL needs to be able to fetched within the acceptable domain. Otherwise,350 // URL needs to be able to fetched within the acceptable domain. Otherwise,
363 // cross-domain errors will be triggered.351 // cross-domain errors will be triggered.
364 var source = '';352 var source = '';
365 if (url.indexOf(document.domain) !== -1) {353 var domain = '';
354 try { domain = document.domain; } catch (e) {}
355 if (url.indexOf(domain) !== -1) {
366 source = loadSource(url);356 source = loadSource(url);
367 }357 }
368 sourceCache[url] = source ? source.split('\n') : [];358 sourceCache[url] = source ? source.split('\n') : [];
@@ -524,6 +514,9 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 155 unmodified lines
524 * the url, line, and column number of the defined function.514 * the url, line, and column number of the defined function.
525 */515 */
526 function findSourceByFunctionBody(func) {516 function findSourceByFunctionBody(func) {
517 if (typeof document === 'undefined')
518 return;
519
527 var urls = [window.location.href],520 var urls = [window.location.href],
528 scripts = document.getElementsByTagName('script'),521 scripts = document.getElementsByTagName('script'),
529 body,522 body,
@@ -627,12 +620,11 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 97 unmodified lines
627 * @return {?Object.<string, *>} Stack trace information.620 * @return {?Object.<string, *>} Stack trace information.
628 */621 */
629 function computeStackTraceFromStackProp(ex) {622 function computeStackTraceFromStackProp(ex) {
630 if (!ex.stack) {623 if (isUndefined(ex.stack) || !ex.stack) return;
631 return null;
632 }
633 624
634 var chrome = /^\s*at (.*?) ?\(?((?:file|https?|chrome-extension):.*?):(\d+)(?::(\d+))?\)?\s*$/i,625 var chrome = /^\s*at (.*?) ?\(?((?:(?:file|https?|chrome-extension):.*?)|<anonymous>):(\d+)(?::(\d+))?\)?\s*$/i,
635 gecko = /^\s*(.*?)(?:\((.*?)\))?@((?:file|https?|chrome).*?):(\d+)(?::(\d+))?\s*$/i,626 gecko = /^\s*(.*?)(?:\((.*?)\))?@((?:file|https?|chrome).*?):(\d+)(?::(\d+))?\s*$/i,
627 winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:ms-appx|http|https):.*?):(\d+)(?::(\d+))?\)?\s*$/i,
636 lines = ex.stack.split('\n'),628 lines = ex.stack.split('\n'),
637 stack = [],629 stack = [],
638 parts,630 parts,
@@ -655,6 +647,13 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 16 unmodified lines
655 'line': +parts[3],647 'line': +parts[3],
656 'column': parts[4] ? +parts[4] : null648 'column': parts[4] ? +parts[4] : null
657 };649 };
650 } else if ((parts = winjs.exec(lines[i]))) {
651 element = {
652 'url': parts[2],
653 'func': parts[1] || UNKNOWN_FUNCTION,
654 'line': +parts[3],
655 'column': parts[4] ? +parts[4] : null
656 };
658 } else {657 } else {
659 continue;658 continue;
660 }659 }
@@ -686,7 +685,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 25 unmodified lines
686 return {685 return {
687 'name': ex.name,686 'name': ex.name,
688 'message': ex.message,687 'message': ex.message,
689 'url': document.location.href,688 'url': getLocationHref(),
690 'stack': stack689 'stack': stack
691 };690 };
692 }691 }
@@ -702,6 +701,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 9 unmodified lines
702 // else to it because Opera is not very good at providing it701 // else to it because Opera is not very good at providing it
703 // reliably in other circumstances.702 // reliably in other circumstances.
704 var stacktrace = ex.stacktrace;703 var stacktrace = ex.stacktrace;
704 if (isUndefined(ex.stacktrace) || !ex.stacktrace) return;
705 705
706 var testRE = / line (\d+), column (\d+) in (?:<anonymous function: ([^>]+)>|([^\)]+))\((.*)\) in (.*):\s*$/i,706 var testRE = / line (\d+), column (\d+) in (?:<anonymous function: ([^>]+)>|([^\)]+))\((.*)\) in (.*):\s*$/i,
707 lines = stacktrace.split('\n'),707 lines = stacktrace.split('\n'),
@@ -742,7 +742,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 34 unmodified lines
742 return {742 return {
743 'name': ex.name,743 'name': ex.name,
744 'message': ex.message,744 'message': ex.message,
745 'url': document.location.href,745 'url': getLocationHref(),
746 'stack': stack746 'stack': stack
747 };747 };
748 }748 }
@@ -852,7 +852,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 103 unmodified lines
852 return {852 return {
853 'name': ex.name,853 'name': ex.name,
854 'message': lines[0],854 'message': lines[0],
855 'url': document.location.href,855 'url': getLocationHref(),
856 'stack': stack856 'stack': stack
857 };857 };
858 }858 }
@@ -951,6 +951,12 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 92 unmodified lines
951 item.func = parts[1];951 item.func = parts[1];
952 }952 }
953 953
954 if (typeof item.func === 'undefined') {
955 try {
956 item.func = parts.input.substring(0, parts.input.indexOf('{'));
957 } catch (e) { }
958 }
959
954 if ((source = findSourceByFunctionBody(curr))) {960 if ((source = findSourceByFunctionBody(curr))) {
955 item.url = source.url;961 item.url = source.url;
956 item.line = source.line;962 item.line = source.line;
@@ -983,7 +989,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 26 unmodified lines
983 var result = {989 var result = {
984 'name': ex.name,990 'name': ex.name,
985 'message': ex.message,991 'message': ex.message,
986 'url': document.location.href,992 'url': getLocationHref(),
987 'stack': stack993 'stack': stack
988 };994 };
989 augmentStackTraceWithInitialElement(result, ex.sourceURL || ex.fileName, ex.line || ex.lineNumber, ex.message || ex.description);995 augmentStackTraceWithInitialElement(result, ex.sourceURL || ex.fileName, ex.line || ex.lineNumber, ex.message || ex.description);
@@ -1008,7 +1014,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 18 unmodified lines
1008 return stack;1014 return stack;
1009 }1015 }
1010 } catch (e) {1016 } catch (e) {
1011 if (debug) {1017 if (TraceKit.debug) {
1012 throw e;1018 throw e;
1013 }1019 }
1014 }1020 }
@@ -1019,7 +1025,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 4 unmodified lines
1019 return stack;1025 return stack;
1020 }1026 }
1021 } catch (e) {1027 } catch (e) {
1022 if (debug) {1028 if (TraceKit.debug) {
1023 throw e;1029 throw e;
1024 }1030 }
1025 }1031 }
@@ -1030,7 +1036,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 4 unmodified lines
1030 return stack;1036 return stack;
1031 }1037 }
1032 } catch (e) {1038 } catch (e) {
1033 if (debug) {1039 if (TraceKit.debug) {
1034 throw e;1040 throw e;
1035 }1041 }
1036 }1042 }
@@ -1041,12 +1047,16 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 4 unmodified lines
1041 return stack;1047 return stack;
1042 }1048 }
1043 } catch (e) {1049 } catch (e) {
1044 if (debug) {1050 if (TraceKit.debug) {
1045 throw e;1051 throw e;
1046 }1052 }
1047 }1053 }
1048 1054
1049 return {};1055 return {
1056 'name': ex.name,
1057 'message': ex.message,
1058 'url': getLocationHref()
1059 };
1050 }1060 }
1051 1061
1052 computeStackTrace.augmentStackTraceWithInitialElement = augmentStackTraceWithInitialElement;1062 computeStackTrace.augmentStackTraceWithInitialElement = augmentStackTraceWithInitialElement;
@@ -1064,38 +1074,45 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 11 unmodified lines
1064// since JSON is required to encode the payload1074// since JSON is required to encode the payload
1065var _Raven = window.Raven,1075var _Raven = window.Raven,
1066 hasJSON = !!(typeof JSON === 'object' && JSON.stringify),1076 hasJSON = !!(typeof JSON === 'object' && JSON.stringify),
1077 // Raven can run in contexts where there's no document (react-native)
1078 hasDocument = typeof document !== 'undefined',
1067 lastCapturedException,1079 lastCapturedException,
1068 lastEventId,1080 lastEventId,
1069 globalServer,1081 globalServer,
1070 globalUser,
1071 globalKey,1082 globalKey,
1072 globalProject,1083 globalProject,
1084 globalContext = {},
1073 globalOptions = {1085 globalOptions = {
1074 logger: 'javascript',1086 logger: 'javascript',
1075 ignoreErrors: [],1087 ignoreErrors: [],
1076 ignoreUrls: [],1088 ignoreUrls: [],
1077 whitelistUrls: [],1089 whitelistUrls: [],
1078 includePaths: [],1090 includePaths: [],
1091 crossOrigin: 'anonymous',
1079 collectWindowErrors: true,1092 collectWindowErrors: true,
1080 tags: {},1093 maxMessageLength: 100
1081 maxMessageLength: 100,
1082 extra: {}
1083 },1094 },
1084 authQueryString,
1085 isRavenInstalled = false,1095 isRavenInstalled = false,
1086
1087 objectPrototype = Object.prototype,1096 objectPrototype = Object.prototype,
1097 // capture references to window.console *and* all its methods first
1098 // before the console plugin has a chance to monkey patch
1099 originalConsole = window.console || {},
1100 originalConsoleMethods = {},
1101 plugins = [],
1088 startTime = now();1102 startTime = now();
1089 1103
1104for (var method in originalConsole) {
1105 originalConsoleMethods[method] = originalConsole[method];
1106}
1090/*1107/*
1091 * The core Raven singleton1108 * The core Raven singleton
1092 *1109 *
1093 * @this {Raven}1110 * @this {Raven}
1094 */1111 */
1095var Raven = {1112var Raven = {
1096 VERSION: '1.1.18',1113 VERSION: '1.3.0',
1097 1114
1098 debug: true,1115 debug: false,
1099 1116
1100 /*1117 /*
1101 * Allow multiple versions of Raven to be installed.1118 * Allow multiple versions of Raven to be installed.
@@ -1129,7 +1146,12 @@ var Raven = { · 27 unmodified lines
1129 // merge in options1146 // merge in options
1130 if (options) {1147 if (options) {
1131 each(options, function(key, value){1148 each(options, function(key, value){
1132 globalOptions[key] = value;1149 // tags and extra are special and need to be put into context
1150 if (key == 'tags' || key == 'extra') {
1151 globalContext[key] = value;
1152 } else {
1153 globalOptions[key] = value;
1154 }
1133 });1155 });
1134 }1156 }
1135 1157
@@ -1166,8 +1188,6 @@ var Raven = { · 30 unmodified lines
1166 1188
1167 TraceKit.collectWindowErrors = !!globalOptions.collectWindowErrors;1189 TraceKit.collectWindowErrors = !!globalOptions.collectWindowErrors;
1168 1190
1169 setAuthQueryString();
1170
1171 // return for chaining1191 // return for chaining
1172 return Raven;1192 return Raven;
1173 },1193 },
@@ -1183,6 +1203,12 @@ var Raven = { · 9 unmodified lines
1183 install: function() {1203 install: function() {
1184 if (isSetup() && !isRavenInstalled) {1204 if (isSetup() && !isRavenInstalled) {
1185 TraceKit.report.subscribe(handleStackInfo);1205 TraceKit.report.subscribe(handleStackInfo);
1206
1207 // Install all of the plugins
1208 each(plugins, function(_, plugin) {
1209 plugin();
1210 });
1211
1186 isRavenInstalled = true;1212 isRavenInstalled = true;
1187 }1213 }
1188 1214
@@ -1261,6 +1287,7 @@ var Raven = { · 72 unmodified lines
1261 wrapped[property] = func[property];1287 wrapped[property] = func[property];
1262 }1288 }
1263 }1289 }
1290 wrapped.prototype = func.prototype;
1264 1291
1265 // Signal that this function has been wrapped already1292 // Signal that this function has been wrapped already
1266 // for both debugging and to prevent it to being wrapped twice1293 // for both debugging and to prevent it to being wrapped twice
@@ -1302,7 +1329,8 @@ var Raven = { · 35 unmodified lines
1302 // raises an exception different from the one we asked to1329 // raises an exception different from the one we asked to
1303 // report on.1330 // report on.
1304 try {1331 try {
1305 TraceKit.report(ex, options);1332 var stack = TraceKit.computeStackTrace(ex);
1333 handleStackInfo(stack, options);
1306 } catch(ex1) {1334 } catch(ex1) {
1307 if(ex !== ex1) {1335 if(ex !== ex1) {
1308 throw ex1;1336 throw ex1;
@@ -1337,6 +1365,12 @@ var Raven = { · 28 unmodified lines
1337 return Raven;1365 return Raven;
1338 },1366 },
1339 1367
1368 addPlugin: function(plugin) {
1369 plugins.push(plugin);
1370 if (isRavenInstalled) plugin();
1371 return Raven;
1372 },
1373
1340 /*1374 /*
1341 * Set/clear a user to be sent along with the payload.1375 * Set/clear a user to be sent along with the payload.
1342 *1376 *
@@ -1344,47 +1378,110 @@ var Raven = { · 1 unmodified line
1344 * @return {Raven}1378 * @return {Raven}
1345 */1379 */
1346 setUserContext: function(user) {1380 setUserContext: function(user) {
1347 globalUser = user;1381 // Intentionally do not merge here since that's an unexpected behavior.
1382 globalContext.user = user;
1348 1383
1349 return Raven;1384 return Raven;
1350 },1385 },
1351 1386
1352 /*1387 /*
1353 * Set extra attributes to be sent along with the payload.1388 * Merge extra attributes to be sent along with the payload.
1354 *1389 *
1355 * @param {object} extra An object representing extra data [optional]1390 * @param {object} extra An object representing extra data [optional]
1356 * @return {Raven}1391 * @return {Raven}
1357 */1392 */
1358 setExtraContext: function(extra) {1393 setExtraContext: function(extra) {
1359 globalOptions.extra = extra || {};1394 mergeContext('extra', extra);
1360 1395
1361 return Raven;1396 return Raven;
1362 },1397 },
1363 1398
1364 /*1399 /*
1365 * Set tags to be sent along with the payload.1400 * Merge tags to be sent along with the payload.
1366 *1401 *
1367 * @param {object} tags An object representing tags [optional]1402 * @param {object} tags An object representing tags [optional]
1368 * @return {Raven}1403 * @return {Raven}
1369 */1404 */
1370 setTagsContext: function(tags) {1405 setTagsContext: function(tags) {
1371 globalOptions.tags = tags || {};1406 mergeContext('tags', tags);
1372 1407
1373 return Raven;1408 return Raven;
1374 },1409 },
1375 1410
1411 /*
1412 * Clear all of the context.
1413 *
1414 * @return {Raven}
1415 */
1416 clearContext: function() {
1417 globalContext = {};
1418
1419 return Raven;
1420 },
1421
1422 /*
1423 * Get a copy of the current context. This cannot be mutated.
1424 *
1425 * @return {object} copy of context
1426 */
1427 getContext: function() {
1428 // lol javascript
1429 return JSON.parse(JSON.stringify(globalContext));
1430 },
1431
1376 /*1432 /*
1377 * Set release version of application1433 * Set release version of application
1378 *1434 *
1379 * @param {string} release Typically something like a git SHA to identify version1435 * @param {string} release Typically something like a git SHA to identify version
1380 * @return {Raven}1436 * @return {Raven}
1381 */1437 */
1382 setReleaseContext: function(release) {1438 setRelease: function(release) {
1383 globalOptions.release = release;1439 globalOptions.release = release;
1384 1440
1385 return Raven;1441 return Raven;
1386 },1442 },
1387 1443
1444 /*
1445 * Set the dataCallback option
1446 *
1447 * @param {function} callback The callback to run which allows the
1448 * data blob to be mutated before sending
1449 * @return {Raven}
1450 */
1451 setDataCallback: function(callback) {
1452 globalOptions.dataCallback = callback;
1453
1454 return Raven;
1455 },
1456
1457 /*
1458 * Set the shouldSendCallback option
1459 *
1460 * @param {function} callback The callback to run which allows
1461 * introspecting the blob before sending
1462 * @return {Raven}
1463 */
1464 setShouldSendCallback: function(callback) {
1465 globalOptions.shouldSendCallback = callback;
1466
1467 return Raven;
1468 },
1469
1470 /**
1471 * Override the default HTTP transport mechanism that transmits data
1472 * to the Sentry server.
1473 *
1474 * @param {function} transport Function invoked instead of the default
1475 * `makeRequest` handler.
1476 *
1477 * @return {Raven}
1478 */
1479 setTransport: function(transport) {
1480 globalOptions.transport = transport;
1481
1482 return Raven;
1483 },
1484
1388 /*1485 /*
1389 * Get the latest raw exception that was captured by Raven.1486 * Get the latest raw exception that was captured by Raven.
1390 *1487 *
@@ -1413,41 +1510,47 @@ var Raven = { · 22 unmodified lines
1413 }1510 }
1414};1511};
1415 1512
1416Raven.setUser = Raven.setUserContext; // To be deprecated1513// Deprecations
1514Raven.setUser = Raven.setUserContext;
1515Raven.setReleaseContext = Raven.setRelease;
1417 1516
1418function triggerEvent(eventType, options) {1517function triggerEvent(eventType, options) {
1419 var event, key;1518 // NOTE: `event` is a native browser thing, so let's avoid conflicting wiht it
1519 var evt, key;
1520
1521 if (!hasDocument)
1522 return;
1420 1523
1421 options = options || {};1524 options = options || {};
1422 1525
1423 eventType = 'raven' + eventType.substr(0,1).toUpperCase() + eventType.substr(1);1526 eventType = 'raven' + eventType.substr(0,1).toUpperCase() + eventType.substr(1);
1424 1527
1425 if (document.createEvent) {1528 if (document.createEvent) {
1426 event = document.createEvent('HTMLEvents');1529 evt = document.createEvent('HTMLEvents');
1427 event.initEvent(eventType, true, true);1530 evt.initEvent(eventType, true, true);
1428 } else {1531 } else {
1429 event = document.createEventObject();1532 evt = document.createEventObject();
1430 event.eventType = eventType;1533 evt.eventType = eventType;
1431 }1534 }
1432 1535
1433 for (key in options) if (hasKey(options, key)) {1536 for (key in options) if (hasKey(options, key)) {
1434 event[key] = options[key];1537 evt[key] = options[key];
1435 }1538 }
1436 1539
1437 if (document.createEvent) {1540 if (document.createEvent) {
1438 // IE9 if standards1541 // IE9 if standards
1439 document.dispatchEvent(event);1542 document.dispatchEvent(evt);
1440 } else {1543 } else {
1441 // IE8 regardless of Quirks or Standards1544 // IE8 regardless of Quirks or Standards
1442 // IE9 if quirks1545 // IE9 if quirks
1443 try {1546 try {
1444 document.fireEvent('on' + event.eventType.toLowerCase(), event);1547 document.fireEvent('on' + evt.eventType.toLowerCase(), evt);
1445 } catch(e) {}1548 } catch(e) {}
1446 }1549 }
1447}1550}
1448 1551
1449var dsnKeys = 'source protocol user pass host port path'.split(' '),1552var dsnKeys = 'source protocol user pass host port path'.split(' '),
1450 dsnPattern = /^(?:(\w+):)?\/\/(\w+)(:\w+)?@([\w\.-]+)(?::(\d+))?(\/.*)/;1553 dsnPattern = /^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/;
1451 1554
1452function RavenConfigError(message) {1555function RavenConfigError(message) {
1453 this.name = 'RavenConfigError';1556 this.name = 'RavenConfigError';
@@ -1475,7 +1578,7 @@ function parseDSN(str) { · 21 unmodified lines
1475}1578}
1476 1579
1477function isUndefined(what) {1580function isUndefined(what) {
1478 return typeof what === 'undefined';1581 return what === void 0;
1479}1582}
1480 1583
1481function isFunction(what) {1584function isFunction(what) {
@@ -1483,7 +1586,7 @@ function isFunction(what) { · 1 unmodified line
1483}1586}
1484 1587
1485function isString(what) {1588function isString(what) {
1486 return typeof what === 'string';1589 return objectPrototype.toString.call(what) === '[object String]';
1487}1590}
1488 1591
1489function isObject(what) {1592function isObject(what) {
@@ -1533,15 +1636,6 @@ function each(obj, callback) { · 43 unmodified lines
1533 }1636 }
1534}1637}
1535 1638
1536
1537function setAuthQueryString() {
1538 authQueryString =
1539 '?sentry_version=4' +
1540 '&sentry_client=raven-js/' + Raven.VERSION +
1541 '&sentry_key=' + globalKey;
1542}
1543
1544
1545function handleStackInfo(stackInfo, options) {1639function handleStackInfo(stackInfo, options) {
1546 var frames = [];1640 var frames = [];
1547 1641
@@ -1588,7 +1682,7 @@ function normalizeFrame(frame) { · 40 unmodified lines
1588 1682
1589 normalized.in_app = !( // determine if an exception came from outside of our app1683 normalized.in_app = !( // determine if an exception came from outside of our app
1590 // first we check the global includePaths list.1684 // first we check the global includePaths list.
1591 !globalOptions.includePaths.test(normalized.filename) ||1685 (!!globalOptions.includePaths.test && !globalOptions.includePaths.test(normalized.filename)) ||
1592 // Now we check for fun, if the function name is Raven or TraceKit1686 // Now we check for fun, if the function name is Raven or TraceKit
1593 /(Raven|TraceKit)\./.test(normalized['function']) ||1687 /(Raven|TraceKit)\./.test(normalized['function']) ||
1594 // finally, we do a last ditch effort and check for raven.min.js1688 // finally, we do a last ditch effort and check for raven.min.js
@@ -1638,20 +1732,12 @@ function extractContextFromFrame(frame) { · 43 unmodified lines
1638}1732}
1639 1733
1640function processException(type, message, fileurl, lineno, frames, options) {1734function processException(type, message, fileurl, lineno, frames, options) {
1641 var stacktrace, label, i;1735 var stacktrace, i, fullMessage;
1642 1736
1643 // In some instances message is not actually a string, no idea why,1737 if (!!globalOptions.ignoreErrors.test && globalOptions.ignoreErrors.test(message)) return;
1644 // so we want to always coerce it to one.
1645 message += '';
1646
1647 // Sometimes an exception is getting logged in Sentry as
1648 // <no message value>
1649 // This can only mean that the message was falsey since this value
1650 // is hardcoded into Sentry itself.
1651 // At this point, if the message is falsey, we bail since it's useless
1652 if (type === 'Error' && !message) return;
1653 1738
1654 if (globalOptions.ignoreErrors.test(message)) return;1739 message += '';
1740 fullMessage = type + ': ' + message;
1655 1741
1656 if (frames && frames.length) {1742 if (frames && frames.length) {
1657 fileurl = frames[0].filename || fileurl;1743 fileurl = frames[0].filename || fileurl;
@@ -1669,26 +1755,22 @@ function processException(type, message, fileurl, lineno, frames, options) { · 11 unmodified lines
1669 };1755 };
1670 }1756 }
1671 1757
1672 // Truncate the message to a max of characters1758 if (!!globalOptions.ignoreUrls.test && globalOptions.ignoreUrls.test(fileurl)) return;
1673 message = truncate(message, globalOptions.maxMessageLength);1759 if (!!globalOptions.whitelistUrls.test && !globalOptions.whitelistUrls.test(fileurl)) return;
1674
1675 if (globalOptions.ignoreUrls && globalOptions.ignoreUrls.test(fileurl)) return;
1676 if (globalOptions.whitelistUrls && !globalOptions.whitelistUrls.test(fileurl)) return;
1677
1678 label = lineno ? message + ' at ' + lineno : message;
1679 1760
1680 // Fire away!1761 // Fire away!
1681 send(1762 send(
1682 objectMerge({1763 objectMerge({
1683 // sentry.interfaces.Exception1764 // sentry.interfaces.Exception
1684 exception: {1765 exception: {
1685 type: type,1766 values: [{
1686 value: message1767 type: type,
1768 value: message,
1769 stacktrace: stacktrace
1770 }]
1687 },1771 },
1688 // sentry.interfaces.Stacktrace
1689 stacktrace: stacktrace,
1690 culprit: fileurl,1772 culprit: fileurl,
1691 message: label1773 message: fullMessage
1692 }, options)1774 }, options)
1693 );1775 );
1694}1776}
@@ -1707,58 +1789,83 @@ function truncate(str, max) { · 12 unmodified lines
1707 return str.length <= max ? str : str.substr(0, max) + '\u2026';1789 return str.length <= max ? str : str.substr(0, max) + '\u2026';
1708}1790}
1709 1791
1792function trimPacket(data) {
1793 // For now, we only want to truncate the two different messages
1794 // but this could/should be expanded to just trim everything
1795 var max = globalOptions.maxMessageLength;
1796 data.message = truncate(data.message, max);
1797 if (data.exception) {
1798 var exception = data.exception.values[0];
1799 exception.value = truncate(exception.value, max);
1800 }
1801
1802 return data;
1803}
1804
1710function now() {1805function now() {
1711 return +new Date();1806 return +new Date();
1712}1807}
1713 1808
1714function getHttpData() {1809function getHttpData() {
1715 var http = {1810 if (!hasDocument || !document.location || !document.location.href) {
1716 url: document.location.href,1811 return;
1812 }
1813
1814 var httpData = {
1717 headers: {1815 headers: {
1718 'User-Agent': navigator.userAgent1816 'User-Agent': navigator.userAgent
1719 }1817 }
1720 };1818 };
1721 1819
1820 httpData.url = document.location.href;
1821
1722 if (document.referrer) {1822 if (document.referrer) {
1723 http.headers.Referer = document.referrer;1823 httpData.headers.Referer = document.referrer;
1724 }1824 }
1725 1825
1726 return http;1826 return httpData;
1727}1827}
1728 1828
1729function send(data) {1829function send(data) {
1730 if (!isSetup()) return;1830 var baseData = {
1731
1732 data = objectMerge({
1733 project: globalProject,1831 project: globalProject,
1734 logger: globalOptions.logger,1832 logger: globalOptions.logger,
1735 platform: 'javascript',1833 platform: 'javascript'
1736 // sentry.interfaces.Http1834 }, httpData = getHttpData();
1737 request: getHttpData()1835
1738 }, data);1836 if (httpData) {
1837 baseData.request = httpData;
1838 }
1839
1840 data = objectMerge(baseData, data);
1739 1841
1740 // Merge in the tags and extra separately since objectMerge doesn't handle a deep merge1842 // Merge in the tags and extra separately since objectMerge doesn't handle a deep merge
1741 data.tags = objectMerge(objectMerge({}, globalOptions.tags), data.tags);1843 data.tags = objectMerge(objectMerge({}, globalContext.tags), data.tags);
1742 data.extra = objectMerge(objectMerge({}, globalOptions.extra), data.extra);1844 data.extra = objectMerge(objectMerge({}, globalContext.extra), data.extra);
1743 1845
1744 // Send along our own collected metadata with extra1846 // Send along our own collected metadata with extra
1745 data.extra = objectMerge({1847 data.extra['session:duration'] = now() - startTime;
1746 'session:duration': now() - startTime
1747 }, data.extra);
1748 1848
1749 // If there are no tags/extra, strip the key from the payload alltogther.1849 // If there are no tags/extra, strip the key from the payload alltogther.
1750 if (isEmptyObject(data.tags)) delete data.tags;1850 if (isEmptyObject(data.tags)) delete data.tags;
1751 1851
1752 if (globalUser) {1852 if (globalContext.user) {
1753 // sentry.interfaces.User1853 // sentry.interfaces.User
1754 data.user = globalUser;1854 data.user = globalContext.user;
1755 }1855 }
1756 1856
1757 // Include the release iff it's defined in globalOptions1857 // Include the release if it's defined in globalOptions
1758 if (globalOptions.release) data.release = globalOptions.release;1858 if (globalOptions.release) data.release = globalOptions.release;
1859 // Include server_name if it's defined in globalOptions
1860 if (globalOptions.serverName) data.server_name = globalOptions.serverName;
1759 1861
1760 if (isFunction(globalOptions.dataCallback)) {1862 if (isFunction(globalOptions.dataCallback)) {
1761 data = globalOptions.dataCallback(data);1863 data = globalOptions.dataCallback(data) || data;
1864 }
1865
1866 // Why??????????
1867 if (!data || isEmptyObject(data)) {
1868 return;
1762 }1869 }
1763 1870
1764 // Check if the request should be filtered or not1871 // Check if the request should be filtered or not
@@ -1771,34 +1878,68 @@ function send(data) { · 6 unmodified lines
1771 // Set lastEventId after we know the error should actually be sent1878 // Set lastEventId after we know the error should actually be sent
1772 lastEventId = data.event_id || (data.event_id = uuid4());1879 lastEventId = data.event_id || (data.event_id = uuid4());
1773 1880
1774 makeRequest(data);1881 // Try and clean up the packet before sending by truncating long values
1882 data = trimPacket(data);
1883
1884 logDebug('debug', 'Raven about to send:', data);
1885
1886 if (!isSetup()) return;
1887
1888 (globalOptions.transport || makeRequest)({
1889 url: globalServer,
1890 auth: {
1891 sentry_version: '7',
1892 sentry_client: 'raven-js/' + Raven.VERSION,
1893 sentry_key: globalKey
1894 },
1895 data: data,
1896 options: globalOptions,
1897 onSuccess: function success() {
1898 triggerEvent('success', {
1899 data: data,
1900 src: globalServer
1901 });
1902 },
1903 onError: function failure() {
1904 triggerEvent('failure', {
1905 data: data,
1906 src: globalServer
1907 });
1908 }
1909 });
1775}1910}
1776 1911
1912function makeRequest(opts) {
1913 // Tack on sentry_data to auth options, which get urlencoded
1914 opts.auth.sentry_data = JSON.stringify(opts.data);
1777 1915
1778function makeRequest(data) {1916 var img = newImage(),
1779 var img = new Image(),1917 src = opts.url + '?' + urlencode(opts.auth),
1780 src = globalServer + authQueryString + '&sentry_data=' + encodeURIComponent(JSON.stringify(data));1918 crossOrigin = opts.options.crossOrigin;
1781 1919
1782 img.crossOrigin = 'anonymous';1920 if (crossOrigin || crossOrigin === '') {
1783 img.onload = function success() {1921 img.crossOrigin = crossOrigin;
1784 triggerEvent('success', {1922 }
1785 data: data,1923 img.onload = opts.onSuccess;
1786 src: src1924 img.onerror = img.onabort = opts.onError;
1787 });
1788 };
1789 img.onerror = img.onabort = function failure() {
1790 triggerEvent('failure', {
1791 data: data,
1792 src: src
1793 });
1794 };
1795 img.src = src;1925 img.src = src;
1796}1926}
1797 1927
1928// Note: this is shitty, but I can't figure out how to get
1929// sinon to stub document.createElement without breaking everything
1930// so this wrapper is just so I can stub it for tests.
1931function newImage() {
1932 return document.createElement('img');
1933}
1934
1935var ravenNotConfiguredError;
1936
1798function isSetup() {1937function isSetup() {
1799 if (!hasJSON) return false; // needs JSON support1938 if (!hasJSON) return false; // needs JSON support
1800 if (!globalServer) {1939 if (!globalServer) {
1801 logDebug('error', 'Error: Raven has not been configured.');1940 if (!ravenNotConfiguredError)
1941 logDebug('error', 'Error: Raven has not been configured.');
1942 ravenNotConfiguredError = true;
1802 return false;1943 return false;
1803 }1944 }
1804 return true;1945 return true;
@@ -1826,18 +1967,44 @@ function joinRegExp(patterns) { · 21 unmodified lines
1826 return new RegExp(sources.join('|'), 'i');1967 return new RegExp(sources.join('|'), 'i');
1827}1968}
1828 1969
1829// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
1830function uuid4() {1970function uuid4() {
1831 return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {1971 var crypto = window.crypto || window.msCrypto;
1832 var r = Math.random()*16|0,1972
1833 v = c == 'x' ? r : (r&0x3|0x8);1973 if (!isUndefined(crypto) && crypto.getRandomValues) {
1834 return v.toString(16);1974 // Use window.crypto API if available
1835 });1975 var arr = new Uint16Array(8);
1976 crypto.getRandomValues(arr);
1977
1978 // set 4 in byte 7
1979 arr[3] = arr[3] & 0xFFF | 0x4000;
1980 // set 2 most significant bits of byte 9 to '10'
1981 arr[4] = arr[4] & 0x3FFF | 0x8000;
1982
1983 var pad = function(num) {
1984 var v = num.toString(16);
1985 while (v.length < 4) {
1986 v = '0' + v;
1987 }
1988 return v;
1989 };
1990
1991 return (pad(arr[0]) + pad(arr[1]) + pad(arr[2]) + pad(arr[3]) + pad(arr[4]) +
1992 pad(arr[5]) + pad(arr[6]) + pad(arr[7]));
1993 } else {
1994 // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
1995 return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
1996 var r = Math.random()*16|0,
1997 v = c == 'x' ? r : (r&0x3|0x8);
1998 return v.toString(16);
1999 });
2000 }
1836}2001}
1837 2002
1838function logDebug(level, message) {2003function logDebug(level) {
1839 if (window.console && console[level] && Raven.debug) {2004 if (originalConsoleMethods[level] && Raven.debug) {
1840 console[level](message);2005 // _slice is coming from vendor/TraceKit/tracekit.js
2006 // so it's accessible globally
2007 originalConsoleMethods[level].apply(originalConsole, _slice.call(arguments, 1));
1841 }2008 }
1842}2009}
1843 2010
@@ -1848,12 +2015,32 @@ function afterLoad() { · 4 unmodified lines
1848 Raven.config(RavenConfig.dsn, RavenConfig.config).install();2015 Raven.config(RavenConfig.dsn, RavenConfig.config).install();
1849 }2016 }
1850}2017}
2018
2019function urlencode(o) {
2020 var pairs = [];
2021 each(o, function(key, value) {
2022 pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
2023 });
2024 return pairs.join('&');
2025}
2026
2027function mergeContext(key, context) {
2028 if (isUndefined(context)) {
2029 delete globalContext[key];
2030 } else {
2031 globalContext[key] = objectMerge(globalContext[key] || {}, context);
2032 }
2033}
2034
1851afterLoad();2035afterLoad();
1852 2036
2037// This is being exposed no matter what because there are too many weird
2038// usecases for how people use Raven. If this is really a problem, I'm sorry.
2039window.Raven = Raven;
2040
1853// Expose Raven to the world2041// Expose Raven to the world
1854if (typeof define === 'function' && define.amd) {2042if (typeof define === 'function' && define.amd) {
1855 // AMD2043 // AMD
1856 window.Raven = Raven;
1857 define('raven', [], function() {2044 define('raven', [], function() {
1858 return Raven;2045 return Raven;
1859 });2046 });
@@ -1863,9 +2050,6 @@ if (typeof define === 'function' && define.amd) { · 3 unmodified lines
1863} else if (typeof exports === 'object') {2050} else if (typeof exports === 'object') {
1864 // CommonJS2051 // CommonJS
1865 exports = Raven;2052 exports = Raven;
1866} else {
1867 // Everything else
1868 window.Raven = Raven;
1869}2053}
1870 2054
1871})(window);2055})(typeof window !== 'undefined' ? window : this);