Spaces:
Sleeping
Sleeping
Sync from enhance: d795216 feat: implement patch response parser for search and replace functionality
9bd4242 | /** | |
| * Logger Utility | |
| * 统一日志工具 | |
| */ | |
| import { appConfig } from '../config/app' | |
| /** | |
| * 日志级别 | |
| */ | |
| export enum LogLevel { | |
| DEBUG = 0, | |
| INFO = 1, | |
| WARN = 2, | |
| ERROR = 3 | |
| } | |
| /** | |
| * 日志级别映射 | |
| */ | |
| const LOG_LEVEL_MAP: Record<string, LogLevel> = { | |
| debug: LogLevel.DEBUG, | |
| info: LogLevel.INFO, | |
| warn: LogLevel.WARN, | |
| error: LogLevel.ERROR | |
| } | |
| function parseBooleanEnv(value: string | undefined): boolean | undefined { | |
| if (typeof value !== 'string') { | |
| return undefined | |
| } | |
| const normalized = value.trim().toLowerCase() | |
| if (['1', 'true', 'yes', 'on'].includes(normalized)) { | |
| return true | |
| } | |
| if (['0', 'false', 'no', 'off'].includes(normalized)) { | |
| return false | |
| } | |
| return undefined | |
| } | |
| /** | |
| * 当前日志级别 | |
| */ | |
| const currentLogLevel = LOG_LEVEL_MAP[appConfig.logging.level] || LogLevel.INFO | |
| const prodSummaryLogOnly = | |
| appConfig.nodeEnv === 'production' && | |
| (parseBooleanEnv(process.env.PROD_SUMMARY_LOG_ONLY) ?? true) | |
| /** | |
| * 格式化时间戳 | |
| */ | |
| function formatTimestamp(): string { | |
| return new Date().toISOString() | |
| } | |
| /** | |
| * 安全的 JSON 序列化,处理大对象和循环引用 | |
| */ | |
| function safeStringify(obj: any, maxLength?: number): string { | |
| try { | |
| const seen = new WeakSet() | |
| const json = JSON.stringify(obj, (key, value) => { | |
| // 处理循环引用 | |
| if (typeof value === 'object' && value !== null) { | |
| if (seen.has(value)) { | |
| return '[Circular]' | |
| } | |
| seen.add(value) | |
| } | |
| return value | |
| }, 2) | |
| // 如果指定了最大长度且超出,则截断 | |
| if (maxLength && json.length > maxLength) { | |
| return json.slice(0, maxLength) + `...(truncated, total ${json.length} chars)` | |
| } | |
| return json | |
| } catch (error) { | |
| return '[Serialization Error]' | |
| } | |
| } | |
| /** | |
| * 格式化日志消息 | |
| */ | |
| function formatMessage(level: string, message: string, meta?: any): string { | |
| const timestamp = formatTimestamp() | |
| // 智能处理 meta 数据 | |
| let metaStr = '' | |
| if (meta) { | |
| // 对于大文本字段,不进行截断(如 AI 响应、代码等) | |
| const largeTextFields = ['content', 'code', 'response', 'aiResponse', 'manimCode', 'stdout', 'stderr', 'output'] | |
| const hasLargeText = largeTextFields.some(field => field in meta) | |
| if (hasLargeText) { | |
| // 包含大文本,使用更大的限制或不限制 | |
| metaStr = ` ${safeStringify(meta)}` | |
| } else { | |
| // 普通元数据,可以适当限制 | |
| metaStr = ` ${safeStringify(meta, 5000)}` | |
| } | |
| } | |
| if (appConfig.logging.pretty) { | |
| // 开发环境:带颜色的格式 | |
| const colors: Record<string, string> = { | |
| DEBUG: '\x1b[36m', // Cyan | |
| INFO: '\x1b[32m', // Green | |
| WARN: '\x1b[33m', // Yellow | |
| ERROR: '\x1b[31m' // Red | |
| } | |
| const reset = '\x1b[0m' | |
| const color = colors[level] || '' | |
| return `${color}[${timestamp}] ${level}${reset}: ${message}${metaStr}` | |
| } else { | |
| // 生产环境:JSON 格式 | |
| return JSON.stringify({ | |
| timestamp, | |
| level, | |
| message, | |
| ...meta | |
| }) | |
| } | |
| } | |
| /** | |
| * Logger 类 | |
| */ | |
| class Logger { | |
| private context?: string | |
| constructor(context?: string) { | |
| this.context = context | |
| } | |
| /** | |
| * 添加上下文信息 | |
| */ | |
| private addContext(meta?: any): any { | |
| if (!this.context) return meta | |
| return { ...meta, context: this.context } | |
| } | |
| private shouldEmit(level: LogLevel, meta?: any): boolean { | |
| if (!prodSummaryLogOnly) { | |
| return true | |
| } | |
| // In production summary-only mode, always keep warnings/errors visible. | |
| if (level >= LogLevel.WARN) { | |
| return true | |
| } | |
| return meta && typeof meta === 'object' && meta._logType === 'job_summary' | |
| } | |
| /** | |
| * 调试日志 | |
| */ | |
| debug(message: string, meta?: any): void { | |
| const contextMeta = this.addContext(meta) | |
| if (currentLogLevel <= LogLevel.DEBUG && this.shouldEmit(LogLevel.DEBUG, contextMeta)) { | |
| console.debug(formatMessage('DEBUG', message, contextMeta)) | |
| } | |
| } | |
| /** | |
| * 信息日志 | |
| */ | |
| info(message: string, meta?: any): void { | |
| const contextMeta = this.addContext(meta) | |
| if (currentLogLevel <= LogLevel.INFO && this.shouldEmit(LogLevel.INFO, contextMeta)) { | |
| console.log(formatMessage('INFO', message, contextMeta)) | |
| } | |
| } | |
| /** | |
| * 警告日志 | |
| */ | |
| warn(message: string, meta?: any): void { | |
| const contextMeta = this.addContext(meta) | |
| if (currentLogLevel <= LogLevel.WARN && this.shouldEmit(LogLevel.WARN, contextMeta)) { | |
| console.warn(formatMessage('WARN', message, contextMeta)) | |
| } | |
| } | |
| /** | |
| * 错误日志 | |
| */ | |
| error(message: string, meta?: any): void { | |
| const contextMeta = this.addContext(meta) | |
| if (currentLogLevel <= LogLevel.ERROR && this.shouldEmit(LogLevel.ERROR, contextMeta)) { | |
| console.error(formatMessage('ERROR', message, contextMeta)) | |
| } | |
| } | |
| /** | |
| * 创建子 logger 带上下文 | |
| */ | |
| child(context: string): Logger { | |
| const childContext = this.context ? `${this.context}:${context}` : context | |
| return new Logger(childContext) | |
| } | |
| } | |
| /** | |
| * 默认 logger 实例 | |
| */ | |
| export const logger = new Logger() | |
| /** | |
| * 创建带上下文的 logger | |
| */ | |
| export function createLogger(context: string): Logger { | |
| return new Logger(context) | |
| } | |