1/** 2 * errorLogger.js 3 * Best-effort capture of client-side problems for the support portal's 4 * Page Load Performance / RUM diagnosis: 5 * - uncaught JS errors (window 'error') 6 * - unhandled promise rejections ('unhandledrejection') 7 * - console.error / console.warn (patched; console.log is left alone) 8 * - resource load failures (404 on img/script/link/css) 9 * 10 * Hard rules (same as apiLogger.js): 11 * - Never throw. Never block. Silently no-ops if logUserActivity is missing. 12 * - Preserves original console behavior. Capped per page so nothing floods. 13 * - Logged shape: ('JS_ERROR', { kind, msg, src, line, col, stack }) 14 */ 15(function (global) { 16 'use strict'; 17 try { 18 if (!global || typeof global.addEventListener !== 'function') return; 19 if (global.__errorLoggerInstalled) return; 20 global.__errorLoggerInstalled = true; 21 22 var MAX_EVENTS = 30; 23 var sent = 0; 24 var reentrant = false; // stop console-patch recursion 25 26 function safeLog(payload) { 27 try { 28 if (sent >= MAX_EVENTS) return; 29 if (typeof global.logUserActivity !== 'function') return; 30 sent++; 31 global.logUserActivity('JS_ERROR', payload); 32 } catch (e) {} 33 } 34 35 function clip(s, n) { 36 try { return s == null ? '' : String(s).substring(0, n); } catch (e) { return ''; } 37 } 38 39 function stringifyArg(a) { 40 try { 41 if (a == null) return String(a); 42 if (a.message) return a.message; // Error-like
43 if (typeof a === 'object') { try { return JSON.stringify(a); } catch (e) { return String(a); } } 44 return String(a); 45 } catch (e) { return ''; } 46 } 47 48 // --- JS runtime errors + resource load failures (capture phase so 49 // resource errors, which don't bubble, are still seen). --- 50 global.addEventListener('error', function (e) { 51 try { 52 var t = e && e.target; 53 // Resource load error: target is an element with a src/href. 54 if (t && t !== global && t.tagName && (t.src || t.href)) { 55 safeLog({ 56 kind: 'resource', 57 msg: 'Failed to load ' + String(t.tagName).toLowerCase(), 58 src: clip(t.src || t.href, 300) 59 }); 60 return; 61 } 62 // Script runtime error. 63 if (!e || (!e.message && !e.error)) return; 64 safeLog({ 65 kind: 'error', 66 msg: clip(e.message, 300), 67 src: clip(e.filename, 300), 68 line: e.lineno || 0, 69 col: e.colno || 0, 70 stack: clip(e.error && e.error.stack, 800) 71 }); 72 } catch (err) { /* swallow */ } 73 }, true); 74 75 // --- Unhandled promise rejections. --- 76 global.addEventListener('unhandledrejection', function (e) { 77 try { 78 var r = e ? e.reason : null; 79 safeLog({ 80 kind: 'unhandledrejection', 81 msg: clip(r && r.message ? r.message : stringifyArg(r), 300), 82 stack: clip(r && r.stack, 800) 83 }); 84 } catch (err) { /* swallow */ } 85 }); 86 87 // --- Patch console.error / console.warn (NOT console.log). --- 88 try { 89 var c = global.console; 90 if (c) { 91 ['error', 'warn'].forEach(function (level) { 92 var orig = c[level]; 93 if (typeof orig !== 'function') return; 94 c[level] = function () { 95 if (!reentrant) { 96 reentrant = true; 97 try { 98 var parts = []; 99 for (var i = 0; i < arguments.length; i++) parts.push(stringifyArg(arguments[i])); 100 var first = arguments.length ? arguments[0] : null; 101 safeLog({ 102 kind: 'console.' + level, 103 msg: clip(parts.join(' '), 400), 104 stack: clip(first && first.stack, 600) 105 }); 106 } catch (e2) { /* swallow */ } 107 reentrant = false; 108 } 109 try { return orig.apply(this, arguments); } catch (e3) { /* swallow */ } 110 }; 111 }); 112 } 113 } catch (e) {} 114 } catch (e) { /* never affect the user */ } 115})(typeof window !== 'undefined' ? window : this);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.