package service import ( "context" "fmt" "log" "os" "sync" ) var ( debugMode bool debugModeOnce sync.Once ) // IsDebugMode 检查是否启用调试模式 func IsDebugMode() bool { debugModeOnce.Do(func() { debugMode = os.Getenv("DEBUG") == "true" || os.Getenv("DEBUG") == "1" }) return debugMode } // RequestLogger 用于收集请求级日志 type RequestLogger struct { logs []string mu sync.Mutex hasError bool } // NewRequestLogger 创建新的请求日志记录器 func NewRequestLogger() *RequestLogger { return &RequestLogger{ logs: make([]string, 0, 20), } } // Log 记录一条日志 func (l *RequestLogger) Log(format string, args ...interface{}) { msg := fmt.Sprintf(format, args...) // 如果全局 DEBUG 开启,直接打印 if IsDebugMode() { log.Print("[DEBUG] " + msg) return } // 否则缓冲 l.mu.Lock() l.logs = append(l.logs, "[DEBUG] " + msg) l.mu.Unlock() } // MarkError 标记发生错误 func (l *RequestLogger) MarkError() { l.mu.Lock() l.hasError = true l.mu.Unlock() } // Flush 输出缓冲的日志(如果有错误) func (l *RequestLogger) Flush() { // 只有在非 Debug 模式且发生错误时才需要 Flush (Debug 模式下已经实时打印了) if !IsDebugMode() && l.hasError { l.mu.Lock() defer l.mu.Unlock() for _, msg := range l.logs { log.Print(msg) } } } type contextKey string const loggerContextKey contextKey = "request_logger" // WithLogger 将 logger 注入 context func WithLogger(ctx context.Context, logger *RequestLogger) context.Context { return context.WithValue(ctx, loggerContextKey, logger) } // GetLogger 从 context 获取 logger func GetLogger(ctx context.Context) *RequestLogger { val := ctx.Value(loggerContextKey) if val != nil { if logger, ok := val.(*RequestLogger); ok { return logger } } return nil } // 辅助函数:获取 logger 并记录 func logToContext(ctx context.Context, format string, args ...interface{}) { logger := GetLogger(ctx) if logger != nil { logger.Log(format, args...) } else if IsDebugMode() { log.Printf("[DEBUG] "+format, args...) } } // DebugLog 调试日志输出 func DebugLog(ctx context.Context, format string, args ...interface{}) { logToContext(ctx, format, args...) } // DebugLogRequest 请求开始日志 func DebugLogRequest(ctx context.Context, provider, endpoint, model string) { logToContext(ctx, "[%s] >>> 请求开始: endpoint=%s, model=%s", provider, endpoint, model) } // DebugLogRetry 重试日志 func DebugLogRetry(ctx context.Context, provider string, attempt int, accountID uint, err error) { if logger := GetLogger(ctx); logger != nil { logger.MarkError() } logToContext(ctx, "[%s] ↻ 重试 #%d: accountID=%d, error=%v", provider, attempt, accountID, err) } // DebugLogAccountSelected 账号选择日志 func DebugLogAccountSelected(ctx context.Context, provider string, accountID uint, email string) { logToContext(ctx, "[%s] ✓ 选择账号: id=%d, email=%s", provider, accountID, email) } // DebugLogRequestSent 请求发送日志 func DebugLogRequestSent(ctx context.Context, provider, url string) { logToContext(ctx, "[%s] → 发送请求: %s", provider, url) } // DebugLogResponseReceived 响应接收日志 func DebugLogResponseReceived(ctx context.Context, provider string, statusCode int) { logToContext(ctx, "[%s] ← 收到响应: status=%d", provider, statusCode) } // DebugLogRequestEnd 请求结束日志 func DebugLogRequestEnd(ctx context.Context, provider string, success bool, err error) { if !success || err != nil { if logger := GetLogger(ctx); logger != nil { logger.MarkError() } logToContext(ctx, "[%s] <<< 请求完成: success=false, error=%v", provider, err) } else { logToContext(ctx, "[%s] <<< 请求完成: success=true", provider) } } // DebugLogRequestHeaders 请求头日志 func DebugLogRequestHeaders(ctx context.Context, provider string, headers map[string][]string) { logToContext(ctx, "[%s] 请求头:", provider) for k, v := range headers { // 隐藏敏感信息 if k == "Authorization" || k == "x-api-key" { logToContext(ctx, "[%s] %s: ***", provider, k) } else { logToContext(ctx, "[%s] %s: %v", provider, k, v) } } } // DebugLogResponseHeaders 响应头日志 func DebugLogResponseHeaders(ctx context.Context, provider string, headers map[string][]string) { logToContext(ctx, "[%s] 响应头:", provider) for k, v := range headers { // 隐藏敏感信息 if k == "X-Api-Key" || k == "Authorization" { logToContext(ctx, "[%s] %s: ***", provider, k) } else { logToContext(ctx, "[%s] %s: %v", provider, k, v) } } } // DebugLogActualModel 实际调用模型日志 func DebugLogActualModel(ctx context.Context, provider, requestModel, actualModel string) { logToContext(ctx, "[%s] 模型映射: %s → %s", provider, requestModel, actualModel) } // DebugLogErrorResponse 错误响应内容日志 func DebugLogErrorResponse(ctx context.Context, provider string, statusCode int, body string) { if logger := GetLogger(ctx); logger != nil { logger.MarkError() } logToContext(ctx, "[%s] ✗ 错误响应 [%d]: %s", provider, statusCode, body) }