Showing
1 changed file
with
131 additions
and
1 deletions
| ... | @@ -35,7 +35,7 @@ extension UIDevice { | ... | @@ -35,7 +35,7 @@ extension UIDevice { | 
| 35 | let machineMirror = Mirror(reflecting: systemInfo.machine) | 35 | let machineMirror = Mirror(reflecting: systemInfo.machine) | 
| 36 | let identifier = machineMirror.children.reduce("") { identifier, element in | 36 | let identifier = machineMirror.children.reduce("") { identifier, element in | 
| 37 | guard let value = element.value as? Int8, value != 0 else { return identifier } | 37 | guard let value = element.value as? Int8, value != 0 else { return identifier } | 
| 38 | - return identifier + String(UnicodeScalar(UInt8(value))!) | 38 | + return identifier + String(UnicodeScalar(UInt8(value))) | 
| 39 | } | 39 | } | 
| 40 | return identifier | 40 | return identifier | 
| 41 | } | 41 | } | 
| ... | @@ -182,16 +182,27 @@ public final class NetworkService: NetworkServiceProtocol { | ... | @@ -182,16 +182,27 @@ public final class NetworkService: NetworkServiceProtocol { | 
| 182 | private func performRequest(_ endpoint: Endpoint) async throws -> Data { | 182 | private func performRequest(_ endpoint: Endpoint) async throws -> Data { | 
| 183 | // Check network connectivity | 183 | // Check network connectivity | 
| 184 | guard isConnected else { | 184 | guard isConnected else { | 
| 185 | + print("🔴 [NetworkService] No internet connection") | ||
| 185 | throw NetworkError.networkError(NSError(domain: "NetworkService", code: -1009, userInfo: [NSLocalizedDescriptionKey: "No internet connection"])) | 186 | throw NetworkError.networkError(NSError(domain: "NetworkService", code: -1009, userInfo: [NSLocalizedDescriptionKey: "No internet connection"])) | 
| 186 | } | 187 | } | 
| 187 | 188 | ||
| 188 | let request = try buildRequest(for: endpoint) | 189 | let request = try buildRequest(for: endpoint) | 
| 189 | 190 | ||
| 191 | + // 📤 LOG REQUEST DETAILS | ||
| 192 | + logRequest(request, endpoint: endpoint) | ||
| 193 | + | ||
| 190 | do { | 194 | do { | 
| 191 | let (data, response) = try await session.data(for: request) | 195 | let (data, response) = try await session.data(for: request) | 
| 196 | + | ||
| 197 | + // 📥 LOG RESPONSE DETAILS | ||
| 198 | + logResponse(response, data: data, endpoint: endpoint) | ||
| 199 | + | ||
| 192 | try validateResponse(response) | 200 | try validateResponse(response) | 
| 193 | return data | 201 | return data | 
| 194 | } catch { | 202 | } catch { | 
| 203 | + // 🔴 LOG ERROR DETAILS | ||
| 204 | + logError(error, endpoint: endpoint) | ||
| 205 | + | ||
| 195 | // Handle token refresh if needed | 206 | // Handle token refresh if needed | 
| 196 | if let httpResponse = error as? HTTPURLResponse, httpResponse.statusCode == 401 { | 207 | if let httpResponse = error as? HTTPURLResponse, httpResponse.statusCode == 401 { | 
| 197 | if endpoint.requiresAuthentication { | 208 | if endpoint.requiresAuthentication { | 
| ... | @@ -358,6 +369,125 @@ public final class NetworkService: NetworkServiceProtocol { | ... | @@ -358,6 +369,125 @@ public final class NetworkService: NetworkServiceProtocol { | 
| 358 | throw NetworkError.serverError(httpResponse.statusCode) | 369 | throw NetworkError.serverError(httpResponse.statusCode) | 
| 359 | } | 370 | } | 
| 360 | } | 371 | } | 
| 372 | + | ||
| 373 | + // MARK: - Logging Methods | ||
| 374 | + | ||
| 375 | + /// Log detailed request information | ||
| 376 | + private func logRequest(_ request: URLRequest, endpoint: Endpoint) { | ||
| 377 | + print("\n📤 [NetworkService] REQUEST") | ||
| 378 | + print("🔗 URL: \(request.url?.absoluteString ?? "Unknown")") | ||
| 379 | + print("🔧 Method: \(request.httpMethod ?? "Unknown")") | ||
| 380 | + print("⏱️ Timeout: \(request.timeoutInterval)s") | ||
| 381 | + | ||
| 382 | + // Log headers | ||
| 383 | + print("📋 Headers:") | ||
| 384 | + if let headers = request.allHTTPHeaderFields { | ||
| 385 | + for (key, value) in headers.sorted(by: { $0.key < $1.key }) { | ||
| 386 | + // Mask sensitive headers for security | ||
| 387 | + let maskedValue = maskSensitiveHeader(key: key, value: value) | ||
| 388 | + print(" \(key): \(maskedValue)") | ||
| 389 | + } | ||
| 390 | + } else { | ||
| 391 | + print(" (No headers)") | ||
| 392 | + } | ||
| 393 | + | ||
| 394 | + // Log body | ||
| 395 | + if let body = request.httpBody { | ||
| 396 | + print("📦 Body Size: \(body.count) bytes") | ||
| 397 | + if let bodyString = String(data: body, encoding: .utf8) { | ||
| 398 | + print("📦 Body Content: \(bodyString)") | ||
| 399 | + } else { | ||
| 400 | + print("📦 Body Content: (Binary data)") | ||
| 401 | + } | ||
| 402 | + } else { | ||
| 403 | + print("📦 Body: (No body)") | ||
| 404 | + } | ||
| 405 | + | ||
| 406 | + print("🎯 Endpoint Info:") | ||
| 407 | + print(" Path: \(endpoint.path)") | ||
| 408 | + print(" Requires Auth: \(endpoint.requiresAuthentication)") | ||
| 409 | + print(" Parameters: \(endpoint.parameters?.count ?? 0) items") | ||
| 410 | + print("===============================") | ||
| 411 | + } | ||
| 412 | + | ||
| 413 | + /// Log detailed response information | ||
| 414 | + private func logResponse(_ response: URLResponse, data: Data, endpoint: Endpoint) { | ||
| 415 | + print("\n📥 [NetworkService] RESPONSE") | ||
| 416 | + print("🔗 URL: \(response.url?.absoluteString ?? "Unknown")") | ||
| 417 | + | ||
| 418 | + if let httpResponse = response as? HTTPURLResponse { | ||
| 419 | + let statusEmoji = httpResponse.statusCode >= 200 && httpResponse.statusCode < 300 ? "✅" : "❌" | ||
| 420 | + print("\(statusEmoji) Status: \(httpResponse.statusCode)") | ||
| 421 | + | ||
| 422 | + // Log response headers | ||
| 423 | + print("📋 Response Headers:") | ||
| 424 | + for (key, value) in httpResponse.allHeaderFields.sorted(by: { "\($0.key)" < "\($1.key)" }) { | ||
| 425 | + print(" \(key): \(value)") | ||
| 426 | + } | ||
| 427 | + } | ||
| 428 | + | ||
| 429 | + print("📦 Response Size: \(data.count) bytes") | ||
| 430 | + | ||
| 431 | + // Log response body | ||
| 432 | + if let responseString = String(data: data, encoding: .utf8) { | ||
| 433 | + print("📦 Response Body:") | ||
| 434 | + // Pretty print JSON if possible | ||
| 435 | + if let jsonData = responseString.data(using: .utf8), | ||
| 436 | + let jsonObject = try? JSONSerialization.jsonObject(with: jsonData, options: []), | ||
| 437 | + let prettyData = try? JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted), | ||
| 438 | + let prettyString = String(data: prettyData, encoding: .utf8) { | ||
| 439 | + print(prettyString) | ||
| 440 | + } else { | ||
| 441 | + print(responseString) | ||
| 442 | + } | ||
| 443 | + } else { | ||
| 444 | + print("📦 Response Body: (Binary data)") | ||
| 445 | + } | ||
| 446 | + print("===============================") | ||
| 447 | + } | ||
| 448 | + | ||
| 449 | + /// Log error information | ||
| 450 | + private func logError(_ error: Error, endpoint: Endpoint) { | ||
| 451 | + print("\n🔴 [NetworkService] ERROR") | ||
| 452 | + print("🔗 Endpoint: \(endpoint.path)") | ||
| 453 | + print("❌ Error: \(error.localizedDescription)") | ||
| 454 | + | ||
| 455 | + if let urlError = error as? URLError { | ||
| 456 | + print("🌐 URL Error Code: \(urlError.code.rawValue)") | ||
| 457 | + print("🌐 URL Error Description: \(urlError.localizedDescription)") | ||
| 458 | + } | ||
| 459 | + | ||
| 460 | + if let httpResponse = (error as NSError).userInfo["response"] as? HTTPURLResponse { | ||
| 461 | + print("📊 HTTP Status: \(httpResponse.statusCode)") | ||
| 462 | + } | ||
| 463 | + | ||
| 464 | + print("🔍 Error Details: \(error)") | ||
| 465 | + print("===============================") | ||
| 466 | + } | ||
| 467 | + | ||
| 468 | + /// Mask sensitive header values for security | ||
| 469 | + private func maskSensitiveHeader(key: String, value: String) -> String { | ||
| 470 | + let sensitiveHeaders = [ | ||
| 471 | + "authorization", | ||
| 472 | + "loyalty-signature", | ||
| 473 | + "access-token", | ||
| 474 | + "refresh-token", | ||
| 475 | + "api-key", | ||
| 476 | + "x-api-key" | ||
| 477 | + ] | ||
| 478 | + | ||
| 479 | + if sensitiveHeaders.contains(key.lowercased()) { | ||
| 480 | + if value.count > 8 { | ||
| 481 | + let prefix = String(value.prefix(4)) | ||
| 482 | + let suffix = String(value.suffix(4)) | ||
| 483 | + return "\(prefix)***\(suffix)" | ||
| 484 | + } else { | ||
| 485 | + return "***" | ||
| 486 | + } | ||
| 487 | + } | ||
| 488 | + | ||
| 489 | + return value | ||
| 490 | + } | ||
| 361 | } | 491 | } | 
| 362 | 492 | ||
| 363 | // MARK: - Network Service Extensions | 493 | // MARK: - Network Service Extensions | ... | ... | 
- 
Please register or login to post a comment