|
|
|
|
|
(function () { |
|
|
|
|
|
if (window.__matrix_errors_initialized__) return; |
|
|
window.__matrix_errors_initialized__ = true; |
|
|
|
|
|
|
|
|
if (!window.__matrix_errors__) { |
|
|
window.__matrix_errors__ = []; |
|
|
} |
|
|
|
|
|
|
|
|
if (!window.__matrix_api_success__) { |
|
|
window.__matrix_api_success__ = []; |
|
|
} |
|
|
|
|
|
|
|
|
const TRUNCATE_CONFIG = { |
|
|
maxStringLength: 1000, |
|
|
maxArrayLength: 50, |
|
|
maxObjectKeys: 20, |
|
|
maxStackLines: 20, |
|
|
}; |
|
|
|
|
|
|
|
|
function truncateData(data, depth = 0) { |
|
|
if (depth > 3) return '[Max Depth Exceeded]'; |
|
|
|
|
|
if (typeof data === 'string') { |
|
|
if (data.length > TRUNCATE_CONFIG.maxStringLength) { |
|
|
return data.substring(0, TRUNCATE_CONFIG.maxStringLength) + `... [truncated ${data.length - TRUNCATE_CONFIG.maxStringLength} chars]`; |
|
|
} |
|
|
return data; |
|
|
} |
|
|
|
|
|
if (Array.isArray(data)) { |
|
|
if (data.length > TRUNCATE_CONFIG.maxArrayLength) { |
|
|
return data |
|
|
.slice(0, TRUNCATE_CONFIG.maxArrayLength) |
|
|
.map(item => truncateData(item, depth + 1)) |
|
|
.concat([`... [truncated ${data.length - TRUNCATE_CONFIG.maxArrayLength} items]`]); |
|
|
} |
|
|
return data.map(item => truncateData(item, depth + 1)); |
|
|
} |
|
|
|
|
|
if (data && typeof data === 'object') { |
|
|
const keys = Object.keys(data); |
|
|
if (keys.length > TRUNCATE_CONFIG.maxObjectKeys) { |
|
|
const truncatedObj = {}; |
|
|
keys.slice(0, TRUNCATE_CONFIG.maxObjectKeys).forEach(key => { |
|
|
truncatedObj[key] = truncateData(data[key], depth + 1); |
|
|
}); |
|
|
truncatedObj['__truncated'] = `[${keys.length - TRUNCATE_CONFIG.maxObjectKeys} more fields]`; |
|
|
return truncatedObj; |
|
|
} |
|
|
const processedObj = {}; |
|
|
keys.forEach(key => { |
|
|
processedObj[key] = truncateData(data[key], depth + 1); |
|
|
}); |
|
|
return processedObj; |
|
|
} |
|
|
|
|
|
return data; |
|
|
} |
|
|
|
|
|
|
|
|
function truncateStack(stack) { |
|
|
if (!stack) return null; |
|
|
const lines = stack.split('\n'); |
|
|
if (lines.length > TRUNCATE_CONFIG.maxStackLines) { |
|
|
return lines |
|
|
.slice(0, TRUNCATE_CONFIG.maxStackLines) |
|
|
.concat([`... [truncated ${lines.length - TRUNCATE_CONFIG.maxStackLines} stack lines]`]) |
|
|
.join('\n'); |
|
|
} |
|
|
return stack; |
|
|
} |
|
|
|
|
|
|
|
|
function safeLogError(error) { |
|
|
if (!window.__matrix_errors__) { |
|
|
window.__matrix_errors__ = []; |
|
|
} |
|
|
|
|
|
if (window.__matrix_errors__.length >= 1000) { |
|
|
window.__matrix_errors__.shift(); |
|
|
} |
|
|
window.__matrix_errors__.push(truncateData(error)); |
|
|
} |
|
|
|
|
|
|
|
|
function safeLogApiSuccess(apiResponse) { |
|
|
if (!window.__matrix_api_success__) { |
|
|
window.__matrix_api_success__ = []; |
|
|
} |
|
|
|
|
|
if (window.__matrix_api_success__.length >= 500) { |
|
|
window.__matrix_api_success__.shift(); |
|
|
} |
|
|
window.__matrix_api_success__.push(truncateData(apiResponse)); |
|
|
} |
|
|
|
|
|
|
|
|
if (!window.__original_console_error__) { |
|
|
window.__original_console_error__ = console.error; |
|
|
} |
|
|
|
|
|
if (!window.__original_console_log__) { |
|
|
window.__original_console_log__ = console.log; |
|
|
} |
|
|
|
|
|
|
|
|
window.addEventListener('message', function (event) { |
|
|
|
|
|
if (event.source === window && event.data) { |
|
|
if (event.data.type === 'MATRIX_ERROR_LOG') { |
|
|
safeLogError(event.data.data); |
|
|
} else if (event.data.type === 'MATRIX_API_SUCCESS_LOG') { |
|
|
safeLogApiSuccess(event.data.data); |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
console.error = function (...args) { |
|
|
safeLogError({ |
|
|
type: 'console.error', |
|
|
message: truncateData(args.join(' ')), |
|
|
timestamp: new Date().toISOString(), |
|
|
stack: truncateStack(new Error().stack) |
|
|
}); |
|
|
window.__original_console_error__.apply(console, args); |
|
|
}; |
|
|
|
|
|
|
|
|
console.log = function (...args) { |
|
|
safeLogError({ |
|
|
type: 'console.log', |
|
|
message: truncateData(args.join(' ')), |
|
|
timestamp: new Date().toISOString() |
|
|
}); |
|
|
window.__original_console_log__.apply(console, args); |
|
|
}; |
|
|
|
|
|
|
|
|
document.addEventListener('error', function (event) { |
|
|
if (event.target.tagName === 'IMG') { |
|
|
safeLogError({ |
|
|
type: 'image.error', |
|
|
message: `Failed to load image: ${event.target.src}`, |
|
|
timestamp: new Date().toISOString(), |
|
|
stack: truncateStack(new Error().stack), |
|
|
element: truncateData({ |
|
|
tagName: event.target.tagName, |
|
|
src: event.target.src, |
|
|
id: event.target.id, |
|
|
className: event.target.className |
|
|
}) |
|
|
}); |
|
|
} |
|
|
}, true); |
|
|
|
|
|
|
|
|
window.addEventListener('error', function (event) { |
|
|
safeLogError({ |
|
|
type: 'uncaught.error', |
|
|
message: event.message, |
|
|
filename: event.filename, |
|
|
lineno: event.lineno, |
|
|
colno: event.colno, |
|
|
timestamp: new Date().toISOString(), |
|
|
stack: truncateStack(event.error ? event.error.stack : null) |
|
|
}); |
|
|
return false; |
|
|
}, true); |
|
|
|
|
|
|
|
|
window.addEventListener('unhandledrejection', function (event) { |
|
|
let message = 'Promise rejection: '; |
|
|
if (typeof event.reason === 'object') { |
|
|
message += truncateData(event.reason.message || JSON.stringify(event.reason)); |
|
|
} else { |
|
|
message += truncateData(String(event.reason)); |
|
|
} |
|
|
|
|
|
safeLogError({ |
|
|
type: 'unhandled.promise', |
|
|
message: message, |
|
|
timestamp: new Date().toISOString(), |
|
|
stack: truncateStack(event.reason && event.reason.stack ? event.reason.stack : null) |
|
|
}); |
|
|
}); |
|
|
})(); |
|
|
|