mirror of
https://github.com/Shu-Ying/noname-shuying.git
synced 2026-10-19 05:39:59 +08:00
fixed # 优化部分已知问题
This commit is contained in:
@@ -43,6 +43,9 @@ occurrences 表示被捕获的次数,不表示奖励发放次数。最近报
|
||||
系统自己生成的旧文件,保留总量约 5 MiB、最多 64 个文件。报告包含截断和
|
||||
丢弃计数;“完整诊断”指受限的错误链与现场记录,不是无限保留整个游戏过程。
|
||||
|
||||
待写队列默认最多 12 项、合计 2 MiB,优先保存错误报告;另有最多一项正在写入。
|
||||
错误报告复用已脱敏的记录文本,按字节预算一次裁剪,保留首次和最近异常。
|
||||
|
||||
PC 使用异步文件操作,安卓使用 Cordova 目录和 FileWriter 回调,写入前截断旧
|
||||
内容,使用 UTF-8 Blob。单次保存操作设置 5 秒观察超时;超时后停止使用该
|
||||
文件通道,避免迟到写入与后续写入重叠。写入异常不会中断游戏业务。
|
||||
@@ -56,4 +59,4 @@ PC 使用异步文件操作,安卓使用 Cordova 目录和 FileWriter 回调
|
||||
和剧情等待不会被当作超时错误;观察器不会结束业务事件。
|
||||
|
||||
字段过滤会隐藏凭据字段、常见 URL 凭据参数和 Bearer 内容。报告不会复制完整
|
||||
玩家对象、DOM、引擎状态或整个存档。日志文件不进入发布清单和 Git。
|
||||
玩家对象、DOM、引擎状态或整个存档。日志文件不进入发布清单和 Git。
|
||||
|
||||
+35
-14
@@ -27,6 +27,7 @@ export function createDiagnostics(options = {}) {
|
||||
const maxDiskBytes = options.maxDiskBytes ?? 5 * 1024 * 1024;
|
||||
const maxFiles = options.maxFiles ?? 64;
|
||||
const maxPending = options.maxPending ?? 12;
|
||||
const maxPendingBytes = options.maxPendingBytes ?? 2 * 1024 * 1024;
|
||||
const flushMs = options.flushMs ?? 1000;
|
||||
const recent = [], contexts = new Map(), pending = new Map();
|
||||
const errors = new WeakMap(), fingerprints = new Map(), listeners = [];
|
||||
@@ -35,6 +36,7 @@ export function createDiagnostics(options = {}) {
|
||||
let flushTimer = null, worker = null, stopped = false, unavailable = false;
|
||||
let latestReport = null, droppedRecords = 0, droppedWrites = 0;
|
||||
let inventory = null, inventoryKind = null;
|
||||
let pendingBytes = 0;
|
||||
const metadata = snapshot({
|
||||
extension: "术樱包", extensionVersion: options.version || "unknown",
|
||||
engineVersion: env.lib?.version || "unknown", launchId,
|
||||
@@ -86,17 +88,19 @@ export function createDiagnostics(options = {}) {
|
||||
context: contextFor(extra),
|
||||
};
|
||||
if (error !== undefined) entry.error = serializeError(error);
|
||||
const item = { entry, bytes: 0 };
|
||||
const item = { entry, bytes: 0, text: "" };
|
||||
recent.push(item);
|
||||
if (level === "ERROR") createReport(entry, error);
|
||||
const text = JSON.stringify(entry) + "\n";
|
||||
const bytes = byteLength(text);
|
||||
const text = JSON.stringify(entry);
|
||||
const bytes = byteLength(text) + 1;
|
||||
item.text = text;
|
||||
delete item.entry;
|
||||
item.bytes = bytes; memoryBytes += bytes;
|
||||
if (journalBytes + bytes > maxJournalBytes && journal.length) {
|
||||
enqueue(runtimeName(), journal.join(""));
|
||||
segment++; journal = []; journalBytes = 0; queuedRevision = -1;
|
||||
}
|
||||
journal.push(text); journalBytes += bytes; revision++;
|
||||
journal.push(text + "\n"); journalBytes += bytes; revision++;
|
||||
while (recent.length > 400 || memoryBytes > maxMemoryBytes) {
|
||||
memoryBytes -= recent.shift().bytes; droppedRecords++;
|
||||
}
|
||||
@@ -128,14 +132,22 @@ export function createDiagnostics(options = {}) {
|
||||
schemaVersion: 1, reportId: known.id, firstSeen: known.first,
|
||||
lastSeen: entry.time, occurrences: known.count, environment: metadata,
|
||||
storageAtCapture: snapshot(storageStatus()), firstFailure: known.firstFailure,
|
||||
failure: entry, records: recent.map(item => item.entry),
|
||||
failure: entry,
|
||||
droppedRecords, droppedWrites,
|
||||
};
|
||||
let text = JSON.stringify(report, null, 2);
|
||||
while (byteLength(text) > maxReportBytes && report.records.length > 1) {
|
||||
report.records.shift(); report.droppedRecords++;
|
||||
text = JSON.stringify(report, null, 2);
|
||||
const records = recent.map(item => {
|
||||
const text = item.text || JSON.stringify(item.entry);
|
||||
return { text, bytes: item.text ? item.bytes - 1 : byteLength(text) };
|
||||
});
|
||||
let start = 0;
|
||||
let bytes = byteLength(JSON.stringify(report)) + 14
|
||||
+ records.reduce((total, item) => total + item.bytes + 1, 0);
|
||||
while (bytes + 32 > maxReportBytes && start < records.length - 1) {
|
||||
bytes -= records[start++].bytes + 1;
|
||||
}
|
||||
report.droppedRecords += start;
|
||||
const text = JSON.stringify(report).slice(0, -1) + ',"records":['
|
||||
+ records.slice(start).map(item => item.text).join(",") + "]}";
|
||||
latestReport = { id: known.id, file, revision: known.count,
|
||||
persisted: false, event: entry.event };
|
||||
enqueue(file, text, true, known.count);
|
||||
@@ -143,12 +155,19 @@ export function createDiagnostics(options = {}) {
|
||||
|
||||
function enqueue(name, text, priority = false, reportRevision = null) {
|
||||
if (unavailable || stopped) return;
|
||||
if (!pending.has(name) && pending.size >= maxPending) {
|
||||
const victim = [...pending].find(([, item]) => !item.priority)?.[0];
|
||||
const bytes = byteLength(text);
|
||||
const previous = pending.get(name);
|
||||
if (previous) { pendingBytes -= previous.bytes; pending.delete(name); }
|
||||
if (bytes > maxPendingBytes) { droppedWrites++; return; }
|
||||
while (pending.size >= maxPending || pendingBytes + bytes > maxPendingBytes) {
|
||||
const victim = [...pending].find(([, item]) => !item.priority)?.[0]
|
||||
|| (priority ? pending.keys().next().value : null);
|
||||
if (!victim) { droppedWrites++; return; }
|
||||
pendingBytes -= pending.get(victim).bytes;
|
||||
pending.delete(victim); droppedWrites++;
|
||||
}
|
||||
pending.set(name, { text, priority, reportRevision });
|
||||
pending.set(name, { text, bytes, priority, reportRevision });
|
||||
pendingBytes += bytes;
|
||||
startWorker();
|
||||
}
|
||||
|
||||
@@ -182,6 +201,7 @@ export function createDiagnostics(options = {}) {
|
||||
|| pending.keys().next().value;
|
||||
const item = pending.get(name);
|
||||
pending.delete(name);
|
||||
pendingBytes -= item.bytes;
|
||||
try {
|
||||
await storage.write(name, item.text);
|
||||
if (latestReport?.file === name && latestReport.revision === item.reportRevision) {
|
||||
@@ -190,10 +210,10 @@ export function createDiagnostics(options = {}) {
|
||||
}
|
||||
try { await prune(name, item.text); } catch { inventory = null; }
|
||||
} catch {
|
||||
unavailable = true; pending.clear();
|
||||
unavailable = true; pending.clear(); pendingBytes = 0;
|
||||
}
|
||||
}
|
||||
}).catch(() => { unavailable = true; pending.clear(); }).finally(() => {
|
||||
}).catch(() => { unavailable = true; pending.clear(); pendingBytes = 0; }).finally(() => {
|
||||
worker = null;
|
||||
if (pending.size && !unavailable) startWorker();
|
||||
});
|
||||
@@ -305,6 +325,7 @@ export function createDiagnostics(options = {}) {
|
||||
flush,
|
||||
status: () => snapshot({ enabled: true, ...storageStatus(),
|
||||
unavailable, latestReport, droppedRecords, droppedWrites,
|
||||
pendingFiles: pending.size, pendingBytes,
|
||||
runtimeFile: runtimeName(), launchId }),
|
||||
dispose() {
|
||||
void flush(); stopped = true; clearTimeout(flushTimer);
|
||||
|
||||
Reference in New Issue
Block a user