Update swift logging

This commit is contained in:
Balazs Perlaki-Horvath 2025-09-21 23:02:12 +02:00
parent 83ef29630e
commit 9d5dc55c2e
9 changed files with 55 additions and 68 deletions

View File

@ -106,7 +106,7 @@ enum Config: String {
static func value<T>(for key: Config) -> T? where T: LosslessStringConvertible { static func value<T>(for key: Config) -> T? where T: LosslessStringConvertible {
guard let object = Bundle.main.object(forInfoDictionaryKey: key.rawValue) else { guard let object = Bundle.main.object(forInfoDictionaryKey: key.rawValue) else {
os_log("Missing key from bundle: %@", log: Log.Branding, type: .error, key.rawValue) Log.Branding.info("Missing key from bundle: \(key.rawValue, privacy: .public)")
return nil return nil
} }
switch object { switch object {
@ -116,7 +116,7 @@ enum Config: String {
guard let value = T(string) else { fallthrough } guard let value = T(string) else { fallthrough }
return value return value
default: default:
os_log("Invalid value type found for key: %@", log: Log.Branding, type: .error, key.rawValue) Log.Branding.error("Invalid value type found for key: \(key.rawValue, privacy: .public)")
return nil return nil
} }
} }

View File

@ -146,12 +146,8 @@ final class DownloadService: NSObject, URLSessionDelegate, URLSessionTaskDelegat
context.delete(downloadTask) context.delete(downloadTask)
try context.save() try context.save()
} catch { } catch {
os_log( Log.DownloadService.error(
"Error deleting download task. Error: %s", "Error deleting download task for zimFile: \(zimFileID.uuidString, privacy: .public). Error: \(error.localizedDescription, privacy: .public)")
log: Log.DownloadService,
type: .error,
error.localizedDescription
)
} }
} }
} }
@ -192,20 +188,12 @@ final class DownloadService: NSObject, URLSessionDelegate, URLSessionTaskDelegat
// and the status code is in the 200 < 300 range // and the status code is in the 200 < 300 range
guard let error = error as NSError? else { guard let error = error as NSError? else {
if (200..<300).contains(httpResponse.statusCode) { if (200..<300).contains(httpResponse.statusCode) {
os_log( Log.DownloadService.info(
"Download finished successfully. File ID: %s.", "Download finished successfully. File ID: \(zimFileID.uuidString, privacy: .public)",
log: Log.DownloadService,
type: .info,
zimFileID.uuidString
) )
} else { } else {
os_log( Log.DownloadService.info(
"Download was unsuccessful. File ID: %s. status code: %i", "Download was unsuccessful. File ID: \(zimFileID.uuidString, privacy: .public). status code: \(httpResponse.statusCode, privacy: .public)")
log: Log.DownloadService,
type: .info,
zimFileID.uuidString,
httpResponse.statusCode
)
self.deleteDownloadTask(zimFileID: zimFileID) self.deleteDownloadTask(zimFileID: zimFileID)
} }
return return
@ -230,13 +218,7 @@ final class DownloadService: NSObject, URLSessionDelegate, URLSessionTaskDelegat
try? context.save() try? context.save()
} }
} }
os_log( Log.DownloadService.error("Download finished for File ID: \(zimFileID.uuidString, privacy: .public). with: \(error.localizedDescription, privacy: .public)")
"Download finished for File ID: %s. with: %s",
log: Log.DownloadService,
type: .error,
zimFileID.uuidString,
error.localizedDescription
)
} }
// MARK: - URLSessionDownloadDelegate // MARK: - URLSessionDownloadDelegate
@ -261,6 +243,7 @@ final class DownloadService: NSObject, URLSessionDelegate, URLSessionTaskDelegat
guard let httpResponse = downloadTask.response as? HTTPURLResponse else { return } guard let httpResponse = downloadTask.response as? HTTPURLResponse else { return }
guard (200..<300).contains(httpResponse.statusCode) else { guard (200..<300).contains(httpResponse.statusCode) else {
Log.DownloadService.error("Download didFinish failed with http status for: \(downloadTask.taskIdentifier.description, privacy: .public), httpStatusCode: \(httpResponse.statusCode, privacy: .public)")
Task { @MainActor in Task { @MainActor in
NotificationCenter.default.post( NotificationCenter.default.post(
name: .alert, name: .alert,
@ -279,17 +262,27 @@ final class DownloadService: NSObject, URLSessionDelegate, URLSessionTaskDelegat
#endif #endif
// move file // move file
guard let directory = FileManager.default.urls(for: searchPath, in: .userDomainMask).first, guard let directory = FileManager.default.urls(for: searchPath, in: .userDomainMask).first else {
let zimFileID = UUID(uuidString: downloadTask.taskDescription ?? "") else { return } Log.DownloadService.fault("Cannot find download directory!! downloadTask: \(downloadTask.taskDescription ?? "", privacy: .public)")
return
}
guard let zimFileID = UUID(uuidString: downloadTask.taskDescription ?? "") else {
Log.DownloadService.fault("Cannot convert downloadTask to zimFileID: \(downloadTask.taskDescription ?? "", privacy: .public)")
return
}
let fileName = downloadTask.response?.suggestedFilename let fileName = downloadTask.response?.suggestedFilename
?? downloadTask.originalRequest?.url?.lastPathComponent ?? downloadTask.originalRequest?.url?.lastPathComponent
?? zimFileID.uuidString + ".zim" ?? zimFileID.uuidString + ".zim"
let destination = directory.appendingPathComponent(fileName) let destination = directory.appendingPathComponent(fileName)
Log.DownloadService.info("Start moving downloaded zimFile: \(fileName, privacy: .public), zimFileID: \(zimFileID.uuidString, privacy: .public)")
try? FileManager.default.moveItem(at: location, to: destination) try? FileManager.default.moveItem(at: location, to: destination)
Log.DownloadService.info("Completed moving downloaded zimFile: \(zimFileID.uuidString, privacy: .public)")
// open the file // open the file
Task { @ZimActor in Task { @ZimActor in
Log.DownloadService.info("start opening downloaded zimFile: \(zimFileID.uuidString, privacy: .public)")
await LibraryOperations.open(url: destination) await LibraryOperations.open(url: destination)
Log.DownloadService.info("opened downloaded zimFile: \(zimFileID.uuidString, privacy: .public)")
// schedule notification // schedule notification
scheduleDownloadCompleteNotification(zimFileID: zimFileID) scheduleDownloadCompleteNotification(zimFileID: zimFileID)
deleteDownloadTask(zimFileID: zimFileID) deleteDownloadTask(zimFileID: zimFileID)

View File

@ -183,9 +183,9 @@ struct Payment {
phase: PayWithApplePayButtonPaymentAuthorizationPhase) { phase: PayWithApplePayButtonPaymentAuthorizationPhase) {
switch phase { switch phase {
case .willAuthorize: case .willAuthorize:
os_log("onPaymentAuthPhase: .willAuthorize") Log.Payment.info("onPaymentAuthPhase: .willAuthorize")
case .didAuthorize(let payment, let resultHandler): case .didAuthorize(let payment, let resultHandler):
os_log("onPaymentAuthPhase: .didAuthorize") Log.Payment.info("onPaymentAuthPhase: .didAuthorize")
// call our server to get payment / setup intent and return the client.secret // call our server to get payment / setup intent and return the client.secret
Task { @MainActor [resultHandler] in Task { @MainActor [resultHandler] in
let paymentServer = StripeKiwix(endPoint: Self.kiwixPaymentServer, let paymentServer = StripeKiwix(endPoint: Self.kiwixPaymentServer,
@ -218,13 +218,13 @@ struct Payment {
Self.finalResult = nil Self.finalResult = nil
} }
resultHandler(result) resultHandler(result)
os_log("onPaymentAuthPhase: .didAuthorize: \(result.status == .success)") Log.Payment.info("onPaymentAuthPhase: .didAuthorize: \(result.status == .success, privacy: .public)")
} }
case .didFinish: case .didFinish:
os_log("onPaymentAuthPhase: .didFinish") Log.Payment.info("onPaymentAuthPhase: .didFinish")
completeSubject.send(()) completeSubject.send(())
@unknown default: @unknown default:
os_log("onPaymentAuthPhase: @unknown default") Log.Payment.error("onPaymentAuthPhase: @unknown default")
} }
} }

View File

@ -76,12 +76,12 @@ struct StripeKiwix {
throw StripeError.serverError throw StripeError.serverError
} }
guard let dictionary = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else { guard let dictionary = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
os_log("Merchant session not established: unable to decode server response", type: .debug) Log.Payment.error("Merchant session not established: unable to decode server response")
return nil return nil
} }
return PKPaymentMerchantSession(dictionary: dictionary) return PKPaymentMerchantSession(dictionary: dictionary)
} catch let serverError { } catch let serverError {
os_log("Merchant session not established: %@", type: .debug, serverError.localizedDescription) Log.Payment.error("Merchant session not established: \(serverError.localizedDescription, privacy: .public)")
return nil return nil
} }
} }

View File

@ -18,11 +18,12 @@ import os
private let subsystem = "org.kiwix.kiwix" private let subsystem = "org.kiwix.kiwix"
struct Log { struct Log {
static let DownloadService = OSLog(subsystem: subsystem, category: "DownloadService") static let DownloadService = Logger(subsystem: subsystem, category: "DownloadService")
static let FaviconDownloadService = OSLog(subsystem: subsystem, category: "FaviconDownloadService") static let FaviconDownloadService = Logger(subsystem: subsystem, category: "FaviconDownloadService")
static let LibraryService = OSLog(subsystem: subsystem, category: "LibraryService") static let LibraryOperations = Logger(subsystem: subsystem, category: "LibraryOperations")
static let LibraryOperations = OSLog(subsystem: subsystem, category: "LibraryOperations") static let QRCode = Logger(subsystem: subsystem, category: "QRCode")
static let OPDS = OSLog(subsystem: subsystem, category: "OPDS") static let OPDS = Logger(subsystem: subsystem, category: "OPDS")
static let URLSchemeHandler = OSLog(subsystem: subsystem, category: "URLSchemeHandler") static let URLSchemeHandler = Logger(subsystem: subsystem, category: "URLSchemeHandler")
static let Branding = OSLog(subsystem: subsystem, category: "Branding") static let Branding = Logger(subsystem: subsystem, category: "Branding")
static let Payment = Logger(subsystem: subsystem, category: "Payment")
} }

View File

@ -22,7 +22,7 @@ struct QRCode {
static func image(from text: String) async -> CGImage? { static func image(from text: String) async -> CGImage? {
let data = Data(text.utf8) let data = Data(text.utf8)
guard let filter = CIFilter(name: "CIQRCodeGenerator") else { guard let filter = CIFilter(name: "CIQRCodeGenerator") else {
os_log("QRCode cannot create CIFilter", log: Log.LibraryService, type: .error) Log.QRCode.error("QRCode cannot create CIFilter")
return nil return nil
} }
filter.setValue(data, forKey: "inputMessage") filter.setValue(data, forKey: "inputMessage")
@ -31,7 +31,7 @@ struct QRCode {
let transform = CGAffineTransform(scaleX: 20, y: 20) let transform = CGAffineTransform(scaleX: 20, y: 20)
guard let outputImage = filter.outputImage?.transformed(by: transform), guard let outputImage = filter.outputImage?.transformed(by: transform),
let image = context.createCGImage(outputImage, from: outputImage.extent.insetBy(dx: 20, dy: 20)) else { let image = context.createCGImage(outputImage, from: outputImage.extent.insetBy(dx: 20, dy: 20)) else {
os_log("QRCode cannot create image", log: Log.LibraryService, type: .error) Log.QRCode.error("QRCode cannot create image")
return nil return nil
} }
return image return image

View File

@ -91,7 +91,7 @@ struct LibraryOperations {
try? context.save() try? context.save()
} }
} }
os_log("Reopened %d out of %d zim files", log: Log.LibraryOperations, type: .info, successCount, zimFiles.count) Log.LibraryOperations.info("Reopened \(successCount, privacy: .public) out of \(zimFiles.count, privacy: .public) zim files")
} }
/// Scan a directory and open available zim files inside it /// Scan a directory and open available zim files inside it
@ -102,7 +102,7 @@ struct LibraryOperations {
includingPropertiesForKeys: nil, includingPropertiesForKeys: nil,
options: [.skipsHiddenFiles, .skipsPackageDescendants, .skipsSubdirectoryDescendants] options: [.skipsHiddenFiles, .skipsPackageDescendants, .skipsSubdirectoryDescendants]
).filter({ $0.pathExtension == "zim"}) else { return } ).filter({ $0.pathExtension == "zim"}) else { return }
os_log("Discovered %d probable zim files.", log: Log.LibraryOperations, type: .info, fileURLs.count) Log.LibraryOperations.info("Discovered \(fileURLs.count, privacy: .public) probable zim files.")
Task { Task {
for fileURL in fileURLs { for fileURL in fileURLs {
await LibraryOperations.open(url: fileURL) await LibraryOperations.open(url: fileURL)
@ -207,13 +207,10 @@ struct LibraryOperations {
var url = url var url = url
try url.setResourceValues(resourceValues) try url.setResourceValues(resourceValues)
} }
os_log( let status = backupDocumentDirectory ? "backing up" : "not backing up"
"Applying zim file backup setting (%s) on %u zim file(s).", Log.LibraryOperations.info("Applying zim file backup setting (\(status, privacy: .public)) on \(urls.count, privacy: .public) zim file(s).")
log: Log.LibraryOperations, } catch {
type: .info, Log.LibraryOperations.error("Unable to change iCloud backup settings, due to \(error.localizedDescription, privacy: .public)")
backupDocumentDirectory ? "backing up" : "not backing up", }
urls.count
)
} catch {}
} }
} }

