Last active
July 10, 2022 17:10
-
-
Save boehlerlukas/0e54a1a0c8377ba5cd519faa6f3b7bb1 to your computer and use it in GitHub Desktop.
Gleap Plugin for Moya (v13)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import Moya | |
import Gleap | |
import Result | |
/// Logs network activity (outgoing requests and incoming responses). | |
public final class GleapMoyaPlugin { | |
public var data: GleapNetworkLoggerData | |
/// Initializes a GleapMoyaPlugin. | |
public init(data: GleapNetworkLoggerData = GleapNetworkLoggerData.shared()) { | |
self.data = data | |
} | |
} | |
// MARK: - PluginType | |
extension GleapMoyaPlugin: PluginType { | |
public func didReceive(_ result: Result<Moya.Response, MoyaError>, target: TargetType) { | |
switch result { | |
case .success(let response): | |
logNetworkResponse(response, target: target, isFromError: false) | |
case let .failure(error): | |
logNetworkError(error, target: target) | |
} | |
} | |
} | |
// MARK: - Logging | |
private extension GleapMoyaPlugin { | |
func logNetworkResponse(_ response: Response, target: TargetType, isFromError: Bool) { | |
guard let originalRequest = response.request else { | |
return | |
} | |
let isoDateFormatter = ISO8601DateFormatter() | |
let contentType = response.response?.allHeaderFields["Content-Type"] as? String ?? "" | |
var request: [String: Any] = [ | |
"type": originalRequest.httpMethod ?? "--", | |
"url": originalRequest.url?.absoluteString ?? "--", | |
"date": isoDateFormatter.string(from: Date()), | |
"success": true, | |
"contentType": contentType, | |
"duration": 100, | |
] | |
// Request | |
var requestContent: [String: Any] = [:] | |
requestContent["headers"] = originalRequest.allHTTPHeaderFields | |
// Set request payload | |
if let bodyStream = originalRequest.httpBodyStream { | |
requestContent["payload"] = bodyStream.description | |
} | |
if let body = originalRequest.httpBody { | |
requestContent["payload"] = getPayload(data: body, contentType: originalRequest.allHTTPHeaderFields?["Content-Type"] ?? "") | |
} | |
// Append the request | |
request["request"] = requestContent | |
// Response | |
var responseContent: [String: Any] = [:] | |
// Set http status | |
responseContent["status"] = response.response?.statusCode ?? 0 | |
// Set response http headers | |
var responseHeaders = [String: String]() | |
if let httpHeaders = response.response?.allHeaderFields { | |
for (key, value) in httpHeaders { | |
if let stringValue = value as? String, let keyString = key as? String { | |
responseHeaders[keyString] = stringValue | |
} | |
} | |
} | |
responseContent["headers"] = responseHeaders | |
responseContent["payload"] = getPayload(data: response.data, contentType: contentType) | |
// Append the request | |
request["response"] = responseContent | |
// Append new request | |
data.logRequest(request: request) | |
} | |
func logNetworkError(_ error: MoyaError, target: TargetType) { | |
if let moyaResponse = error.response { | |
return logNetworkResponse(moyaResponse, target: target, isFromError: true) | |
} | |
} | |
func getPayload(data: Data?, contentType: String?) -> String { | |
guard let data = data else { | |
return "<no_content>" | |
} | |
if (data.count <= 0) { | |
return "<no_content>" | |
} | |
let maxBodySize = 1024 * 500; | |
if (isTextBased(contentType: contentType) && data.count < maxBodySize) { | |
return String(decoding: data, as: UTF8.self) | |
} | |
return "<response_too_large>" | |
} | |
func isTextBased(contentType: String?) -> Bool { | |
guard let contentType = contentType else { | |
return false | |
} | |
if (contentType.contains("text/")) { | |
return true; | |
} | |
if (contentType.contains("application/javascript")) { | |
return true; | |
} | |
if (contentType.contains("application/xhtml+xml")) { | |
return true; | |
} | |
if (contentType.contains("application/json")) { | |
return true; | |
} | |
if (contentType.contains("application/xml")) { | |
return true; | |
} | |
if (contentType.contains("application/x-www-form-urlencoded")) { | |
return true; | |
} | |
if (contentType.contains("multipart/")) { | |
return true; | |
} | |
return false; | |
} | |
} | |
/// Logs network activity (outgoing requests and incoming responses). | |
public class GleapNetworkLoggerData { | |
private var logs = [Any]() | |
private let maxRequests = 15 | |
private static var sharedGleapNetworkLoggerData: GleapNetworkLoggerData = { | |
return GleapNetworkLoggerData() | |
}() | |
public func logRequest(request: [String: Any]) { | |
if (logs.count > maxRequests) { | |
logs.remove(at: 0) | |
} | |
// Append the request | |
logs.append(request) | |
// Send the updated logs to Gleap | |
Gleap.attachExternalData(["networkLogs": logs]) | |
} | |
public class func shared() -> GleapNetworkLoggerData { | |
return sharedGleapNetworkLoggerData | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment