File size: 5,945 Bytes
7d3d63c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
// 幂等的错误捕获实现
(function () {
// 如果已经初始化过,直接返回
if (window.__matrix_errors_initialized__) return;
window.__matrix_errors_initialized__ = true;
// 初始化错误存储数组
if (!window.__matrix_errors__) {
window.__matrix_errors__ = [];
}
// 初始化成功API响应存储数组
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));
}
// 安全地记录成功的API响应
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));
}
// 保存原始console方法(如果尚未保存)
if (!window.__original_console_error__) {
window.__original_console_error__ = console.error;
}
if (!window.__original_console_log__) {
window.__original_console_log__ = console.log;
}
// 监听来自injector.js的消息
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
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
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);
// 捕获未处理的Promise拒绝
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)
});
});
})();
|