import Foundation import Alamofire /// Advanced logging system for network requests and responses enum NetworkLogger { enum LogLevel { case none case minimal case verbose case debug } static var logLevel: LogLevel = .debug static func logRequest(_ request: URLRequest) { guard logLevel != .none else { return } var log = "\n🌐 ===== HTTP REQUEST =====" log += "\nšŸ“¤ Method: \(request.httpMethod ?? "UNKNOWN")" log += "\nšŸ”— URL: \(request.url?.absoluteString ?? "N/A")" if logLevel == .verbose || logLevel == .debug { if let headers = request.allHTTPHeaderFields, !headers.isEmpty { log += "\nšŸ“‹ Headers:" headers.forEach { log += "\n \($0.key): \($0.value)" } } /* if let body = request.httpBody { if let jsonString = String(data: body, encoding: .utf8) { log += "\nšŸ“¦ Body: \(jsonString)" } else { log += "\nšŸ“¦ Body: " } } */ } log += "\n========================\n" fluxlog(log) } static func logResponse(_ response: HTTPURLResponse, data: Data?, duration: TimeInterval) { guard logLevel != .none else { return } let statusEmoji = getStatusEmoji(for: response.statusCode) var log = "\nāœ… ===== HTTP RESPONSE =====" log += "\n\(statusEmoji) Status: \(response.statusCode)" log += "\nšŸ”— URL: \(response.url?.absoluteString ?? "N/A")" log += "\nā±ļø Duration: \(String(format: "%.3f", duration))s" if logLevel == .verbose || logLevel == .debug { if !response.allHeaderFields.isEmpty { log += "\nšŸ“‹ Headers:" response.allHeaderFields.forEach { log += "\n \($0.key): \($0.value)" } } if let data = data { if let jsonString = String(data: data, encoding: .utf8) { log += "\nšŸ“¦ Response Data: \(jsonString.prefix(500))" if jsonString.count > 500 { log += "... (truncated)" } } else { log += "\nšŸ“¦ Response Data: " } } } log += "\n=========================\n" fluxlog(log) } static func logError(_ error: AFError, request: URLRequest?, data: Data?, duration: TimeInterval) { guard logLevel != .none else { return } var log = "\nāŒ ===== HTTP ERROR =====" log += "\nšŸ”— URL: \(request?.url?.absoluteString ?? "N/A")" log += "\nāš ļø Error: \(error.localizedDescription)" log += "\nā±ļø Duration: \(String(format: "%.3f", duration))s" if let statusCode = error.responseCode { log += "\nšŸ”¢ Status Code: \(statusCode)" } // ALWAYS log error response JSON (regardless of log level, without truncation) if let data = data, let errorString = String(data: data, encoding: .utf8) { log += "\nšŸ“¦ Error Response JSON:" log += "\n\(errorString)" } // Log underlying error in verbose/debug mode if logLevel == .verbose || logLevel == .debug { if case .sessionTaskFailed(let underlyingError) = error { log += "\nšŸ› Underlying Error: \(underlyingError.localizedDescription)" } } log += "\n======================\n" fluxlog(log) } private static func getStatusEmoji(for statusCode: Int) -> String { switch statusCode { case 200...299: return "āœ…" case 300...399: return "šŸ”„" case 400...499: return "āš ļø" case 500...599: return "šŸ”„" default: return "ā“" } } }