Created
April 11, 2013 03:59
-
-
Save cheeaun/5360637 to your computer and use it in GitHub Desktop.
Crittercism's JS lib for logging errors/exceptions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var Crittercism = function () { | |
function l(a) { | |
var a = a || { | |
guess: !0 | |
}, b = a.e || null, | |
a = !! a.guess, | |
c = new l.implementation, | |
b = c.run(b); | |
return a ? c.guessAnonymousFunctions(b) : b | |
} | |
var k = null, | |
B = null, | |
m = !1, | |
i = function () { | |
try { | |
return "localStorage" in window && null !== window.localStorage | |
} catch (a) { | |
return !1 | |
} | |
}, n = function () { | |
i() && (localStorage["Crittercism.last_seen"] = (new Date).toString()) | |
}, C = function () { | |
var a = localStorage.getItem("Crittercism.last_seen"); | |
if (a) try { | |
return new Date(a) | |
} catch (b) { | |
return null | |
} else return null | |
}, t = function () { | |
if (i()) try { | |
return localStorage.getItem("Crittercism.did") | |
} catch (a) { | |
return "" | |
} else return "" | |
}, | |
j = null, | |
q = !1, | |
r = [], | |
w = 0, | |
u = function (a) { | |
q ? j.postMessage(a, "*") : r.push(a) | |
}, D = function () { | |
for (; message = r.pop();) j.postMessage(message, "*") | |
}, o = function (a) { | |
switch (a.data.type) { | |
case "iframeSyn": | |
j = a.source; | |
j.postMessage({ | |
type: "clientSynAck" | |
}, "*"); | |
break; | |
case "iframeSynAck": | |
j = a.source; | |
j.postMessage({ | |
type: "clientAck" | |
}, "*"); | |
q = !0; | |
D(); | |
break; | |
case "iframeAck": | |
q = !0; | |
D(); | |
break; | |
case "setDeviceId": | |
a = a.data.contents.deviceId, i() && localStorage.setItem("Crittercism.did", a) | |
} | |
}; | |
"undefined" === typeof inTest && window.addEventListener("message", | |
o, !1); | |
document.getElementById("crittercism_iframe") && (j = document.getElementById("crittercism_iframe"), j.postMessage({ | |
type: "clientSyn" | |
}, "*")); | |
l.implementation = function () {}; | |
l.implementation.prototype = { | |
run: function (a, b) { | |
a = a || this.createException(); | |
b = b || this.mode(a); | |
return b === "other" ? this.other(arguments.callee) : this[b](a) | |
}, | |
createException: function () { | |
try { | |
this.undef() | |
} catch (a) { | |
return a | |
} | |
}, | |
mode: function (a) { | |
return a.arguments && a.stack ? "chrome" : typeof a.message === "string" && typeof window !== "undefined" && window.opera ? !a.stacktrace || a.message.indexOf("\n") > -1 && a.message.split("\n").length > a.stacktrace.split("\n").length ? "opera9" : !a.stack ? "opera10a" : a.stacktrace.indexOf("called from line") < 0 ? "opera10b" : "opera11" : a.stack ? "firefox" : "other" | |
}, | |
instrumentFunction: function (a, b, c) { | |
var a = a || window, | |
d = a[b]; | |
a[b] = function () { | |
c.call(this, l().slice(4)); | |
return a[b]._instrumented.apply(this, arguments) | |
}; | |
a[b]._instrumented = d | |
}, | |
deinstrumentFunction: function (a, b) { | |
if (a[b].constructor === Function && a[b]._instrumented && a[b]._instrumented.constructor === | |
Function) a[b] = a[b]._instrumented | |
}, | |
chrome: function (a) { | |
a = (a.stack + "\n").replace(/^\S[^\(]+?[\n$]/gm, "").replace(/^\s+(at eval )?at\s+/gm, "").replace(/^([^\(]+?)([\n$])/gm, "{anonymous}()@$1$2").replace(/^Object.<anonymous>\s*\(([^\)]+)\)/gm, "{anonymous}()@$1").split("\n"); | |
a.pop(); | |
return a | |
}, | |
firefox: function (a) { | |
return a.stack.replace(/(?:\n@:0)?\s+$/m, "").replace(/^\(/gm, "{anonymous}(").split("\n") | |
}, | |
opera11: function (a) { | |
for (var b = /^.*line (\d+), column (\d+)(?: in (.+))? in (\S+):$/, a = a.stacktrace.split("\n"), | |
c = [], d = 0, f = a.length; d < f; d = d + 2) { | |
var e = b.exec(a[d]); | |
if (e) { | |
var g = e[4] + ":" + e[1] + ":" + e[2], | |
e = e[3] || "global code", | |
e = e.replace(/<anonymous function: (\S+)>/, "$1").replace(/<anonymous function>/, "{anonymous}"); | |
c.push(e + "@" + g + " -- " + a[d + 1].replace(/^\s+/, "")) | |
} | |
} | |
return c | |
}, | |
opera10b: function (a) { | |
for (var b = /^(.*)@(.+):(\d+)$/, a = a.stacktrace.split("\n"), c = [], d = 0, f = a.length; d < f; d++) { | |
var e = b.exec(a[d]); | |
e && c.push((e[1] ? e[1] + "()" : "global code") + "@" + e[2] + ":" + e[3]) | |
} | |
return c | |
}, | |
opera10a: function (a) { | |
for (var b = /Line (\d+).*script (?:in )?(\S+)(?:: In function (\S+))?$/i, | |
a = a.stacktrace.split("\n"), c = [], d = 0, f = a.length; d < f; d = d + 2) { | |
var e = b.exec(a[d]); | |
e && c.push((e[3] || "{anonymous}") + "()@" + e[2] + ":" + e[1] + " -- " + a[d + 1].replace(/^\s+/, "")) | |
} | |
return c | |
}, | |
opera9: function (a) { | |
for (var b = /Line (\d+).*script (?:in )?(\S+)/i, a = a.message.split("\n"), c = [], d = 2, f = a.length; d < f; d = d + 2) { | |
var e = b.exec(a[d]); | |
e && c.push("{anonymous}()@" + e[2] + ":" + e[1] + " -- " + a[d + 1].replace(/^\s+/, "")) | |
} | |
return c | |
}, | |
other: function (a) { | |
for (var b = /function\s*([\w\-$]+)?\s*\(/i, c = [], d, f; a && a.arguments && c.length < 10;) { | |
d = b.test(a.toString()) ? | |
RegExp.$1 || "{anonymous}" : "{anonymous}"; | |
f = Array.prototype.slice.call(a.arguments || []); | |
c[c.length] = d + "(" + this.stringifyArguments(f) + ")"; | |
a = a.caller | |
} | |
return c | |
}, | |
stringifyArguments: function (a) { | |
for (var b = [], c = Array.prototype.slice, d = 0; d < a.length; ++d) { | |
var f = a[d]; | |
f === void 0 ? b[d] = "undefined" : f === null ? b[d] = "null" : f.constructor && (f.constructor === Array ? b[d] = f.length < 3 ? "[" + this.stringifyArguments(f) + "]" : "[" + this.stringifyArguments(c.call(f, 0, 1)) + "..." + this.stringifyArguments(c.call(f, -1)) + "]" : f.constructor === Object ? | |
b[d] = "#object" : f.constructor === Function ? b[d] = "#function" : f.constructor === String ? b[d] = '"' + f + '"' : f.constructor === Number && (b[d] = f)) | |
} | |
return b.join(",") | |
}, | |
sourceCache: {}, | |
ajax: function (a) { | |
var b = this.createXMLHTTPObject(); | |
if (b) try { | |
b.open("GET", a, false); | |
b.send(null); | |
return b.responseText | |
} catch (c) {} | |
return "" | |
}, | |
createXMLHTTPObject: function () { | |
for (var a, b = [function () { | |
return new XMLHttpRequest | |
}, function () { | |
return new ActiveXObject("Msxml2.XMLHTTP") | |
}, function () { | |
return new ActiveXObject("Msxml3.XMLHTTP") | |
}, function () { | |
return new ActiveXObject("Microsoft.XMLHTTP") | |
} | |
], | |
c = 0; c < b.length; c++) try { | |
a = b[c](); | |
this.createXMLHTTPObject = b[c]; | |
return a | |
} catch (d) {} | |
}, | |
isSameDomain: function (a) { | |
return typeof location !== "undefined" && a.indexOf(location.hostname) !== -1 | |
}, | |
getSource: function (a) { | |
a in this.sourceCache || (this.sourceCache[a] = this.ajax(a).split("\n")); | |
return this.sourceCache[a] | |
}, | |
guessAnonymousFunctions: function (a) { | |
for (var b = 0; b < a.length; ++b) { | |
var c = /^(.*?)(?::(\d+))(?::(\d+))?(?: -- .+)?$/, | |
d = a[b], | |
f = /\{anonymous\}\(.*\)@(.*)/.exec(d); | |
if (f) { | |
var e = c.exec(f[1]); | |
if (e) { | |
c = e[1]; | |
f = e[2]; | |
e = e[3] || 0; | |
if (c && this.isSameDomain(c) && f) { | |
c = this.guessAnonymousFunction(c, f, e); | |
a[b] = d.replace("{anonymous}", c) | |
} | |
} | |
} | |
} | |
return a | |
}, | |
guessAnonymousFunction: function (a, b) { | |
var c; | |
try { | |
c = this.findFunctionName(this.getSource(a), b) | |
} catch (d) { | |
c = "getSource failed with url: " + a + ", exception: " + d.toString() | |
} | |
return c | |
}, | |
findFunctionName: function (a, b) { | |
for (var c = /function\s+([^(]*?)\s*\(([^)]*)\)/, d = /['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*function\b/, f = /['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*(?:eval|new Function)\b/, e = "", g, h = Math.min(b, | |
20), i, j = 0; j < h; ++j) { | |
g = a[b - j - 1]; | |
i = g.indexOf("//"); | |
i >= 0 && (g = g.substr(0, i)); | |
if (g) { | |
e = g + e; | |
if ((g = d.exec(e)) && g[1]) return g[1]; | |
if ((g = c.exec(e)) && g[1]) return g[1]; | |
if ((g = f.exec(e)) && g[1]) return g[1] | |
} | |
} | |
return "(?)" | |
} | |
}; | |
var E = function (a) { | |
for (var b = [], c = [/^crittercismErrorHandler/i, /^printStackTrace/i], d = 0, f = a.length; d < f; d++) { | |
for (var e = a[d], g = false, h = 0, i = c.length; h < i; h++) if (e.match(c[h])) { | |
g = true; | |
break | |
} | |
g || b.push(e) | |
} | |
return b | |
}, F, h = { | |
metadata: {} | |
}, x = !1, | |
y = function (a) { | |
return typeof a == "undefined" || a == null || a == "" | |
}, G = function () { | |
battery = | |
null; | |
if (navigator.battery) battery = navigator.battery.level; | |
else if (navigator.mozBattery) battery = navigator.mozBattery.level; | |
else if (navigator.webkitBattery) battery = navigator.webkitBattery.level; | |
return battery | |
}, H = function () { | |
u({ | |
type: "metadata", | |
contents: { | |
app_id: k, | |
device_id: t(), | |
library_version: "pre", | |
device_name: "html5", | |
metadata: h.metadata | |
} | |
}) | |
}, J = function () { | |
if (i()) try { | |
return JSON.parse(localStorage.getItem("Crittercism.app_state")) || {} | |
} catch (a) { | |
return h || {} | |
} else return h || {} | |
}, z = function () { | |
var a = J(); | |
if (i()) { | |
for (var b = | |
h, c = 0, d = 0; d < localStorage.length; d++) { | |
var f = localStorage.key(d), | |
c = c + f.length * 2; | |
y(localStorage.getItem(f)) || (c = c + localStorage.getItem(localStorage.key(d)).length * 2) | |
} | |
b.local_storage = c | |
} | |
G() && (a.battery_level = G()); | |
a.app_version = F; | |
return a | |
}; | |
window.onerror = function (a) { | |
++w; | |
var b = E(l({ | |
e: a, | |
guess: true | |
})); | |
u({ | |
type: "crash", | |
contents: { | |
app_id: k, | |
app_state: z(), | |
breadcrumbs: s, | |
did: t(), | |
exception_name: "Error", | |
exception_reason: a, | |
library_version: "pre", | |
unsymbolized_stacktrace: b | |
} | |
}); | |
return true | |
}; | |
var s; | |
i() ? (o = localStorage.getItem("Crittercism.breadcrumbs") || | |
"[]", o = JSON.parse(o)) : o = []; | |
s = { | |
current_session: [], | |
previous_session: o | |
}; | |
var K = function () { | |
function a(a) { | |
return a < 10 ? "0" + a : a | |
} | |
var b = new Date; | |
return b.getUTCFullYear() + "-" + a(b.getUTCMonth() + 1) + "-" + a(b.getUTCDate()) + "T" + a(b.getUTCHours()) + ":" + a(b.getUTCMinutes()) + ":" + a(b.getUTCSeconds()) + "Z" | |
}, p = [], | |
A = null, | |
I = 21, | |
v = null, | |
L = function (a) { | |
if (p.length < 20) { | |
var b = a && typeof a.name == "string" ? a.name : "Unknown Exception (No name passed by caller)", | |
a = a && typeof a.message == "string" ? a.message : "Unknown Exception Reason (No reason passed by caller)", | |
c = E(l({ | |
e: a, | |
guess: true | |
})), | |
b = { | |
type: "handled_exception", | |
contents: { | |
app_id: k, | |
hashed_device_id: t(), | |
library_version: "pre", | |
exceptions: [{ | |
library_version: "pre", | |
exception_name: b, | |
exception_reason: a, | |
library_version: "pre", | |
state: z(), | |
unsymbolized_stacktrace: c | |
} | |
] | |
} | |
}; | |
p.push(b) | |
} | |
return this | |
}; | |
return { | |
init: function (a) { | |
m = true; | |
k = a.appId; | |
F = a.appVersion || "unspecified"; | |
B = a._iframeSrc || "https://api.crittercism.com/html5-static/html/iframe.html"; | |
if (document.getElementById("critterframe") == null) { | |
a = document.createElement("iframe"); | |
a.id = "critterframe"; | |
a.src = B; | |
a.style.display = "none"; | |
document.body.appendChild(a) | |
} | |
if (a = x == false) if (i()) a = (a = C()) ? new Date - a >= 18E5 ? true : false : true; | |
else a = true; | |
if (a) { | |
u({ | |
type: "appLoad", | |
contents: { | |
app_id: k, | |
did: t(), | |
library_version: "pre", | |
app_state: z() | |
} | |
}); | |
x = true | |
} | |
n(); | |
return this | |
}, | |
setMetadata: function (a) { | |
if (m) { | |
h.metadata.username && y(a.username) && (a.username = h.metadata.username); | |
h.metadata = a; | |
H() | |
} else throw Error("Crittercism.init call required before setMetadata"); | |
n(); | |
return this | |
}, | |
setValue: function (a, b) { | |
if (m) { | |
y(a) || | |
(h.metadata[a] = b); | |
H() | |
} else throw Error("Crittercism.init call required before setValue"); | |
n(); | |
return this | |
}, | |
setUsername: function (a) { | |
if (m) h.metadata.username = a; | |
else throw Error("Crittercism.init call required before setUsername"); | |
n(); | |
return this | |
}, | |
logHandledException: function (a) { | |
if (m) { | |
L(a); | |
var b = function () { | |
v = p.length; | |
v > 0 && u(p.pop()); | |
A = v != 0 || I != 0 ? window.setTimeout(b, 2E4) : null; | |
I = v | |
}; | |
A == null && b() | |
} else throw Error("Crittercism.init call required before logHandledException"); | |
n(); | |
return this | |
}, | |
leaveBreadcrumb: function (a) { | |
if (m) if (typeof a == | |
"string") { | |
s.current_session.push([a, K()]); | |
i() && (localStorage["Crittercism.breadcrumbs"] = JSON.stringify(s.current_session)) | |
} else throw Error("Invalid breadcrumb type; must be a string"); | |
else throw Error("Crittercism.init call required before leaveBreadcrumb"); | |
n(); | |
return this | |
}, | |
_dumpState: function () { | |
return { | |
appId: k, | |
appState: h, | |
breadcrumbs: s, | |
communicationReady: q, | |
crashesRecorded: w, | |
messageQueue: r.slice(), | |
lastSeen: C(), | |
handledExceptionQueue: p, | |
exceptionSendTimer: A | |
} | |
}, | |
_reset: function () { | |
x = q = k = false; | |
h = {}; | |
r = [] | |
}, | |
_crashesRecorded: function () { | |
return w | |
}, | |
_resetQueues: function () { | |
r = []; | |
p = [] | |
} | |
} | |
}(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment