import { ReporterOptions, ReportItemType, Reporter } from '@tencent/merlin-core'; import { buildIssueFromError } from './utils'; import type { ErrorReportItemData } from './types'; import { ErrorReportStatus } from './common'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ErrorReporterOptions, R extends Reporter> extends ReporterOptions { /** 是否在控制台 console.error 被捕获的错误 * @default true */ logError?: boolean; } export class ErrorReporter extends Reporter { logError = true; // TODO: fingerprint 去重 setOptions(options: ErrorReporterOptions) { if (options.logError !== undefined) { this.logError = options.logError; } super.setOptions(options); } init(options: ErrorReporterOptions) { try { this.setOptions(options); super.init(options); } catch (e) { this.errorHandler(e as Error); } } /** 上报错误 * * 使用注意:错误上报总是应当发生在 Error 对象冒泡的最上层,在 report 后 Error 对象就不该被继续向上抛出了,否则会被更高层再次捕获,导致反复上报 */ reportError( error: Error, info?: { /** 额外日志信息 */ log?: string; /** 索引字段 1 */ idx1?: string; /** 索引字段 2 */ idx2?: string; /** 索引字段 3 */ idx3?: string; }, ) { const issue = buildIssueFromError(error); if (this.logError) { console.error(error); if (info) { console.info('extra error info:', info); } } this.capture({ ...issue, log: info?.log, idx1: info?.idx1, idx2: info?.idx2, idx3: info?.idx3, }); } /** 上报错误恢复 */ reportRecover( error: Error, info?: { /** 额外日志信息 */ log?: string; /** 索引字段 1 */ idx1?: string; /** 索引字段 2 */ idx2?: string; /** 索引字段 3 */ idx3?: string; }, ) { const issue = buildIssueFromError(error); this.capture({ ...issue, log: info?.log, idx1: info?.idx1, idx2: info?.idx2, idx3: info?.idx3, status: ErrorReportStatus.RECOVER, }); } /** 捕获标准错误数据 */ capture(data: ErrorReportItemData) { this.report({ type: ReportItemType.ERROR, data, }); } } export const errorReporter = new ErrorReporter();