@@ -31,7 +31,7 @@ public class URLSessionInstrumentation {
31
31
32
32
private var _configuration : URLSessionInstrumentationConfiguration
33
33
public var configuration : URLSessionInstrumentationConfiguration {
34
- get { configurationQueue. sync { _configuration } }
34
+ configurationQueue. sync { _configuration }
35
35
}
36
36
37
37
private let queue = DispatchQueue (
@@ -41,6 +41,10 @@ public class URLSessionInstrumentation {
41
41
42
42
static var instrumentedKey = " io.opentelemetry.instrumentedCall "
43
43
44
+ static let excludeList : [ String ] = [
45
+ " __NSCFURLProxySessionConnection "
46
+ ]
47
+
44
48
static let AVTaskClassList : [ AnyClass ] = [
45
49
" __NSCFBackgroundAVAggregateAssetDownloadTask " ,
46
50
" __NSCFBackgroundAVAssetDownloadTask " ,
@@ -94,16 +98,25 @@ public class URLSessionInstrumentation {
94
98
}
95
99
defer { free ( methodList) }
96
100
101
+ var foundClasses : [ AnyClass ] = [ ]
97
102
for j in 0 ..< selectorsCount {
98
103
for i in 0 ..< Int ( methodCount)
99
104
where method_getName ( methodList [ i] ) == selectors [ j] {
100
105
selectorFound = true
101
- injectIntoDelegateClass ( cls : theClass)
106
+ foundClasses . append ( theClass)
102
107
}
103
108
if selectorFound {
104
109
break
105
110
}
106
111
}
112
+
113
+ foundClasses. removeAll { cls in
114
+ Self . excludeList. contains ( NSStringFromClass ( cls) )
115
+ }
116
+
117
+ foundClasses. forEach { cls in
118
+ injectIntoDelegateClass ( cls: cls)
119
+ }
107
120
}
108
121
109
122
if #available( OSX 10 . 15 , iOS 13 . 0 , watchOS 6 . 0 , tvOS 13 . 0 , * ) {
@@ -205,53 +218,53 @@ public class URLSessionInstrumentation {
205
218
private func injectIntoNSURLSessionCreateTaskWithParameterMethods( ) {
206
219
typealias UploadWithDataIMP = @convention ( c) ( URLSession , Selector , URLRequest , Data ? ) -> URLSessionTask
207
220
typealias UploadWithFileIMP = @convention ( c) ( URLSession , Selector , URLRequest , URL ) -> URLSessionTask
208
-
221
+
209
222
let cls = URLSession . self
210
-
223
+
211
224
// MARK: Swizzle `uploadTask(with:from:)`
212
225
if let method = class_getInstanceMethod ( cls, #selector( URLSession . uploadTask ( with: from: ) ) ) {
213
226
let originalIMP = method_getImplementation ( method)
214
227
let imp = unsafeBitCast ( originalIMP, to: UploadWithDataIMP . self)
215
-
228
+
216
229
let block : @convention ( block) ( URLSession , URLRequest , Data ? ) -> URLSessionTask = { [ weak self] session, request, data in
217
230
guard let instrumentation = self else {
218
231
return imp ( session, #selector( URLSession . uploadTask ( with: from: ) ) , request, data)
219
232
}
220
-
233
+
221
234
let sessionTaskId = UUID ( ) . uuidString
222
235
let instrumentedRequest = URLSessionLogger . processAndLogRequest (
223
236
request,
224
237
sessionTaskId: sessionTaskId,
225
238
instrumentation: instrumentation,
226
239
shouldInjectHeaders: true
227
240
)
228
-
241
+
229
242
let task = imp ( session, #selector( URLSession . uploadTask ( with: from: ) ) , instrumentedRequest ?? request, data)
230
243
instrumentation. setIdKey ( value: sessionTaskId, for: task)
231
244
return task
232
245
}
233
246
let swizzledIMP = imp_implementationWithBlock ( block)
234
247
method_setImplementation ( method, swizzledIMP)
235
248
}
236
-
249
+
237
250
// MARK: Swizzle `uploadTask(with:fromFile:)`
238
251
if let method = class_getInstanceMethod ( cls, #selector( URLSession . uploadTask ( with: fromFile: ) ) ) {
239
252
let originalIMP = method_getImplementation ( method)
240
253
let imp = unsafeBitCast ( originalIMP, to: UploadWithFileIMP . self)
241
-
254
+
242
255
let block : @convention ( block) ( URLSession , URLRequest , URL ) -> URLSessionTask = { [ weak self] session, request, fileURL in
243
256
guard let instrumentation = self else {
244
257
return imp ( session, #selector( URLSession . uploadTask ( with: fromFile: ) ) , request, fileURL)
245
258
}
246
-
259
+
247
260
let sessionTaskId = UUID ( ) . uuidString
248
261
let instrumentedRequest = URLSessionLogger . processAndLogRequest (
249
262
request,
250
263
sessionTaskId: sessionTaskId,
251
264
instrumentation: instrumentation,
252
265
shouldInjectHeaders: true
253
266
)
254
-
267
+
255
268
let task = imp ( session, #selector( URLSession . uploadTask ( with: fromFile: ) ) , instrumentedRequest ?? request, fileURL)
256
269
instrumentation. setIdKey ( value: sessionTaskId, for: task)
257
270
return task
@@ -756,17 +769,17 @@ public class URLSessionInstrumentation {
756
769
// Check if we can determine if this is an async/await call
757
770
// For iOS 15/macOS 12, we can't use Task.basePriority, so we check other indicators
758
771
var isAsyncContext = false
759
-
772
+
760
773
if #available( OSX 13 . 0 , iOS 16 . 0 , watchOS 9 . 0 , tvOS 16 . 0 , * ) {
761
774
isAsyncContext = Task . basePriority != nil
762
775
} else {
763
776
// For iOS 15/macOS 12, check if the task has no delegate and no session delegate
764
777
// This is a heuristic that works for async/await methods
765
- isAsyncContext = task. delegate == nil &&
778
+ isAsyncContext = task. delegate == nil &&
766
779
( task. value ( forKey: " session " ) as? URLSession ) ? . delegate == nil &&
767
780
task. state != . running
768
781
}
769
-
782
+
770
783
if isAsyncContext {
771
784
// This is likely an async/await call
772
785
let instrumentedRequest = URLSessionLogger . processAndLogRequest ( request,
@@ -777,11 +790,11 @@ public class URLSessionInstrumentation {
777
790
task. setValue ( instrumentedRequest, forKey: " currentRequest " )
778
791
}
779
792
self . setIdKey ( value: taskId, for: task)
780
-
793
+
781
794
// For async/await methods, we need to ensure the delegate is set
782
795
// to capture the completion, but only if there's no existing delegate
783
796
// AND no session delegate (session delegates are called for async/await too)
784
- if task. delegate == nil ,
797
+ if task. delegate == nil ,
785
798
task. state != . running,
786
799
( task. value ( forKey: " session " ) as? URLSession ) ? . delegate == nil {
787
800
task. delegate = AsyncTaskDelegate ( instrumentation: self , sessionTaskId: taskId)
@@ -844,20 +857,20 @@ class FakeDelegate: NSObject, URLSessionTaskDelegate {
844
857
class AsyncTaskDelegate : NSObject , URLSessionTaskDelegate {
845
858
private weak var instrumentation : URLSessionInstrumentation ?
846
859
private let sessionTaskId : String
847
-
860
+
848
861
init ( instrumentation: URLSessionInstrumentation , sessionTaskId: String ) {
849
862
self . instrumentation = instrumentation
850
863
self . sessionTaskId = sessionTaskId
851
864
super. init ( )
852
865
}
853
-
866
+
854
867
func urlSession( _ session: URLSession , task: URLSessionTask ,
855
868
didCompleteWithError error: Error ? ) {
856
869
guard let instrumentation = instrumentation else { return }
857
-
870
+
858
871
// Get the task ID that was set when the task was created
859
872
let taskId = sessionTaskId
860
-
873
+
861
874
if let error = error {
862
875
let status = ( task. response as? HTTPURLResponse ) ? . statusCode ?? 0
863
876
URLSessionLogger . logError ( error, dataOrFile: nil , statusCode: status,
0 commit comments