Skip to content

Commit 4b57cae

Browse files
committed
Enable RemoteLoggerURLProtocol automatically when using URLSessionProxy
1 parent fcfd94d commit 4b57cae

File tree

2 files changed

+70
-19
lines changed

2 files changed

+70
-19
lines changed

Sources/Pulse/NetworkLogger/URLSessionProxy.swift

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,22 @@ public final class URLSessionProxy {
1414
self.logger = logger
1515
}
1616

17-
/// Enables automatic `URLSession` logging.
17+
/// Enables automatic logging and remote debugging of network requests.
18+
///
19+
/// - warning: This method of logging relies heavily on swizzling and might
20+
/// stop working in the future versions of the native SDKs. If you are looking
21+
/// for a more stable solution, consider using ``URLSessionProxyDelegate`` or
22+
/// manually logging the requests using ``NetworkLogger``.
1823
///
1924
/// - parameter logger: The network logger to be used for recording the requests.
2025
public static func enable(with logger: NetworkLogger = .init()) {
21-
guard URLSessionProxy.proxy == nil else {
22-
NSLog("Error: Pulse.URLSessionProxy already enabled")
23-
return
24-
}
25-
guard sharedNetworkLogger == nil else {
26-
NSLog("Error: Pulse network request logging is already enabled")
27-
return
28-
}
26+
guard !isAutomaticNetworkLoggingEnabled else { return }
27+
2928
let proxy = URLSessionProxy(logger: logger)
3029
proxy.enable()
3130
URLSessionProxy.proxy = proxy
31+
32+
RemoteLoggerURLProtocol.enableAutomaticRegistration()
3233
}
3334

3435
func enable() {
@@ -120,6 +121,28 @@ public final class URLSessionProxy {
120121
}
121122
}
122123

124+
// MARK: - RemoteLoggerURLProtocol (Automatic Regisration)
125+
126+
extension RemoteLoggerURLProtocol {
127+
@MainActor
128+
static func enableAutomaticRegistration() {
129+
if let lhs = class_getClassMethod(URLSession.self, #selector(URLSession.init(configuration:delegate:delegateQueue:))),
130+
let rhs = class_getClassMethod(URLSession.self, #selector(URLSession.pulse_init2(configuration:delegate:delegateQueue:))) {
131+
method_exchangeImplementations(lhs, rhs)
132+
}
133+
}
134+
}
135+
136+
private extension URLSession {
137+
@objc class func pulse_init2(configuration: URLSessionConfiguration, delegate: URLSessionDelegate?, delegateQueue: OperationQueue?) -> URLSession {
138+
guard isConfiguringSessionSafe(delegate: delegate) else {
139+
return self.pulse_init2(configuration: configuration, delegate: delegate, delegateQueue: delegateQueue)
140+
}
141+
configuration.protocolClasses = [RemoteLoggerURLProtocol.self] + (configuration.protocolClasses ?? [])
142+
return self.pulse_init2(configuration: configuration, delegate: delegate, delegateQueue: delegateQueue)
143+
}
144+
}
145+
123146
// MARK: - Experimental (Deprecated)
124147

125148
@available(*, deprecated, message: "Experimental.URLSessionProxy is replaced with a reworked URLSessionProxy")

Sources/Pulse/NetworkLogger/URLSessionProxyDelegate+AutomaticRegistration.swift

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,22 @@
55
import Foundation
66

77
extension URLSessionProxyDelegate {
8-
/// Enables automatic registration of `URLSessionProxyDelegate`. After calling this method, every time
9-
/// you initialize a `URLSession` using `init(configuration:delegate:delegateQueue:))` method, the
10-
/// delegate will automatically get replaced with a `URLSessionProxyDelegate` that logs all the
11-
/// needed events and forwards the methods to your original delegate.
8+
/// Enables automatic logging and remote debugging of network requests using
9+
/// `URLSessionProxyDelegate`.
10+
///
11+
/// - note: This method works by swizzling `URLSession` init and adding
12+
/// `URLSessionProxyDelegate` to the delegate chain and adding
13+
/// `RemoteLoggerURLProtocol` to the list of session protocol classes.
14+
///
15+
/// - warning: This logging method works only with delegate-based `URLSession`
16+
/// instances. If it doesn't work for you, consider using ``URLSessionProxy``
17+
/// for automatic logging or manually logging the requests using ``NetworkLogger``.
18+
///
19+
/// - parameter logger: The network logger to be used for recording the requests.
1220
@MainActor
1321
public static func enableAutomaticRegistration(logger: NetworkLogger = .init()) {
14-
guard sharedNetworkLogger == nil else {
15-
NSLog("Error: Puls network request logging is already enabled")
16-
return
17-
}
22+
guard !isAutomaticNetworkLoggingEnabled else { return }
23+
1824
sharedNetworkLogger = logger
1925
if let lhs = class_getClassMethod(URLSession.self, #selector(URLSession.init(configuration:delegate:delegateQueue:))),
2026
let rhs = class_getClassMethod(URLSession.self, #selector(URLSession.pulse_init(configuration:delegate:delegateQueue:))) {
@@ -23,15 +29,37 @@ extension URLSessionProxyDelegate {
2329
}
2430
}
2531

26-
var sharedNetworkLogger: NetworkLogger? {
32+
/// Returns `true` if automatic logging was already enabled using one of the
33+
/// existing mechanisms provided by Pulse.
34+
@MainActor
35+
var isAutomaticNetworkLoggingEnabled: Bool {
36+
guard URLSessionProxy.proxy == nil else {
37+
NSLog("Error: Pulse.URLSessionProxy already enabled")
38+
return true
39+
}
40+
guard sharedNetworkLogger == nil else {
41+
NSLog("Error: Pulse network request logging is already enabled")
42+
return true
43+
}
44+
return false
45+
}
46+
47+
func isConfiguringSessionSafe(delegate: URLSessionDelegate?) -> Bool {
48+
if String(describing: delegate).contains("GTMSessionFetcher") {
49+
return false
50+
}
51+
return true
52+
}
53+
54+
private var sharedNetworkLogger: NetworkLogger? {
2755
get { _sharedLogger.value }
2856
set { _sharedLogger.value = newValue }
2957
}
3058
private let _sharedLogger = Mutex<NetworkLogger?>(nil)
3159

3260
private extension URLSession {
3361
@objc class func pulse_init(configuration: URLSessionConfiguration, delegate: URLSessionDelegate?, delegateQueue: OperationQueue?) -> URLSession {
34-
guard !String(describing: delegate).contains("GTMSessionFetcher") else {
62+
guard isConfiguringSessionSafe(delegate: delegate) else {
3563
return self.pulse_init(configuration: configuration, delegate: delegate, delegateQueue: delegateQueue)
3664
}
3765
configuration.protocolClasses = [RemoteLoggerURLProtocol.self] + (configuration.protocolClasses ?? [])

0 commit comments

Comments
 (0)