Skip to content

Commit adcc669

Browse files
committed
fix: pass through data when network request completes
1 parent bdab1a1 commit adcc669

File tree

5 files changed

+129
-15
lines changed

5 files changed

+129
-15
lines changed

Datadog/Example/ExampleAppDelegate.swift

+5-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,11 @@ class ExampleAppDelegate: UIResponder, UIApplicationDelegate {
6666
RUM.enable(
6767
with: RUM.Configuration(
6868
applicationID: Environment.readRUMApplicationID(),
69-
urlSessionTracking: .init(firstPartyHostsTracing: .trace(hosts: [], sampleRate: 100)),
69+
urlSessionTracking: .init(
70+
resourceAttributesProvider: { req, resp, data, err in
71+
print("⭐️ [Attributes Provider] data: \(data)")
72+
return [:]
73+
}),
7074
trackBackgroundEvents: true,
7175
customEndpoint: Environment.readCustomRUMURL(),
7276
telemetrySampleRate: 100

Datadog/IntegrationUnitTests/Public/NetworkInstrumentationIntegrationTests.swift

+113-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import XCTest
88
import TestUtilities
99
import DatadogInternal
1010

11+
@testable import DatadogRUM
1112
@testable import DatadogTrace
1213
@testable import DatadogCore
1314

@@ -50,7 +51,7 @@ class NetworkInstrumentationIntegrationTests: XCTestCase {
5051
core.flushAndTearDown()
5152
core = nil
5253
}
53-
54+
5455
func testParentSpanPropagation() throws {
5556
let expectation = expectation(description: "request completes")
5657
// Given
@@ -88,4 +89,115 @@ class NetworkInstrumentationIntegrationTests: XCTestCase {
8889

8990
class MockDelegate: NSObject, URLSessionDataDelegate {
9091
}
92+
93+
func testResourceAttributesProvider_givenURLSessionDataTaskRequest() {
94+
core = DatadogCoreProxy(
95+
context: .mockWith(
96+
env: "test",
97+
version: "1.1.1",
98+
serverTimeOffset: 123
99+
)
100+
)
101+
102+
let providerExpectation = expectation(description: "provider called")
103+
var providerDataCount = 0
104+
RUM.enable(
105+
with: .init(
106+
applicationID: .mockAny(),
107+
urlSessionTracking: .init(
108+
resourceAttributesProvider: { req, resp, data, err in
109+
XCTAssertNotNil(data)
110+
XCTAssertTrue(data!.count > 0)
111+
providerDataCount = data!.count
112+
providerExpectation.fulfill()
113+
return [:]
114+
})
115+
),
116+
in: core
117+
)
118+
119+
URLSessionInstrumentation.enable(
120+
with: .init(
121+
delegateClass: InstrumentedSessionDelegate.self
122+
),
123+
in: core
124+
)
125+
126+
let session = URLSession(
127+
configuration: .ephemeral,
128+
delegate: InstrumentedSessionDelegate(),
129+
delegateQueue: nil
130+
)
131+
var request = URLRequest(url: URL(string: "https://www.datadoghq.com/")!)
132+
request.httpMethod = "GET"
133+
134+
let task = session.dataTask(with: request)
135+
task.resume()
136+
137+
wait(for: [providerExpectation], timeout: 10)
138+
XCTAssertTrue(providerDataCount > 0)
139+
}
140+
141+
func testResourceAttributesProvider_givenURLSessionDataTaskRequestWithCompletionHandler() {
142+
core = DatadogCoreProxy(
143+
context: .mockWith(
144+
env: "test",
145+
version: "1.1.1",
146+
serverTimeOffset: 123
147+
)
148+
)
149+
150+
let providerExpectation = expectation(description: "provider called")
151+
var providerDataCount = 0
152+
var providerData: Data?
153+
RUM.enable(
154+
with: .init(
155+
applicationID: .mockAny(),
156+
urlSessionTracking: .init(
157+
resourceAttributesProvider: { req, resp, data, err in
158+
XCTAssertNotNil(data)
159+
XCTAssertTrue(data!.count > 0)
160+
providerDataCount = data!.count
161+
data.map { providerData = $0 }
162+
providerExpectation.fulfill()
163+
return [:]
164+
})
165+
),
166+
in: core
167+
)
168+
169+
URLSessionInstrumentation.enable(
170+
with: .init(
171+
delegateClass: InstrumentedSessionDelegate.self
172+
),
173+
in: core
174+
)
175+
176+
let session = URLSession(
177+
configuration: .ephemeral,
178+
delegate: InstrumentedSessionDelegate(),
179+
delegateQueue: nil
180+
)
181+
var request = URLRequest(url: URL(string: "https://www.datadoghq.com/")!)
182+
request.httpMethod = "GET"
183+
184+
let taskExpectation = self.expectation(description: "task completed")
185+
var taskDataCount = 0
186+
var taskData: Data?
187+
let task = session.dataTask(with: request) { data, _, _ in
188+
XCTAssertNotNil(data)
189+
XCTAssertTrue(data!.count > 0)
190+
taskDataCount = data!.count
191+
data.map { taskData = $0 }
192+
taskExpectation.fulfill()
193+
}
194+
task.resume()
195+
196+
wait(for: [providerExpectation, taskExpectation], timeout: 10)
197+
XCTAssertEqual(providerDataCount, taskDataCount)
198+
XCTAssertEqual(providerData, taskData)
199+
}
200+
201+
class InstrumentedSessionDelegate: NSObject, URLSessionDataDelegate {
202+
}
91203
}

DatadogInternal/Sources/NetworkInstrumentation/NetworkInstrumentationFeature.swift

+9-11
Original file line numberDiff line numberDiff line change
@@ -91,15 +91,9 @@ internal final class NetworkInstrumentationFeature: DatadogFeature {
9191
delegateClass: configuration.delegateClass,
9292
interceptDidFinishCollecting: { [weak self] session, task, metrics in
9393
self?.task(task, didFinishCollecting: metrics)
94-
95-
if #available(iOS 15, tvOS 15, *) {
96-
// iOS 15 and above, didCompleteWithError is not called hence we use task state to detect task completion
97-
// while prior to iOS 15, task state doesn't change to completed hence we use didCompleteWithError to detect task completion
98-
self?.task(task, didCompleteWithError: task.error)
99-
}
10094
},
10195
interceptDidCompleteWithError: { [weak self] session, task, error in
102-
self?.task(task, didCompleteWithError: error)
96+
self?.task(task, data: nil, didCompleteWithError: error)
10397
}
10498
)
10599

@@ -111,8 +105,8 @@ internal final class NetworkInstrumentationFeature: DatadogFeature {
111105
)
112106

113107
try swizzler.swizzle(
114-
interceptCompletionHandler: { [weak self] task, _, error in
115-
self?.task(task, didCompleteWithError: error)
108+
interceptCompletionHandler: { [weak self] task, data, error in
109+
self?.task(task, data: data, didCompleteWithError: error)
116110
}
117111
)
118112
}
@@ -231,12 +225,16 @@ extension NetworkInstrumentationFeature {
231225
/// - Parameters:
232226
/// - task: The task that has finished transferring data.
233227
/// - error: If an error occurred, an error object indicating how the transfer failed, otherwise NULL.
234-
func task(_ task: URLSessionTask, didCompleteWithError error: Error?) {
235-
queue.async { [weak self] in
228+
func task(_ task: URLSessionTask, data: Data?, didCompleteWithError error: Error?) {
229+
queue.async { [weak self, data] in
236230
guard let self = self, let interception = self.interceptions[task] else {
237231
return
238232
}
239233

234+
if let data = data {
235+
self.interceptions[task]?.register(nextData: data)
236+
}
237+
240238
interception.register(
241239
response: task.response,
242240
error: error

DatadogInternal/Sources/NetworkInstrumentation/URLSession/URLSessionInterceptor.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,6 @@ public struct URLSessionInterceptor {
7070
/// - task: The task that has finished transferring data.
7171
/// - error: If an error occurred, an error object indicating how the transfer failed, otherwise NULL.
7272
public func task(_ task: URLSessionTask, didCompleteWithError error: Error?) {
73-
feature.task(task, didCompleteWithError: error)
73+
feature.task(task, data: nil, didCompleteWithError: error)
7474
}
7575
}

DatadogInternal/Tests/NetworkInstrumentation/NetworkInstrumentationFeatureTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -703,7 +703,7 @@ class NetworkInstrumentationFeatureTests: XCTestCase {
703703
{ feature.intercept(task: tasks.randomElement()!, additionalFirstPartyHosts: nil) },
704704
{ feature.task(tasks.randomElement()!, didReceive: .mockRandom()) },
705705
{ feature.task(tasks.randomElement()!, didFinishCollecting: .mockAny()) },
706-
{ feature.task(tasks.randomElement()!, didCompleteWithError: nil) },
706+
{ feature.task(tasks.randomElement()!, data: nil, didCompleteWithError: nil) },
707707
{ try? feature.bind(configuration: .init(delegateClass: MockDelegate.self)) },
708708
{ feature.unbind(delegateClass: MockDelegate.self) }
709709
],

0 commit comments

Comments
 (0)