97 lines
2.5 KiB
JavaScript
97 lines
2.5 KiB
JavaScript
import { PATHS } from "./constants.js";
|
|
|
|
const RECENT_EVENT_TTL_MS = 15_000;
|
|
const recentEventMap = new Map();
|
|
|
|
function normalizeErrorDetail(detail) {
|
|
if (!detail) return "";
|
|
if (detail instanceof Error) {
|
|
return detail.stack || detail.message || String(detail);
|
|
}
|
|
if (typeof detail === "string") {
|
|
return detail;
|
|
}
|
|
try {
|
|
return JSON.stringify(detail);
|
|
} catch {
|
|
return String(detail);
|
|
}
|
|
}
|
|
|
|
function dedupeKey(level, message, detail, category) {
|
|
return `${level}::${category || ""}::${message}::${detail}`;
|
|
}
|
|
|
|
function shouldSkip(level, message, detail, category) {
|
|
const key = dedupeKey(level, message, detail, category);
|
|
const now = Date.now();
|
|
const lastSeenAt = recentEventMap.get(key);
|
|
recentEventMap.set(key, now);
|
|
|
|
for (const [entryKey, entryTime] of recentEventMap.entries()) {
|
|
if (now - entryTime > RECENT_EVENT_TTL_MS) {
|
|
recentEventMap.delete(entryKey);
|
|
}
|
|
}
|
|
|
|
return lastSeenAt && now - lastSeenAt < RECENT_EVENT_TTL_MS;
|
|
}
|
|
|
|
export async function reportEarthClientLog({
|
|
level = "error",
|
|
message,
|
|
category = "runtime",
|
|
module = "earth",
|
|
detail = "",
|
|
}) {
|
|
if (!message) return;
|
|
const normalizedDetail = normalizeErrorDetail(detail);
|
|
if (shouldSkip(level, message, normalizedDetail, category)) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await fetch(PATHS.earthClientLogsApi, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
level,
|
|
message,
|
|
category,
|
|
module,
|
|
url: window.location.href,
|
|
detail: normalizedDetail.slice(0, 4000),
|
|
}),
|
|
keepalive: true,
|
|
});
|
|
} catch {
|
|
// Swallow reporting failures to avoid recursive log noise.
|
|
}
|
|
}
|
|
|
|
export function registerEarthClientErrorHandlers() {
|
|
window.addEventListener("error", (event) => {
|
|
console.error("全局错误:", event.error);
|
|
void reportEarthClientLog({
|
|
level: "error",
|
|
category: "window-error",
|
|
module: "main",
|
|
message: event.message || "Earth 页面发生未捕获错误",
|
|
detail: event.error || `${event.filename || ""}:${event.lineno || 0}:${event.colno || 0}`,
|
|
});
|
|
});
|
|
|
|
window.addEventListener("unhandledrejection", (event) => {
|
|
console.error("未处理的 Promise 错误:", event.reason);
|
|
void reportEarthClientLog({
|
|
level: "error",
|
|
category: "unhandledrejection",
|
|
module: "main",
|
|
message: "Earth 页面发生未处理 Promise 错误",
|
|
detail: event.reason,
|
|
});
|
|
});
|
|
}
|