You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
4.4 KiB
177 lines
4.4 KiB
import { LogLevel, LogLevelName } from "./common"
|
|
import logger from "./main"
|
|
|
|
/**
|
|
* 错误详情接口
|
|
*/
|
|
export interface ErrorDetail {
|
|
message: string
|
|
stack?: string
|
|
componentInfo?: string
|
|
additionalInfo?: Record<string, any>
|
|
timestamp: string
|
|
type: string
|
|
}
|
|
|
|
/**
|
|
* 错误处理配置
|
|
*/
|
|
export interface ErrorHandlerOptions {
|
|
namespace?: string
|
|
level?: LogLevel
|
|
includeStack?: boolean
|
|
includeComponentInfo?: boolean
|
|
formatError?: (error: any) => ErrorDetail
|
|
}
|
|
|
|
/**
|
|
* 默认错误处理配置
|
|
*/
|
|
const DEFAULT_OPTIONS: ErrorHandlerOptions = {
|
|
namespace: "error",
|
|
level: LogLevel.ERROR,
|
|
includeStack: true,
|
|
includeComponentInfo: true,
|
|
}
|
|
|
|
/**
|
|
* 格式化错误信息
|
|
*/
|
|
const formatError = (error: any, options: ErrorHandlerOptions): ErrorDetail => {
|
|
// 如果已经是ErrorDetail格式,直接返回
|
|
if (error && typeof error === "object" && error.type && error.message && error.timestamp) {
|
|
return error as ErrorDetail
|
|
}
|
|
|
|
// 基本错误信息
|
|
const errorDetail: ErrorDetail = {
|
|
message: "",
|
|
timestamp: new Date().toISOString(),
|
|
type: "Unknown",
|
|
}
|
|
|
|
// 处理不同类型的错误
|
|
if (error instanceof Error) {
|
|
errorDetail.message = error.message
|
|
errorDetail.type = error.name || error.constructor.name
|
|
if (options.includeStack) {
|
|
errorDetail.stack = error.stack
|
|
}
|
|
} else if (typeof error === "string") {
|
|
errorDetail.message = error
|
|
errorDetail.type = "String"
|
|
} else if (error === null) {
|
|
errorDetail.message = "Null error received"
|
|
errorDetail.type = "Null"
|
|
} else if (error === undefined) {
|
|
errorDetail.message = "Undefined error received"
|
|
errorDetail.type = "Undefined"
|
|
} else if (typeof error === "object") {
|
|
try {
|
|
errorDetail.message = error.message || JSON.stringify(error)
|
|
errorDetail.type = "Object"
|
|
errorDetail.additionalInfo = { ...error }
|
|
} catch (e) {
|
|
errorDetail.message = "Unserializable error object"
|
|
errorDetail.type = "Unserializable"
|
|
}
|
|
} else {
|
|
try {
|
|
errorDetail.message = String(error)
|
|
errorDetail.type = typeof error
|
|
} catch (e) {
|
|
errorDetail.message = "Error converting to string"
|
|
errorDetail.type = "Unknown"
|
|
}
|
|
}
|
|
|
|
return errorDetail
|
|
}
|
|
|
|
/**
|
|
* 错误处理类
|
|
*/
|
|
export class ErrorHandler {
|
|
private options: ErrorHandlerOptions
|
|
|
|
constructor(options?: Partial<ErrorHandlerOptions>) {
|
|
this.options = { ...DEFAULT_OPTIONS, ...options }
|
|
}
|
|
|
|
/**
|
|
* 记录错误
|
|
*/
|
|
public captureError(error: any, componentInfo?: string, additionalInfo?: Record<string, any>): void {
|
|
const errorDetail = formatError(error, this.options)
|
|
|
|
// 添加组件信息
|
|
if (this.options.includeComponentInfo && componentInfo) {
|
|
errorDetail.componentInfo = componentInfo
|
|
}
|
|
|
|
// 添加额外信息
|
|
if (additionalInfo) {
|
|
errorDetail.additionalInfo = {
|
|
...errorDetail.additionalInfo,
|
|
...additionalInfo,
|
|
}
|
|
}
|
|
|
|
// 使用logger记录错误
|
|
const namespace = this.options.namespace || "error"
|
|
const level = LogLevelName[this.options.level || LogLevel.ERROR].toLowerCase()
|
|
|
|
// 构建错误消息
|
|
let errorMessage = `${errorDetail.type}: ${errorDetail.message}`
|
|
if (errorDetail.componentInfo) {
|
|
errorMessage += ` | Component: ${errorDetail.componentInfo}`
|
|
}
|
|
|
|
// 记录错误
|
|
logger[level](namespace, errorMessage)
|
|
|
|
// 如果有堆栈信息,单独记录
|
|
if (errorDetail.stack) {
|
|
logger[level](namespace, `Stack: ${errorDetail.stack}`)
|
|
}
|
|
|
|
// 如果有额外信息,单独记录
|
|
if (errorDetail.additionalInfo) {
|
|
try {
|
|
const additionalInfoStr = JSON.stringify(errorDetail.additionalInfo, null, 2)
|
|
logger[level](namespace, `Additional Info: ${additionalInfoStr}`)
|
|
} catch (e) {
|
|
logger[level](namespace, "Additional Info: [Unserializable]")
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 设置错误处理选项
|
|
*/
|
|
public setOptions(options: Partial<ErrorHandlerOptions>): void {
|
|
this.options = { ...this.options, ...options }
|
|
}
|
|
|
|
/**
|
|
* 获取当前选项
|
|
*/
|
|
public getOptions(): ErrorHandlerOptions {
|
|
return { ...this.options }
|
|
}
|
|
}
|
|
|
|
// 创建默认实例
|
|
const errorHandler = new ErrorHandler()
|
|
|
|
// 捕获未处理的Promise异常
|
|
process.on("unhandledRejection", reason => {
|
|
errorHandler.captureError(reason)
|
|
})
|
|
|
|
// 捕获未捕获的异常
|
|
process.on("uncaughtException", error => {
|
|
errorHandler.captureError(error)
|
|
})
|
|
|
|
export default errorHandler
|
|
|