Manos Chorianopoulos

add network logging

...@@ -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
......