medmap-ios/medmap/Network/NetworkLogger.swift
2026-08-27 23:26:14 +01:00

114 lines
3.9 KiB
Swift

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: <binary data, \(body.count) bytes>"
}
}
*/
}
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: <binary data, \(data.count) bytes>"
}
}
}
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 "❓"
}
}
}