UNPKG

route-claudecode

Version:

Advanced routing and transformation system for Claude Code outputs to multiple AI providers

338 lines 13.6 kB
"use strict"; /** * Request Lifecycle Logger with Individual Request Tracking * 按request单独文件记录全流程,支持时间分块和图形界面解析 */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.RequestLifecycleLogger = void 0; const fs_1 = require("fs"); const path = __importStar(require("path")); const os = __importStar(require("os")); class RequestLifecycleLogger { config; baseLogDir; portLogDir; timeBlockSizeMs; requestFiles = new Map(); nodeResponseFiles = new Map(); systemLogFile = null; stopReasonLogFile = null; constructor(config) { this.config = { port: config.port, logDir: config.logDir || path.join(os.homedir(), '.route-claude-code', 'request-lifecycle-logs'), timeBlockSize: config.timeBlockSize || 5, maxRetentionDays: config.maxRetentionDays || 7 }; this.baseLogDir = this.config.logDir; this.portLogDir = path.join(this.baseLogDir, `port-${this.config.port}`); this.timeBlockSizeMs = this.config.timeBlockSize * 60 * 1000; this.initialize().catch(error => { console.error('Failed to initialize request lifecycle logger:', error); }); } async initialize() { try { // Create base directories await fs_1.promises.mkdir(this.baseLogDir, { recursive: true }); await fs_1.promises.mkdir(this.portLogDir, { recursive: true }); // Initialize log files await this.initializeSystemLogFile(); await this.initializeStopReasonLogFile(); // 使用统一日志系统而不是直接console输出 // console.log('Request lifecycle logger initialized'); } catch (error) { console.error('Failed to initialize request lifecycle logger:', error); } } getBeijingTimestamp() { const now = new Date(); const beijingOffset = 8 * 60 * 60 * 1000; const beijingTime = new Date(now.getTime() + beijingOffset); const year = beijingTime.getUTCFullYear(); const month = String(beijingTime.getUTCMonth() + 1).padStart(2, '0'); const day = String(beijingTime.getUTCDate()).padStart(2, '0'); const hours = String(beijingTime.getUTCHours()).padStart(2, '0'); const minutes = String(beijingTime.getUTCMinutes()).padStart(2, '0'); const seconds = String(beijingTime.getUTCSeconds()).padStart(2, '0'); return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`; } getTimeBlockDirectory(timestamp) { const time = timestamp ? new Date(timestamp) : new Date(); const timeBlockMs = Math.floor(time.getTime() / this.timeBlockSizeMs) * this.timeBlockSizeMs; const timeBlockTime = new Date(timeBlockMs); const year = timeBlockTime.getFullYear(); const month = String(timeBlockTime.getMonth() + 1).padStart(2, '0'); const day = String(timeBlockTime.getDate()).padStart(2, '0'); const hours = String(timeBlockTime.getHours()).padStart(2, '0'); const minutes = String(timeBlockTime.getMinutes()).padStart(2, '0'); return path.join(this.portLogDir, `timeblock-${year}${month}${day}-${hours}${minutes}`); } async initializeSystemLogFile() { const filename = `system-${this.getBeijingTimestamp()}.log`; const filepath = path.join(this.portLogDir, filename); this.systemLogFile = await fs_1.promises.open(filepath, 'a'); // Write header const header = { timestamp: new Date().toISOString(), beijingTimestamp: this.getBeijingTimestamp(), type: 'system_log_initialized', port: this.config.port }; await this.systemLogFile.writeFile(JSON.stringify(header) + '\n'); } async initializeStopReasonLogFile() { const filename = `stop-reason-${this.getBeijingTimestamp()}.log`; const filepath = path.join(this.portLogDir, filename); this.stopReasonLogFile = await fs_1.promises.open(filepath, 'a'); // Write header const header = { timestamp: new Date().toISOString(), beijingTimestamp: this.getBeijingTimestamp(), type: 'stop_reason_log_initialized', port: this.config.port }; await this.stopReasonLogFile.writeFile(JSON.stringify(header) + '\n'); } async getRequestFileHandle(requestId) { if (this.requestFiles.has(requestId)) { return this.requestFiles.get(requestId); } const filename = `request-${requestId}.jsonl`; const filepath = path.join(this.portLogDir, filename); const fileHandle = await fs_1.promises.open(filepath, 'a'); this.requestFiles.set(requestId, fileHandle); return fileHandle; } async getNodeResponseFileHandle(timeBlockDir) { const cacheKey = timeBlockDir; if (this.nodeResponseFiles.has(cacheKey)) { return this.nodeResponseFiles.get(cacheKey); } await fs_1.promises.mkdir(timeBlockDir, { recursive: true }); const filename = 'node-responses.jsonl'; const filepath = path.join(timeBlockDir, filename); const fileHandle = await fs_1.promises.open(filepath, 'a'); this.nodeResponseFiles.set(cacheKey, fileHandle); return fileHandle; } /** * 开始记录请求生命周期 */ async startRequestLifecycle(requestId, provider, model, method, path, data) { try { const startTime = new Date().toISOString(); const beijingTimestamp = this.getBeijingTimestamp(); const lifecycle = { requestId, port: this.config.port, startTime, provider, model, status: 'started', stages: [{ stage: 'request_start', timestamp: startTime, beijingTimestamp, data: { method, path, ...data } }] }; const fileHandle = await this.getRequestFileHandle(requestId); await fileHandle.writeFile(JSON.stringify(lifecycle) + '\n'); // Log to system file if (this.systemLogFile) { await this.systemLogFile.writeFile(JSON.stringify({ timestamp: startTime, beijingTimestamp, type: 'request_started', requestId, provider, model, method, path }) + '\n'); } // 使用统一日志系统而不是直接console输出 // console.log(`Request lifecycle started for ${requestId}`); } catch (error) { console.error('Failed to start request lifecycle:', error); } } /** * 记录请求阶段 */ async logRequestStage(requestId, stage, data, duration) { try { const timestamp = new Date().toISOString(); const beijingTimestamp = this.getBeijingTimestamp(); const stageData = { stage, timestamp, beijingTimestamp, data, duration }; const fileHandle = await this.getRequestFileHandle(requestId); // Read current lifecycle, add stage, and write back // For performance, we'll append a stage entry instead of rewriting the whole file const stageEntry = { type: 'stage', requestId, stage: stageData }; await fileHandle.writeFile(JSON.stringify(stageEntry) + '\n'); } catch (error) { console.error('Failed to log request stage:', error); } } /** * 记录节点响应(按时间分块) */ async logNodeResponse(nodeId, response, metadata) { try { const timestamp = new Date().toISOString(); const beijingTimestamp = this.getBeijingTimestamp(); const timeBlockDir = this.getTimeBlockDirectory(); const responseEntry = { timestamp, beijingTimestamp, nodeId, response, metadata, timeBlock: timeBlockDir.split('-').pop() }; const fileHandle = await this.getNodeResponseFileHandle(timeBlockDir); await fileHandle.writeFile(JSON.stringify(responseEntry) + '\n'); } catch (error) { console.error('Failed to log node response:', error); } } /** * 完成请求生命周期 */ async completeRequestLifecycle(requestId, status, responseTime, finishReason, responseData) { try { const endTime = new Date().toISOString(); const beijingTimestamp = this.getBeijingTimestamp(); const completionEntry = { type: 'completion', requestId, endTime, beijingTimestamp, status, responseTime, finishReason, responseData }; const fileHandle = await this.getRequestFileHandle(requestId); await fileHandle.writeFile(JSON.stringify(completionEntry) + '\n'); // Log finish reason to separate file if (finishReason) { await this.logStopReason(requestId, finishReason, endTime, beijingTimestamp); } // Log to system file if (this.systemLogFile) { await this.systemLogFile.writeFile(JSON.stringify({ timestamp: endTime, beijingTimestamp, type: 'request_completed', requestId, status, responseTime, finishReason }) + '\n'); } // 使用统一日志系统而不是直接console输出 // console.log(`Request lifecycle completed for ${requestId} in ${responseTime}ms`); } catch (error) { console.error('Failed to complete request lifecycle:', error); } } /** * 记录stop reason */ async logStopReason(requestId, finishReason, timestamp, beijingTimestamp) { if (!this.stopReasonLogFile) return; const stopReasonEntry = { timestamp, beijingTimestamp, requestId, finishReason, port: this.config.port }; await this.stopReasonLogFile.writeFile(JSON.stringify(stopReasonEntry) + '\n'); } /** * 清理资源 */ async cleanup() { try { // Close all request file handles for (const [requestId, fileHandle] of this.requestFiles) { await fileHandle.close(); } this.requestFiles.clear(); // Close all node response file handles for (const [timeBlockDir, fileHandle] of this.nodeResponseFiles) { await fileHandle.close(); } this.nodeResponseFiles.clear(); // Close system log file if (this.systemLogFile) { await this.systemLogFile.close(); this.systemLogFile = null; } // Close stop reason log file if (this.stopReasonLogFile) { await this.stopReasonLogFile.close(); this.stopReasonLogFile = null; } // 使用统一日志系统而不是直接console输出 // console.log('Request lifecycle logger cleanup completed'); } catch (error) { console.error('Failed to cleanup request lifecycle logger:', error); } } } exports.RequestLifecycleLogger = RequestLifecycleLogger; //# sourceMappingURL=request-lifecycle-logger.js.map