rp_11009/assets/Main/Scripts/managers/ErrorManager.ts
TJH 9a08747464
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 2m6s
添加新音效
2026-05-15 15:51:38 +08:00

103 lines
3.9 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { _decorator, Component, log, sys } from 'cc';
import { uploadError } from '../main/comm';
export class ErrorManager {
private static _instance: ErrorManager = null;
// 用于存储已上报的错误指纹
private reportedErrors: Set<string> = new Set();
public static get instance(): ErrorManager {
if (!this._instance) {
this._instance = new ErrorManager();
}
return this._instance;
}
private constructor() {
this.initialize();
}
// 放在 ErrorManager.initialize() 里
private initialize(): void {
if ((window as any).__rp_err_init__) return;
(window as any).__rp_err_init__ = true;
// 1) JS 运行时 & 资源加载错误
window.addEventListener('error', (event: any) => {
// 资源错误img/script/link的 event 没有 error 对象
if (event && event.target && (event.target.src || event.target.href)) {
const el = event.target;
const url = el.src || el.href;
this.reportError(`resource error: ${el.tagName} ${url}`);
return;
}
const err: any = event?.error || {};
const msg = `error: ${event?.message}\nfrom: ${event?.filename}\npos: ${event?.lineno}:${event?.colno}\nstack: ${err.stack || 'no stack'}`;
this.reportError(msg);
}, true);
// 2) Promise 未捕获
window.addEventListener('unhandledrejection', (event: any) => {
const r: any = event?.reason || {};
const msg = `unhandledrejection: ${r.message || String(r)}\nstack: ${r.stack || 'no stack'}`;
this.reportError(msg);
}, true);
// 3) 覆盖 console
const rawErr = console.error.bind(console);
const rawWarn = console.warn.bind(console);
console.error = (...args: any[]) => {
try { this.reportError(args.map(a => (a && a.stack) ? a.stack : String(a)).join(' ')); } catch { }
rawErr(...args);
};
console.warn = (...args: any[]) => {
try { this.reportError(args.map(a => (a && a.stack) ? a.stack : String(a)).join(' ')); } catch { }
rawWarn(...args);
};
// 4) 覆盖 Cocos 日志(引擎内部 try/catch 只会调 cc.error/cc.warn
const ccAny: any = (window as any).cc;
if (ccAny && !ccAny.__rp_hooked__) {
ccAny.__rp_hooked__ = true;
const e0 = ccAny.error?.bind(ccAny);
const e1 = ccAny.errorID?.bind(ccAny);
const w0 = ccAny.warn?.bind(ccAny);
if (e0) ccAny.error = (...args: any[]) => { try { this.reportError(args.map(String).join(' ')); } catch { } e0(...args); };
if (e1) ccAny.errorID = (...args: any[]) => { try { this.reportError(args.map(String).join(' ')); } catch { } e1(...args); };
if (w0) ccAny.warn = (...args: any[]) => { try { this.reportError(args.map(String).join(' ')); } catch { } w0(...args); };
}
}
// 简单的指纹生成方法
private generateErrorFingerprint(error: string): string {
// 只取错误消息的前100个字符作为指纹
return error.substring(0, 100);
}
// 手动上报错误
public reportError(errorMessage: string): void {
try {
let fingerprint = this.generateErrorFingerprint(errorMessage);
log("start report error", fingerprint);
// 检查是否已经上报过相同错误
if (this.reportedErrors.has(fingerprint)) {
log("same error already reported, skip");
return;
}
// 记录已上报错误
this.reportedErrors.add(fingerprint);
uploadError(errorMessage)
} catch (err) {
log("report error error", err);
}
}
}
// 初始化全局错误管理器
export function initErrorManager() {
let errorManager = ErrorManager.instance;
return errorManager;
}