@@ -14,10 +14,34 @@ export const logCollectorCode = `
1414 var logs = [];
1515 window.__pilot_errorCount = 0;
1616
17- function stringify(arg) {
18- if (typeof arg === 'string') return arg;
19- if (arg instanceof Error) return arg.message + '\\n' + arg.stack;
20- try { return JSON.stringify(arg); } catch(e) { return String(arg); }
17+ /** 安全字符串化,限制深度和长度,防止复杂对象(Vue 实例、DOM 等)卡死主线程 */
18+ var MAX_STRINGIFY_DEPTH = 3;
19+ var MAX_STRINGIFY_LEN = 500;
20+
21+ function stringify(arg, depth) {
22+ if (depth === undefined) depth = 0;
23+ if (typeof arg === 'string') return arg.length > MAX_STRINGIFY_LEN ? arg.slice(0, MAX_STRINGIFY_LEN) + '...' : arg;
24+ if (typeof arg === 'number' || typeof arg === 'boolean') return String(arg);
25+ if (arg === null || arg === undefined) return String(arg);
26+ if (arg instanceof Error) return arg.message;
27+ if (depth >= MAX_STRINGIFY_DEPTH) return '[Object]';
28+ try {
29+ /** 数组特殊处理:只取前 5 项 */
30+ if (Array.isArray(arg)) {
31+ if (arg.length > 5) return '[' + arg.slice(0, 5).map(function(a) { return stringify(a, depth + 1); }).join(', ') + ', ...(' + arg.length + ')]';
32+ return '[' + arg.map(function(a) { return stringify(a, depth + 1); }).join(', ') + ']';
33+ }
34+ /** 普通对象:只取前 5 个 key */
35+ var keys = Object.keys(arg);
36+ if (keys.length > 5) {
37+ var parts = keys.slice(0, 5).map(function(k) { return k + ': ' + stringify(arg[k], depth + 1); });
38+ var result = '{' + parts.join(', ') + ', ...(' + keys.length + ')}';
39+ return result.length > MAX_STRINGIFY_LEN ? result.slice(0, MAX_STRINGIFY_LEN) + '...' : result;
40+ }
41+ var parts = keys.map(function(k) { return k + ': ' + stringify(arg[k], depth + 1); });
42+ var result = '{' + parts.join(', ') + '}';
43+ return result.length > MAX_STRINGIFY_LEN ? result.slice(0, MAX_STRINGIFY_LEN) + '...' : result;
44+ } catch(e) { return String(arg); }
2145 }
2246
2347 /** 存储最近 3 条错误信息,供 snapshot 采集 */
@@ -28,10 +52,18 @@ export const logCollectorCode = `
2852 /** 已知噪音日志(vite 警告等),不计入 errorCount 也不纳入 lastErrors */
2953 var ERROR_NOISE = ['[vite]', 'failed to connect to websocket', '[Vue warn]'];
3054
55+ /** 将 args 延迟转换为 message 字符串(首次访问时缓存),暴露给 ws-client 消费 */
56+ window.__pilot_logToMessage = function(entry) {
57+ if (entry.message !== undefined) return entry.message;
58+ entry.message = Array.from(entry.args).map(stringify).join(' ');
59+ entry.args = null;
60+ return entry.message;
61+ }
62+
3163 function addLog(type, args) {
3264 if (type === 'error') {
65+ /** error 路径仍需立即 stringify(噪音检测+lastErrors),但 error 频率低 */
3366 var msg = Array.from(args).map(stringify).join(' ').slice(0, 100);
34- /** 噪音日志仍记录到 logs(完整日志),但不计入错误统计 */
3567 var isNoise = ERROR_NOISE.some(function(k) { return msg.indexOf(k) >= 0; });
3668 if (!isNoise) {
3769 window.__pilot_errorCount++;
@@ -42,7 +74,7 @@ export const logCollectorCode = `
4274 logs.push({
4375 timestamp: new Date().toISOString(),
4476 type: type,
45- message: Array.from( args).map(stringify).join(' ')
77+ args: args
4678 });
4779 if (logs.length > maxLogs) logs.shift();
4880 }
0 commit comments