Skip to content

Commit 11826f1

Browse files
authored
Firelog events (#7404)
* Restores ML Pods after M77. * Fix Package.swift * Re-add catalyst to GHA workflow. * Firelog 1/2 * More Firelog + fix sdk version. * Fix whitespace in proto.
1 parent bcc5d82 commit 11826f1

10 files changed

+606
-166
lines changed

FirebaseMLModelDownloader/Sources/DeviceLogger.swift

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ enum LoggerMessageCode: Int {
3131
case localModelFound
3232
case backgroundModelDownloaded
3333
case modelNameParseError
34-
case localModelInfoRetrievalError
34+
case noLocalModelInfo
3535
case outdatedModelPathError
3636
case allLocalModelsFound
3737
case listModelsError
@@ -43,12 +43,24 @@ enum LoggerMessageCode: Int {
4343
case invalidModelName
4444
case permissionDenied
4545
case notEnoughSpace
46-
case validModelDownloadResponse
46+
case validHTTPResponse
47+
case invalidModelInfoFetchURL
48+
case modelInfoRetrievalError
49+
case validAuthToken
4750
case hostnameError
4851
case invalidDownloadSessionError
49-
case invalidResponseError
52+
case invalidHTTPResponse
53+
case missingModelHash
54+
case invalidModelInfoJSON
55+
case modelInfoDeleted
56+
case modelInfoDownloaded
57+
case modelInfoUnmodified
58+
case authTokenError
59+
case expiredModelInfo
5060
case modelDownloadError
5161
case downloadedModelSaveError
62+
case modelHashMismatchError
63+
case noModelHash
5264
case analyticsEventEncodeError
5365
case telemetryInitError
5466
case backgroundDownloadError

FirebaseMLModelDownloader/Sources/FileDownloader.swift

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import Foundation
1616

1717
enum FileDownloaderError: Error {
18-
case sessionInvalidated(Error)
1918
case unexpectedResponseType
2019
case networkError(Error)
2120
}
@@ -83,6 +82,7 @@ extension ModelFileDownloader: URLSessionDownloadDelegate {
8382
/// Handle client-side errors.
8483
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
8584
guard let error = error else { return }
85+
session.finishTasksAndInvalidate()
8686
/// Unable to resolve hostname or connect to host.
8787
completion?(.failure(FileDownloaderError.networkError(error)))
8888
}
@@ -96,6 +96,7 @@ extension ModelFileDownloader: URLSessionDownloadDelegate {
9696
return
9797
}
9898
let downloaderResponse = FileDownloaderResponse(urlResponse: urlResponse, fileURL: location)
99+
session.finishTasksAndInvalidate()
99100
completion?(.success(downloaderResponse))
100101
}
101102

@@ -106,14 +107,4 @@ extension ModelFileDownloader: URLSessionDownloadDelegate {
106107
totalBytesExpectedToWrite: Int64) {
107108
progressHandler?(totalBytesWritten, totalBytesExpectedToWrite)
108109
}
109-
110-
func urlSession(_ session: URLSession, taskIsWaitingForConnectivity task: URLSessionTask) {
111-
// TODO: Handle waiting for connectivity, if needed.
112-
}
113-
114-
func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {
115-
guard let error = error else { return }
116-
/// Unable to resolve hostname or connect to host.
117-
completion?(.failure(FileDownloaderError.sessionInvalidated(error)))
118-
}
119110
}

FirebaseMLModelDownloader/Sources/ModelDownloadTask.swift

Lines changed: 108 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,16 @@ import FirebaseCore
1919
enum ModelDownloadStatus {
2020
case notStarted
2121
case inProgress
22-
case successful
23-
case failed
22+
case complete
23+
}
24+
25+
/// Download error codes.
26+
enum ModelDownloadErrorCode {
27+
case noError
28+
case urlExpired
29+
case noConnection
30+
case downloadFailed
31+
case httpError(code: Int)
2432
}
2533

2634
/// Manager to handle model downloading device and storing downloaded model info to persistent storage.
@@ -64,13 +72,19 @@ extension ModelDownloadTask {
6472
func download(progressHandler: ProgressHandler?, completion: @escaping Completion) {
6573
/// Prevent multiple concurrent downloads.
6674
guard downloadStatus == .notStarted else {
67-
completion(.failure(.internalError(description: ModelDownloadTask.ErrorDescription
68-
.anotherDownloadInProgress)))
6975
DeviceLogger.logEvent(level: .debug,
7076
message: ModelDownloadTask.ErrorDescription.anotherDownloadInProgress,
7177
messageCode: .anotherDownloadInProgressError)
78+
telemetryLogger?.logModelDownloadEvent(eventName: .modelDownload,
79+
status: .failed,
80+
downloadErrorCode: .downloadFailed)
81+
completion(.failure(.internalError(description: ModelDownloadTask.ErrorDescription
82+
.anotherDownloadInProgress)))
7283
return
7384
}
85+
telemetryLogger?.logModelDownloadEvent(eventName: .modelDownload,
86+
status: .downloading,
87+
downloadErrorCode: .noError)
7488
downloader.downloadFile(with: remoteModelInfo.downloadURL,
7589
progressHandler: { downloadedBytes, totalBytes in
7690
/// Fraction of model file downloaded.
@@ -82,7 +96,7 @@ extension ModelDownloadTask {
8296
DeviceLogger.logEvent(level: .debug,
8397
message: ModelDownloadTask.DebugDescription
8498
.receivedServerResponse,
85-
messageCode: .validModelDownloadResponse)
99+
messageCode: .validHTTPResponse)
86100
self.handleResponse(
87101
response: response.urlResponse,
88102
tempURL: response.fileURL,
@@ -98,25 +112,33 @@ extension ModelDownloadTask {
98112
DeviceLogger.logEvent(level: .debug,
99113
message: description,
100114
messageCode: .hostnameError)
101-
// TODO: Handle this case better.
102-
case FileDownloaderError.sessionInvalidated:
103-
downloadError = .failedPrecondition
104-
DeviceLogger.logEvent(level: .debug,
105-
message: ModelDownloadTask.ErrorDescription.sessionInvalidated,
106-
messageCode: .invalidDownloadSessionError)
115+
self.telemetryLogger?.logModelDownloadEvent(
116+
eventName: .modelDownload,
117+
status: .failed,
118+
downloadErrorCode: .noConnection
119+
)
107120
case FileDownloaderError.unexpectedResponseType:
108-
let description = ModelDownloadTask.ErrorDescription.invalidServerResponse
121+
let description = ModelDownloadTask.ErrorDescription.invalidHTTPResponse
109122
downloadError = .internalError(description: description)
110123
DeviceLogger.logEvent(level: .debug,
111124
message: description,
112-
messageCode: .invalidResponseError)
113-
125+
messageCode: .invalidHTTPResponse)
126+
self.telemetryLogger?.logModelDownloadEvent(
127+
eventName: .modelDownload,
128+
status: .failed,
129+
downloadErrorCode: .downloadFailed
130+
)
114131
default:
115132
let description = ModelDownloadTask.ErrorDescription.unknownDownloadError
116133
downloadError = .internalError(description: description)
117134
DeviceLogger.logEvent(level: .debug,
118135
message: description,
119136
messageCode: .modelDownloadError)
137+
self.telemetryLogger?.logModelDownloadEvent(
138+
eventName: .modelDownload,
139+
status: .failed,
140+
downloadErrorCode: .downloadFailed
141+
)
120142
}
121143
completion(.failure(downloadError))
122144
}
@@ -125,22 +147,67 @@ extension ModelDownloadTask {
125147

126148
/// Handle model download response.
127149
func handleResponse(response: HTTPURLResponse, tempURL: URL, completion: @escaping Completion) {
150+
downloadStatus = .complete
128151
guard (200 ..< 299).contains(response.statusCode) else {
129152
switch response.statusCode {
130153
/// Possible failure due to download URL expiry.
131154
case 400:
132155
let currentDateTime = Date()
133156
/// Check if download url has expired.
134157
guard currentDateTime > remoteModelInfo.urlExpiryTime else {
158+
DeviceLogger.logEvent(level: .debug,
159+
message: ModelDownloadTask.ErrorDescription
160+
.invalidModelName(remoteModelInfo.name),
161+
messageCode: .invalidModelName)
162+
telemetryLogger?.logModelDownloadEvent(
163+
eventName: .modelDownload,
164+
status: .failed,
165+
downloadErrorCode: .httpError(code: response.statusCode)
166+
)
135167
completion(.failure(.invalidArgument))
136168
return
137169
}
170+
DeviceLogger.logEvent(level: .debug,
171+
message: ModelDownloadTask.ErrorDescription.expiredModelInfo,
172+
messageCode: .expiredModelInfo)
173+
telemetryLogger?.logModelDownloadEvent(
174+
eventName: .modelDownload,
175+
status: .failed,
176+
downloadErrorCode: .urlExpired
177+
)
138178
completion(.failure(.expiredDownloadURL))
139-
case 401, 403: completion(.failure(.permissionDenied))
140-
case 404: completion(.failure(.notFound))
179+
case 401, 403:
180+
DeviceLogger.logEvent(level: .debug,
181+
message: ModelDownloadTask.ErrorDescription.permissionDenied,
182+
messageCode: .permissionDenied)
183+
telemetryLogger?.logModelDownloadEvent(
184+
eventName: .modelDownload,
185+
status: .failed,
186+
downloadErrorCode: .httpError(code: response.statusCode)
187+
)
188+
completion(.failure(.permissionDenied))
189+
case 404:
190+
DeviceLogger.logEvent(level: .debug,
191+
message: ModelDownloadTask.ErrorDescription
192+
.modelNotFound(remoteModelInfo.name),
193+
messageCode: .modelNotFound)
194+
telemetryLogger?.logModelDownloadEvent(
195+
eventName: .modelDownload,
196+
status: .failed,
197+
downloadErrorCode: .httpError(code: response.statusCode)
198+
)
199+
completion(.failure(.notFound))
141200
default:
142201
let description = ModelDownloadTask.ErrorDescription
143202
.modelDownloadFailed(response.statusCode)
203+
DeviceLogger.logEvent(level: .debug,
204+
message: description,
205+
messageCode: .modelDownloadError)
206+
telemetryLogger?.logModelDownloadEvent(
207+
eventName: .modelDownload,
208+
status: .failed,
209+
downloadErrorCode: .httpError(code: response.statusCode)
210+
)
144211
completion(.failure(.internalError(description: description)))
145212
}
146213
return
@@ -169,16 +236,17 @@ extension ModelDownloadTask {
169236
messageCode: .downloadedModelInfoSaved)
170237
/// Build model from model info.
171238
let model = CustomModel(localModelInfo: localModelInfo)
172-
downloadStatus = .successful
239+
DeviceLogger.logEvent(level: .debug,
240+
message: ModelDownloadTask.DebugDescription.modelDownloaded,
241+
messageCode: .modelDownloaded)
173242
telemetryLogger?.logModelDownloadEvent(
174243
eventName: .modelDownload,
175-
status: downloadStatus,
176-
model: model
244+
status: .succeeded,
245+
model: model,
246+
downloadErrorCode: .noError
177247
)
178248
completion(.success(model))
179249
} catch let error as DownloadError {
180-
downloadStatus = .failed
181-
telemetryLogger?.logModelDownloadEvent(eventName: .modelDownload, status: downloadStatus)
182250
if error == .notEnoughSpace {
183251
DeviceLogger.logEvent(level: .debug,
184252
message: ModelDownloadTask.ErrorDescription.notEnoughSpace,
@@ -188,14 +256,18 @@ extension ModelDownloadTask {
188256
message: ModelDownloadTask.ErrorDescription.saveModel,
189257
messageCode: .downloadedModelSaveError)
190258
}
259+
telemetryLogger?.logModelDownloadEvent(eventName: .modelDownload,
260+
status: .succeeded,
261+
downloadErrorCode: .downloadFailed)
191262
completion(.failure(error))
192263
return
193264
} catch {
194-
downloadStatus = .failed
195-
telemetryLogger?.logModelDownloadEvent(eventName: .modelDownload, status: downloadStatus)
196265
DeviceLogger.logEvent(level: .debug,
197266
message: ModelDownloadTask.ErrorDescription.saveModel,
198267
messageCode: .downloadedModelSaveError)
268+
telemetryLogger?.logModelDownloadEvent(eventName: .modelDownload,
269+
status: .succeeded,
270+
downloadErrorCode: .downloadFailed)
199271
completion(.failure(.internalError(description: error.localizedDescription)))
200272
return
201273
}
@@ -208,7 +280,8 @@ extension ModelDownloadTask {
208280
private enum DebugDescription {
209281
static let savedModelFile = "Model file saved successfully to device."
210282
static let savedLocalModelInfo = "Downloaded model info saved successfully to user defaults."
211-
static let receivedServerResponse = "Received a valid response from server."
283+
static let receivedServerResponse = "Received a valid response from download server."
284+
static let modelDownloaded = "Model download completed successfully."
212285
}
213286

214287
/// Error descriptions.
@@ -221,13 +294,22 @@ extension ModelDownloadTask {
221294
"Model download failed with HTTP error code: \(code)"
222295
}
223296

297+
static let modelNotFound = { (name: String) in
298+
"No model found with name: \(name)"
299+
}
300+
301+
static let invalidModelName = { (name: String) in
302+
"Invalid model name: \(name)"
303+
}
304+
224305
static let sessionInvalidated = "Session invalidated due to failed pre-conditions."
225-
static let invalidServerResponse =
226-
"Could not get valid server response for model downloading."
306+
static let invalidHTTPResponse =
307+
"Could not get valid HTTP response for model downloading."
227308
static let unknownDownloadError = "Unable to download model due to unknown error."
228309
static let saveModel = "Unable to save downloaded remote model file."
229310
static let notEnoughSpace = "Not enough space on device."
230311
static let expiredModelInfo = "Unable to update expired model info."
231312
static let anotherDownloadInProgress = "Download already in progress."
313+
static let permissionDenied = "Invalid or missing permissions to download model."
232314
}
233315
}

0 commit comments

Comments
 (0)