/** * 日志信息提取辅助函数 * * 用于从请求和响应中提取详细的日志信息 */ /** * 提取用户标识信息 * @param {Object} req - Express 请求对象 * @returns {Object} 用户标识信息 */ export function extractUserInfo(req) { const userInfo = {}; // 从请求头提取用户标识 if (req.headers['x-user-id']) { userInfo.user_id = req.headers['x-user-id']; } // 从 metadata 中提取用户信息(Anthropic API) if (req.body?.metadata?.user_id) { userInfo.user_id = req.body.metadata.user_id; } // 提取客户端信息 if (req.headers['user-agent']) { userInfo.user_agent = req.headers['user-agent']; } // 提取会话ID if (req.headers['x-session-id']) { userInfo.session_id = req.headers['x-session-id']; } // 提取 IP 地址 userInfo.ip = req.ip || req.connection?.remoteAddress; return userInfo; } /** * 提取请求参数(扁平化) * @param {Object} reqBody - 请求体 * @returns {Object} 扁平化的请求参数 */ export function extractRequestParams(reqBody) { const params = {}; if (reqBody?.temperature !== undefined) { params.param_temperature = reqBody.temperature; } if (reqBody?.max_tokens !== undefined) { params.param_max_tokens = reqBody.max_tokens; } if (reqBody?.top_p !== undefined) { params.param_top_p = reqBody.top_p; } if (reqBody?.stream !== undefined) { params.param_stream = reqBody.stream; } return params; } /** * 提取消息摘要 * @param {Object} reqBody - 请求体 * @returns {Object} 消息摘要信息 */ export function extractMessageSummary(reqBody) { const summary = {}; // Anthropic API 格式 (/v1/messages) if (reqBody?.messages && Array.isArray(reqBody.messages)) { summary.message_count = reqBody.messages.length; // 提取第一条消息的前100字符作为摘要 if (reqBody.messages.length > 0) { const firstMsg = reqBody.messages[0]; if (firstMsg.content) { if (typeof firstMsg.content === 'string') { summary.first_message = firstMsg.content.substring(0, 100); } else if (Array.isArray(firstMsg.content)) { // 处理多模态内容 const textContent = firstMsg.content.find(c => c.type === 'text'); if (textContent?.text) { summary.first_message = textContent.text.substring(0, 100); } } } summary.first_message_role = firstMsg.role; } // 统计角色分布(扁平化) const roles = reqBody.messages.map(m => m.role); summary.role_user_count = roles.filter(r => r === 'user').length; summary.role_assistant_count = roles.filter(r => r === 'assistant').length; summary.role_system_count = roles.filter(r => r === 'system').length; } // System prompt if (reqBody?.system) { summary.has_system_prompt = true; summary.system_prompt_length = typeof reqBody.system === 'string' ? reqBody.system.length : JSON.stringify(reqBody.system).length; } // Tools if (reqBody?.tools && Array.isArray(reqBody.tools)) { summary.tool_count = reqBody.tools.length; // 将工具名数组转换为逗号分隔的字符串,最多记录10个 summary.tool_names = reqBody.tools.map(t => t.name).slice(0, 10).join(','); } return summary; } /** * 提取 Token 使用统计 * @param {Object} responseData - API 响应数据 * @returns {Object} Token 统计信息 */ export function extractTokenUsage(responseData) { const usage = {}; if (responseData?.usage) { if (responseData.usage.input_tokens !== undefined) { usage.input_tokens = responseData.usage.input_tokens; } if (responseData.usage.output_tokens !== undefined) { usage.output_tokens = responseData.usage.output_tokens; } if (responseData.usage.total_tokens !== undefined) { usage.total_tokens = responseData.usage.total_tokens; } // 缓存相关 tokens if (responseData.usage.cache_creation_input_tokens !== undefined) { usage.cache_creation_input_tokens = responseData.usage.cache_creation_input_tokens; } if (responseData.usage.cache_read_input_tokens !== undefined) { usage.cache_read_input_tokens = responseData.usage.cache_read_input_tokens; } } return usage; } /** * 构建完整的日志对象 * @param {Object} options - 日志选项 * @param {string} options.method - HTTP 方法 * @param {string} options.endpoint - 请求端点 * @param {string} options.model - 模型 ID * @param {number} options.status - 响应状态码 * @param {number} options.duration_ms - 请求耗时 * @param {Object} options.req - Express 请求对象 * @param {Object} [options.responseData] - 响应数据(可选,非流式响应时提供) * @param {string} [options.error] - 错误信息(可选) * @returns {Object} 完整的日志对象 */ export function buildDetailedLog(options) { const { method, endpoint, model, status, duration_ms, req, responseData, error } = options; const log = { method, endpoint, model, status, duration_ms }; // 添加错误信息 if (error) { log.error = error; } // 提取用户信息 if (req) { const userInfo = extractUserInfo(req); Object.assign(log, userInfo); // 提取请求参数(已扁平化) const params = extractRequestParams(req.body); Object.assign(log, params); // 提取消息摘要 const summary = extractMessageSummary(req.body); if (Object.keys(summary).length > 0) { Object.assign(log, summary); } } // 提取 Token 使用统计 if (responseData) { const tokenUsage = extractTokenUsage(responseData); if (Object.keys(tokenUsage).length > 0) { Object.assign(log, tokenUsage); } // 添加响应信息 if (responseData.id) { log.response_id = responseData.id; } if (responseData.stop_reason) { log.stop_reason = responseData.stop_reason; } } return log; }