From d9313a16547e04ed486d6080172414db00274706 Mon Sep 17 00:00:00 2001 From: ronaldheft Date: Tue, 6 Sep 2022 21:26:48 -0400 Subject: [PATCH] Use os logging framework, so logs can be retrieved later --- ios/App/App.xcodeproj/project.pbxproj | 4 ++ ios/App/Shared/player/PlayerProgress.swift | 32 ++++----- ios/App/Shared/util/Logger.swift | 76 ++++++++++++++++++++++ 3 files changed, 97 insertions(+), 15 deletions(-) create mode 100644 ios/App/Shared/util/Logger.swift diff --git a/ios/App/App.xcodeproj/project.pbxproj b/ios/App/App.xcodeproj/project.pbxproj index 3c92a7ed..8084e2c9 100644 --- a/ios/App/App.xcodeproj/project.pbxproj +++ b/ios/App/App.xcodeproj/project.pbxproj @@ -60,6 +60,7 @@ E9D5507528AEF93100C746DD /* PlayerSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9D5507428AEF93100C746DD /* PlayerSettings.swift */; }; E9DFCBFB28C28F4A00B36356 /* AudioPlayerSleepTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9DFCBFA28C28F4A00B36356 /* AudioPlayerSleepTimer.swift */; }; E9E985F828B02D9400957F23 /* PlayerProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E985F728B02D9400957F23 /* PlayerProgress.swift */; }; + E9FA07E328C82848005520B0 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9FA07E228C82848005520B0 /* Logger.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -120,6 +121,7 @@ E9D5507428AEF93100C746DD /* PlayerSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerSettings.swift; sourceTree = ""; }; E9DFCBFA28C28F4A00B36356 /* AudioPlayerSleepTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayerSleepTimer.swift; sourceTree = ""; }; E9E985F728B02D9400957F23 /* PlayerProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerProgress.swift; sourceTree = ""; }; + E9FA07E228C82848005520B0 /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = ""; }; FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -199,6 +201,7 @@ 3AFCB5E627EA23F700ECCC05 /* util */ = { isa = PBXGroup; children = ( + E9FA07E228C82848005520B0 /* Logger.swift */, 3AFCB5E727EA240D00ECCC05 /* NowPlayingInfo.swift */, 3AD4FCEA280443DD006DB301 /* Database.swift */, 3AD4FCEC28044E6C006DB301 /* Store.swift */, @@ -412,6 +415,7 @@ E9D5506228AC1CC900C746DD /* PlayerState.swift in Sources */, 3AD4FCE728043E72006DB301 /* AbsDatabase.m in Sources */, 504EC3081FED79650016851F /* AppDelegate.swift in Sources */, + E9FA07E328C82848005520B0 /* Logger.swift in Sources */, 3A90295F280968E700E1D427 /* PlaybackReport.swift in Sources */, E9D5505A28AC1C4500C746DD /* Folder.swift in Sources */, 3ABF580928059BAE005DFBE5 /* PlaybackSession.swift in Sources */, diff --git a/ios/App/Shared/player/PlayerProgress.swift b/ios/App/Shared/player/PlayerProgress.swift index c39cce8d..9f4834c9 100644 --- a/ios/App/Shared/player/PlayerProgress.swift +++ b/ios/App/Shared/player/PlayerProgress.swift @@ -14,6 +14,8 @@ class PlayerProgress { private static let TIME_BETWEEN_SESSION_SYNC_IN_SECONDS = 10.0 + private let logger = AppLogger(category: "PlayerProgress") + private init() {} @@ -28,8 +30,8 @@ class PlayerProgress { try await updateServerSessionFromLocalSession(session, rateLimitSync: !isStopping) } } catch { - debugPrint("Failed to syncFromPlayer") - debugPrint(error) + logger.error("Failed to syncFromPlayer") + logger.error(error) } await UIApplication.shared.endBackgroundTask(backgroundToken) } @@ -39,8 +41,8 @@ class PlayerProgress { do { try await updateAllServerSessionFromLocalSession() } catch { - debugPrint("Failed to syncToServer") - debugPrint(error) + logger.error("Failed to syncToServer") + logger.error(error) } await UIApplication.shared.endBackgroundTask(backgroundToken) } @@ -50,8 +52,8 @@ class PlayerProgress { do { try await updateLocalSessionFromServerMediaProgress() } catch { - debugPrint("Failed to syncFromServer") - debugPrint(error) + logger.error("Failed to syncFromServer") + logger.error(error) } await UIApplication.shared.endBackgroundTask(backgroundToken) } @@ -96,7 +98,7 @@ class PlayerProgress { try localMediaProgress.updateFromPlaybackSession(session) - NSLog("Local progress saved to the database") + logger.debug("Local progress saved to the database") // Send the local progress back to front-end NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.localProgress.rawValue), object: nil) @@ -141,7 +143,7 @@ class PlayerProgress { session = session.freeze() guard safeToSync else { return } - NSLog("Sending sessionId(\(session.id)) to server with currentTime(\(session.currentTime))") + logger.debug("Sending sessionId(\(session.id)) to server with currentTime(\(session.currentTime))") var success = false if session.isLocal { @@ -161,25 +163,25 @@ class PlayerProgress { } private func updateLocalSessionFromServerMediaProgress() async throws { - NSLog("updateLocalSessionFromServerMediaProgress: Checking if local media progress was updated on server") + logger.debug("updateLocalSessionFromServerMediaProgress: Checking if local media progress was updated on server") guard let session = try await Realm().objects(PlaybackSession.self).last(where: { $0.isActiveSession == true && $0.serverConnectionConfigId == Store.serverConfig?.id })?.freeze() else { - NSLog("updateLocalSessionFromServerMediaProgress: Failed to get session") + logger.debug("updateLocalSessionFromServerMediaProgress: Failed to get session") return } // Fetch the current progress let progress = await ApiClient.getMediaProgress(libraryItemId: session.libraryItemId!, episodeId: session.episodeId) guard let progress = progress else { - NSLog("updateLocalSessionFromServerMediaProgress: No progress object") + logger.debug("updateLocalSessionFromServerMediaProgress: No progress object") return } // Determine which session is newer let serverLastUpdate = progress.lastUpdate guard let localLastUpdate = session.updatedAt else { - NSLog("updateLocalSessionFromServerMediaProgress: No local session updatedAt") + logger.debug("updateLocalSessionFromServerMediaProgress: No local session updatedAt") return } let serverCurrentTime = progress.currentTime @@ -190,16 +192,16 @@ class PlayerProgress { // Update the session, if needed if serverIsNewerThanLocal && currentTimeIsDifferent { - NSLog("updateLocalSessionFromServerMediaProgress: Server has newer time than local serverLastUpdate=\(serverLastUpdate) localLastUpdate=\(localLastUpdate)") + logger.debug("updateLocalSessionFromServerMediaProgress: Server has newer time than local serverLastUpdate=\(serverLastUpdate) localLastUpdate=\(localLastUpdate)") guard let session = session.thaw() else { return } try session.update { session.currentTime = serverCurrentTime session.updatedAt = serverLastUpdate } - NSLog("updateLocalSessionFromServerMediaProgress: Updated session currentTime newCurrentTime=\(serverCurrentTime) previousCurrentTime=\(localCurrentTime)") + logger.debug("updateLocalSessionFromServerMediaProgress: Updated session currentTime newCurrentTime=\(serverCurrentTime) previousCurrentTime=\(localCurrentTime)") PlayerHandler.seek(amount: session.currentTime) } else { - NSLog("updateLocalSessionFromServerMediaProgress: Local session does not need updating; local has latest progress") + logger.debug("updateLocalSessionFromServerMediaProgress: Local session does not need updating; local has latest progress") } } diff --git a/ios/App/Shared/util/Logger.swift b/ios/App/Shared/util/Logger.swift new file mode 100644 index 00000000..336f76e9 --- /dev/null +++ b/ios/App/Shared/util/Logger.swift @@ -0,0 +1,76 @@ +// +// AppLogger.swift +// AppLogger +// +// Created by Fernando Fernandes on 29.06.20. +// + +import Foundation +import os + +/// Logs app info by using the newest Swift unified logging APIs. +/// +/// Reference: +/// - [Explore logging in Swift (WWDC20)](https://developer.apple.com/wwdc20/10168) +/// - [Unified Logging](https://developer.apple.com/documentation/os/logging) +/// - [OSLog](https://developer.apple.com/documentation/os/oslog) +/// - [Logger](https://developer.apple.com/documentation/os/logger) +public struct AppLogger { + + // MARK: - Properties + + /// Default values used by the `AppLogger`. + public struct Defaults { + public static let subsystem = Bundle.main.bundleIdentifier ?? "ABS" + public static let category = "default" + public static let isPrivate = false + } + + // MARK: - Private Properties + + private let logger: Logger + + // MARK: - Lifecycle + + /// Creates an `AppLogger` instance. + /// + /// - Parameters: + /// - subsystem: `String`. Organizes large topic areas within the app or apps. For example, you might define + /// a subsystem for each process that you create. The default is `Bundle.main.bundleIdentifier ?? "AppLogger"`. + /// - category: `String`. Within a `subsystem`, you define categories to further distinguish parts of that + /// subsystem. For example, if you used a single subsystem for your app, you might create separate categories for + /// model code and user-interface code. In a game, you might use categories to distinguish between physics, AI, + /// world simulation, and rendering. The default is `default`. + public init(subsystem: String = Defaults.subsystem, category: String = Defaults.category) { + self.logger = Logger(subsystem: subsystem, category: category) + } +} + +// MARK: - Interface + +public extension AppLogger { + + func log(_ information: String, isPrivate: Bool = Defaults.isPrivate) { + if isPrivate { + logger.debug("\(information, privacy: .private)") + } else { + logger.debug("\(information, privacy: .public)") + } + } + + func debug(_ information: String, isPrivate: Bool = Defaults.isPrivate) { + this.log(information, isPrivate) + } + + func error(_ information: String, isPrivate: Bool = Defaults.isPrivate) { + if isPrivate { + logger.error("\(information, privacy: .private)") + } else { + logger.error("\(information, privacy: .public)") + } + } + + func error(_ error: Error) { + logger.error("\(String(describing: error))") + } +}