Skip to content

Commit 459e227

Browse files
committed
feat(network-details): Add NetworkRequestData -> breadcrumb -> RRBWebEvent
Add populated NetworkRequestData to breadcrumb data SentryNetworkTracker#addBreadcrumbForSessionTask Read NetworkRequestData from breadcrumb when converting for session replay SentrySRDefaultBreadcrumbConverter
1 parent d5a8320 commit 459e227

2 files changed

Lines changed: 68 additions & 0 deletions

File tree

Sources/Sentry/SentryNetworkTracker.m

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,15 @@ - (void)addBreadcrumbForSessionTask:(NSURLSessionTask *)sessionTask
478478
breadcrumbData[@"http.fragment"] = urlComponents.fragment;
479479
}
480480

481+
// Add network details if available for session replay
482+
SentryReplayNetworkDetails *networkDetails
483+
= objc_getAssociatedObject(sessionTask, &SentryNetworkDetailsKey);
484+
if (networkDetails) {
485+
breadcrumbData[SentryReplayNetworkDetails.replayNetworkDetailsKey] = networkDetails;
486+
SENTRY_LOG_DEBUG(@"[NetworkCapture] Added network details to breadcrumb: %@",
487+
[networkDetails description]);
488+
}
489+
481490
breadcrumb.data = breadcrumbData;
482491
[SentrySDK addBreadcrumb:breadcrumb];
483492

Sources/Swift/Integrations/SessionReplay/SentrySRDefaultBreadcrumbConverter.swift

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,67 @@ import Foundation
8080
data[newKey.snakeToCamelCase()] = value
8181
})
8282

83+
// Add Network Details data when available
84+
if let networkRequestData = breadcrumb.data?["_networkDetails"] as? SentryReplayNetworkDetails {
85+
addNetworkDetails(from: networkRequestData, to: &data)
86+
}
87+
8388
//We dont have end of the request in the breadcrumb.
8489
return SentryRRWebSpanEvent(timestamp: startTimestamp, endTimestamp: timestamp, operation: "resource.http", description: description, data: data)
8590
}
91+
92+
private func addNetworkDetails(from networkRequestData: SentryReplayNetworkDetails, to data: inout [String: Any]) {
93+
let networkData = networkRequestData.serialize()
94+
95+
// Add top-level network metadata
96+
if let method = networkData["method"] as? String {
97+
data["method"] = method
98+
}
99+
if let statusCode = networkData["statusCode"] as? NSNumber {
100+
data["statusCode"] = statusCode
101+
}
102+
if let requestBodySize = networkData["requestBodySize"] as? NSNumber {
103+
data["requestBodySize"] = requestBodySize
104+
}
105+
if let responseBodySize = networkData["responseBodySize"] as? NSNumber {
106+
data["responseBodySize"] = responseBodySize
107+
}
108+
109+
// Process request and response details using shared logic
110+
if let request = networkData["request"] as? [String: Any] {
111+
if let requestData = processRequestOrResponseData(request), !requestData.isEmpty {
112+
data["request"] = requestData
113+
}
114+
}
115+
116+
if let response = networkData["response"] as? [String: Any] {
117+
if let responseData = processRequestOrResponseData(response), !responseData.isEmpty {
118+
data["response"] = responseData
119+
}
120+
}
121+
}
122+
123+
private func processRequestOrResponseData(_ sourceData: [String: Any]) -> [String: Any]? {
124+
var result = [String: Any]()
125+
126+
if let size = sourceData["size"] as? NSNumber {
127+
result["size"] = size
128+
}
129+
130+
if let body = sourceData["body"] as? [String: Any] {
131+
if let bodyContent = body["body"] {
132+
result["body"] = bodyContent
133+
}
134+
if let warnings = body["warnings"] as? [String], !warnings.isEmpty {
135+
result["_meta"] = ["warnings": warnings]
136+
}
137+
}
138+
139+
if let headers = sourceData["headers"] as? [String: String], !headers.isEmpty {
140+
result["headers"] = headers
141+
}
142+
143+
return result.isEmpty ? nil : result
144+
}
86145
}
87146
// swiftlint:enable missing_docs

0 commit comments

Comments
 (0)