aaxaxax's picture
force update files
1de7911
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)
}