import Foundation // MARK: - API Logger @MainActor class APILogger { enum LogLevel { case none case basic case detailed } #if DEBUG static var logLevel: LogLevel = .detailed #else static var logLevel: LogLevel = .none #endif private static let dateFormatter: DateFormatter = { let formatter = DateFormatter() formatter.dateFormat = "HH:mm:ss.SSS" return formatter }() // MARK: - Request Logging @MainActor static func logRequest( _ request: T, url: URL, body: Data?, finalHeaders: [String: String]? = nil ) { #if DEBUG guard logLevel != .none else { return } #else return #endif let timestamp = dateFormatter.string(from: Date()) print("\n🚀 [API Request] [\(timestamp)] ==================") print("📍 Endpoint: \(request.endpoint)") print("🔗 Full URL: \(url.absoluteString)") print("📝 Method: \(request.method.rawValue)") print("⏰ Timeout: \(request.timeout)s") // 显示最终的完整 headers(包括默认 headers 和自定义 headers) if let headers = finalHeaders, !headers.isEmpty { if logLevel == .detailed { print("📋 Final Headers (包括默认 + 自定义):") for (key, value) in headers.sorted(by: { $0.key < $1.key }) { print(" \(key): \(value)") } } else if logLevel == .basic { print("📋 Headers: \(headers.count) 个 headers") // 只显示重要的 headers let importantHeaders = ["Content-Type", "Accept", "User-Agent", "Authorization"] for key in importantHeaders { if let value = headers[key] { print(" \(key): \(value)") } } } } else if let customHeaders = request.headers, !customHeaders.isEmpty { print("📋 Custom Headers:") for (key, value) in customHeaders.sorted(by: { $0.key < $1.key }) { print(" \(key): \(value)") } } else { print("📋 Headers: 使用默认 headers") } if let queryParams = request.queryParameters, !queryParams.isEmpty { print("🔍 Query Parameters:") for (key, value) in queryParams.sorted(by: { $0.key < $1.key }) { print(" \(key): \(value)") } } if logLevel == .detailed { if let body = body { print("📦 Request Body (\(body.count) bytes):") if let jsonObject = try? JSONSerialization.jsonObject(with: body, options: []), let prettyData = try? JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted), let prettyString = String(data: prettyData, encoding: .utf8) { print(prettyString) } else if let rawString = String(data: body, encoding: .utf8) { print(rawString) } else { print("Binary data") } } else { print("📦 Request Body: No body") } // 显示基础参数信息(仅详细模式) if request.includeBaseParameters { print("📱 Base Parameters: 自动注入设备和应用信息") let baseParams = BaseRequest() print(" Device: \(baseParams.model), OS: \(baseParams.os) \(baseParams.osVersion)") print(" App: \(baseParams.app) v\(baseParams.appVersion)") print(" Language: \(baseParams.acceptLanguage)") } } else if logLevel == .basic { if let body = body { print("📦 Request Body: \(formatBytes(body.count))") } else { print("📦 Request Body: No body") } // 基础模式也显示是否包含基础参数 if request.includeBaseParameters { print("📱 Base Parameters: 已自动注入") } } print("=====================================") } // MARK: - Response Logging static func logResponse(data: Data, response: HTTPURLResponse, duration: TimeInterval) { #if DEBUG guard logLevel != .none else { return } #else return #endif let timestamp = dateFormatter.string(from: Date()) let statusEmoji = response.statusCode < 400 ? "✅" : "❌" print("\n\(statusEmoji) [API Response] [\(timestamp)] ===================") print("⏱️ Duration: \(String(format: "%.3f", duration))s") print("📊 Status Code: \(response.statusCode)") print("🔗 URL: \(response.url?.absoluteString ?? "Unknown")") print("📏 Data Size: \(formatBytes(data.count))") if logLevel == .detailed { print("📋 Response Headers:") for (key, value) in response.allHeaderFields.sorted(by: { "\($0.key)" < "\($1.key)" }) { print(" \(key): \(value)") } print("📦 Response Data:") if data.isEmpty { print(" Empty response") } else if let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []), let prettyData = try? JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted), let prettyString = String(data: prettyData, encoding: .utf8) { print(prettyString) } else if let rawString = String(data: data, encoding: .utf8) { print(rawString) } else { print(" Binary data (\(data.count) bytes)") } } print("=====================================") } // MARK: - Error Logging static func logError(_ error: Error, url: URL?, duration: TimeInterval) { #if DEBUG guard logLevel != .none else { return } #else return #endif let timestamp = dateFormatter.string(from: Date()) print("\n❌ [API Error] [\(timestamp)] ======================") print("⏱️ Duration: \(String(format: "%.3f", duration))s") if let url = url { print("🔗 URL: \(url.absoluteString)") } if let apiError = error as? APIError { print("🚨 API Error: \(apiError.localizedDescription)") } else { print("🚨 System Error: \(error.localizedDescription)") } if logLevel == .detailed { if let urlError = error as? URLError { print("🔍 URLError Code: \(urlError.code.rawValue)") print("🔍 URLError Localized: \(urlError.localizedDescription)") // 详细的网络错误分析 switch urlError.code { case .timedOut: print("💡 建议:检查网络连接或增加超时时间") case .notConnectedToInternet: print("💡 建议:检查网络连接") case .cannotConnectToHost: print("💡 建议:检查服务器地址和端口") case .resourceUnavailable: print("💡 建议:检查 API 端点是否正确") default: break } } print("🔍 Full Error: \(error)") } print("=====================================\n") } // MARK: - Decoded Response Logging static func logDecodedResponse(_ response: T, type: T.Type) { #if DEBUG guard logLevel == .detailed else { return } #else return #endif let timestamp = dateFormatter.string(from: Date()) print("🎯 [Decoded Response] [\(timestamp)] Type: \(type)") print("=====================================\n") } // MARK: - Helper Methods private static func formatBytes(_ bytes: Int) -> String { let formatter = ByteCountFormatter() formatter.allowedUnits = [.useKB, .useMB] formatter.countStyle = .file return formatter.string(fromByteCount: Int64(bytes)) } // MARK: - Performance Logging static func logPerformanceWarning(duration: TimeInterval, threshold: TimeInterval = 5.0) { #if DEBUG guard logLevel != .none && duration > threshold else { return } #else return #endif let timestamp = dateFormatter.string(from: Date()) print("\n⚠️ [Performance Warning] [\(timestamp)] ============") print("🐌 Request took \(String(format: "%.3f", duration))s (threshold: \(threshold)s)") print("💡 建议:检查网络条件或优化 API 响应") print("================================================\n") } }