162 lines
3.9 KiB
TypeScript
162 lines
3.9 KiB
TypeScript
/*
|
||
* Copyright 2025 coze-dev Authors
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
|
||
import { isAxiosError } from 'axios';
|
||
import { logger, reporter } from '@coze-arch/logger';
|
||
import { isApiError } from '@coze-arch/bot-http';
|
||
|
||
import { isChunkError } from './source-error';
|
||
import { isCustomError, type CustomError } from './custom-error';
|
||
import { ReportEventNames, type CertainErrorName } from './const';
|
||
const loggerWithScope = logger.createLoggerWith({
|
||
ctx: {
|
||
namespace: 'bot-error',
|
||
scope: 'certain-error',
|
||
},
|
||
});
|
||
const notInstanceError = (error: Error) => !(error instanceof Error);
|
||
|
||
const errorList: { func: (error: Error) => boolean; name: CertainErrorName }[] =
|
||
[
|
||
{
|
||
func: isCustomError,
|
||
name: 'CustomError',
|
||
},
|
||
{
|
||
func: isAxiosError,
|
||
name: 'AxiosError',
|
||
},
|
||
{
|
||
func: isApiError,
|
||
name: 'ApiError',
|
||
},
|
||
{
|
||
func: isChunkError,
|
||
name: 'ChunkLoadError',
|
||
},
|
||
{
|
||
func: notInstanceError,
|
||
name: 'notInstanceError',
|
||
},
|
||
];
|
||
|
||
const handleCertainError: (error: Error) => void = error => {
|
||
const errorName = getErrorName(error);
|
||
|
||
loggerWithScope.info({
|
||
message: 'handleCertainError',
|
||
meta: {
|
||
errorName,
|
||
error,
|
||
},
|
||
});
|
||
|
||
if (errorName === 'unknown') {
|
||
return;
|
||
}
|
||
|
||
// 上报到自定义错误
|
||
if (errorName === 'CustomError') {
|
||
const { eventName, msg } = error as CustomError;
|
||
// 补充统一上报custom error event_name 用于监控
|
||
loggerWithScope.persist.error({
|
||
eventName: ReportEventNames.CustomErrorReport,
|
||
message: msg,
|
||
error,
|
||
meta: {
|
||
name: error.name,
|
||
originEventName: eventName, // 原始originEventName
|
||
originErrorMessage: msg, // 原始 error msg
|
||
},
|
||
});
|
||
loggerWithScope.persist.error({
|
||
eventName,
|
||
message: msg,
|
||
error,
|
||
meta: {
|
||
name: error.name,
|
||
},
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 滤除已经上报到自定义事件
|
||
if (errorName === 'ApiError' || errorName === 'AxiosError') {
|
||
return;
|
||
}
|
||
|
||
// ChunkLoad 失败, 不上报,在slardar 静态资源异常统计
|
||
if (errorName === 'ChunkLoadError') {
|
||
reporter.info({
|
||
message: 'chunkLoadError',
|
||
meta: {
|
||
error,
|
||
errorName: error.name,
|
||
message: error.message,
|
||
stack: error.stack,
|
||
},
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 不继承 Error 的错误,目前 case(semi 表单校验 )
|
||
if (errorName === 'notInstanceError') {
|
||
let errorInfo;
|
||
try {
|
||
errorInfo =
|
||
typeof error === 'object' ? JSON.stringify(error) : String(error);
|
||
} catch (e) {
|
||
errorInfo = 'notInstanceError json is invalid';
|
||
}
|
||
loggerWithScope.persist.error({
|
||
eventName: ReportEventNames.NotInstanceError,
|
||
message: errorInfo,
|
||
error,
|
||
meta: {
|
||
name: 'notInstanceError',
|
||
errorInfo,
|
||
},
|
||
});
|
||
return;
|
||
}
|
||
};
|
||
export const getErrorName = (error: Error) => {
|
||
if (!error) {
|
||
return 'unknown';
|
||
}
|
||
const result = errorList.find(({ func }) => func(error));
|
||
if (result && result.name) {
|
||
return result.name;
|
||
}
|
||
return 'unknown';
|
||
};
|
||
|
||
export const isCertainError = (error: Error) => {
|
||
const errorName = getErrorName(error);
|
||
return errorName !== 'unknown';
|
||
};
|
||
export const sendCertainError = (
|
||
error: Error,
|
||
handle?: (reason: string) => void,
|
||
) => {
|
||
if (isCertainError(error)) {
|
||
handleCertainError(error);
|
||
return;
|
||
}
|
||
|
||
handle?.(error?.message);
|
||
};
|