View File

@ -445,13 +445,7 @@ final class BrowserViewModel: NSObject, ObservableObject,
return .cancel return .cancel
} else if url.isZIMURL { } else if url.isZIMURL {
guard await ZimFileService.shared.getContentSize(url: url) != nil else { guard await ZimFileService.shared.getContentSize(url: url) != nil else {
os_log( Log.URLSchemeHandler.error("Missing content at url: \(url.absoluteString, privacy: .public) => \(url.contentPath, privacy: .public)")
"Missing content at url: %@ => %@",
log: Log.URLSchemeHandler,
type: .error,
url.absoluteString,
url.contentPath
)
if navigationAction.request.mainDocumentURL == url { if navigationAction.request.mainDocumentURL == url {
// only show alerts for missing main document // only show alerts for missing main document
NotificationCenter.default.post( NotificationCenter.default.post(

View File

@ -204,8 +204,10 @@ final class LibraryViewModel: ObservableObject {
process.state = .complete process.state = .complete
// logging // logging
os_log("Refresh finished -- addition: %d, deletion: %d, total: %d", let insertedCount = insertionCount
log: Log.OPDS, type: .default, insertionCount, deletionCount, parser.zimFileIDs.count) let deletedCount = deletionCount
let totalCount = parser.zimFileIDs.count
Log.OPDS.notice("Refresh finished -- insertion: \(insertedCount, privacy: .public), deletion: \(deletedCount, privacy: .public), total: \(totalCount, privacy: .public)")
} catch { } catch {
self.error = error self.error = error
process.state = .error process.state = .error
@ -291,7 +293,7 @@ final class LibraryViewModel: ObservableObject {
defaults[.libraryETag] = eTag defaults[.libraryETag] = eTag
} }
// OK to process further // OK to process further
os_log("Retrieved OPDS Data, size: %llu bytes", log: Log.OPDS, type: .info, data.count) Log.OPDS.debug("Retrieved OPDS Data, size: \(data.count, format: .byteCount, privacy: .public) bytes")
return (data, responseURL) return (data, responseURL)
case 304: case 304:
return nil // already downloaded return nil // already downloaded
@ -299,7 +301,7 @@ final class LibraryViewModel: ObservableObject {
throw LibraryRefreshError.retrieve(description: "HTTP Status \(response.statusCode).") throw LibraryRefreshError.retrieve(description: "HTTP Status \(response.statusCode).")
} }
} catch { } catch {
os_log("Error retrieving OPDS Data: %s", log: Log.OPDS, type: .error, error.localizedDescription) Log.OPDS.error("Error retrieving OPDS Data: \(error.localizedDescription, privacy: .public)")
if let error = error as? LibraryRefreshError { if let error = error as? LibraryRefreshError {
throw error throw error
} else { } else {
@ -349,7 +351,7 @@ final class LibraryViewModel: ObservableObject {
continuation.resume() continuation.resume()
} catch { } catch {
os_log("Error saving OPDS Data: %s", log: Log.OPDS, type: .error, error.localizedDescription) Log.OPDS.error("Error saving OPDS Data: \(error.localizedDescription, privacy: .public)")
continuation.resume(throwing: LibraryRefreshError.process) continuation.resume(throwing: LibraryRefreshError.process)
} }
} }