| | package service |
| |
|
| | import ( |
| | "context" |
| | "fmt" |
| | "log" |
| | "os" |
| | "sync" |
| | ) |
| |
|
| | var ( |
| | debugMode bool |
| | debugModeOnce sync.Once |
| | ) |
| |
|
| | |
| | func IsDebugMode() bool { |
| | debugModeOnce.Do(func() { |
| | debugMode = os.Getenv("DEBUG") == "true" || os.Getenv("DEBUG") == "1" |
| | }) |
| | return debugMode |
| | } |
| |
|
| | |
| | type RequestLogger struct { |
| | logs []string |
| | mu sync.Mutex |
| | hasError bool |
| | } |
| |
|
| | |
| | func NewRequestLogger() *RequestLogger { |
| | return &RequestLogger{ |
| | logs: make([]string, 0, 20), |
| | } |
| | } |
| |
|
| | |
| | func (l *RequestLogger) Log(format string, args ...interface{}) { |
| | msg := fmt.Sprintf(format, args...) |
| | |
| | |
| | if IsDebugMode() { |
| | log.Print("[DEBUG] " + msg) |
| | return |
| | } |
| |
|
| | |
| | l.mu.Lock() |
| | l.logs = append(l.logs, "[DEBUG] " + msg) |
| | l.mu.Unlock() |
| | } |
| |
|
| | |
| | func (l *RequestLogger) MarkError() { |
| | l.mu.Lock() |
| | l.hasError = true |
| | l.mu.Unlock() |
| | } |
| |
|
| | |
| | func (l *RequestLogger) Flush() { |
| | |
| | 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" |
| |
|
| | |
| | func WithLogger(ctx context.Context, logger *RequestLogger) context.Context { |
| | return context.WithValue(ctx, loggerContextKey, logger) |
| | } |
| |
|
| | |
| | func GetLogger(ctx context.Context) *RequestLogger { |
| | val := ctx.Value(loggerContextKey) |
| | if val != nil { |
| | if logger, ok := val.(*RequestLogger); ok { |
| | return logger |
| | } |
| | } |
| | return nil |
| | } |
| |
|
| | |
| | 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...) |
| | } |
| | } |
| |
|
| | |
| | func DebugLog(ctx context.Context, format string, args ...interface{}) { |
| | logToContext(ctx, format, args...) |
| | } |
| |
|
| | |
| | func DebugLogRequest(ctx context.Context, provider, endpoint, model string) { |
| | logToContext(ctx, "[%s] >>> 请求开始: endpoint=%s, model=%s", provider, endpoint, model) |
| | } |
| |
|
| | |
| | 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) |
| | } |
| |
|
| | |
| | func DebugLogAccountSelected(ctx context.Context, provider string, accountID uint, email string) { |
| | logToContext(ctx, "[%s] ✓ 选择账号: id=%d, email=%s", provider, accountID, email) |
| | } |
| |
|
| | |
| | func DebugLogRequestSent(ctx context.Context, provider, url string) { |
| | logToContext(ctx, "[%s] → 发送请求: %s", provider, url) |
| | } |
| |
|
| | |
| | func DebugLogResponseReceived(ctx context.Context, provider string, statusCode int) { |
| | logToContext(ctx, "[%s] ← 收到响应: status=%d", provider, statusCode) |
| | } |
| |
|
| | |
| | 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) |
| | } |
| | } |
| |
|
| | |
| | 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) |
| | } |
| | } |
| | } |
| |
|
| | |
| | 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) |
| | } |
| | } |
| | } |
| |
|
| | |
| | func DebugLogActualModel(ctx context.Context, provider, requestModel, actualModel string) { |
| | logToContext(ctx, "[%s] 模型映射: %s → %s", provider, requestModel, actualModel) |
| | } |
| |
|
| | |
| | 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) |
| | } |
| |
|