Manos Chorianopoulos

add network logging

......@@ -35,7 +35,7 @@ extension UIDevice {
let machineMirror = Mirror(reflecting: systemInfo.machine)
let identifier = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8, value != 0 else { return identifier }
return identifier + String(UnicodeScalar(UInt8(value))!)
return identifier + String(UnicodeScalar(UInt8(value)))
}
return identifier
}
......@@ -182,16 +182,27 @@ public final class NetworkService: NetworkServiceProtocol {
private func performRequest(_ endpoint: Endpoint) async throws -> Data {
// Check network connectivity
guard isConnected else {
print("🔴 [NetworkService] No internet connection")
throw NetworkError.networkError(NSError(domain: "NetworkService", code: -1009, userInfo: [NSLocalizedDescriptionKey: "No internet connection"]))
}
let request = try buildRequest(for: endpoint)
// 📤 LOG REQUEST DETAILS
logRequest(request, endpoint: endpoint)
do {
let (data, response) = try await session.data(for: request)
// 📥 LOG RESPONSE DETAILS
logResponse(response, data: data, endpoint: endpoint)
try validateResponse(response)
return data
} catch {
// 🔴 LOG ERROR DETAILS
logError(error, endpoint: endpoint)
// Handle token refresh if needed
if let httpResponse = error as? HTTPURLResponse, httpResponse.statusCode == 401 {
if endpoint.requiresAuthentication {
......@@ -358,6 +369,125 @@ public final class NetworkService: NetworkServiceProtocol {
throw NetworkError.serverError(httpResponse.statusCode)
}
}
// MARK: - Logging Methods
/// Log detailed request information
private func logRequest(_ request: URLRequest, endpoint: Endpoint) {
print("\n📤 [NetworkService] REQUEST")
print("🔗 URL: \(request.url?.absoluteString ?? "Unknown")")
print("🔧 Method: \(request.httpMethod ?? "Unknown")")
print("⏱️ Timeout: \(request.timeoutInterval)s")
// Log headers
print("📋 Headers:")
if let headers = request.allHTTPHeaderFields {
for (key, value) in headers.sorted(by: { $0.key < $1.key }) {
// Mask sensitive headers for security
let maskedValue = maskSensitiveHeader(key: key, value: value)
print(" \(key): \(maskedValue)")
}
} else {
print(" (No headers)")
}
// Log body
if let body = request.httpBody {
print("📦 Body Size: \(body.count) bytes")
if let bodyString = String(data: body, encoding: .utf8) {
print("📦 Body Content: \(bodyString)")
} else {
print("📦 Body Content: (Binary data)")
}
} else {
print("📦 Body: (No body)")
}
print("🎯 Endpoint Info:")
print(" Path: \(endpoint.path)")
print(" Requires Auth: \(endpoint.requiresAuthentication)")
print(" Parameters: \(endpoint.parameters?.count ?? 0) items")
print("===============================")
}
/// Log detailed response information
private func logResponse(_ response: URLResponse, data: Data, endpoint: Endpoint) {
print("\n📥 [NetworkService] RESPONSE")
print("🔗 URL: \(response.url?.absoluteString ?? "Unknown")")
if let httpResponse = response as? HTTPURLResponse {
let statusEmoji = httpResponse.statusCode >= 200 && httpResponse.statusCode < 300 ? "✅" : "❌"
print("\(statusEmoji) Status: \(httpResponse.statusCode)")
// Log response headers
print("📋 Response Headers:")
for (key, value) in httpResponse.allHeaderFields.sorted(by: { "\($0.key)" < "\($1.key)" }) {
print(" \(key): \(value)")
}
}
print("📦 Response Size: \(data.count) bytes")
// Log response body
if let responseString = String(data: data, encoding: .utf8) {
print("📦 Response Body:")
// Pretty print JSON if possible
if let jsonData = responseString.data(using: .utf8),
let jsonObject = try? JSONSerialization.jsonObject(with: jsonData, options: []),
let prettyData = try? JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted),
let prettyString = String(data: prettyData, encoding: .utf8) {
print(prettyString)
} else {
print(responseString)
}
} else {
print("📦 Response Body: (Binary data)")
}
print("===============================")
}
/// Log error information
private func logError(_ error: Error, endpoint: Endpoint) {
print("\n🔴 [NetworkService] ERROR")
print("🔗 Endpoint: \(endpoint.path)")
print("❌ Error: \(error.localizedDescription)")
if let urlError = error as? URLError {
print("🌐 URL Error Code: \(urlError.code.rawValue)")
print("🌐 URL Error Description: \(urlError.localizedDescription)")
}
if let httpResponse = (error as NSError).userInfo["response"] as? HTTPURLResponse {
print("📊 HTTP Status: \(httpResponse.statusCode)")
}
print("🔍 Error Details: \(error)")
print("===============================")
}
/// Mask sensitive header values for security
private func maskSensitiveHeader(key: String, value: String) -> String {
let sensitiveHeaders = [
"authorization",
"loyalty-signature",
"access-token",
"refresh-token",
"api-key",
"x-api-key"
]
if sensitiveHeaders.contains(key.lowercased()) {
if value.count > 8 {
let prefix = String(value.prefix(4))
let suffix = String(value.suffix(4))
return "\(prefix)***\(suffix)"
} else {
return "***"
}
}
return value
}
}
// MARK: - Network Service Extensions
......