This commit is contained in:
2026-10-16 16:34:15 +08:00
parent 7a3769670b
commit ff366a4daf
80 changed files with 9961 additions and 888 deletions

105
main/main-log-writer.js Normal file
View File

@@ -0,0 +1,105 @@
// P2-10 / P2-12(audit):主进程日志异步缓冲写出。
//
// 旧实现(main.js 顶部 console 重写层):每行 mkdirSync + appendFileSync ——
// 同步 IO 直接阻塞 main 事件循环。AI 流式 / fsWatcher 高频日志期间,
// 每次 console.* 都是一次磁盘往返;顶层同步 fs 也拖慢启动路径。
//
// 新设计:write(line) 只进内存缓冲并调度一次 flush 定时器(默认 250ms,
// .unref() 不拖进程退出);flush 把整段缓冲拼成一次 mkdir(recursive) +
// appendFile 异步写出。崩溃窗口 = 最多 flushMs 毫秒的日志丢失 ——
// 对诊断日志可接受(崩溃路径另有 stderr 兜底)。
//
// 失败语义与旧版一致:写盘失败静默丢弃(不应影响主流程)。
// 缓冲上限 maxBuffered 行,超出丢最老,防 AI 刷屏撑爆内存。
'use strict';
/**
* @param {object} opts
* @param {string} opts.logDir
* @param {string} opts.logFile
* @param {{ mkdir: Function, appendFile: Function }} [opts.fsImpl] 默认 require('fs').promises
* @param {number} [opts.flushMs=250]
* @param {number} [opts.maxBuffered=1000]
* @param {Function} [opts.setTimeoutImpl]
* @param {Function} [opts.clearTimeoutImpl]
*/
function createMainLogWriter({
logDir,
logFile,
fsImpl,
flushMs = 250,
maxBuffered = 1000,
setTimeoutImpl,
clearTimeoutImpl,
}) {
const fs = fsImpl || require('fs').promises;
const _setTimeout = setTimeoutImpl || setTimeout;
const _clearTimeout = clearTimeoutImpl || clearTimeout;
/** @type {string[]} */
let buffer = [];
/** @type {Promise<void>|null} mkdir 只做一次,缓存 promise */
let mkdirPromise = null;
/** @type {Promise<void>|null} in-flight flush,dispose/重复 flush 复用 */
let flushing = null;
let timer = null;
function ensureDir() {
if (!mkdirPromise) {
mkdirPromise = fs.mkdir(logDir, { recursive: true }).catch(() => {
// mkdir 失败:下次 flush 重试(不缓存失败的 promise)
mkdirPromise = null;
throw new Error('mkdir failed');
});
}
return mkdirPromise;
}
async function flush() {
if (flushing) return flushing;
if (buffer.length === 0) return;
const lines = buffer;
buffer = [];
flushing = (async () => {
try {
await ensureDir();
await fs.appendFile(logFile, lines.join(''));
} catch {
// 写日志失败静默丢弃 —— 与旧同步实现「catch 忽略」语义一致
} finally {
flushing = null;
}
})();
return flushing;
}
function scheduleFlush() {
if (timer) return;
timer = _setTimeout(() => {
timer = null;
flush();
}, flushMs);
// 日志定时器不应单独吊住进程退出
if (timer && typeof timer.unref === 'function') timer.unref();
}
return {
write(line) {
buffer.push(line);
if (buffer.length > maxBuffered) {
buffer.splice(0, buffer.length - maxBuffered);
}
scheduleFlush();
},
flush,
dispose() {
if (timer) {
_clearTimeout(timer);
timer = null;
}
},
};
}
module.exports = { createMainLogWriter };