File size: 4,309 Bytes
f39c319 a273844 f39c319 a273844 f39c319 a273844 f39c319 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | import { Request, Response, NextFunction } from 'express';
import { MissingMaterialItem } from './models';
export class AppError extends Error {
public statusCode: number;
public errorCode: number;
constructor(message: string, statusCode: number, errorCode: number) {
super(message);
this.statusCode = statusCode;
this.errorCode = errorCode;
Object.setPrototypeOf(this, AppError.prototype);
}
}
export class MissingMaterialError extends AppError {
public missingItems: MissingMaterialItem[];
constructor(missingItems: MissingMaterialItem[]) {
super('need_more_material', 400, 4001);
this.missingItems = missingItems;
Object.setPrototypeOf(this, MissingMaterialError.prototype);
}
}
// 请求日志中间件
export const requestLogger = (req: Request, res: Response, next: NextFunction) => {
const started_at = new Date();
// 拦截 res.send 记录结束时间
const originalSend = res.send;
res.send = function (body: any) {
const ended_at = new Date();
// 提取 case_context
const case_context = req.body?.case_context || req.body;
const case_id = case_context?.case_id || 'unknown';
// 提取 meta 数据和 retry_count
const metadata = case_context?.metadata || {};
const retry_count = metadata.retry_count || req.headers['x-retry-count'] || req.body?.retry_count || 0;
// 解析 agent_name
let agent_name = 'unknown';
if (req.path.includes('peer-reg-summary')) agent_name = 'AGENT-01';
else if (req.path.includes('policy-rewrite')) agent_name = 'AGENT-02';
else if (req.path.includes('compliance-check')) agent_name = 'AGENT-03';
else if (req.path.includes('legal-pack')) agent_name = 'AGENT-04';
else if (req.path.includes('log-analysis')) agent_name = 'LOG_ANALYSIS';
else if (req.path.includes('code-security')) agent_name = 'CODE_SECURITY';
else if (req.path.includes('regulatory-penalty-summary')) agent_name = 'REG_PENALTY_SUMMARY';
const status = res.statusCode >= 400 ? 'failed' : 'success';
const error_code = res.locals.errorCode || 0;
const api_latency_ms = ended_at.getTime() - started_at.getTime();
const llm_latency_ms = res.locals.llm_latency_ms || 0;
// 确保绝对不记录 materials,只输出 meta 数据
console.log(JSON.stringify({
case_id,
retry_count,
agent_name,
metadata,
started_at: started_at.toISOString(),
ended_at: ended_at.toISOString(),
api_latency_ms,
llm_latency_ms,
status,
error_code
}));
return originalSend.call(this, body);
};
next();
};
// 全局错误处理中间件
export const errorHandler = (err: any, req: Request, res: Response, next: NextFunction) => {
let statusCode = 500;
let errorCode = 5000;
let message = 'Internal Server Error';
let extraData: any = null;
if (err instanceof MissingMaterialError) {
statusCode = err.statusCode;
errorCode = err.errorCode;
message = err.message;
extraData = { missing_materials: err.missingItems };
} else if (err instanceof AppError) {
statusCode = err.statusCode;
errorCode = err.errorCode;
message = err.message;
} else if (err.message === 'LLM_INFERENCE_FAILED') {
statusCode = 500;
errorCode = 5001;
message = '智能体推理失败';
} else if (err.message === 'MISSING_MATERIALS') {
statusCode = 400;
errorCode = 4001;
message = 'need_more_material';
} else if (err.message === 'INVALID_FORMAT') {
statusCode = 400;
errorCode = 4002;
message = '输入格式错误';
} else if (err.message === 'MISSING_CONTEXT') {
statusCode = 500;
errorCode = 5002;
message = '外部上下文缺失';
} else if (err.message === 'MISSING_LLM_API_KEY') {
statusCode = 500;
errorCode = 5003;
message = 'LLM密钥未配置';
}
// 记录 errorCode 给 logger 使用
res.locals.errorCode = errorCode;
if (err instanceof MissingMaterialError) {
res.status(statusCode).json({
schema_version: 'v1.0',
error_code: 'need_more_material',
message: message,
...(extraData || {})
});
} else {
res.status(statusCode).json({
error: {
code: errorCode,
message: message,
...(extraData || {})
}
});
}
};
|