Skip to content

Instantly share code, notes, and snippets.

@rgoldfinger
Created October 17, 2017 23:10
Show Gist options
  • Save rgoldfinger/e945c7cf949ceb5e6506659a8cd35d0e to your computer and use it in GitHub Desktop.
Save rgoldfinger/e945c7cf949ceb5e6506659a8cd35d0e to your computer and use it in GitHub Desktop.
// --------------------------------------------------
// rollbar.ejs
// --------------------------------------------------
<%_ if (!__DEV__ && !__FUNCTIONAL__) { _%>
<script>
var _rollbarConfig = {
accessToken: "37c613c5a8b34fba89cd4fcfebc76808",
captureUncaught: true,
captureUnhandledRejections: true,
reportLevel: 'error',
payload: {
environment: '<%= ROLLBAR_ENVIRONMENT %>',
release: '<%= VERSION %>',
client: {
javascript: {
source_map_enabled: true,
guess_uncaught_frames: true,
code_version: '<%= COMMIT_SHA %>',
}
},
},
transform: function(payload) {
if (window._rolbarTransform) {
console.warn('initial transform sending to window._rolbarTransform');
window._rolbarTransform(payload);
} else {
console.warn('initial transform called without window._rolbarTransform');
}
},
checkIgnore: function(isUncaught, args, payload) {
if (window._rollbarCheckIgnore) {
console.warn('initial checkIgnore sending to window._rollbarCheckIgnore');
return window._rollbarCheckIgnore(isUncaught, args, payload);
} else {
console.warn('initial transform called without window._rollbarCheckIgnore');
return false;
}
},
};
// Rollbar Snippet
!function(r){function o(n){if(e[n])return e[n].exports;var t=e[n]={exports:{},id:n,loaded:!1};return r[n].call(t.exports,t,t.exports,o),t.loaded=!0,t.exports}var e={};return o.m=r,o.c=e,o.p="",o(0)}([function(r,o,e){"use strict";var n=e(1),t=e(4);_rollbarConfig=_rollbarConfig||{},_rollbarConfig.rollbarJsUrl=_rollbarConfig.rollbarJsUrl||"https://cdnjs.cloudflare.com/ajax/libs/rollbar.js/2.2.9/rollbar.min.js",_rollbarConfig.async=void 0===_rollbarConfig.async||_rollbarConfig.async;var a=n.setupShim(window,_rollbarConfig),l=t(_rollbarConfig);window.rollbar=n.Rollbar,a.loadFull(window,document,!_rollbarConfig.async,_rollbarConfig,l)},function(r,o,e){"use strict";function n(r){return function(){try{return r.apply(this,arguments)}catch(r){try{console.error("[Rollbar]: Internal error",r)}catch(r){}}}}function t(r,o){this.options=r,this._rollbarOldOnError=null;var e=s++;this.shimId=function(){return e},window&&window._rollbarShims&&(window._rollbarShims[e]={handler:o,messages:[]})}function a(r,o){var e=o.globalAlias||"Rollbar";if("object"==typeof r[e])return r[e];r._rollbarShims={},r._rollbarWrappedError=null;var t=new p(o);return n(function(){o.captureUncaught&&(t._rollbarOldOnError=r.onerror,i.captureUncaughtExceptions(r,t,!0),i.wrapGlobals(r,t,!0)),o.captureUnhandledRejections&&i.captureUnhandledRejections(r,t,!0);var n=o.autoInstrument;return o.enabled!==!1&&(void 0===n||n===!0||"object"==typeof n&&n.network)&&r.addEventListener&&(r.addEventListener("load",t.captureLoad.bind(t)),r.addEventListener("DOMContentLoaded",t.captureDomContentLoaded.bind(t))),r[e]=t,t})()}function l(r){return n(function(){var o=this,e=Array.prototype.slice.call(arguments,0),n={shim:o,method:r,args:e,ts:new Date};window._rollbarShims[this.shimId()].messages.push(n)})}var i=e(2),s=0,d=e(3),c=function(r,o){return new t(r,o)},p=d.bind(null,c);t.prototype.loadFull=function(r,o,e,t,a){var l=function(){var o;if(void 0===r._rollbarDidLoad){o=new Error("rollbar.js did not load");for(var e,n,t,l,i=0;e=r._rollbarShims[i++];)for(e=e.messages||[];n=e.shift();)for(t=n.args||[],i=0;i<t.length;++i)if(l=t[i],"function"==typeof l){l(o);break}}"function"==typeof a&&a(o)},i=!1,s=o.createElement("script"),d=o.getElementsByTagName("script")[0],c=d.parentNode;s.crossOrigin="",s.src=t.rollbarJsUrl,e||(s.async=!0),s.onload=s.onreadystatechange=n(function(){if(!(i||this.readyState&&"loaded"!==this.readyState&&"complete"!==this.readyState)){s.onload=s.onreadystatechange=null;try{c.removeChild(s)}catch(r){}i=!0,l()}}),c.insertBefore(s,d)},t.prototype.wrap=function(r,o,e){try{var n;if(n="function"==typeof o?o:function(){return o||{}},"function"!=typeof r)return r;if(r._isWrap)return r;if(!r._rollbar_wrapped&&(r._rollbar_wrapped=function(){e&&"function"==typeof e&&e.apply(this,arguments);try{return r.apply(this,arguments)}catch(e){var o=e;throw"string"==typeof o&&(o=new String(o)),o._rollbarContext=n()||{},o._rollbarContext._wrappedSource=r.toString(),window._rollbarWrappedError=o,o}},r._rollbar_wrapped._isWrap=!0,r.hasOwnProperty))for(var t in r)r.hasOwnProperty(t)&&(r._rollbar_wrapped[t]=r[t]);return r._rollbar_wrapped}catch(o){return r}};for(var u="log,debug,info,warn,warning,error,critical,global,configure,handleUncaughtException,handleUnhandledRejection,captureEvent,captureDomContentLoaded,captureLoad".split(","),f=0;f<u.length;++f)t.prototype[u[f]]=l(u[f]);r.exports={setupShim:a,Rollbar:p}},function(r,o){"use strict";function e(r,o,e){if(r){var t;"function"==typeof o._rollbarOldOnError?t=o._rollbarOldOnError:r.onerror&&!r.onerror.belongsToShim&&(t=r.onerror,o._rollbarOldOnError=t);var a=function(){var e=Array.prototype.slice.call(arguments,0);n(r,o,t,e)};a.belongsToShim=e,r.onerror=a}}function n(r,o,e,n){r._rollbarWrappedError&&(n[4]||(n[4]=r._rollbarWrappedError),n[5]||(n[5]=r._rollbarWrappedError._rollbarContext),r._rollbarWrappedError=null),o.handleUncaughtException.apply(o,n),e&&e.apply(r,n)}function t(r,o,e){if(r){"function"==typeof r._rollbarURH&&r._rollbarURH.belongsToShim&&r.removeEventListener("unhandledrejection",r._rollbarURH);var n=function(r){var e=r.reason,n=r.promise,t=r.detail;!e&&t&&(e=t.reason,n=t.promise),o&&o.handleUnhandledRejection&&o.handleUnhandledRejection(e,n)};n.belongsToShim=e,r._rollbarURH=n,r.addEventListener("unhandledrejection",n)}}function a(r,o,e){if(r){var n,t,a="EventTarget,Window,Node,ApplicationCache,AudioTrackList,ChannelMergerNode,CryptoOperation,EventSource,FileReader,HTMLUnknownElement,IDBDatabase,IDBRequest,IDBTransaction,KeyOperation,MediaController,MessagePort,ModalWindow,Notification,SVGElementInstance,Screen,TextTrack,TextTrackCue,TextTrackList,WebSocket,WebSocketWorker,Worker,XMLHttpRequest,XMLHttpRequestEventTarget,XMLHttpRequestUpload".split(",");for(n=0;n<a.length;++n)t=a[n],r[t]&&r[t].prototype&&l(o,r[t].prototype,e)}}function l(r,o,e){if(o.hasOwnProperty&&o.hasOwnProperty("addEventListener")){for(var n=o.addEventListener;n._rollbarOldAdd&&n.belongsToShim;)n=n._rollbarOldAdd;var t=function(o,e,t){n.call(this,o,r.wrap(e),t)};t._rollbarOldAdd=n,t.belongsToShim=e,o.addEventListener=t;for(var a=o.removeEventListener;a._rollbarOldRemove&&a.belongsToShim;)a=a._rollbarOldRemove;var l=function(r,o,e){a.call(this,r,o&&o._rollbar_wrapped||o,e)};l._rollbarOldRemove=a,l.belongsToShim=e,o.removeEventListener=l}}r.exports={captureUncaughtExceptions:e,captureUnhandledRejections:t,wrapGlobals:a}},function(r,o){"use strict";function e(r,o){this.impl=r(o,this),this.options=o,n(e.prototype)}function n(r){for(var o=function(r){return function(){var o=Array.prototype.slice.call(arguments,0);if(this.impl[r])return this.impl[r].apply(this.impl,o)}},e="log,debug,info,warn,warning,error,critical,global,configure,handleUncaughtException,handleUnhandledRejection,_createItem,wrap,loadFull,shimId,captureEvent,captureDomContentLoaded,captureLoad".split(","),n=0;n<e.length;n++)r[e[n]]=o(e[n])}e.prototype._swapAndProcessMessages=function(r,o){this.impl=r(this.options);for(var e,n,t;e=o.shift();)n=e.method,t=e.args,this[n]&&"function"==typeof this[n]&&("captureDomContentLoaded"===n||"captureLoad"===n?this[n].apply(this,[t[0],e.ts]):this[n].apply(this,t));return this},r.exports=e},function(r,o){"use strict";r.exports=function(r){return function(o){if(!o&&!window._rollbarInitialized){r=r||{};for(var e,n,t=r.globalAlias||"Rollbar",a=window.rollbar,l=function(r){return new a(r)},i=0;e=window._rollbarShims[i++];)n||(n=e.handler),e.handler._swapAndProcessMessages(l,e.messages);window[t]=n,window._rollbarInitialized=!0}}}}]);
// End Rollbar Snippet
</script>
<%_ } _%>
// --------------------------------------------------
// setupErrorLogging.js
// --------------------------------------------------
/* @flow */
import idx from 'idx';
const regexsToIgnore = [
/Branch init failed/gi,
/GoogleAPI.*popup_closed_by_user/gi, // google auth
/GoogleAPI.*access_denied/gi, // google auth
/unhandled rejection was null or undefined/gi,
/script error/gi,
/object Object/gi,
/GraphQL error: 503/gi,
/GraphQL error: Unauthorized/gi,
/GraphQL error: 401/gi,
/Network error: Failed to fetch/gi,
// prettier-ignore
/\$ is not defined/gi, // eslint-disable-line
/Blocked a frame with origin "https:\/\/www.remind.com" from accessing a frame with origin "https:\/\/accounts.google.com". Protocols, domains, and ports must match./gi, // error with chrome on ios. Verified that it works correctly.
/event is not defined/gi,
/Failed to load because no supported source was found./gi,
/maxItems has been hit. Ignoring errors until reset./gi, // When rollbar's max items per browser session have been hit
/Cannot read property 'load' of undefined/gi, // chrome 47 auth
];
export function checkIgnore(isUncaught: boolean, args: Array<*>, payload: Object) {
try {
if (payload.fingerprint) {
return regexsToIgnore.some(pattern => payload.fingerprint.search(pattern) !== -1);
}
return false;
} catch (e) {
// if we did this wrong, lets log it so we can track why, and send the error anyway.
console.error(e);
return false;
}
}
export function transform(payload: Object) {
const message =
idx(payload, _ => _.body.message.body) ||
idx(payload, _ => _.body.message) ||
idx(payload, _ => _.body.trace.exception.message) ||
idx(payload, _ => _.body.trace.extra.extraArgs[0].message) ||
idx(payload, _ => _.body.trace.extra.extraArgs[1].message) ||
idx(payload, _ => _.body.trace.extra.extraArgs[0]) ||
idx(payload, _ => _.body.trace.extra.extraArgs[1]);
const description =
idx(payload, _ => _.body.trace.exception.description) ||
idx(payload, _ => _.body.message.extra.error);
if (typeof message === 'string' && message !== '') {
const shouldAddDescription = typeof description === 'string' && description !== message;
payload.fingerprint = message + (shouldAddDescription ? ` ${description || ''}` : '');
} else if (description && typeof description === 'string') {
payload.fingerprint = description;
}
}
if (typeof window !== 'undefined' && window.Rollbar) {
// TODO some way to disable console output. This seems to require a PR to rollbar's lib.
const { Rollbar } = window;
const nativeConsoleError = console.error;
// $FlowFixMe
console.error = (...args) => {
// If there's an error passed to the console, we want to use thar directly to preserve the stacktrace
const hasError = args.some(e => e instanceof Error);
if (hasError) {
Rollbar.error(...args);
} else {
// otherwise generate a stack trace
try {
throw Error(args[0]);
} catch (e) {
Rollbar.error(e, ...args.slice(1));
}
}
return nativeConsoleError.apply(console, args);
};
Rollbar.global({
maxItems: 10,
});
Rollbar.configure({
transform,
checkIgnore,
});
} else if (typeof window !== 'undefined') {
// Put these on the window so they can be picked up by the initial rollbar config, in case Rollbar wasn't initalized at the time this runs.
window._rolbarTransform = transform;
window._rollbarCheckIgnore = checkIgnore;
}
// --------------------------------------------------
// setupErrorLogging-test.js
// --------------------------------------------------
/* @flow weak */
import { transform, checkIgnore } from '../setupErrorLogging';
describe('setupErrorLogging', () => {
const errorsToSend = [
{
body: {
trace: {
exception: {
message: 'Received 401 after finding a window user',
class: 'Error',
},
},
},
},
{
body: {
message: 'abcdefghijklmnopqurstuvwxyz1234567890',
},
},
];
const errorsToIgnore = [
{
body: {
trace: {
exception: {
message: 'Request blocked by client, probably adblock',
class: 'Error',
description: 'Branch init failed',
},
},
},
},
{
body: {
message: {
body: 'GoogleAPI fetchAuthorizationCode failed',
extra: {
error: 'popup_closed_by_user',
},
},
},
},
{
body: {
trace: {
exception: {
message: 'unhandled rejection was null or undefined!',
class: '(unknown)',
description: 'unhandled rejection was null or undefined!',
},
},
},
},
{
body: {
trace: {
exception: {
message: 'Script error.',
class: '(unknown)',
description: 'Script error.',
},
},
},
},
{
body: {
trace: {
exception: {
message: 'Unhandled error',
class: 'Error',
description: 'GraphQL error: Unauthorized',
},
extra: {
extraArgs: [
'Error: GraphQL error: Unauthorized\n at new t (https://d32zu3mt2bvf74.cloudfront.net/assets/dll.vendor_7220b67f6999fe47e18e.js:1:82572)\n at https://d32zu3mt2bvf74.cloudfront.net/assets/dll.vendor_7220b67f6999fe47e18e.js:1:49350\n at https://d32zu3mt2bvf74.cloudfront.net/assets/dll.vendor_7220b67f6999fe47e18e.js:1:59168\n at Array.forEach (<anonymous>)\n at https://d32zu3mt2bvf74.cloudfront.net/assets/dll.vendor_7220b67f6999fe47e18e.js:1:59142\n at Array.forEach (<anonymous>)\n at e.broadcastQueries (https://d32zu3mt2bvf74.cloudfront.net/assets/dll.vendor_7220b67f6999fe47e18e.js:1:59091)\n at https://d32zu3mt2bvf74.cloudfront.net/assets/dll.vendor_7220b67f6999fe47e18e.js:1:58142\n at <anonymous>',
],
},
},
},
},
{
body: {
trace: {
exception: {
message: "Cannot read property 'load' of undefined",
class: 'TypeError',
description: "Uncaught TypeError: Cannot read property 'load' of undefined",
},
},
},
},
{
body: {
trace: {
exception: {
message: '0',
class: 'Error',
description: 'Branch init failed',
},
},
},
},
];
errorsToSend.forEach(payload => {
transform(payload); // mutates the payload
it(`should send with fingerprint ${payload.fingerprint}`, () => {
expect(checkIgnore(false, [], payload)).toBe(false);
});
});
errorsToIgnore.forEach(payload => {
transform(payload); // mutates the payload
it(`should ignore with fingerprint ${payload.fingerprint}`, () => {
expect(checkIgnore(false, [], payload)).toBe(true);
expect(checkIgnore(false, [], payload)).toBe(true); // testing twice becaused regexs are stateful
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment