coze-studio/frontend/packages/arch/bot-error/src/certain-error.ts

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;
}
// Report a custom error
if (errorName === 'CustomError') {
const { eventName, msg } = error as CustomError;
// Supplement unified reporting custom error event_name for monitoring
loggerWithScope.persist.error({
eventName: ReportEventNames.CustomErrorReport,
message: msg,
error,
meta: {
name: error.name,
originEventName: eventName, // originEventName
originErrorMessage: msg, // Original error msg
},
});
loggerWithScope.persist.error({
eventName,
message: msg,
error,
meta: {
name: error.name,
},
});
return;
}
// Filter out custom events that have been reported
if (errorName === 'ApiError' || errorName === 'AxiosError') {
return;
}
// ChunkLoad failed, not reported, static resource exception statistics in slardar
if (errorName === 'ChunkLoadError') {
reporter.info({
message: 'chunkLoadError',
meta: {
error,
errorName: error.name,
message: error.message,
stack: error.stack,
},
});
return;
}
// Error that does not inherit Error, current case (semi form validation)
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);
};