From 0dd4689bf0b56ada264b8cb61cf145e210850035 Mon Sep 17 00:00:00 2001 From: Stuart Breckenridge Date: Wed, 3 Aug 2022 15:37:12 +0800 Subject: [PATCH 1/4] Logging changes - Adds `Logging` protocol - Moves to Swift-style `OSLog` usage os_log to Logger os_log audit Replacment of os.log with Logging --- Account/Package.swift | 2 +- Account/Sources/Account/Account.swift | 3 - .../Sources/Account/AccountMetadataFile.swift | 9 +-- .../CloudKit/CloudKitAccountDelegate.swift | 29 +++++----- .../CloudKitArticlesZoneDelegate.swift | 19 +++---- .../CloudKitReceiveStatusOperation.swift | 11 ++-- .../CloudKitRemoteNotificationOperation.swift | 12 ++-- .../CloudKitSendStatusOperation.swift | 18 +++--- .../Reddit/RedditFeedProvider.swift | 3 - ...ditFeedProviderTokenRefreshOperation.swift | 8 +-- .../Feedbin/FeedbinAccountDelegate.swift | 56 +++++++++---------- .../LocalAccount/LocalAccountDelegate.swift | 7 +-- Account/Sources/Account/OPMLFile.swift | 13 ++--- .../ReaderAPI/ReaderAPIAccountDelegate.swift | 40 +++++++------ .../Sources/Account/WebFeedMetadataFile.swift | 9 +-- Articles/Package.swift | 2 +- ArticlesDatabase/Package.swift | 2 +- Mac/AppDelegate.swift | 19 +++---- Mac/ErrorHandler.swift | 8 +-- .../Timeline/TimelineViewController.swift | 1 - .../AccountsFeedbinWindowController.swift | 4 +- .../AccountsNewsBlurWindowController.swift | 4 +- .../AccountsReaderAPIWindowController.swift | 4 +- .../AppDelegate+Scriptability.swift | 3 +- Mac/ShareExtension/ShareViewController.swift | 2 - NetNewsWire.xcodeproj/project.pbxproj | 18 ++++++ .../xcshareddata/swiftpm/Package.resolved | 8 +-- Secrets/Package.swift | 2 +- .../Article Extractor/ArticleExtractor.swift | 4 +- .../ArticleThemeDownloader.swift | 6 +- .../ArticleStyles/ArticleThemesManager.swift | 4 +- Shared/Extensions/CacheCleaner.swift | 10 ++-- Shared/Favicons/FaviconDownloader.swift | 4 +- Shared/Favicons/SingleFaviconDownloader.swift | 15 +++-- Shared/Images/ImageDownloader.swift | 13 ++--- .../ExtensionContainersFile.swift | 13 ++--- .../ExtensionFeedAddRequestFile.swift | 16 +++--- Shared/Widget/WidgetDataDecoder.swift | 8 ++- Shared/Widget/WidgetDataEncoder.swift | 13 ++--- SyncDatabase/Package.swift | 2 +- Widget/TimelineProvider.swift | 23 +++++--- .../Widget Views/SmartFeedSummaryWidget.swift | 2 +- .../FeedbinAccountViewController.swift | 8 ++- .../NewsBlurAccountViewController.swift | 8 ++- .../ReaderAPIAccountViewController.swift | 4 +- iOS/AppDelegate.swift | 41 +++++++------- iOS/ErrorHandler.swift | 9 +-- iOS/SceneCoordinator.swift | 3 +- iOS/SceneDelegate.swift | 6 +- iOS/Settings/ArticleThemeImporter.swift | 4 +- .../ArticleThemesTableViewController.swift | 5 +- iOS/Settings/SettingsViewController.swift | 4 +- 52 files changed, 270 insertions(+), 271 deletions(-) diff --git a/Account/Package.swift b/Account/Package.swift index b6bbb5587..e80cec9d3 100644 --- a/Account/Package.swift +++ b/Account/Package.swift @@ -26,7 +26,7 @@ dependencies.append(contentsOf: [ let package = Package( name: "Account", - platforms: [.macOS(SupportedPlatform.MacOSVersion.v10_15), .iOS(SupportedPlatform.IOSVersion.v13)], + platforms: [.macOS(SupportedPlatform.MacOSVersion.v11), .iOS(SupportedPlatform.IOSVersion.v14)], products: [ .library( name: "Account", diff --git a/Account/Sources/Account/Account.swift b/Account/Sources/Account/Account.swift index d490b6d1a..13584afe7 100644 --- a/Account/Sources/Account/Account.swift +++ b/Account/Sources/Account/Account.swift @@ -17,7 +17,6 @@ import RSParser import RSDatabase import ArticlesDatabase import RSWeb -import os.log import Secrets // Main thread only. @@ -91,8 +90,6 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container, return defaultName }() - - var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "account") public var isDeleted = false diff --git a/Account/Sources/Account/AccountMetadataFile.swift b/Account/Sources/Account/AccountMetadataFile.swift index d3bc67d65..4f52d2728 100644 --- a/Account/Sources/Account/AccountMetadataFile.swift +++ b/Account/Sources/Account/AccountMetadataFile.swift @@ -7,12 +7,9 @@ // import Foundation -import os.log import RSCore -final class AccountMetadataFile { - - private var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "accountMetadataFile") +final class AccountMetadataFile: Logging { private let fileURL: URL private let account: Account @@ -50,8 +47,8 @@ final class AccountMetadataFile { do { let data = try encoder.encode(account.metadata) try data.write(to: fileURL) - } catch let error as NSError { - os_log(.error, log: log, "Save to disk failed: %@.", error.localizedDescription) + } catch let error { + logger.error("Save to disk failed: \(error.localizedDescription)") } } diff --git a/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift b/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift index 98baf7565..bcd4689bf 100644 --- a/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift +++ b/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift @@ -9,7 +9,6 @@ import Foundation import CloudKit import SystemConfiguration -import os.log import SyncDatabase import RSCore import RSParser @@ -27,9 +26,7 @@ enum CloudKitAccountDelegateError: LocalizedError { } } -final class CloudKitAccountDelegate: AccountDelegate { - - private var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "CloudKit") +final class CloudKitAccountDelegate: AccountDelegate, Logging { private let database: SyncDatabase @@ -318,10 +315,10 @@ final class CloudKitAccountDelegate: AccountDelegate { for webFeed in webFeeds { group.enter() - self.removeWebFeedFromCloud(for: account, with: webFeed, from: folder) { result in + self.removeWebFeedFromCloud(for: account, with: webFeed, from: folder) { [weak self] result in group.leave() if case .failure(let error) = result { - os_log(.error, log: self.log, "Remove folder, remove webfeed error: %@.", error.localizedDescription) + self?.logger.error("Remove folder, remove webfeed error: \(error.localizedDescription, privacy: .public)") errorOccurred = true } } @@ -380,14 +377,14 @@ final class CloudKitAccountDelegate: AccountDelegate { folder.topLevelWebFeeds.remove(feed) group.enter() - self.restoreWebFeed(for: account, feed: feed, container: folder) { result in - self.refreshProgress.completeTask() + self.restoreWebFeed(for: account, feed: feed, container: folder) { [weak self] result in + self?.refreshProgress.completeTask() group.leave() switch result { case .success: break case .failure(let error): - os_log(.error, log: self.log, "Restore folder feed error: %@.", error.localizedDescription) + self?.logger.error("Restore folder feed error: \(error.localizedDescription, privacy: .public)") } } @@ -437,13 +434,13 @@ final class CloudKitAccountDelegate: AccountDelegate { // Check to see if this is a new account and initialize anything we need if account.externalID == nil { - accountZone.findOrCreateAccount() { result in + accountZone.findOrCreateAccount() { [weak self] result in switch result { case .success(let externalID): account.externalID = externalID - self.initialRefreshAll(for: account) { _ in } + self?.initialRefreshAll(for: account) { _ in } case .failure(let error): - os_log(.error, log: self.log, "Error adding account container: %@", error.localizedDescription) + self?.logger.error("Error adding account container: \(error.localizedDescription, privacy: .public)") } } accountZone.subscribeToZoneChanges() @@ -589,7 +586,7 @@ private extension CloudKitAccountDelegate { group.leave() } case .failure(let error): - os_log(.error, log: self.log, "CloudKit Feed refresh update error: %@.", error.localizedDescription) + self.logger.error("CloudKit Feed refresh update error: \(error.localizedDescription, privacy: .public)") self.refreshProgress.completeTask() group.leave() } @@ -597,7 +594,7 @@ private extension CloudKitAccountDelegate { } case .failure(let error): - os_log(.error, log: self.log, "CloudKit Feed refresh error: %@.", error.localizedDescription) + self.logger.error("CloudKit Feed refresh error: \(error.localizedDescription, privacy: .public)") feedProviderError = error self.refreshProgress.completeTask() group.leave() @@ -804,12 +801,12 @@ private extension CloudKitAccountDelegate { case .success: self.articlesZone.fetchChangesInZone() { _ in } case .failure(let error): - os_log(.error, log: self.log, "CloudKit Feed send articles error: %@.", error.localizedDescription) + self.logger.error("CloudKit Feed send articles error: \(error.localizedDescription, privacy: .public)") } } } case .failure(let error): - os_log(.error, log: self.log, "CloudKit Feed send articles error: %@.", error.localizedDescription) + self.logger.error("CloudKit Feed send articles error: \(error.localizedDescription, privacy: .public)") } } } diff --git a/Account/Sources/Account/CloudKit/CloudKitArticlesZoneDelegate.swift b/Account/Sources/Account/CloudKit/CloudKitArticlesZoneDelegate.swift index 9f006c7bc..825de657b 100644 --- a/Account/Sources/Account/CloudKit/CloudKitArticlesZoneDelegate.swift +++ b/Account/Sources/Account/CloudKit/CloudKitArticlesZoneDelegate.swift @@ -7,7 +7,6 @@ // import Foundation -import os.log import RSCore import RSParser import RSWeb @@ -16,10 +15,8 @@ import SyncDatabase import Articles import ArticlesDatabase -class CloudKitArticlesZoneDelegate: CloudKitZoneDelegate { +class CloudKitArticlesZoneDelegate: CloudKitZoneDelegate, Logging { - private var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "CloudKit") - weak var account: Account? var database: SyncDatabase weak var articlesZone: CloudKitArticlesZone? @@ -49,12 +46,12 @@ class CloudKitArticlesZoneDelegate: CloudKitZoneDelegate { } case .failure(let error): - os_log(.error, log: self.log, "Error occurred getting pending starred records: %@", error.localizedDescription) + self.logger.error("Error occurred getting pending starred records: \(error.localizedDescription)") completion(.failure(CloudKitZoneError.unknown)) } } case .failure(let error): - os_log(.error, log: self.log, "Error occurred getting pending read status records: %@", error.localizedDescription) + self.logger.error("Error occurred getting pending read status records: \(error.localizedDescription)") completion(.failure(CloudKitZoneError.unknown)) } @@ -102,7 +99,7 @@ private extension CloudKitArticlesZoneDelegate { account?.markAsUnread(updateableUnreadArticleIDs) { result in if case .failure(let databaseError) = result { errorOccurred = true - os_log(.error, log: self.log, "Error occurred while storing unread statuses: %@", databaseError.localizedDescription) + self.logger.error("Error occurred while storing unread statuses: \(databaseError.localizedDescription)") } group.leave() } @@ -111,7 +108,7 @@ private extension CloudKitArticlesZoneDelegate { account?.markAsRead(updateableReadArticleIDs) { result in if case .failure(let databaseError) = result { errorOccurred = true - os_log(.error, log: self.log, "Error occurred while storing read statuses: %@", databaseError.localizedDescription) + self.logger.error("Error occurred while storing read statuses: \(databaseError.localizedDescription)") } group.leave() } @@ -120,7 +117,7 @@ private extension CloudKitArticlesZoneDelegate { account?.markAsUnstarred(updateableUnstarredArticleIDs) { result in if case .failure(let databaseError) = result { errorOccurred = true - os_log(.error, log: self.log, "Error occurred while storing unstarred statuses: %@", databaseError.localizedDescription) + self.logger.error("Error occurred while storing unstarred statuses: \(databaseError.localizedDescription)") } group.leave() } @@ -129,7 +126,7 @@ private extension CloudKitArticlesZoneDelegate { account?.markAsStarred(updateableStarredArticleIDs) { result in if case .failure(let databaseError) = result { errorOccurred = true - os_log(.error, log: self.log, "Error occurred while storing starred statuses: %@", databaseError.localizedDescription) + self.logger.error("Error occurred while stroing starred records: \(databaseError.localizedDescription)") } group.leave() } @@ -155,7 +152,7 @@ private extension CloudKitArticlesZoneDelegate { } case .failure(let databaseError): errorOccurred = true - os_log(.error, log: self.log, "Error occurred while storing articles: %@", databaseError.localizedDescription) + self.logger.error("Error occurred while storing articles: \(databaseError.localizedDescription)") group.leave() } } diff --git a/Account/Sources/Account/CloudKit/CloudKitReceiveStatusOperation.swift b/Account/Sources/Account/CloudKit/CloudKitReceiveStatusOperation.swift index 012942db5..5892b7164 100644 --- a/Account/Sources/Account/CloudKit/CloudKitReceiveStatusOperation.swift +++ b/Account/Sources/Account/CloudKit/CloudKitReceiveStatusOperation.swift @@ -7,13 +7,10 @@ // import Foundation -import os.log import RSCore -class CloudKitReceiveStatusOperation: MainThreadOperation { +class CloudKitReceiveStatusOperation: MainThreadOperation, Logging { - private var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "CloudKit") - // MainThreadOperation public var isCanceled = false public var id: Int? @@ -33,15 +30,15 @@ class CloudKitReceiveStatusOperation: MainThreadOperation { return } - os_log(.debug, log: log, "Refreshing article statuses...") + logger.debug("Refreshing article statuses...") articlesZone.refreshArticles() { result in - os_log(.debug, log: self.log, "Done refreshing article statuses.") + self.logger.debug("Done refreshing article statuses.") switch result { case .success: self.operationDelegate?.operationDidComplete(self) case .failure(let error): - os_log(.error, log: self.log, "Receive status error: %@.", error.localizedDescription) + self.logger.debug("Receive status error: \(error.localizedDescription)") self.operationDelegate?.cancelOperation(self) } } diff --git a/Account/Sources/Account/CloudKit/CloudKitRemoteNotificationOperation.swift b/Account/Sources/Account/CloudKit/CloudKitRemoteNotificationOperation.swift index 008b84846..73833af34 100644 --- a/Account/Sources/Account/CloudKit/CloudKitRemoteNotificationOperation.swift +++ b/Account/Sources/Account/CloudKit/CloudKitRemoteNotificationOperation.swift @@ -7,14 +7,10 @@ // import Foundation - -import os.log import RSCore -class CloudKitRemoteNotificationOperation: MainThreadOperation { +class CloudKitRemoteNotificationOperation: MainThreadOperation, Logging { - private var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "CloudKit") - // MainThreadOperation public var isCanceled = false public var id: Int? @@ -37,12 +33,12 @@ class CloudKitRemoteNotificationOperation: MainThreadOperation { self.operationDelegate?.operationDidComplete(self) return } - - os_log(.debug, log: log, "Processing remote notification...") + + logger.debug("Processing remote notification...") accountZone.receiveRemoteNotification(userInfo: userInfo) { articlesZone.receiveRemoteNotification(userInfo: self.userInfo) { - os_log(.debug, log: self.log, "Done processing remote notification.") + self.logger.debug("Done processing remote notification.") self.operationDelegate?.operationDidComplete(self) } } diff --git a/Account/Sources/Account/CloudKit/CloudKitSendStatusOperation.swift b/Account/Sources/Account/CloudKit/CloudKitSendStatusOperation.swift index 6592ae7c1..021a73b72 100644 --- a/Account/Sources/Account/CloudKit/CloudKitSendStatusOperation.swift +++ b/Account/Sources/Account/CloudKit/CloudKitSendStatusOperation.swift @@ -8,14 +8,12 @@ import Foundation import Articles -import os.log import RSCore import RSWeb import SyncDatabase -class CloudKitSendStatusOperation: MainThreadOperation { +class CloudKitSendStatusOperation: MainThreadOperation, Logging { - private var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "CloudKit") private let blockSize = 150 // MainThreadOperation @@ -40,7 +38,7 @@ class CloudKitSendStatusOperation: MainThreadOperation { } func run() { - os_log(.debug, log: log, "Sending article statuses...") + logger.debug("Sending article statuses...") if showProgress { @@ -51,7 +49,7 @@ class CloudKitSendStatusOperation: MainThreadOperation { self.refreshProgress?.addToNumberOfTasksAndRemaining(ticks) self.selectForProcessing() case .failure(let databaseError): - os_log(.error, log: self.log, "Send status count pending error: %@.", databaseError.localizedDescription) + self.logger.error("Send status count pending error: \(databaseError.localizedDescription)") self.operationDelegate?.cancelOperation(self) } } @@ -77,7 +75,7 @@ private extension CloudKitSendStatusOperation { if self.showProgress { self.refreshProgress?.completeTask() } - os_log(.debug, log: self.log, "Done sending article statuses.") + self.logger.debug("Done sending article statuses.") self.operationDelegate?.operationDidComplete(self) } @@ -95,7 +93,7 @@ private extension CloudKitSendStatusOperation { } case .failure(let databaseError): - os_log(.error, log: self.log, "Send status error: %@.", databaseError.localizedDescription) + self.logger.error("Send status error: \(databaseError.localizedDescription)") self.operationDelegate?.cancelOperation(self) } } @@ -125,7 +123,7 @@ private extension CloudKitSendStatusOperation { if self.showProgress && self.refreshProgress?.numberRemaining ?? 0 > 1 { self.refreshProgress?.completeTask() } - os_log(.debug, log: self.log, "Done sending article status block...") + self.logger.debug("Done sending article status block...") completion(stop) } @@ -147,7 +145,7 @@ private extension CloudKitSendStatusOperation { case .failure(let error): self.database.resetSelectedForProcessing(syncStatuses.map({ $0.articleID })) { _ in self.processAccountError(account, error) - os_log(.error, log: self.log, "Send article status modify articles error: %@.", error.localizedDescription) + self.logger.error("Send article status modify articles error: \(error.localizedDescription)") completion(true) } } @@ -161,7 +159,7 @@ private extension CloudKitSendStatusOperation { processWithArticles(articles) case .failure(let databaseError): self.database.resetSelectedForProcessing(syncStatuses.map({ $0.articleID })) { _ in - os_log(.error, log: self.log, "Send article status fetch articles error: %@.", databaseError.localizedDescription) + self.logger.error("Send article status fetch articles error: \(databaseError.localizedDescription)") completion(true) } } diff --git a/Account/Sources/Account/FeedProvider/Reddit/RedditFeedProvider.swift b/Account/Sources/Account/FeedProvider/Reddit/RedditFeedProvider.swift index 651825259..5622d6793 100644 --- a/Account/Sources/Account/FeedProvider/Reddit/RedditFeedProvider.swift +++ b/Account/Sources/Account/FeedProvider/Reddit/RedditFeedProvider.swift @@ -7,7 +7,6 @@ // import Foundation -import os.log import OAuthSwift import Secrets import RSCore @@ -40,8 +39,6 @@ public enum RedditFeedType: Int { public final class RedditFeedProvider: FeedProvider, RedditFeedProviderTokenRefreshOperationDelegate { - var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "RedditFeedProvider") - private static let homeURL = "https://www.reddit.com" private static let server = "www.reddit.com" private static let apiBase = "https://oauth.reddit.com" diff --git a/Account/Sources/Account/FeedProvider/Reddit/RedditFeedProviderTokenRefreshOperation.swift b/Account/Sources/Account/FeedProvider/Reddit/RedditFeedProviderTokenRefreshOperation.swift index 6a90e9984..691f9b890 100644 --- a/Account/Sources/Account/FeedProvider/Reddit/RedditFeedProviderTokenRefreshOperation.swift +++ b/Account/Sources/Account/FeedProvider/Reddit/RedditFeedProviderTokenRefreshOperation.swift @@ -19,9 +19,7 @@ protocol RedditFeedProviderTokenRefreshOperationDelegate: AnyObject { var oauthSwift: OAuth2Swift? { get } } -class RedditFeedProviderTokenRefreshOperation: MainThreadOperation { - - var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "RedditFeedProvider") +class RedditFeedProviderTokenRefreshOperation: MainThreadOperation, Logging { public var isCanceled = false public var id: Int? @@ -49,7 +47,7 @@ class RedditFeedProviderTokenRefreshOperation: MainThreadOperation { return } - os_log(.debug, log: self.log, "Access token expired, attempting to renew...") + logger.debug("Access token expired, attempting to renew...") delegate.oauthSwift?.renewAccessToken(withRefreshToken: delegate.oauthRefreshToken) { [weak self] result in guard let self = self else { return } @@ -61,7 +59,7 @@ class RedditFeedProviderTokenRefreshOperation: MainThreadOperation { do { try RedditFeedProvider.storeCredentials(username: username, oauthToken: delegate.oauthToken, oauthRefreshToken: delegate.oauthRefreshToken) delegate.oauthTokenLastRefresh = Date() - os_log(.debug, log: self.log, "Access token renewed.") + self.logger.debug("Access token renewed.") } catch { self.error = error self.operationDelegate?.operationDidComplete(self) diff --git a/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift b/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift index 418c1c81a..43fea522f 100644 --- a/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift +++ b/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift @@ -12,7 +12,6 @@ import RSDatabase import RSParser import RSWeb import SyncDatabase -import os.log import Secrets public enum FeedbinAccountDelegateError: String, Error { @@ -20,12 +19,11 @@ public enum FeedbinAccountDelegateError: String, Error { case unknown = "An unknown error occurred." } -final class FeedbinAccountDelegate: AccountDelegate { +final class FeedbinAccountDelegate: AccountDelegate, Logging { private let database: SyncDatabase private let caller: FeedbinAPICaller - private var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "Feedbin") let behaviors: AccountBehaviors = [.disallowFeedCopyInRootFolder] let server: String? = "api.feedbin.com" @@ -132,7 +130,7 @@ final class FeedbinAccountDelegate: AccountDelegate { func sendArticleStatus(for account: Account, completion: @escaping ((Result) -> Void)) { - os_log(.debug, log: log, "Sending article statuses...") + logger.debug("Sending article statuses") database.selectForProcessing { result in @@ -178,7 +176,7 @@ final class FeedbinAccountDelegate: AccountDelegate { } group.notify(queue: DispatchQueue.main) { - os_log(.debug, log: self.log, "Done sending article statuses.") + self.logger.debug("Done sending article statuses.") if errorOccurred { completion(.failure(FeedbinAccountDelegateError.unknown)) } else { @@ -198,7 +196,7 @@ final class FeedbinAccountDelegate: AccountDelegate { func refreshArticleStatus(for account: Account, completion: @escaping ((Result) -> Void)) { - os_log(.debug, log: log, "Refreshing article statuses...") + logger.debug("Refreshing article statuses...") let group = DispatchGroup() var errorOccurred = false @@ -212,7 +210,7 @@ final class FeedbinAccountDelegate: AccountDelegate { } case .failure(let error): errorOccurred = true - os_log(.info, log: self.log, "Retrieving unread entries failed: %@.", error.localizedDescription) + self.logger.error("Retrieving unread entries failed: \(error.localizedDescription, privacy: .public)") group.leave() } @@ -227,14 +225,14 @@ final class FeedbinAccountDelegate: AccountDelegate { } case .failure(let error): errorOccurred = true - os_log(.info, log: self.log, "Retrieving starred entries failed: %@.", error.localizedDescription) + self.logger.error("Retrieving starred entries failed: \(error.localizedDescription, privacy: .public)") group.leave() } } group.notify(queue: DispatchQueue.main) { - os_log(.debug, log: self.log, "Done refreshing article statuses.") + self.logger.debug("Done refreshing article statuses.") if errorOccurred { completion(.failure(FeedbinAccountDelegateError.unknown)) } else { @@ -260,7 +258,7 @@ final class FeedbinAccountDelegate: AccountDelegate { return } - os_log(.debug, log: log, "Begin importing OPML...") + logger.debug("Begin importing OPML...") isOPMLImportInProgress = true refreshProgress.addToNumberOfTasksAndRemaining(1) @@ -268,7 +266,7 @@ final class FeedbinAccountDelegate: AccountDelegate { switch result { case .success(let importResult): if importResult.complete { - os_log(.debug, log: self.log, "Import OPML done.") + self.logger.debug("Import OPML done.") self.refreshProgress.completeTask() self.isOPMLImportInProgress = false DispatchQueue.main.async { @@ -278,7 +276,7 @@ final class FeedbinAccountDelegate: AccountDelegate { self.checkImportResult(opmlImportResultID: importResult.importResultID, completion: completion) } case .failure(let error): - os_log(.debug, log: self.log, "Import OPML failed.") + self.logger.error("Import OPML failed: \(error.localizedDescription, privacy: .public)") self.refreshProgress.completeTask() self.isOPMLImportInProgress = false DispatchQueue.main.async { @@ -352,7 +350,7 @@ final class FeedbinAccountDelegate: AccountDelegate { self.clearFolderRelationship(for: feed, withFolderName: folder.name ?? "") } case .failure(let error): - os_log(.error, log: self.log, "Remove feed error: %@.", error.localizedDescription) + self.logger.error("Remove feed error: \(error.localizedDescription, privacy: .public)") } } } @@ -371,7 +369,7 @@ final class FeedbinAccountDelegate: AccountDelegate { account.clearWebFeedMetadata(feed) } case .failure(let error): - os_log(.error, log: self.log, "Remove feed error: %@.", error.localizedDescription) + self.logger.error("Remove feed error: \(error.localizedDescription, privacy: .public)") } } @@ -541,7 +539,7 @@ final class FeedbinAccountDelegate: AccountDelegate { case .success: break case .failure(let error): - os_log(.error, log: self.log, "Restore folder feed error: %@.", error.localizedDescription) + self.logger.error("Restore folder feed error: \(error.localizedDescription, privacy: .public)") } } @@ -624,13 +622,13 @@ private extension FeedbinAccountDelegate { Timer.scheduledTimer(withTimeInterval: 15, repeats: true) { timer in - os_log(.debug, log: self.log, "Checking status of OPML import...") + self.logger.debug("Checking status of OPML import...") self.caller.retrieveOPMLImportResult(importID: opmlImportResultID) { result in switch result { case .success(let importResult): if let result = importResult, result.complete { - os_log(.debug, log: self.log, "Checking status of OPML import successfully completed.") + self.logger.debug("Checking status of OPML import successfully completed.") timer.invalidate() self.refreshProgress.completeTask() self.isOPMLImportInProgress = false @@ -639,7 +637,7 @@ private extension FeedbinAccountDelegate { } } case .failure(let error): - os_log(.debug, log: self.log, "Import OPML check failed.") + self.logger.debug("Import OPML check failed.") timer.invalidate() self.refreshProgress.completeTask() self.isOPMLImportInProgress = false @@ -772,7 +770,7 @@ private extension FeedbinAccountDelegate { guard let tags = tags else { return } assert(Thread.isMainThread) - os_log(.debug, log: log, "Syncing folders with %ld tags.", tags.count) + logger.debug("Syncing folders with \(tags.count, privacy: .public) tags.") let tagNames = tags.map { $0.name } @@ -811,7 +809,7 @@ private extension FeedbinAccountDelegate { guard let subscriptions = subscriptions else { return } assert(Thread.isMainThread) - os_log(.debug, log: log, "Syncing feeds with %ld subscriptions.", subscriptions.count) + logger.debug("Syncing feeds with \(subscriptions.count, privacy: .public) subscriptions.") let subFeedIds = subscriptions.map { String($0.feedID) } @@ -865,7 +863,7 @@ private extension FeedbinAccountDelegate { guard let taggings = taggings else { return } assert(Thread.isMainThread) - os_log(.debug, log: log, "Syncing taggings with %ld taggings.", taggings.count) + logger.debug("Syncing taggings with \(taggings.count) taggings.") // Set up some structures to make syncing easier let folderDict = nameToFolderDictionary(with: account.folders) @@ -961,7 +959,7 @@ private extension FeedbinAccountDelegate { group.leave() case .failure(let error): errorOccurred = true - os_log(.error, log: self.log, "Article status sync call failed: %@.", error.localizedDescription) + self.logger.error("Article status sync call failed: \(error.localizedDescription, privacy: .public)") self.database.resetSelectedForProcessing(articleIDGroup.map { String($0) } ) group.leave() } @@ -1122,7 +1120,7 @@ private extension FeedbinAccountDelegate { func refreshArticles(_ account: Account, completion: @escaping VoidResultCompletionBlock) { - os_log(.debug, log: log, "Refreshing articles...") + logger.debug("Refreshing articles...") caller.retrieveEntries() { result in @@ -1143,7 +1141,7 @@ private extension FeedbinAccountDelegate { } self.refreshArticles(account, page: page, updateFetchDate: updateFetchDate) { result in - os_log(.debug, log: self.log, "Done refreshing articles.") + self.logger.debug("Done refreshing articles.") switch result { case .success: completion(.success(())) @@ -1160,7 +1158,7 @@ private extension FeedbinAccountDelegate { } func refreshMissingArticles(_ account: Account, completion: @escaping ((Result) -> Void)) { - os_log(.debug, log: log, "Refreshing missing articles...") + logger.debug("Refreshing missing articles...") account.fetchArticleIDsForStatusesWithoutArticlesNewerThanCutoffDate { result in @@ -1187,7 +1185,7 @@ private extension FeedbinAccountDelegate { case .failure(let error): errorOccurred = true - os_log(.error, log: self.log, "Refresh missing articles failed: %@.", error.localizedDescription) + self.logger.error("Refreshing missing articles failed: \(error.localizedDescription, privacy: .public)") group.leave() } } @@ -1195,7 +1193,7 @@ private extension FeedbinAccountDelegate { group.notify(queue: DispatchQueue.main) { self.refreshProgress.completeTask() - os_log(.debug, log: self.log, "Done refreshing missing articles.") + self.logger.debug("Done refreshing missing articles.") if errorOccurred { completion(.failure(FeedbinAccountDelegateError.unknown)) } else { @@ -1312,7 +1310,7 @@ private extension FeedbinAccountDelegate { case .success(let pendingArticleIDs): process(pendingArticleIDs) case .failure(let error): - os_log(.error, log: self.log, "Sync Article Read Status failed: %@.", error.localizedDescription) + self.logger.error("Sync Articles Read Status failed: \(error.localizedDescription, privacy: .public)") } } @@ -1364,7 +1362,7 @@ private extension FeedbinAccountDelegate { case .success(let pendingArticleIDs): process(pendingArticleIDs) case .failure(let error): - os_log(.error, log: self.log, "Sync Article Starred Status failed: %@.", error.localizedDescription) + self.logger.error("Sync Article Starred Status failed: \(error.localizedDescription, privacy: .public)") } } diff --git a/Account/Sources/Account/LocalAccount/LocalAccountDelegate.swift b/Account/Sources/Account/LocalAccount/LocalAccountDelegate.swift index 456c8b738..9ea2d1f25 100644 --- a/Account/Sources/Account/LocalAccount/LocalAccountDelegate.swift +++ b/Account/Sources/Account/LocalAccount/LocalAccountDelegate.swift @@ -7,7 +7,6 @@ // import Foundation -import os.log import RSCore import RSParser import Articles @@ -19,9 +18,7 @@ public enum LocalAccountDelegateError: String, Error { case invalidParameter = "An invalid parameter was used." } -final class LocalAccountDelegate: AccountDelegate { - - private var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "LocalAccount") +final class LocalAccountDelegate: AccountDelegate, Logging { weak var account: Account? @@ -68,7 +65,7 @@ final class LocalAccountDelegate: AccountDelegate { group.leave() } case .failure(let error): - os_log(.error, log: self.log, "Feed Provider refresh error: %@.", error.localizedDescription) + self.logger.error("Feed Provided refresh error: \(error.localizedDescription)") feedProviderError = error self.refreshProgress.completeTask() group.leave() diff --git a/Account/Sources/Account/OPMLFile.swift b/Account/Sources/Account/OPMLFile.swift index 134358c35..c461c6f33 100644 --- a/Account/Sources/Account/OPMLFile.swift +++ b/Account/Sources/Account/OPMLFile.swift @@ -7,13 +7,10 @@ // import Foundation -import os.log import RSCore import RSParser -final class OPMLFile { - - private var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "opmlFile") +final class OPMLFile: Logging { private let fileURL: URL private let account: Account @@ -50,8 +47,8 @@ final class OPMLFile { do { try opmlDocumentString.write(to: fileURL, atomically: true, encoding: .utf8) - } catch let error as NSError { - os_log(.error, log: log, "OPML save to disk failed: %@.", error.localizedDescription) + } catch let error { + logger.error("OPML save to disk failed: \(error.localizedDescription)") } } @@ -76,7 +73,7 @@ private extension OPMLFile { do { fileData = try Data(contentsOf: fileURL) } catch { - os_log(.error, log: log, "OPML read from disk failed: %@.", error.localizedDescription) + logger.error("OPML read from disk failed: \(error.localizedDescription)") } return fileData @@ -89,7 +86,7 @@ private extension OPMLFile { do { opmlDocument = try RSOPMLParser.parseOPML(with: parserData) } catch { - os_log(.error, log: log, "OPML Import failed: %@.", error.localizedDescription) + logger.error("OPML Import failed: \(error.localizedDescription)") return nil } diff --git a/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift b/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift index 58422a96f..2182fb396 100644 --- a/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift +++ b/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift @@ -11,7 +11,6 @@ import RSCore import RSParser import RSWeb import SyncDatabase -import os.log import Secrets public enum ReaderAPIAccountDelegateError: LocalizedError { @@ -34,14 +33,13 @@ public enum ReaderAPIAccountDelegateError: LocalizedError { } } -final class ReaderAPIAccountDelegate: AccountDelegate { +final class ReaderAPIAccountDelegate: AccountDelegate, Logging { private let variant: ReaderAPIVariant private let database: SyncDatabase private let caller: ReaderAPICaller - private var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "ReaderAPI") var behaviors: AccountBehaviors { var behaviors: AccountBehaviors = [.disallowOPMLImports, .disallowFeedInMultipleFolders] @@ -196,7 +194,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate { } func sendArticleStatus(for account: Account, completion: @escaping ((Result) -> Void)) { - os_log(.debug, log: log, "Sending article statuses...") + logger.debug("Sending article statuses...") database.selectForProcessing { result in @@ -229,7 +227,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate { } group.notify(queue: DispatchQueue.main) { - os_log(.debug, log: self.log, "Done sending article statuses.") + self.logger.debug("Done sending article statuses.") completion(.success(())) } } @@ -244,7 +242,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate { } func refreshArticleStatus(for account: Account, completion: @escaping ((Result) -> Void)) { - os_log(.debug, log: log, "Refreshing article statuses...") + logger.debug("Refreshing article statuses...") let group = DispatchGroup() var errorOccurred = false @@ -258,7 +256,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate { } case .failure(let error): errorOccurred = true - os_log(.info, log: self.log, "Retrieving unread entries failed: %@.", error.localizedDescription) + self.logger.info("Retrieving unread entries failed: \(error.localizedDescription)") group.leave() } @@ -273,14 +271,14 @@ final class ReaderAPIAccountDelegate: AccountDelegate { } case .failure(let error): errorOccurred = true - os_log(.info, log: self.log, "Retrieving starred entries failed: %@.", error.localizedDescription) + self.logger.info("Retrieving starred entries failed: \(error.localizedDescription)") group.leave() } } group.notify(queue: DispatchQueue.main) { - os_log(.debug, log: self.log, "Done refreshing article statuses.") + self.logger.debug("Done refreshing article statuses.") if errorOccurred { completion(.failure(ReaderAPIAccountDelegateError.unknown)) } else { @@ -342,7 +340,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate { self.clearFolderRelationship(for: feed, folderExternalID: folder.externalID) } case .failure(let error): - os_log(.error, log: self.log, "Remove feed error: %@.", error.localizedDescription) + self.logger.error("Remove feed error: \(error.localizedDescription)") } } } @@ -361,7 +359,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate { account.clearWebFeedMetadata(feed) } case .failure(let error): - os_log(.error, log: self.log, "Remove feed error: %@.", error.localizedDescription) + self.logger.error("Remove feed error: \(error.localizedDescription)") } } @@ -593,7 +591,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate { case .success: break case .failure(let error): - os_log(.error, log: self.log, "Restore folder feed error: %@.", error.localizedDescription) + self.logger.error("Restore folder feed error: \(error.localizedDescription)") } } @@ -711,7 +709,7 @@ private extension ReaderAPIAccountDelegate { guard !folderTags.isEmpty else { return } - os_log(.debug, log: log, "Syncing folders with %ld tags.", folderTags.count) + logger.debug("Syncing folders with \(folderTags.count) tags.") let readerFolderExternalIDs = folderTags.compactMap { $0.tagID } @@ -751,7 +749,7 @@ private extension ReaderAPIAccountDelegate { guard let subscriptions = subscriptions else { return } assert(Thread.isMainThread) - os_log(.debug, log: log, "Syncing feeds with %ld subscriptions.", subscriptions.count) + logger.debug("Syncing feeds with \(subscriptions.count) subscriptions") let subFeedIds = subscriptions.map { $0.feedID } @@ -793,7 +791,7 @@ private extension ReaderAPIAccountDelegate { func syncFeedFolderRelationship(_ account: Account, _ subscriptions: [ReaderAPISubscription]?) { guard let subscriptions = subscriptions else { return } assert(Thread.isMainThread) - os_log(.debug, log: log, "Syncing taggings with %ld subscriptions.", subscriptions.count) + logger.debug("Syncing taggins with \(subscriptions.count) subscriptions.") // Set up some structures to make syncing easier let folderDict = externalIDToFolderDictionary(with: account.folders) @@ -887,7 +885,7 @@ private extension ReaderAPIAccountDelegate { self.database.deleteSelectedForProcessing(articleIDGroup.map { $0 } ) group.leave() case .failure(let error): - os_log(.error, log: self.log, "Article status sync call failed: %@.", error.localizedDescription) + self.logger.error("Article status sync call failed: \(error.localizedDescription)") self.database.resetSelectedForProcessing(articleIDGroup.map { $0 } ) group.leave() } @@ -987,7 +985,7 @@ private extension ReaderAPIAccountDelegate { return } - os_log(.debug, log: self.log, "Refreshing missing articles...") + self.logger.debug("Refreshing missing articles...") let group = DispatchGroup() let articleIDs = Array(fetchedArticleIDs) @@ -1007,7 +1005,7 @@ private extension ReaderAPIAccountDelegate { } case .failure(let error): - os_log(.error, log: self.log, "Refresh missing articles failed: %@.", error.localizedDescription) + self.logger.error("Refresh missing articles failed: \(error.localizedDescription)") group.leave() } } @@ -1015,7 +1013,7 @@ private extension ReaderAPIAccountDelegate { group.notify(queue: DispatchQueue.main) { self.refreshProgress.completeTask() - os_log(.debug, log: self.log, "Done refreshing missing articles.") + self.logger.debug("Done refreshing missing articles.") completion() } } @@ -1121,7 +1119,7 @@ private extension ReaderAPIAccountDelegate { case .success(let pendingArticleIDs): process(pendingArticleIDs) case .failure(let error): - os_log(.error, log: self.log, "Sync Article Read Status failed: %@.", error.localizedDescription) + self.logger.error("Sync Article Read Status failed: \(error.localizedDescription)") } } @@ -1170,7 +1168,7 @@ private extension ReaderAPIAccountDelegate { case .success(let pendingArticleIDs): process(pendingArticleIDs) case .failure(let error): - os_log(.error, log: self.log, "Sync Article Starred Status failed: %@.", error.localizedDescription) + self.logger.error("Sync Article Starred Status failed: \(error.localizedDescription)") } } diff --git a/Account/Sources/Account/WebFeedMetadataFile.swift b/Account/Sources/Account/WebFeedMetadataFile.swift index be04530d7..6d6983286 100644 --- a/Account/Sources/Account/WebFeedMetadataFile.swift +++ b/Account/Sources/Account/WebFeedMetadataFile.swift @@ -7,12 +7,9 @@ // import Foundation -import os.log import RSCore -final class WebFeedMetadataFile { - - private var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "webFeedMetadataFile") +final class WebFeedMetadataFile: Logging { private let fileURL: URL private let account: Account @@ -52,8 +49,8 @@ final class WebFeedMetadataFile { do { let data = try encoder.encode(feedMetadata) try data.write(to: fileURL) - } catch let error as NSError { - os_log(.error, log: log, "Save to disk failed: %@.", error.localizedDescription) + } catch let error { + logger.error("Save to disk failed: \(error.localizedDescription)") } } diff --git a/Articles/Package.swift b/Articles/Package.swift index d5353dc79..d79b1815d 100644 --- a/Articles/Package.swift +++ b/Articles/Package.swift @@ -3,7 +3,7 @@ import PackageDescription let package = Package( name: "Articles", - platforms: [.macOS(SupportedPlatform.MacOSVersion.v10_15), .iOS(SupportedPlatform.IOSVersion.v13)], + platforms: [.macOS(SupportedPlatform.MacOSVersion.v11), .iOS(SupportedPlatform.IOSVersion.v14)], products: [ .library( name: "Articles", diff --git a/ArticlesDatabase/Package.swift b/ArticlesDatabase/Package.swift index e47d036b5..cd61a3001 100644 --- a/ArticlesDatabase/Package.swift +++ b/ArticlesDatabase/Package.swift @@ -21,7 +21,7 @@ dependencies.append(contentsOf: [ let package = Package( name: "ArticlesDatabase", - platforms: [.macOS(SupportedPlatform.MacOSVersion.v10_15), .iOS(SupportedPlatform.IOSVersion.v13)], + platforms: [.macOS(SupportedPlatform.MacOSVersion.v11), .iOS(SupportedPlatform.IOSVersion.v14)], products: [ .library( name: "ArticlesDatabase", diff --git a/Mac/AppDelegate.swift b/Mac/AppDelegate.swift index 44c877446..749bcf7b5 100644 --- a/Mac/AppDelegate.swift +++ b/Mac/AppDelegate.swift @@ -15,7 +15,6 @@ import Account import RSCore import RSCoreResources import Secrets -import OSLog import CrashReporter // If we're not going to import Sparkle, provide dummy protocols to make it easy @@ -30,15 +29,13 @@ import Sparkle var appDelegate: AppDelegate! @NSApplicationMain -class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, UNUserNotificationCenterDelegate, UnreadCountProvider, SPUStandardUserDriverDelegate, SPUUpdaterDelegate +class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, UNUserNotificationCenterDelegate, UnreadCountProvider, SPUStandardUserDriverDelegate, SPUUpdaterDelegate, Logging { private struct WindowRestorationIdentifiers { static let mainWindow = "mainWindow" } - var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "Application") - var userNotificationManager: UserNotificationManager! var faviconDownloader: FaviconDownloader! var imageDownloader: ImageDownloader! @@ -194,14 +191,14 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, try self.softwareUpdater.start() } catch { - NSLog("Failed to start software updater with error: \(error)") + logger.error("Failed to start software updater with error: \(error, privacy: .public)") } #endif AppDefaults.shared.registerDefaults() let isFirstRun = AppDefaults.shared.isFirstRun if isFirstRun { - os_log(.debug, log: log, "Is first run.") + logger.debug("Is first run") } let localAccount = AccountManager.shared.defaultAccount @@ -856,6 +853,7 @@ internal extension AppDelegate { confirmImportSuccess(themeName: theme.name) } catch { NSApplication.shared.presentError(error) + logger.error("Error importing theme: \(error.localizedDescription, privacy: .public)") } } @@ -884,6 +882,7 @@ internal extension AppDelegate { } } catch { NotificationCenter.default.post(name: .didFailToImportThemeWithError, object: nil, userInfo: ["error" : error, "path": filename]) + logger.error("Error importing theme: \(error.localizedDescription, privacy: .public)") } } @@ -1012,12 +1011,12 @@ private extension AppDelegate { let account = AccountManager.shared.existingAccount(with: accountID) guard account != nil else { - os_log(.debug, log: log, "No account found from notification.") + logger.debug("No account found from notification.") return } let article = try? account!.fetchArticles(.articleIDs([articleID])) guard article != nil else { - os_log(.debug, log: log, "No article found from search using %@", articleID) + logger.debug("No article found from search using: \(articleID, privacy: .public)") return } account!.markArticles(article!, statusKey: .read, flag: true) { _ in } @@ -1031,12 +1030,12 @@ private extension AppDelegate { } let account = AccountManager.shared.existingAccount(with: accountID) guard account != nil else { - os_log(.debug, log: log, "No account found from notification.") + logger.debug("No account found from notification.") return } let article = try? account!.fetchArticles(.articleIDs([articleID])) guard article != nil else { - os_log(.debug, log: log, "No article found from search using %@", articleID) + logger.debug("No article found from search using: \(articleID, privacy: .public)") return } account!.markArticles(article!, statusKey: .starred, flag: true) { _ in } diff --git a/Mac/ErrorHandler.swift b/Mac/ErrorHandler.swift index 018da1a63..4ec6f59be 100644 --- a/Mac/ErrorHandler.swift +++ b/Mac/ErrorHandler.swift @@ -8,18 +8,18 @@ import AppKit import Account -import os.log +import RSCore -struct ErrorHandler { +struct ErrorHandler: Logging { - private static var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "Account") + public static func present(_ error: Error) { NSApplication.shared.presentError(error) } public static func log(_ error: Error) { - os_log(.error, log: self.log, "%@", error.localizedDescription) + ErrorHandler.logger.error("\(error.localizedDescription, privacy: .public)") } } diff --git a/Mac/MainWindow/Timeline/TimelineViewController.swift b/Mac/MainWindow/Timeline/TimelineViewController.swift index 4d9f55b56..cb9c7e9d3 100644 --- a/Mac/MainWindow/Timeline/TimelineViewController.swift +++ b/Mac/MainWindow/Timeline/TimelineViewController.swift @@ -10,7 +10,6 @@ import Foundation import RSCore import Articles import Account -import os.log protocol TimelineDelegate: AnyObject { func timelineSelectionDidChange(_: TimelineViewController, selectedArticles: [Article]?) diff --git a/Mac/Preferences/Accounts/AccountsFeedbinWindowController.swift b/Mac/Preferences/Accounts/AccountsFeedbinWindowController.swift index 3a4112ca4..6ac802851 100644 --- a/Mac/Preferences/Accounts/AccountsFeedbinWindowController.swift +++ b/Mac/Preferences/Accounts/AccountsFeedbinWindowController.swift @@ -8,10 +8,11 @@ import AppKit import Account +import RSCore import RSWeb import Secrets -class AccountsFeedbinWindowController: NSWindowController { +class AccountsFeedbinWindowController: NSWindowController, Logging { @IBOutlet weak var signInTextField: NSTextField! @IBOutlet weak var noAccountTextField: NSTextField! @@ -115,6 +116,7 @@ class AccountsFeedbinWindowController: NSWindowController { self.hostWindow?.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK) } catch { self.errorMessageLabel.stringValue = NSLocalizedString("Keychain error while storing credentials.", comment: "Credentials Error") + self.logger.error("Keychain error while storing credentials: \(error.localizedDescription, privacy: .public)") } case .failure: diff --git a/Mac/Preferences/Accounts/AccountsNewsBlurWindowController.swift b/Mac/Preferences/Accounts/AccountsNewsBlurWindowController.swift index 9c70fceb5..0af42818e 100644 --- a/Mac/Preferences/Accounts/AccountsNewsBlurWindowController.swift +++ b/Mac/Preferences/Accounts/AccountsNewsBlurWindowController.swift @@ -9,9 +9,10 @@ import AppKit import Account import RSWeb +import RSCore import Secrets -class AccountsNewsBlurWindowController: NSWindowController { +class AccountsNewsBlurWindowController: NSWindowController, Logging { @IBOutlet weak var signInTextField: NSTextField! @IBOutlet weak var noAccountTextField: NSTextField! @@ -113,6 +114,7 @@ class AccountsNewsBlurWindowController: NSWindowController { self.hostWindow?.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK) } catch { self.errorMessageLabel.stringValue = NSLocalizedString("Keychain error while storing credentials.", comment: "Credentials Error") + self.logger.error("Keychain error while storing credentials: \(error.localizedDescription, privacy: .public)") } case .failure: diff --git a/Mac/Preferences/Accounts/AccountsReaderAPIWindowController.swift b/Mac/Preferences/Accounts/AccountsReaderAPIWindowController.swift index 0c4d3c569..b127003db 100644 --- a/Mac/Preferences/Accounts/AccountsReaderAPIWindowController.swift +++ b/Mac/Preferences/Accounts/AccountsReaderAPIWindowController.swift @@ -9,9 +9,10 @@ import AppKit import Account import RSWeb +import RSCore import Secrets -class AccountsReaderAPIWindowController: NSWindowController { +class AccountsReaderAPIWindowController: NSWindowController, Logging { @IBOutlet weak var titleImageView: NSImageView! @IBOutlet weak var titleLabel: NSTextField! @@ -170,6 +171,7 @@ class AccountsReaderAPIWindowController: NSWindowController { self.hostWindow?.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK) } catch { self.errorMessageLabel.stringValue = NSLocalizedString("Keychain error while storing credentials.", comment: "Credentials Error") + self.logger.error("Keychain error while storing credentials: \(error.localizedDescription, privacy: .public)") } case .failure: diff --git a/Mac/Scriptability/AppDelegate+Scriptability.swift b/Mac/Scriptability/AppDelegate+Scriptability.swift index 132fe26be..cfd8310f5 100644 --- a/Mac/Scriptability/AppDelegate+Scriptability.swift +++ b/Mac/Scriptability/AppDelegate+Scriptability.swift @@ -55,7 +55,7 @@ extension AppDelegate : AppDelegateAppleEvents { if let themeURL = URL(string: themeURLString) { let request = URLRequest(url: themeURL) - let task = URLSession.shared.downloadTask(with: request) { location, response, error in + let task = URLSession.shared.downloadTask(with: request) { [weak self] location, response, error in guard let location = location else { return } @@ -64,6 +64,7 @@ extension AppDelegate : AppDelegateAppleEvents { try ArticleThemeDownloader.shared.handleFile(at: location) } catch { NotificationCenter.default.post(name: .didFailToImportThemeWithError, object: nil, userInfo: ["error": error]) + self?.logger.error("Failed to import theme: \(error.localizedDescription, privacy: .public)") } } task.resume() diff --git a/Mac/ShareExtension/ShareViewController.swift b/Mac/ShareExtension/ShareViewController.swift index 2d7558063..bffe4d20d 100644 --- a/Mac/ShareExtension/ShareViewController.swift +++ b/Mac/ShareExtension/ShareViewController.swift @@ -7,7 +7,6 @@ // import Cocoa -import os.log class ShareViewController: NSViewController { @@ -16,7 +15,6 @@ class ShareViewController: NSViewController { private var url: URL? private var extensionContainers: ExtensionContainers? - private var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "ShareViewController") override var nibName: NSNib.Name? { return NSNib.Name("ShareViewController") diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index d6abb9ffb..f0cd1d128 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -847,6 +847,8 @@ D5F4EDB720074D6500B9E363 /* WebFeed+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F4EDB620074D6500B9E363 /* WebFeed+Scriptability.swift */; }; D5F4EDB920074D7C00B9E363 /* Folder+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F4EDB820074D7C00B9E363 /* Folder+Scriptability.swift */; }; DD82AB0A231003F6002269DF /* SharingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD82AB09231003F6002269DF /* SharingTests.swift */; }; + DF2A8F33289BFBD9002455AD /* RSCore in Frameworks */ = {isa = PBXBuildFile; productRef = DF2A8F32289BFBD9002455AD /* RSCore */; }; + DF2A8F34289BFBDA002455AD /* RSCore in Embed Frameworks */ = {isa = PBXBuildFile; productRef = DF2A8F32289BFBD9002455AD /* RSCore */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; DFD6AACF27ADE86E00463FAD /* NewsFax.nnwtheme in Resources */ = {isa = PBXBuildFile; fileRef = DFD6AACD27ADE86E00463FAD /* NewsFax.nnwtheme */; }; DFFB8FC2279B75E300AC21D7 /* Account in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 51BC2F4A24D343A500E90810 /* Account */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; DFFC199827A0D0D7004B7AEF /* NotificationsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFFC199727A0D0D7004B7AEF /* NotificationsViewController.swift */; }; @@ -930,6 +932,7 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( + DF2A8F34289BFBDA002455AD /* RSCore in Embed Frameworks */, 17EF6A2225C4E5B4002C9F81 /* RSWeb in Embed Frameworks */, ); name = "Embed Frameworks"; @@ -1599,6 +1602,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + DF2A8F33289BFBD9002455AD /* RSCore in Frameworks */, 17EF6A2125C4E5B4002C9F81 /* RSWeb in Frameworks */, 176813F72564BB2C00D98635 /* SwiftUI.framework in Frameworks */, 176813F52564BB2C00D98635 /* WidgetKit.framework in Frameworks */, @@ -2583,6 +2587,7 @@ 849A97861ED9ECEF007D329B /* Article Styles */, 84DAEE201F86CAE00058304B /* Importers */, 8444C9011FED81880051386C /* Exporters */, + DF2A8F28289A3EA8002455AD /* Logging */, 51FE0FF9234552490056195D /* UserNotifications */, 84F2D5341FC22FCB00998D64 /* SmartFeeds */, 51B5C85A23F22A7A00032075 /* ShareExtension */, @@ -2862,6 +2867,13 @@ path = Scriptability; sourceTree = ""; }; + DF2A8F28289A3EA8002455AD /* Logging */ = { + isa = PBXGroup; + children = ( + ); + path = Logging; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -2882,6 +2894,7 @@ name = "NetNewsWire iOS Widget Extension"; packageProductDependencies = ( 17EF6A2025C4E5B4002C9F81 /* RSWeb */, + DF2A8F32289BFBD9002455AD /* RSCore */, ); productName = "NetNewsWire WidgetExtension"; productReference = 176813F32564BB2C00D98635 /* NetNewsWire iOS Widget Extension.appex */; @@ -5181,6 +5194,11 @@ package = 653813412680E2DA007A082C /* XCRemoteSwiftPackageReference "RSCore" */; productName = RSCore; }; + DF2A8F32289BFBD9002455AD /* RSCore */ = { + isa = XCSwiftPackageProductDependency; + package = 5102AE4324D17E820050839C /* XCRemoteSwiftPackageReference "RSCore" */; + productName = RSCore; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 849C64581ED37A5D003D8FC0 /* Project object */; diff --git a/NetNewsWire.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/NetNewsWire.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 71fbf0ee7..0f71953cd 100644 --- a/NetNewsWire.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/NetNewsWire.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -51,8 +51,8 @@ "repositoryURL": "https://github.com/microsoft/plcrashreporter.git", "state": { "branch": null, - "revision": "6b27393cad517c067dceea85fadf050e70c4ceaa", - "version": "1.10.1" + "revision": "81cdec2b3827feb03286cb297f4c501a8eb98df1", + "version": "1.10.2" } }, { @@ -60,8 +60,8 @@ "repositoryURL": "https://github.com/Ranchero-Software/RSCore.git", "state": { "branch": null, - "revision": "4cd6b67ed213c0db9c02c9d8ff968b45fd694970", - "version": "1.0.8" + "revision": "814adfd956e5bd099b3b81b6680d0a4f6cd56130", + "version": "1.0.9" } }, { diff --git a/Secrets/Package.swift b/Secrets/Package.swift index fdd6bc08a..f3286fe67 100644 --- a/Secrets/Package.swift +++ b/Secrets/Package.swift @@ -3,7 +3,7 @@ import PackageDescription let package = Package( name: "Secrets", - platforms: [.macOS(SupportedPlatform.MacOSVersion.v10_15), .iOS(SupportedPlatform.IOSVersion.v13)], + platforms: [.macOS(SupportedPlatform.MacOSVersion.v11), .iOS(SupportedPlatform.IOSVersion.v14)], products: [ .library( name: "Secrets", diff --git a/Shared/Article Extractor/ArticleExtractor.swift b/Shared/Article Extractor/ArticleExtractor.swift index 6b26f8f8d..1fd4d151b 100644 --- a/Shared/Article Extractor/ArticleExtractor.swift +++ b/Shared/Article Extractor/ArticleExtractor.swift @@ -9,6 +9,7 @@ import Foundation import Account import Secrets +import RSCore public enum ArticleExtractorState { case ready @@ -23,7 +24,7 @@ protocol ArticleExtractorDelegate { func articleExtractionDidComplete(extractedArticle: ExtractedArticle) } -class ArticleExtractor { +class ArticleExtractor: Logging { private var dataTask: URLSessionDataTask? = nil @@ -91,6 +92,7 @@ class ArticleExtractor { } } } catch { + self.logger.error("Failed to extract article: \(error.localizedDescription, privacy: .public)") self.state = .failedToParse DispatchQueue.main.async { self.delegate?.articleExtractionDidFail(with: error) diff --git a/Shared/ArticleStyles/ArticleThemeDownloader.swift b/Shared/ArticleStyles/ArticleThemeDownloader.swift index d6714e169..703db2ef5 100644 --- a/Shared/ArticleStyles/ArticleThemeDownloader.swift +++ b/Shared/ArticleStyles/ArticleThemeDownloader.swift @@ -8,8 +8,9 @@ import Foundation import Zip +import RSCore -public class ArticleThemeDownloader { +public class ArticleThemeDownloader: Logging { public enum ArticleThemeDownloaderError: LocalizedError { case noThemeFile @@ -63,6 +64,7 @@ public class ArticleThemeDownloader { } return URL(fileURLWithPath: unzipDirectory.appendingPathComponent(themeFilePath!).path) } catch { + logger.error("Failed to unzip theme: \(error.localizedDescription, privacy: .public)") try? FileManager.default.removeItem(at: location) throw error } @@ -101,7 +103,7 @@ public class ArticleThemeDownloader { try FileManager.default.removeItem(atPath: downloadDirectory().appendingPathComponent(path).path) } } catch { - print(error) + logger.error("Failed to clean up theme download: \(error.localizedDescription, privacy: .public)") } } } diff --git a/Shared/ArticleStyles/ArticleThemesManager.swift b/Shared/ArticleStyles/ArticleThemesManager.swift index ff0365e9f..ab66608a9 100644 --- a/Shared/ArticleStyles/ArticleThemesManager.swift +++ b/Shared/ArticleStyles/ArticleThemesManager.swift @@ -14,7 +14,7 @@ public extension Notification.Name { static let CurrentArticleThemeDidChangeNotification = Notification.Name("CurrentArticleThemeDidChangeNotification") } -final class ArticleThemesManager: NSObject, NSFilePresenter { +final class ArticleThemesManager: NSObject, NSFilePresenter, Logging { static var shared: ArticleThemesManager! public let folderPath: String @@ -58,6 +58,7 @@ final class ArticleThemesManager: NSObject, NSFilePresenter { do { try FileManager.default.createDirectory(atPath: folderPath, withIntermediateDirectories: true, attributes: nil) } catch { + logger.error("Could not create folder for themes: \(error.localizedDescription, privacy: .public)") assertionFailure("Could not create folder for Themes.") abort() } @@ -113,6 +114,7 @@ final class ArticleThemesManager: NSObject, NSFilePresenter { return try ArticleTheme(path: path, isAppTheme: isAppTheme) } catch { NotificationCenter.default.post(name: .didFailToImportThemeWithError, object: nil, userInfo: ["error": error]) + logger.error("Failed to import theme: \(error.localizedDescription, privacy: .public)") return nil } diff --git a/Shared/Extensions/CacheCleaner.swift b/Shared/Extensions/CacheCleaner.swift index fa00603e7..2364a59fb 100644 --- a/Shared/Extensions/CacheCleaner.swift +++ b/Shared/Extensions/CacheCleaner.swift @@ -7,12 +7,10 @@ // import Foundation -import os.log import RSWeb +import RSCore -struct CacheCleaner { - - static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "CacheCleaner") +struct CacheCleaner: Logging { static func purgeIfNecessary() { @@ -35,10 +33,10 @@ struct CacheCleaner { for tempItem in [faviconsFolderURL, imagesFolderURL, feedURLToIconURL, homePageToIconURL, homePagesWithNoIconURL] { do { - os_log(.info, log: self.log, "Removing cache file: %@", tempItem.absoluteString) + CacheCleaner.logger.info("Removing cache file: \(tempItem.absoluteString, privacy: .public)") try FileManager.default.removeItem(at: tempItem) } catch { - os_log(.error, log: self.log, "Could not delete cache file: %@", error.localizedDescription) + CacheCleaner.logger.error("Could not delete cache file: \(error.localizedDescription, privacy: .public)") } } diff --git a/Shared/Favicons/FaviconDownloader.swift b/Shared/Favicons/FaviconDownloader.swift index 02c48f6f0..da9822650 100644 --- a/Shared/Favicons/FaviconDownloader.swift +++ b/Shared/Favicons/FaviconDownloader.swift @@ -18,7 +18,7 @@ extension Notification.Name { static let FaviconDidBecomeAvailable = Notification.Name("FaviconDidBecomeAvailableNotification") // userInfo key: FaviconDownloader.UserInfoKey.faviconURL } -final class FaviconDownloader { +final class FaviconDownloader: Logging { private static let saveQueue = CoalescingQueue(name: "Cache Save Queue", interval: 1.0) @@ -297,6 +297,7 @@ private extension FaviconDownloader { let data = try encoder.encode(homePageToFaviconURLCache) try data.write(to: url) } catch { + logger.error("Failed to Save Home Page To Favicon URL Cache: \(error.localizedDescription, privacy: .public)") assertionFailure(error.localizedDescription) } } @@ -311,6 +312,7 @@ private extension FaviconDownloader { let data = try encoder.encode(Array(homePageURLsWithNoFaviconURLCache)) try data.write(to: url) } catch { + logger.error("Failed to Save URLs With No Favicon URL Cache: \(error.localizedDescription, privacy: .public)") assertionFailure(error.localizedDescription) } } diff --git a/Shared/Favicons/SingleFaviconDownloader.swift b/Shared/Favicons/SingleFaviconDownloader.swift index 1b82802f6..d65806e13 100644 --- a/Shared/Favicons/SingleFaviconDownloader.swift +++ b/Shared/Favicons/SingleFaviconDownloader.swift @@ -7,7 +7,6 @@ // import Foundation -import os.log import RSCore import RSWeb @@ -19,7 +18,7 @@ extension Notification.Name { static let DidLoadFavicon = Notification.Name("DidLoadFaviconNotification") } -final class SingleFaviconDownloader { +final class SingleFaviconDownloader: Logging { enum DiskStatus { case unknown, notOnDisk, onDisk @@ -29,8 +28,6 @@ final class SingleFaviconDownloader { var iconImage: IconImage? let homePageURL: String? - private var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "SingleFaviconDownloader") - private var lastDownloadAttemptDate: Date private var diskStatus = DiskStatus.unknown private var diskCache: BinaryDiskCache @@ -128,7 +125,9 @@ private extension SingleFaviconDownloader { self.diskStatus = .onDisk } } - catch {} + catch { + self.logger.error("Unable to save to disk: \(error.localizedDescription, privacy: .public)") + } } } @@ -139,16 +138,16 @@ private extension SingleFaviconDownloader { return } - downloadUsingCache(url) { (data, response, error) in + downloadUsingCache(url) { [weak self] (data, response, error) in if let data = data, !data.isEmpty, let response = response, response.statusIsOK, error == nil { - self.saveToDisk(data) + self?.saveToDisk(data) RSImage.image(with: data, imageResultBlock: completion) return } if let error = error { - os_log(.info, log: self.log, "Error downloading image at %@: %@.", url.absoluteString, error.localizedDescription) + self?.logger.error("Error downloading image at: \(url.absoluteString, privacy: .sensitive): \(error.localizedDescription, privacy: .public)") } completion(nil) diff --git a/Shared/Images/ImageDownloader.swift b/Shared/Images/ImageDownloader.swift index 9a549d3ef..242951eba 100644 --- a/Shared/Images/ImageDownloader.swift +++ b/Shared/Images/ImageDownloader.swift @@ -7,7 +7,6 @@ // import Foundation -import os.log import RSCore import RSWeb @@ -16,9 +15,7 @@ extension Notification.Name { static let ImageDidBecomeAvailable = Notification.Name("ImageDidBecomeAvailableNotification") // UserInfoKey.url } -final class ImageDownloader { - - private var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "ImageDownloader") +final class ImageDownloader: Logging { private let folder: String private var diskCache: BinaryDiskCache @@ -103,19 +100,19 @@ private extension ImageDownloader { return } - downloadUsingCache(imageURL) { (data, response, error) in + downloadUsingCache(imageURL) { [weak self] (data, response, error) in if let data = data, !data.isEmpty, let response = response, response.statusIsOK, error == nil { - self.saveToDisk(url, data) + self?.saveToDisk(url, data) completion(data) return } if let response = response as? HTTPURLResponse, response.statusCode >= HTTPResponseCode.badRequest && response.statusCode <= HTTPResponseCode.notAcceptable { - self.badURLs.insert(url) + self?.badURLs.insert(url) } if let error = error { - os_log(.info, log: self.log, "Error downloading image at %@: %@.", url, error.localizedDescription) + self?.logger.error("Error downloading image at: \(url, privacy: .sensitive): \(error.localizedDescription, privacy: .public)") } completion(nil) diff --git a/Shared/ShareExtension/ExtensionContainersFile.swift b/Shared/ShareExtension/ExtensionContainersFile.swift index 094a5360d..6e85f989b 100644 --- a/Shared/ShareExtension/ExtensionContainersFile.swift +++ b/Shared/ShareExtension/ExtensionContainersFile.swift @@ -7,15 +7,12 @@ // import Foundation -import os.log import RSCore import RSParser import Account -final class ExtensionContainersFile { +final class ExtensionContainersFile: Logging { - private static var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "extensionContainersFile") - private static var filePath: String = { let appGroup = Bundle.main.object(forInfoDictionaryKey: "AppGroup") as! String let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroup) @@ -55,7 +52,7 @@ final class ExtensionContainersFile { }) if let error = errorPointer?.pointee { - os_log(.error, log: log, "Read from disk coordination failed: %@.", error.localizedDescription) + logger.error("Read from coordination failed: \(error.localizedDescription, privacy: .public)") } return extensionContainers @@ -88,19 +85,19 @@ private extension ExtensionContainersFile { let fileCoordinator = NSFileCoordinator() let fileURL = URL(fileURLWithPath: ExtensionContainersFile.filePath) - fileCoordinator.coordinate(writingItemAt: fileURL, options: [], error: errorPointer, byAccessor: { writeURL in + fileCoordinator.coordinate(writingItemAt: fileURL, options: [], error: errorPointer, byAccessor: { [weak self] writeURL in do { let extensionAccounts = AccountManager.shared.sortedActiveAccounts.map { ExtensionAccount(account: $0) } let extensionContainers = ExtensionContainers(accounts: extensionAccounts) let data = try encoder.encode(extensionContainers) try data.write(to: writeURL) } catch let error as NSError { - os_log(.error, log: Self.log, "Save to disk failed: %@.", error.localizedDescription) + self?.logger.error("Save to disk failed: \(error.localizedDescription, privacy: .public)") } }) if let error = errorPointer?.pointee { - os_log(.error, log: Self.log, "Save to disk coordination failed: %@.", error.localizedDescription) + logger.error("Save to disk coordination failed: \(error.localizedDescription, privacy: .public)") } } diff --git a/Shared/ShareExtension/ExtensionFeedAddRequestFile.swift b/Shared/ShareExtension/ExtensionFeedAddRequestFile.swift index 6ac0dd2e4..737d756c6 100644 --- a/Shared/ShareExtension/ExtensionFeedAddRequestFile.swift +++ b/Shared/ShareExtension/ExtensionFeedAddRequestFile.swift @@ -7,13 +7,11 @@ // import Foundation -import os.log import Account +import RSCore -final class ExtensionFeedAddRequestFile: NSObject, NSFilePresenter { +final class ExtensionFeedAddRequestFile: NSObject, NSFilePresenter, Logging { - private static var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "extensionFeedAddRequestFile") - private static var filePath: String = { let appGroup = Bundle.main.object(forInfoDictionaryKey: "AppGroup") as! String let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroup) @@ -82,12 +80,12 @@ final class ExtensionFeedAddRequestFile: NSObject, NSFilePresenter { try data.write(to: url) } catch let error as NSError { - os_log(.error, log: Self.log, "Save to disk failed: %@.", error.localizedDescription) + logger.error("Save to disk failed: \(error.localizedDescription, privacy: .public)") } }) if let error = errorPointer?.pointee { - os_log(.error, log: Self.log, "Save to disk coordination failed: %@.", error.localizedDescription) + logger.error("Save to disk coordination failed: \(error.localizedDescription, privacy: .public)") } } @@ -107,7 +105,7 @@ private extension ExtensionFeedAddRequestFile { var requests: [ExtensionFeedAddRequest]? = nil - fileCoordinator.coordinate(writingItemAt: fileURL, options: [.forMerging], error: errorPointer, byAccessor: { url in + fileCoordinator.coordinate(writingItemAt: fileURL, options: [.forMerging], error: errorPointer, byAccessor: { [weak self] url in do { if let fileData = try? Data(contentsOf: url), @@ -119,12 +117,12 @@ private extension ExtensionFeedAddRequestFile { try data.write(to: url) } catch let error as NSError { - os_log(.error, log: Self.log, "Save to disk failed: %@.", error.localizedDescription) + self?.logger.error("Save to disk failed: \(error.localizedDescription, privacy: .public)") } }) if let error = errorPointer?.pointee { - os_log(.error, log: Self.log, "Save to disk coordination failed: %@.", error.localizedDescription) + logger.error("Save to disk coordination failed: \(error.localizedDescription, privacy: .public)") } requests?.forEach { processRequest($0) } diff --git a/Shared/Widget/WidgetDataDecoder.swift b/Shared/Widget/WidgetDataDecoder.swift index e2d03f53b..de26dc370 100644 --- a/Shared/Widget/WidgetDataDecoder.swift +++ b/Shared/Widget/WidgetDataDecoder.swift @@ -7,10 +7,11 @@ // import Foundation +import RSCore -struct WidgetDataDecoder { +struct WidgetDataDecoder: Logging { - static func decodeWidgetData() throws -> WidgetData { + func decodeWidgetData() throws -> WidgetData { let appGroup = Bundle.main.object(forInfoDictionaryKey: "AppGroup") as! String let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroup) let dataURL = containerURL?.appendingPathComponent("widget-data.json") @@ -22,13 +23,14 @@ struct WidgetDataDecoder { } } - static func sampleData() -> WidgetData { + func sampleData() -> WidgetData { let pathToSample = Bundle.main.url(forResource: "widget-sample", withExtension: "json") do { let data = try Data(contentsOf: pathToSample!) let decoded = try JSONDecoder().decode(WidgetData.self, from: data) return decoded } catch { + logger.error("Error accessing sample widget data: \(error.localizedDescription, privacy: .public)") return WidgetData(currentUnreadCount: 0, currentTodayCount: 0, currentStarredCount: 0, unreadArticles: [], starredArticles: [], todayArticles: [], lastUpdateTime: Date()) } } diff --git a/Shared/Widget/WidgetDataEncoder.swift b/Shared/Widget/WidgetDataEncoder.swift index f0a5b976f..b23525f90 100644 --- a/Shared/Widget/WidgetDataEncoder.swift +++ b/Shared/Widget/WidgetDataEncoder.swift @@ -8,16 +8,15 @@ import Foundation import WidgetKit -import os.log import UIKit import RSCore import Articles import Account -public final class WidgetDataEncoder { +public final class WidgetDataEncoder: Logging { + - private let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "Application") private let fetchLimit = 7 private var backgroundTaskID: UIBackgroundTaskIdentifier! @@ -36,7 +35,7 @@ public final class WidgetDataEncoder { @available(iOS 14, *) func encodeWidgetData() throws { flushSharedContainer() - os_log(.debug, log: log, "Starting encoding widget data.") + logger.debug("Started encoding widget data.") do { let unreadArticles = Array(try AccountManager.shared.fetchArticles(.unread(fetchLimit))).sortedByDate(.orderedDescending) @@ -95,14 +94,14 @@ public final class WidgetDataEncoder { } let encodedData = try? JSONEncoder().encode(latestData) - os_log(.debug, log: self.log, "Finished encoding widget data.") + self.logger.debug("Finished encoding widget data.") if self.fileExists() { try? FileManager.default.removeItem(at: self.dataURL!) - os_log(.debug, log: self.log, "Removed widget data from container.") + self.logger.debug("Removed widget data from container.") } if FileManager.default.createFile(atPath: self.dataURL!.path, contents: encodedData, attributes: nil) { - os_log(.debug, log: self.log, "Wrote widget data to container.") + self.logger.debug("Wrote widget data to container.") WidgetCenter.shared.reloadAllTimelines() UIApplication.shared.endBackgroundTask(self.backgroundTaskID!) self.backgroundTaskID = .invalid diff --git a/SyncDatabase/Package.swift b/SyncDatabase/Package.swift index 19f86b7ce..02fea65c1 100644 --- a/SyncDatabase/Package.swift +++ b/SyncDatabase/Package.swift @@ -18,7 +18,7 @@ dependencies.append(contentsOf: [ let package = Package( name: "SyncDatabase", - platforms: [.macOS(SupportedPlatform.MacOSVersion.v10_15), .iOS(SupportedPlatform.IOSVersion.v13)], + platforms: [.macOS(.v11), .iOS(.v14)], products: [ .library( name: "SyncDatabase", diff --git a/Widget/TimelineProvider.swift b/Widget/TimelineProvider.swift index 8ca18dc5d..87ff6b71b 100644 --- a/Widget/TimelineProvider.swift +++ b/Widget/TimelineProvider.swift @@ -8,35 +8,41 @@ import WidgetKit import SwiftUI +import RSCore -struct Provider: TimelineProvider { +struct Provider: TimelineProvider, Logging { + + let decoder = WidgetDataDecoder() func placeholder(in context: Context) -> WidgetTimelineEntry { do { - let data = try WidgetDataDecoder.decodeWidgetData() + let data = try decoder.decodeWidgetData() return WidgetTimelineEntry(date: Date(), widgetData: data) } catch { - return WidgetTimelineEntry(date: Date(), widgetData: WidgetDataDecoder.sampleData()) + logger.error("Failed to decode widget data: \(error.localizedDescription, privacy: .public)") + return WidgetTimelineEntry(date: Date(), widgetData: decoder.sampleData()) } } func getSnapshot(in context: Context, completion: @escaping (WidgetTimelineEntry) -> Void) { if context.isPreview { do { - let data = try WidgetDataDecoder.decodeWidgetData() + let data = try decoder.decodeWidgetData() completion(WidgetTimelineEntry(date: Date(), widgetData: data)) } catch { + logger.error("Failed to decode widget data: \(error.localizedDescription, privacy: .public)") completion(WidgetTimelineEntry(date: Date(), - widgetData: WidgetDataDecoder.sampleData())) + widgetData: decoder.sampleData())) } } else { do { - let widgetData = try WidgetDataDecoder.decodeWidgetData() + let widgetData = try decoder.decodeWidgetData() let entry = WidgetTimelineEntry(date: Date(), widgetData: widgetData) completion(entry) } catch { + logger.error("Failed to decode widget data: \(error.localizedDescription, privacy: .public)") let entry = WidgetTimelineEntry(date: Date(), - widgetData: WidgetDataDecoder.sampleData()) + widgetData: decoder.sampleData()) completion(entry) } } @@ -48,9 +54,10 @@ struct Provider: TimelineProvider { var entry: WidgetTimelineEntry do { - let widgetData = try WidgetDataDecoder.decodeWidgetData() + let widgetData = try decoder.decodeWidgetData() entry = WidgetTimelineEntry(date: date, widgetData: widgetData) } catch { + logger.error("Failed to decode widget data: \(error.localizedDescription, privacy: .public)") entry = WidgetTimelineEntry(date: date, widgetData: WidgetData(currentUnreadCount: 0, currentTodayCount: 0, currentStarredCount: 0, unreadArticles: [], starredArticles: [], todayArticles: [], lastUpdateTime: Date())) } diff --git a/Widget/Widget Views/SmartFeedSummaryWidget.swift b/Widget/Widget Views/SmartFeedSummaryWidget.swift index efa4fb756..b1baf3611 100644 --- a/Widget/Widget Views/SmartFeedSummaryWidget.swift +++ b/Widget/Widget Views/SmartFeedSummaryWidget.swift @@ -102,6 +102,6 @@ struct SmartFeedSummaryWidgetView: View { struct SmartFeedSummaryWidgetView_Previews: PreviewProvider { static var previews: some View { - SmartFeedSummaryWidgetView(entry: Provider.Entry.init(date: Date(), widgetData: WidgetDataDecoder.sampleData())) + SmartFeedSummaryWidgetView(entry: Provider.Entry.init(date: Date(), widgetData: WidgetDataDecoder().sampleData())) } } diff --git a/iOS/Account/FeedbinAccountViewController.swift b/iOS/Account/FeedbinAccountViewController.swift index c6e66844b..964ff7e93 100644 --- a/iOS/Account/FeedbinAccountViewController.swift +++ b/iOS/Account/FeedbinAccountViewController.swift @@ -11,8 +11,9 @@ import Account import Secrets import RSWeb import SafariServices +import RSCore -class FeedbinAccountViewController: UITableViewController { +class FeedbinAccountViewController: UITableViewController, Logging { @IBOutlet weak var activityIndicator: UIActivityIndicatorView! @IBOutlet weak var cancelBarButtonItem: UIBarButtonItem! @@ -116,7 +117,9 @@ class FeedbinAccountViewController: UITableViewController { do { try self.account?.removeCredentials(type: .basic) - } catch {} + } catch { + self.logger.error("Error removing credentials: \(error.localizedDescription, privacy: .public).") + } try self.account?.storeCredentials(credentials) self.account?.refreshAll() { result in @@ -132,6 +135,7 @@ class FeedbinAccountViewController: UITableViewController { self.delegate?.dismiss() } catch { self.showError(NSLocalizedString("Keychain error while storing credentials.", comment: "Credentials Error")) + self.logger.error("Keychain error while storing credentials: \(error.localizedDescription, privacy: .public).") } } else { self.showError(NSLocalizedString("Invalid email/password combination.", comment: "Credentials Error")) diff --git a/iOS/Account/NewsBlurAccountViewController.swift b/iOS/Account/NewsBlurAccountViewController.swift index e7ebf6e72..9f46361d0 100644 --- a/iOS/Account/NewsBlurAccountViewController.swift +++ b/iOS/Account/NewsBlurAccountViewController.swift @@ -10,9 +10,10 @@ import UIKit import Account import Secrets import RSWeb +import RSCore import SafariServices -class NewsBlurAccountViewController: UITableViewController { +class NewsBlurAccountViewController: UITableViewController, Logging { @IBOutlet weak var activityIndicator: UIActivityIndicatorView! @IBOutlet weak var cancelBarButtonItem: UIBarButtonItem! @@ -118,7 +119,9 @@ class NewsBlurAccountViewController: UITableViewController { do { try self.account?.removeCredentials(type: .newsBlurBasic) try self.account?.removeCredentials(type: .newsBlurSessionId) - } catch {} + } catch { + self.logger.error("Error removing credentials: \(error.localizedDescription, privacy: .public).") + } try self.account?.storeCredentials(basicCredentials) try self.account?.storeCredentials(sessionCredentials) @@ -135,6 +138,7 @@ class NewsBlurAccountViewController: UITableViewController { self.delegate?.dismiss() } catch { self.showError(NSLocalizedString("Keychain error while storing credentials.", comment: "Credentials Error")) + self.logger.error("Keychain error while storing credentials: \(error.localizedDescription, privacy: .public).") } } else { self.showError(NSLocalizedString("Invalid username/password combination.", comment: "Credentials Error")) diff --git a/iOS/Account/ReaderAPIAccountViewController.swift b/iOS/Account/ReaderAPIAccountViewController.swift index 79d603b7e..1f93ad95a 100644 --- a/iOS/Account/ReaderAPIAccountViewController.swift +++ b/iOS/Account/ReaderAPIAccountViewController.swift @@ -11,8 +11,9 @@ import Account import Secrets import RSWeb import SafariServices +import RSCore -class ReaderAPIAccountViewController: UITableViewController { +class ReaderAPIAccountViewController: UITableViewController, Logging { @IBOutlet weak var activityIndicator: UIActivityIndicatorView! @IBOutlet weak var cancelBarButtonItem: UIBarButtonItem! @@ -187,6 +188,7 @@ class ReaderAPIAccountViewController: UITableViewController { self.delegate?.dismiss() } catch { self.showError(NSLocalizedString("Keychain error while storing credentials.", comment: "Credentials Error")) + self.logger.error("Keychain error while storing credentials: \(error.localizedDescription, privacy: .public).") } } else { self.showError(NSLocalizedString("Invalid username/password combination.", comment: "Credentials Error")) diff --git a/iOS/AppDelegate.swift b/iOS/AppDelegate.swift index 298faba77..20e89fe8c 100644 --- a/iOS/AppDelegate.swift +++ b/iOS/AppDelegate.swift @@ -11,14 +11,13 @@ import RSCore import RSWeb import Account import BackgroundTasks -import os.log import Secrets import WidgetKit var appDelegate: AppDelegate! @UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, UnreadCountProvider { +class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, UnreadCountProvider, Logging { private var bgTaskDispatchQueue = DispatchQueue.init(label: "BGTaskScheduler") @@ -36,8 +35,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } } - var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "Application") - var userNotificationManager: UserNotificationManager! var faviconDownloader: FaviconDownloader! var imageDownloader: ImageDownloader! @@ -83,7 +80,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD let isFirstRun = AppDefaults.shared.isFirstRun if isFirstRun { - os_log("Is first run.", log: log, type: .info) + logger.info("Is first run.") } if isFirstRun && !AccountManager.shared.anyAccountHasAtLeastOneFeed() { @@ -166,7 +163,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD func resumeDatabaseProcessingIfNecessary() { if AccountManager.shared.isSuspended { AccountManager.shared.resumeAll() - os_log("Application processing resumed.", log: self.log, type: .info) + logger.info("Application processing resumed.") } } @@ -276,7 +273,7 @@ private extension AppDelegate { self.waitBackgroundUpdateTask = UIApplication.shared.beginBackgroundTask { [weak self] in guard let self = self else { return } self.completeProcessing(true) - os_log("Accounts wait for progress terminated for running too long.", log: self.log, type: .info) + self.logger.info("Accounts wait for progress terminated for running too long.") } DispatchQueue.main.async { [weak self] in @@ -288,18 +285,18 @@ private extension AppDelegate { func waitToComplete(completion: @escaping (Bool) -> Void) { guard UIApplication.shared.applicationState == .background else { - os_log("App came back to foreground, no longer waiting.", log: self.log, type: .info) + logger.info("App came back to foreground, no longer waiting.") completion(false) return } if AccountManager.shared.refreshInProgress || isSyncArticleStatusRunning { - os_log("Waiting for sync to finish...", log: self.log, type: .info) + logger.info("Waiting for sync to finish...") DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in self?.waitToComplete(completion: completion) } } else { - os_log("Refresh progress complete.", log: self.log, type: .info) + logger.info("Refresh progress complete.") completion(true) } } @@ -324,9 +321,9 @@ private extension AppDelegate { self.syncBackgroundUpdateTask = UIBackgroundTaskIdentifier.invalid } - self.syncBackgroundUpdateTask = UIApplication.shared.beginBackgroundTask { + self.syncBackgroundUpdateTask = UIApplication.shared.beginBackgroundTask { [weak self] in completeProcessing() - os_log("Accounts sync processing terminated for running too long.", log: self.log, type: .info) + self?.logger.info("Accounts sync processing terminated for running too long.") } DispatchQueue.main.async { @@ -350,7 +347,7 @@ private extension AppDelegate { } } - os_log("Application processing suspended.", log: self.log, type: .info) + logger.info("Application processing suspended.") } } @@ -374,11 +371,11 @@ private extension AppDelegate { // We send this to a dedicated serial queue because as of 11/05/19 on iOS 13.2 the call to the // task scheduler can hang indefinitely. - bgTaskDispatchQueue.async { + bgTaskDispatchQueue.async { [weak self] in do { try BGTaskScheduler.shared.submit(request) } catch { - os_log(.error, log: self.log, "Could not schedule app refresh: %@", error.localizedDescription) + self?.logger.error("Could not schedule app refresh: \(error.localizedDescription, privacy: .public)") } } } @@ -390,7 +387,7 @@ private extension AppDelegate { scheduleBackgroundFeedRefresh() // schedule next refresh - os_log("Woken to perform account refresh.", log: self.log, type: .info) + logger.info("Woken to perform account refresh.") DispatchQueue.main.async { if AccountManager.shared.isSuspended { @@ -400,7 +397,7 @@ private extension AppDelegate { if !AccountManager.shared.isSuspended { try? WidgetDataEncoder.shared.encodeWidgetData() self.suspendApplication() - os_log("Account refresh operation completed.", log: self.log, type: .info) + self.logger.info("Account refresh operation completed.") task.setTaskCompleted(success: true) } } @@ -408,7 +405,7 @@ private extension AppDelegate { // set expiration handler task.expirationHandler = { [weak task] in - os_log("Accounts refresh processing terminated for running too long.", log: self.log, type: .info) + self.logger.info("Accounts refresh processing terminated for running too long.") DispatchQueue.main.async { self.suspendApplication() task?.setTaskCompleted(success: false) @@ -431,12 +428,12 @@ private extension AppDelegate { resumeDatabaseProcessingIfNecessary() let account = AccountManager.shared.existingAccount(with: accountID) guard account != nil else { - os_log(.debug, log: self.log, "No account found from notification.") + logger.debug("No account found from notification.") return } let article = try? account!.fetchArticles(.articleIDs([articleID])) guard article != nil else { - os_log(.debug, log: self.log, "No article found from search using %@", articleID) + logger.debug("No account found from search using \(articleID, privacy: .public)") return } account!.markArticles(article!, statusKey: .read, flag: true) { _ in } @@ -459,12 +456,12 @@ private extension AppDelegate { resumeDatabaseProcessingIfNecessary() let account = AccountManager.shared.existingAccount(with: accountID) guard account != nil else { - os_log(.debug, log: self.log, "No account found from notification.") + logger.debug("No account found from notification.") return } let article = try? account!.fetchArticles(.articleIDs([articleID])) guard article != nil else { - os_log(.debug, log: self.log, "No article found from search using %@", articleID) + logger.debug("No article found from search using \(articleID, privacy: .public)") return } account!.markArticles(article!, statusKey: .starred, flag: true) { _ in } diff --git a/iOS/ErrorHandler.swift b/iOS/ErrorHandler.swift index 64957ad3b..cb5dd9fe3 100644 --- a/iOS/ErrorHandler.swift +++ b/iOS/ErrorHandler.swift @@ -8,24 +8,21 @@ import UIKit import RSCore -import os.log -struct ErrorHandler { - - private static var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "Application") +struct ErrorHandler: Logging { public static func present(_ viewController: UIViewController) -> (Error) -> () { return { [weak viewController] error in if UIApplication.shared.applicationState == .active { viewController?.presentError(error) } else { - ErrorHandler.log(error) + log(error) } } } public static func log(_ error: Error) { - os_log(.error, log: self.log, "%@", error.localizedDescription) + ErrorHandler.logger.error("\(error.localizedDescription, privacy: .public)") } } diff --git a/iOS/SceneCoordinator.swift b/iOS/SceneCoordinator.swift index da737f550..8eca04869 100644 --- a/iOS/SceneCoordinator.swift +++ b/iOS/SceneCoordinator.swift @@ -50,7 +50,7 @@ struct FeedNode: Hashable { } } -class SceneCoordinator: NSObject, UndoableCommandRunner { +class SceneCoordinator: NSObject, UndoableCommandRunner, Logging { var undoableCommands = [UndoableCommand]() var undoManager: UndoManager? { @@ -1272,6 +1272,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner { try ArticleThemeImporter.importTheme(controller: rootSplitViewController, filename: filename) } catch { NotificationCenter.default.post(name: .didFailToImportThemeWithError, object: nil, userInfo: ["error" : error]) + logger.error("Failed to import theme with error: \(error.localizedDescription, privacy: .public)") } } diff --git a/iOS/SceneDelegate.swift b/iOS/SceneDelegate.swift index 9d086813c..456b34577 100644 --- a/iOS/SceneDelegate.swift +++ b/iOS/SceneDelegate.swift @@ -10,8 +10,9 @@ import UIKit import UserNotifications import Account import Zip +import RSCore -class SceneDelegate: UIResponder, UIWindowSceneDelegate { +class SceneDelegate: UIResponder, UIWindowSceneDelegate, Logging { var window: UIWindow? var coordinator: SceneCoordinator! @@ -184,7 +185,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { DispatchQueue.main.async { NotificationCenter.default.post(name: .didBeginDownloadingTheme, object: nil) } - let task = URLSession.shared.downloadTask(with: request) { location, response, error in + let task = URLSession.shared.downloadTask(with: request) { [weak self] location, response, error in guard let location = location else { return } @@ -192,6 +193,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { try ArticleThemeDownloader.shared.handleFile(at: location) } catch { NotificationCenter.default.post(name: .didFailToImportThemeWithError, object: nil, userInfo: ["error": error]) + self?.logger.error("Failed to import theme with error: \(error.localizedDescription, privacy: .public)") } } task.resume() diff --git a/iOS/Settings/ArticleThemeImporter.swift b/iOS/Settings/ArticleThemeImporter.swift index bfc8ff23a..1f71e6033 100644 --- a/iOS/Settings/ArticleThemeImporter.swift +++ b/iOS/Settings/ArticleThemeImporter.swift @@ -7,8 +7,9 @@ // import UIKit +import RSCore -struct ArticleThemeImporter { +struct ArticleThemeImporter: Logging { static func importTheme(controller: UIViewController, filename: String) throws { let theme = try ArticleTheme(path: filename, isAppTheme: false) @@ -39,6 +40,7 @@ struct ArticleThemeImporter { confirmImportSuccess(controller: controller, themeName: theme.name) } catch { controller.presentError(error) + ArticleThemeImporter.logger.error("Error importing theme: \(error.localizedDescription, privacy: .public)") } } diff --git a/iOS/Settings/ArticleThemesTableViewController.swift b/iOS/Settings/ArticleThemesTableViewController.swift index d9a3d7f99..66d118caf 100644 --- a/iOS/Settings/ArticleThemesTableViewController.swift +++ b/iOS/Settings/ArticleThemesTableViewController.swift @@ -8,10 +8,10 @@ import Foundation import UniformTypeIdentifiers - +import RSCore import UIKit -class ArticleThemesTableViewController: UITableViewController { +class ArticleThemesTableViewController: UITableViewController, Logging { override func viewDidLoad() { let importBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(importTheme(_:))); @@ -118,6 +118,7 @@ extension ArticleThemesTableViewController: UIDocumentPickerDelegate { try ArticleThemeImporter.importTheme(controller: self, filename: url.standardizedFileURL.path) } catch { NotificationCenter.default.post(name: .didFailToImportThemeWithError, object: nil, userInfo: ["error": error]) + logger.error("Did fail to import theme: \(error.localizedDescription, privacy: .public)") } } diff --git a/iOS/Settings/SettingsViewController.swift b/iOS/Settings/SettingsViewController.swift index 6bd34618e..a1ab1f4af 100644 --- a/iOS/Settings/SettingsViewController.swift +++ b/iOS/Settings/SettingsViewController.swift @@ -13,8 +13,9 @@ import SafariServices import SwiftUI import UniformTypeIdentifiers import UserNotifications +import RSCore -class SettingsViewController: UITableViewController { +class SettingsViewController: UITableViewController, Logging { private weak var opmlAccount: Account? @@ -509,6 +510,7 @@ private extension SettingsViewController { try opmlString.write(to: tempFile, atomically: true, encoding: String.Encoding.utf8) } catch { self.presentError(title: "OPML Export Error", message: error.localizedDescription) + logger.error("OPML Export Error: \(error.localizedDescription, privacy: .public)") } let docPicker = UIDocumentPickerViewController(forExporting: [tempFile], asCopy: true) From abd8aeceba97b3f798b35574adfef84ef476c25b Mon Sep 17 00:00:00 2001 From: Stuart Breckenridge Date: Sun, 4 Sep 2022 21:47:55 +0800 Subject: [PATCH 2/4] Adds Logs technote --- Technotes/Logs.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Technotes/Logs.md diff --git a/Technotes/Logs.md b/Technotes/Logs.md new file mode 100644 index 000000000..c9bbdf20c --- /dev/null +++ b/Technotes/Logs.md @@ -0,0 +1,20 @@ +# Logs + +`RSCore` contains a protocol called `Logging`. Classes and Structs that conform to `Logging` have a `logger` variable that the Class or Struct can use instead of importing `os.log` and creating a `var log = Logger(..)` variable. + +Example: + +```swift + + import Foundation + import RSCore + + class Sample: Logging { + + init() { + logger.debug("Init") + } + } + +} +``` From 932ca403cd3bc65eaa4cff6fe6ae4bf82fd481a2 Mon Sep 17 00:00:00 2001 From: Stuart Breckenridge Date: Sun, 4 Sep 2022 21:49:01 +0800 Subject: [PATCH 3/4] Fixes typos --- Technotes/Logs.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Technotes/Logs.md b/Technotes/Logs.md index c9bbdf20c..284b29c5d 100644 --- a/Technotes/Logs.md +++ b/Technotes/Logs.md @@ -6,15 +6,13 @@ Example: ```swift - import Foundation - import RSCore +import Foundation +import RSCore - class Sample: Logging { +class Sample: Logging { - init() { - logger.debug("Init") - } + init() { + logger.debug("Init") } - } ``` From d419beb15ea624719e7c509c6b5305c2733f1864 Mon Sep 17 00:00:00 2001 From: Stuart Breckenridge Date: Mon, 19 Sep 2022 09:22:54 +0800 Subject: [PATCH 4/4] Replaces final `os_log` entries with `Logging` --- .../Sources/Account/AccountSyncError.swift | 7 ++-- .../Feedly/FeedlyAccountDelegate.swift | 38 ++++++++---------- .../FeedlyAddExistingFeedOperation.swift | 7 ++-- .../FeedlyAddNewFeedOperation.swift | 15 +++---- ...teFeedsForCollectionFoldersOperation.swift | 13 +++--- .../FeedlyDownloadArticlesOperation.swift | 22 ++++------ ...yFetchIdsForMissingArticlesOperation.swift | 9 ++--- .../FeedlyGetCollectionsOperation.swift | 14 +++---- .../FeedlyGetEntriesOperation.swift | 23 +++++------ .../FeedlyGetStreamContentsOperation.swift | 16 ++++---- .../FeedlyGetStreamIdsOperation.swift | 10 ++--- .../FeedlyGetUpdatedArticleIdsOperation.swift | 17 ++++---- ...edlyIngestStarredArticleIdsOperation.swift | 12 +++--- ...eedlyIngestStreamArticleIdsOperation.swift | 14 +++---- ...eedlyIngestUnreadArticleIdsOperation.swift | 12 +++--- .../Operations/FeedlyLogoutOperation.swift | 14 +++---- ...yMirrorCollectionsAsFoldersOperation.swift | 14 +++---- ...lyOrganiseParsedItemsByFeedOperation.swift | 10 ++--- .../FeedlyRefreshAccessTokenOperation.swift | 16 ++++---- .../FeedlyRequestStreamsOperation.swift | 13 +++--- .../FeedlySendArticleStatusesOperation.swift | 12 +++--- .../Operations/FeedlySyncAllOperation.swift | 40 +++++++++---------- .../FeedlySyncStreamContentsOperation.swift | 30 ++++++-------- ...UpdateAccountFeedsWithItemsOperation.swift | 10 ++--- .../NewsBlurAccountDelegate+Internal.swift | 18 ++++----- .../NewsBlur/NewsBlurAccountDelegate.swift | 33 +++++++-------- .../xcshareddata/swiftpm/Package.resolved | 4 +- 27 files changed, 191 insertions(+), 252 deletions(-) diff --git a/Account/Sources/Account/AccountSyncError.swift b/Account/Sources/Account/AccountSyncError.swift index efc88da1e..ee90b8806 100644 --- a/Account/Sources/Account/AccountSyncError.swift +++ b/Account/Sources/Account/AccountSyncError.swift @@ -7,22 +7,21 @@ // import Foundation -import os.log +import RSCore public extension Notification.Name { static let AccountsDidFailToSyncWithErrors = Notification.Name("AccountsDidFailToSyncWithErrors") } -public struct AccountSyncError { +public struct AccountSyncError: Logging { - private static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "Application") public let account: Account public let error: Error init(account: Account, error: Error) { self.account = account self.error = error - os_log(.error, log: AccountSyncError.log, "%@", error.localizedDescription) + AccountSyncError.logger.error("Account Sync Error: \(error.localizedDescription)") } } diff --git a/Account/Sources/Account/Feedly/FeedlyAccountDelegate.swift b/Account/Sources/Account/Feedly/FeedlyAccountDelegate.swift index efa7436ae..1c8bda76c 100644 --- a/Account/Sources/Account/Feedly/FeedlyAccountDelegate.swift +++ b/Account/Sources/Account/Feedly/FeedlyAccountDelegate.swift @@ -11,10 +11,9 @@ import RSCore import RSParser import RSWeb import SyncDatabase -import os.log import Secrets -final class FeedlyAccountDelegate: AccountDelegate { +final class FeedlyAccountDelegate: AccountDelegate, Logging { /// Feedly has a sandbox API and a production API. /// This property is referred to when clients need to know which environment it should be pointing to. @@ -61,7 +60,6 @@ final class FeedlyAccountDelegate: AccountDelegate { internal let caller: FeedlyAPICaller - private let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "Feedly") private let database: SyncDatabase private weak var currentSyncAllOperation: MainThreadOperation? @@ -112,20 +110,18 @@ final class FeedlyAccountDelegate: AccountDelegate { assert(Thread.isMainThread) guard currentSyncAllOperation == nil else { - os_log(.debug, log: log, "Ignoring refreshAll: Feedly sync already in progress.") + self.logger.debug("Ignoring refreshAll: Feedly sync already in progress.") completion(.success(())) return } guard let credentials = credentials else { - os_log(.debug, log: log, "Ignoring refreshAll: Feedly account has no credentials.") + self.logger.debug("Ignoring refreshAll: Feedly account has no credentials.") completion(.failure(FeedlyAccountDelegateError.notLoggedIn)) return } - let log = self.log - - let syncAllOperation = FeedlySyncAllOperation(account: account, feedlyUserId: credentials.username, caller: caller, database: database, lastSuccessfulFetchStartDate: accountMetadata?.lastArticleFetchStartTime, downloadProgress: refreshProgress, log: log) + let syncAllOperation = FeedlySyncAllOperation(account: account, feedlyUserId: credentials.username, caller: caller, database: database, lastSuccessfulFetchStartDate: accountMetadata?.lastArticleFetchStartTime, downloadProgress: refreshProgress) syncAllOperation.downloadProgress = refreshProgress @@ -136,7 +132,7 @@ final class FeedlyAccountDelegate: AccountDelegate { self?.accountMetadata?.lastArticleFetchEndTime = Date() } - os_log(.debug, log: log, "Sync took %{public}.3f seconds", -date.timeIntervalSinceNow) + self?.logger.debug("Sync took \(-date.timeIntervalSinceNow) seconds.") completion(result) } @@ -154,10 +150,12 @@ final class FeedlyAccountDelegate: AccountDelegate { case .success: completion?(.success(())) case .failure(let error): + self.logger.error("Failed to refresh article status for account \(String(describing: account.type)): \(error.localizedDescription)") completion?(.failure(error)) } } case .failure(let error): + self.logger.error("Failed to send article status for account \(String(describing: account.type)): \(error.localizedDescription)") completion?(.failure(error)) } } @@ -165,7 +163,7 @@ final class FeedlyAccountDelegate: AccountDelegate { func sendArticleStatus(for account: Account, completion: @escaping ((Result) -> Void)) { // Ensure remote articles have the same status as they do locally. - let send = FeedlySendArticleStatusesOperation(database: database, service: caller, log: log) + let send = FeedlySendArticleStatusesOperation(database: database, service: caller) send.completionBlock = { operation in // TODO: not call with success if operation was canceled? Not sure. DispatchQueue.main.async { @@ -188,7 +186,7 @@ final class FeedlyAccountDelegate: AccountDelegate { let group = DispatchGroup() - let ingestUnread = FeedlyIngestUnreadArticleIdsOperation(account: account, userId: credentials.username, service: caller, database: database, newerThan: nil, log: log) + let ingestUnread = FeedlyIngestUnreadArticleIdsOperation(account: account, userId: credentials.username, service: caller, database: database, newerThan: nil) group.enter() ingestUnread.completionBlock = { _ in @@ -196,7 +194,7 @@ final class FeedlyAccountDelegate: AccountDelegate { } - let ingestStarred = FeedlyIngestStarredArticleIdsOperation(account: account, userId: credentials.username, service: caller, database: database, newerThan: nil, log: log) + let ingestStarred = FeedlyIngestStarredArticleIdsOperation(account: account, userId: credentials.username, service: caller, database: database, newerThan: nil) group.enter() ingestStarred.completionBlock = { _ in @@ -220,21 +218,21 @@ final class FeedlyAccountDelegate: AccountDelegate { return } - os_log(.debug, log: log, "Begin importing OPML...") + logger.debug("Begin importing OPML...") isOPMLImportInProgress = true refreshProgress.addToNumberOfTasksAndRemaining(1) caller.importOpml(data) { result in switch result { case .success: - os_log(.debug, log: self.log, "Import OPML done.") + self.logger.debug("Import OPML done.") self.refreshProgress.completeTask() self.isOPMLImportInProgress = false DispatchQueue.main.async { completion(.success(())) } case .failure(let error): - os_log(.debug, log: self.log, "Import OPML failed.") + self.logger.error("Import OPML failed: \(error.localizedDescription)") self.refreshProgress.completeTask() self.isOPMLImportInProgress = false DispatchQueue.main.async { @@ -331,8 +329,7 @@ final class FeedlyAccountDelegate: AccountDelegate { getStreamContentsService: caller, database: database, container: container, - progress: refreshProgress, - log: log) + progress: refreshProgress) addNewFeed.addCompletionHandler = { result in completion(result) @@ -388,7 +385,6 @@ final class FeedlyAccountDelegate: AccountDelegate { service: caller, container: container, progress: refreshProgress, - log: log, customFeedName: feed.editedName) @@ -494,7 +490,7 @@ final class FeedlyAccountDelegate: AccountDelegate { case .success: break case .failure(let error): - os_log(.error, log: self.log, "Restore folder feed error: %@.", error.localizedDescription) + self.logger.error("Restore folder feed error: \(error.localizedDescription)") } } @@ -534,7 +530,7 @@ final class FeedlyAccountDelegate: AccountDelegate { } func accountWillBeDeleted(_ account: Account) { - let logout = FeedlyLogoutOperation(account: account, service: caller, log: log) + let logout = FeedlyLogoutOperation(account: account, service: caller) // Dispatch on the shared queue because the lifetime of the account delegate is uncertain. MainThreadOperationQueue.shared.add(logout) } @@ -582,7 +578,7 @@ extension FeedlyAccountDelegate: FeedlyAPICallerDelegate { } } - let refreshAccessToken = FeedlyRefreshAccessTokenOperation(account: account, service: self, oauthClient: oauthAuthorizationClient, log: log) + let refreshAccessToken = FeedlyRefreshAccessTokenOperation(account: account, service: self, oauthClient: oauthAuthorizationClient) refreshAccessToken.downloadProgress = refreshProgress /// This must be strongly referenced by the completionBlock of the `FeedlyRefreshAccessTokenOperation`. diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyAddExistingFeedOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyAddExistingFeedOperation.swift index ed0824663..7df86127a 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyAddExistingFeedOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyAddExistingFeedOperation.swift @@ -7,17 +7,16 @@ // import Foundation -import os.log import RSWeb import RSCore import Secrets -class FeedlyAddExistingFeedOperation: FeedlyOperation, FeedlyOperationDelegate, FeedlyCheckpointOperationDelegate { +class FeedlyAddExistingFeedOperation: FeedlyOperation, FeedlyOperationDelegate, FeedlyCheckpointOperationDelegate, Logging { private let operationQueue = MainThreadOperationQueue() var addCompletionHandler: ((Result) -> ())? - init(account: Account, credentials: Credentials, resource: FeedlyFeedResourceId, service: FeedlyAddFeedToCollectionService, container: Container, progress: DownloadProgress, log: OSLog, customFeedName: String? = nil) throws { + init(account: Account, credentials: Credentials, resource: FeedlyFeedResourceId, service: FeedlyAddFeedToCollectionService, container: Container, progress: DownloadProgress, customFeedName: String? = nil) throws { let validator = FeedlyFeedContainerValidator(container: container) let (folder, collectionId) = try validator.getValidContainer() @@ -33,7 +32,7 @@ class FeedlyAddExistingFeedOperation: FeedlyOperation, FeedlyOperationDelegate, addRequest.downloadProgress = progress self.operationQueue.add(addRequest) - let createFeeds = FeedlyCreateFeedsForCollectionFoldersOperation(account: account, feedsAndFoldersProvider: addRequest, log: log) + let createFeeds = FeedlyCreateFeedsForCollectionFoldersOperation(account: account, feedsAndFoldersProvider: addRequest) createFeeds.downloadProgress = progress createFeeds.addDependency(addRequest) self.operationQueue.add(createFeeds) diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyAddNewFeedOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyAddNewFeedOperation.swift index b1a549607..2078d2610 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyAddNewFeedOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyAddNewFeedOperation.swift @@ -7,13 +7,12 @@ // import Foundation -import os.log import SyncDatabase import RSWeb import RSCore import Secrets -class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, FeedlySearchOperationDelegate, FeedlyCheckpointOperationDelegate { +class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, FeedlySearchOperationDelegate, FeedlyCheckpointOperationDelegate, Logging { private let operationQueue = MainThreadOperationQueue() private let folder: Folder @@ -26,11 +25,10 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl private let addToCollectionService: FeedlyAddFeedToCollectionService private let syncUnreadIdsService: FeedlyGetStreamIdsService private let getStreamContentsService: FeedlyGetStreamContentsService - private let log: OSLog private var feedResourceId: FeedlyFeedResourceId? var addCompletionHandler: ((Result) -> ())? - init(account: Account, credentials: Credentials, url: String, feedName: String?, searchService: FeedlySearchService, addToCollectionService: FeedlyAddFeedToCollectionService, syncUnreadIdsService: FeedlyGetStreamIdsService, getStreamContentsService: FeedlyGetStreamContentsService, database: SyncDatabase, container: Container, progress: DownloadProgress, log: OSLog) throws { + init(account: Account, credentials: Credentials, url: String, feedName: String?, searchService: FeedlySearchService, addToCollectionService: FeedlyAddFeedToCollectionService, syncUnreadIdsService: FeedlyGetStreamIdsService, getStreamContentsService: FeedlyGetStreamContentsService, database: SyncDatabase, container: Container, progress: DownloadProgress) throws { let validator = FeedlyFeedContainerValidator(container: container) @@ -45,7 +43,6 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl self.addToCollectionService = addToCollectionService self.syncUnreadIdsService = syncUnreadIdsService self.getStreamContentsService = getStreamContentsService - self.log = log super.init() @@ -91,19 +88,19 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl addRequest.downloadProgress = downloadProgress operationQueue.add(addRequest) - let createFeeds = FeedlyCreateFeedsForCollectionFoldersOperation(account: account, feedsAndFoldersProvider: addRequest, log: log) + let createFeeds = FeedlyCreateFeedsForCollectionFoldersOperation(account: account, feedsAndFoldersProvider: addRequest) createFeeds.delegate = self createFeeds.addDependency(addRequest) createFeeds.downloadProgress = downloadProgress operationQueue.add(createFeeds) - let syncUnread = FeedlyIngestUnreadArticleIdsOperation(account: account, userId: credentials.username, service: syncUnreadIdsService, database: database, newerThan: nil, log: log) + let syncUnread = FeedlyIngestUnreadArticleIdsOperation(account: account, userId: credentials.username, service: syncUnreadIdsService, database: database, newerThan: nil) syncUnread.addDependency(createFeeds) syncUnread.downloadProgress = downloadProgress syncUnread.delegate = self operationQueue.add(syncUnread) - let syncFeed = FeedlySyncStreamContentsOperation(account: account, resource: feedResourceId, service: getStreamContentsService, isPagingEnabled: false, newerThan: nil, log: log) + let syncFeed = FeedlySyncStreamContentsOperation(account: account, resource: feedResourceId, service: getStreamContentsService, isPagingEnabled: false, newerThan: nil) syncFeed.addDependency(syncUnread) syncFeed.downloadProgress = downloadProgress syncFeed.delegate = self @@ -121,7 +118,7 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl addCompletionHandler?(.failure(error)) addCompletionHandler = nil - os_log(.debug, log: log, "Unable to add new feed: %{public}@.", error as NSError) + logger.debug("Unale to add new feed: \(error.localizedDescription, privacy: .public)") cancel() } diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyCreateFeedsForCollectionFoldersOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyCreateFeedsForCollectionFoldersOperation.swift index b5424b384..4637228e8 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyCreateFeedsForCollectionFoldersOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyCreateFeedsForCollectionFoldersOperation.swift @@ -7,19 +7,17 @@ // import Foundation -import os.log +import RSCore /// Single responsibility is to accurately reflect Collections and their Feeds as Folders and their Feeds. -final class FeedlyCreateFeedsForCollectionFoldersOperation: FeedlyOperation { +final class FeedlyCreateFeedsForCollectionFoldersOperation: FeedlyOperation, Logging { let account: Account let feedsAndFoldersProvider: FeedlyFeedsAndFoldersProviding - let log: OSLog - init(account: Account, feedsAndFoldersProvider: FeedlyFeedsAndFoldersProviding, log: OSLog) { + init(account: Account, feedsAndFoldersProvider: FeedlyFeedsAndFoldersProviding) { self.feedsAndFoldersProvider = feedsAndFoldersProvider self.account = account - self.log = log } override func run() { @@ -40,7 +38,6 @@ final class FeedlyCreateFeedsForCollectionFoldersOperation: FeedlyOperation { let feedsToRemove = feedsInFolder.filter { !feedsInCollection.contains($0.webFeedID) } if !feedsToRemove.isEmpty { folder.removeFeeds(feedsToRemove) -// os_log(.debug, log: log, "\"%@\" - removed: %@", collection.label, feedsToRemove.map { $0.feedID }, feedsInCollection) } } @@ -94,7 +91,7 @@ final class FeedlyCreateFeedsForCollectionFoldersOperation: FeedlyOperation { return (feed, folder) } - os_log(.debug, log: log, "Processing %i feeds.", feedsAndFolders.count) + logger.debug("Processing \(feedsAndFolders.count) feeds.") feedsAndFolders.forEach { (feed, folder) in if !folder.has(feed) { folder.addWebFeed(feed) @@ -107,7 +104,7 @@ final class FeedlyCreateFeedsForCollectionFoldersOperation: FeedlyOperation { account.removeFeeds(feedsWithoutCollections) if !feedsWithoutCollections.isEmpty { - os_log(.debug, log: log, "Removed %i feeds", feedsWithoutCollections.count) + logger.debug("Removed \(feedsWithoutCollections.count) feeds.") } } } diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyDownloadArticlesOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyDownloadArticlesOperation.swift index 550ee34d7..3e497468f 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyDownloadArticlesOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyDownloadArticlesOperation.swift @@ -7,28 +7,25 @@ // import Foundation -import os.log import RSCore import RSWeb -class FeedlyDownloadArticlesOperation: FeedlyOperation { +class FeedlyDownloadArticlesOperation: FeedlyOperation, Logging { private let account: Account - private let log: OSLog private let missingArticleEntryIdProvider: FeedlyEntryIdentifierProviding private let updatedArticleEntryIdProvider: FeedlyEntryIdentifierProviding private let getEntriesService: FeedlyGetEntriesService private let operationQueue = MainThreadOperationQueue() private let finishOperation: FeedlyCheckpointOperation - init(account: Account, missingArticleEntryIdProvider: FeedlyEntryIdentifierProviding, updatedArticleEntryIdProvider: FeedlyEntryIdentifierProviding, getEntriesService: FeedlyGetEntriesService, log: OSLog) { + init(account: Account, missingArticleEntryIdProvider: FeedlyEntryIdentifierProviding, updatedArticleEntryIdProvider: FeedlyEntryIdentifierProviding, getEntriesService: FeedlyGetEntriesService) { self.account = account self.operationQueue.suspend() self.missingArticleEntryIdProvider = missingArticleEntryIdProvider self.updatedArticleEntryIdProvider = updatedArticleEntryIdProvider self.getEntriesService = getEntriesService self.finishOperation = FeedlyCheckpointOperation() - self.log = log super.init() self.finishOperation.checkpointDelegate = self self.operationQueue.add(self.finishOperation) @@ -38,26 +35,24 @@ class FeedlyDownloadArticlesOperation: FeedlyOperation { var articleIds = missingArticleEntryIdProvider.entryIds articleIds.formUnion(updatedArticleEntryIdProvider.entryIds) - os_log(.debug, log: log, "Requesting %{public}i articles.", articleIds.count) + self.logger.debug("Requesting \(articleIds.count) articles.") let feedlyAPILimitBatchSize = 1000 for articleIds in Array(articleIds).chunked(into: feedlyAPILimitBatchSize) { let provider = FeedlyEntryIdentifierProvider(entryIds: Set(articleIds)) - let getEntries = FeedlyGetEntriesOperation(account: account, service: getEntriesService, provider: provider, log: log) + let getEntries = FeedlyGetEntriesOperation(account: account, service: getEntriesService, provider: provider) getEntries.delegate = self self.operationQueue.add(getEntries) let organiseByFeed = FeedlyOrganiseParsedItemsByFeedOperation(account: account, - parsedItemProvider: getEntries, - log: log) + parsedItemProvider: getEntries) organiseByFeed.delegate = self organiseByFeed.addDependency(getEntries) self.operationQueue.add(organiseByFeed) let updateAccount = FeedlyUpdateAccountFeedsWithItemsOperation(account: account, - organisedItemsProvider: organiseByFeed, - log: log) + organisedItemsProvider: organiseByFeed) updateAccount.delegate = self updateAccount.addDependency(organiseByFeed) @@ -70,8 +65,7 @@ class FeedlyDownloadArticlesOperation: FeedlyOperation { } override func didCancel() { - // TODO: fix error on below line: "Expression type '()' is ambiguous without more context" - //os_log(.debug, log: log, "Cancelling %{public}@.", self) + logger.debug("Cancelling \(String(describing: self)).") operationQueue.cancelAllOperations() super.didCancel() } @@ -90,7 +84,7 @@ extension FeedlyDownloadArticlesOperation: FeedlyOperationDelegate { assert(Thread.isMainThread) // Having this log is useful for debugging missing required JSON keys in the response from Feedly, for example. - os_log(.debug, log: log, "%{public}@ failed with error: %{public}@.", String(describing: operation), error as NSError) + self.logger.debug("\(String(describing: operation)) failed with error: \(error.localizedDescription)") cancel() } diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyFetchIdsForMissingArticlesOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyFetchIdsForMissingArticlesOperation.swift index bc37dfdb7..a9f53f633 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyFetchIdsForMissingArticlesOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyFetchIdsForMissingArticlesOperation.swift @@ -7,18 +7,16 @@ // import Foundation -import os.log +import RSCore -final class FeedlyFetchIdsForMissingArticlesOperation: FeedlyOperation, FeedlyEntryIdentifierProviding { +final class FeedlyFetchIdsForMissingArticlesOperation: FeedlyOperation, FeedlyEntryIdentifierProviding, Logging { private let account: Account - private let log: OSLog private(set) var entryIds = Set() - init(account: Account, log: OSLog) { + init(account: Account) { self.account = account - self.log = log } override func run() { @@ -29,6 +27,7 @@ final class FeedlyFetchIdsForMissingArticlesOperation: FeedlyOperation, FeedlyEn self.didFinish() case .failure(let error): + self.logger.error("Failed to fetch articleIDs: \(error.localizedDescription).") self.didFinish(with: error) } } diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyGetCollectionsOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyGetCollectionsOperation.swift index 151fc2e28..f6feec0a4 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyGetCollectionsOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyGetCollectionsOperation.swift @@ -7,37 +7,35 @@ // import Foundation -import os.log +import RSCore protocol FeedlyCollectionProviding: AnyObject { var collections: [FeedlyCollection] { get } } /// Get Collections from Feedly. -final class FeedlyGetCollectionsOperation: FeedlyOperation, FeedlyCollectionProviding { +final class FeedlyGetCollectionsOperation: FeedlyOperation, FeedlyCollectionProviding, Logging { let service: FeedlyGetCollectionsService - let log: OSLog private(set) var collections = [FeedlyCollection]() - init(service: FeedlyGetCollectionsService, log: OSLog) { + init(service: FeedlyGetCollectionsService) { self.service = service - self.log = log } override func run() { - os_log(.debug, log: log, "Requesting collections.") + logger.debug("Requesting collections.") service.getCollections { result in switch result { case .success(let collections): - os_log(.debug, log: self.log, "Received collections: %{public}@", collections.map { $0.id }) + self.logger.debug("Receving collections: \(collections.map({ $0.id }))") self.collections = collections self.didFinish() case .failure(let error): - os_log(.debug, log: self.log, "Unable to request collections: %{public}@.", error as NSError) + self.logger.error("Unable to request collections: \(error.localizedDescription).") self.didFinish(with: error) } } diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyGetEntriesOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyGetEntriesOperation.swift index f306792f6..2cf78e8b1 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyGetEntriesOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyGetEntriesOperation.swift @@ -7,22 +7,20 @@ // import Foundation -import os.log +import RSCore import RSParser /// Get full entries for the entry identifiers. -final class FeedlyGetEntriesOperation: FeedlyOperation, FeedlyEntryProviding, FeedlyParsedItemProviding { +final class FeedlyGetEntriesOperation: FeedlyOperation, FeedlyEntryProviding, FeedlyParsedItemProviding, Logging { let account: Account let service: FeedlyGetEntriesService let provider: FeedlyEntryIdentifierProviding - let log: OSLog - init(account: Account, service: FeedlyGetEntriesService, provider: FeedlyEntryIdentifierProviding, log: OSLog) { + init(account: Account, service: FeedlyGetEntriesService, provider: FeedlyEntryIdentifierProviding) { self.account = account self.service = service self.provider = provider - self.log = log } private (set) var entries = [FeedlyEntry]() @@ -38,13 +36,12 @@ final class FeedlyGetEntriesOperation: FeedlyOperation, FeedlyEntryProviding, Fe FeedlyEntryParser(entry: $0).parsedItemRepresentation }) - // TODO: Fix the below. There’s an error on the os.log line: "Expression type '()' is ambiguous without more context" -// if parsed.count != entries.count { -// let entryIds = Set(entries.map { $0.id }) -// let parsedIds = Set(parsed.map { $0.uniqueID }) -// let difference = entryIds.subtracting(parsedIds) -// os_log(.debug, log: log, "%{public}@ dropping articles with ids: %{public}@.", self, difference) -// } + if parsed.count != entries.count { + let entryIds = Set(entries.map { $0.id }) + let parsedIds = Set(parsed.map { $0.uniqueID }) + let difference = entryIds.subtracting(parsedIds) + self.logger.debug("\(String(describing: self)) dropping articles with ids: \(difference)).") + } storedParsedEntries = parsed @@ -63,7 +60,7 @@ final class FeedlyGetEntriesOperation: FeedlyOperation, FeedlyEntryProviding, Fe self.didFinish() case .failure(let error): - os_log(.debug, log: self.log, "Unable to get entries: %{public}@.", error as NSError) + self.logger.error("Unable to get entries: \(error.localizedDescription)") self.didFinish(with: error) } } diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyGetStreamContentsOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyGetStreamContentsOperation.swift index 7cdde6576..f5bd51fb4 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyGetStreamContentsOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyGetStreamContentsOperation.swift @@ -8,7 +8,7 @@ import Foundation import RSParser -import os.log +import RSCore protocol FeedlyEntryProviding { var entries: [FeedlyEntry] { get } @@ -24,7 +24,7 @@ protocol FeedlyGetStreamContentsOperationDelegate: AnyObject { } /// Get the stream content of a Collection from Feedly. -final class FeedlyGetStreamContentsOperation: FeedlyOperation, FeedlyEntryProviding, FeedlyParsedItemProviding { +final class FeedlyGetStreamContentsOperation: FeedlyOperation, FeedlyEntryProviding, FeedlyParsedItemProviding, Logging { struct ResourceProvider: FeedlyResourceProviding { var resource: FeedlyResourceId @@ -58,7 +58,7 @@ final class FeedlyGetStreamContentsOperation: FeedlyOperation, FeedlyEntryProvid let entryIds = Set(entries.map { $0.id }) let parsedIds = Set(parsed.map { $0.uniqueID }) let difference = entryIds.subtracting(parsedIds) - os_log(.debug, log: log, "Dropping articles with ids: %{public}@.", difference) + logger.debug("Dropping articles with ids: \(difference)") } storedParsedEntries = parsed @@ -79,22 +79,20 @@ final class FeedlyGetStreamContentsOperation: FeedlyOperation, FeedlyEntryProvid let unreadOnly: Bool? let newerThan: Date? let continuation: String? - let log: OSLog weak var streamDelegate: FeedlyGetStreamContentsOperationDelegate? - init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamContentsService, continuation: String? = nil, newerThan: Date?, unreadOnly: Bool? = nil, log: OSLog) { + init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamContentsService, continuation: String? = nil, newerThan: Date?, unreadOnly: Bool? = nil) { self.account = account self.resourceProvider = ResourceProvider(resource: resource) self.service = service self.continuation = continuation self.unreadOnly = unreadOnly self.newerThan = newerThan - self.log = log } - convenience init(account: Account, resourceProvider: FeedlyResourceProviding, service: FeedlyGetStreamContentsService, newerThan: Date?, unreadOnly: Bool? = nil, log: OSLog) { - self.init(account: account, resource: resourceProvider.resource, service: service, newerThan: newerThan, unreadOnly: unreadOnly, log: log) + convenience init(account: Account, resourceProvider: FeedlyResourceProviding, service: FeedlyGetStreamContentsService, newerThan: Date?, unreadOnly: Bool? = nil) { + self.init(account: account, resource: resourceProvider.resource, service: service, newerThan: newerThan, unreadOnly: unreadOnly) } override func run() { @@ -108,7 +106,7 @@ final class FeedlyGetStreamContentsOperation: FeedlyOperation, FeedlyEntryProvid self.didFinish() case .failure(let error): - os_log(.debug, log: self.log, "Unable to get stream contents: %{public}@.", error as NSError) + self.logger.error("Unable to get stream contents: \(error.localizedDescription)") self.didFinish(with: error) } } diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyGetStreamIdsOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyGetStreamIdsOperation.swift index 602520720..2761d9e13 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyGetStreamIdsOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyGetStreamIdsOperation.swift @@ -7,14 +7,14 @@ // import Foundation -import os.log +import RSCore protocol FeedlyGetStreamIdsOperationDelegate: AnyObject { func feedlyGetStreamIdsOperation(_ operation: FeedlyGetStreamIdsOperation, didGet streamIds: FeedlyStreamIds) } /// Single responsibility is to get the stream ids from Feedly. -final class FeedlyGetStreamIdsOperation: FeedlyOperation, FeedlyEntryIdentifierProviding { +final class FeedlyGetStreamIdsOperation: FeedlyOperation, FeedlyEntryIdentifierProviding, Logging { var entryIds: Set { guard let ids = streamIds?.ids else { @@ -32,16 +32,14 @@ final class FeedlyGetStreamIdsOperation: FeedlyOperation, FeedlyEntryIdentifierP let resource: FeedlyResourceId let unreadOnly: Bool? let newerThan: Date? - let log: OSLog - init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, continuation: String? = nil, newerThan: Date? = nil, unreadOnly: Bool?, log: OSLog) { + init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, continuation: String? = nil, newerThan: Date? = nil, unreadOnly: Bool?) { self.account = account self.resource = resource self.service = service self.continuation = continuation self.newerThan = newerThan self.unreadOnly = unreadOnly - self.log = log } weak var streamIdsDelegate: FeedlyGetStreamIdsOperationDelegate? @@ -57,7 +55,7 @@ final class FeedlyGetStreamIdsOperation: FeedlyOperation, FeedlyEntryIdentifierP self.didFinish() case .failure(let error): - os_log(.debug, log: self.log, "Unable to get stream ids: %{public}@.", error as NSError) + self.logger.error("Unable to get stream ids: \(error.localizedDescription)") self.didFinish(with: error) } } diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyGetUpdatedArticleIdsOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyGetUpdatedArticleIdsOperation.swift index 09968d750..0520d910b 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyGetUpdatedArticleIdsOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyGetUpdatedArticleIdsOperation.swift @@ -7,32 +7,30 @@ // import Foundation -import os.log +import RSCore import Secrets /// Single responsibility is to identify articles that have changed since a particular date. /// /// Typically, it pages through the article ids of the global.all stream. /// When all the article ids are collected, it is the responsibility of another operation to download them when appropriate. -class FeedlyGetUpdatedArticleIdsOperation: FeedlyOperation, FeedlyEntryIdentifierProviding { +class FeedlyGetUpdatedArticleIdsOperation: FeedlyOperation, FeedlyEntryIdentifierProviding, Logging { private let account: Account private let resource: FeedlyResourceId private let service: FeedlyGetStreamIdsService private let newerThan: Date? - private let log: OSLog - init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, newerThan: Date?, log: OSLog) { + init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, newerThan: Date?) { self.account = account self.resource = resource self.service = service self.newerThan = newerThan - self.log = log } - convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, newerThan: Date?, log: OSLog) { + convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, newerThan: Date?) { let all = FeedlyCategoryResourceId.Global.all(for: userId) - self.init(account: account, resource: all, service: service, newerThan: newerThan, log: log) + self.init(account: account, resource: all, service: service, newerThan: newerThan) } var entryIds: Set { @@ -47,7 +45,7 @@ class FeedlyGetUpdatedArticleIdsOperation: FeedlyOperation, FeedlyEntryIdentifie private func getStreamIds(_ continuation: String?) { guard let date = newerThan else { - os_log(.debug, log: log, "No date provided so everything must be new (nothing is updated).") + logger.debug("No date provided so everything must be new (nothing is updated).") didFinish() return } @@ -66,7 +64,7 @@ class FeedlyGetUpdatedArticleIdsOperation: FeedlyOperation, FeedlyEntryIdentifie storedUpdatedArticleIds.formUnion(streamIds.ids) guard let continuation = streamIds.continuation else { - os_log(.debug, log: log, "%{public}i articles updated since last successful sync start date.", storedUpdatedArticleIds.count) + self.logger.debug("\(self.storedUpdatedArticleIds.count) articles updated since last successful sync start date.") didFinish() return } @@ -74,6 +72,7 @@ class FeedlyGetUpdatedArticleIdsOperation: FeedlyOperation, FeedlyEntryIdentifie getStreamIds(continuation) case .failure(let error): + self.logger.error("Error getting FeedlyStreamIds: \(error.localizedDescription).") didFinish(with: error) } } diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyIngestStarredArticleIdsOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyIngestStarredArticleIdsOperation.swift index 8c0ba5b03..29022c3fa 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyIngestStarredArticleIdsOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyIngestStarredArticleIdsOperation.swift @@ -7,7 +7,7 @@ // import Foundation -import os.log +import RSCore import SyncDatabase import Secrets @@ -17,26 +17,24 @@ import Secrets /// When all the article ids are collected, a status is created for each. /// The article ids previously marked as starred but not collected become unstarred. /// So this operation has side effects *for the entire account* it operates on. -final class FeedlyIngestStarredArticleIdsOperation: FeedlyOperation { +final class FeedlyIngestStarredArticleIdsOperation: FeedlyOperation, Logging { private let account: Account private let resource: FeedlyResourceId private let service: FeedlyGetStreamIdsService private let database: SyncDatabase private var remoteEntryIds = Set() - private let log: OSLog - convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?, log: OSLog) { + convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?) { let resource = FeedlyTagResourceId.Global.saved(for: userId) - self.init(account: account, resource: resource, service: service, database: database, newerThan: newerThan, log: log) + self.init(account: account, resource: resource, service: service, database: database, newerThan: newerThan) } - init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?, log: OSLog) { + init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?) { self.account = account self.resource = resource self.service = service self.database = database - self.log = log } override func run() { diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyIngestStreamArticleIdsOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyIngestStreamArticleIdsOperation.swift index 02dc9af61..cad5c1653 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyIngestStreamArticleIdsOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyIngestStreamArticleIdsOperation.swift @@ -7,7 +7,7 @@ // import Foundation -import os.log +import RSCore import Secrets /// Ensure a status exists for every article id the user might be interested in. @@ -15,23 +15,21 @@ import Secrets /// Typically, it pages through the article ids of the global.all stream. /// As the article ids are collected, a default read status is created for each. /// So this operation has side effects *for the entire account* it operates on. -class FeedlyIngestStreamArticleIdsOperation: FeedlyOperation { +class FeedlyIngestStreamArticleIdsOperation: FeedlyOperation, Logging { private let account: Account private let resource: FeedlyResourceId private let service: FeedlyGetStreamIdsService - private let log: OSLog - init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, log: OSLog) { + init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService) { self.account = account self.resource = resource self.service = service - self.log = log } - convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, log: OSLog) { + convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService) { let all = FeedlyCategoryResourceId.Global.all(for: userId) - self.init(account: account, resource: all, service: service, log: log) + self.init(account: account, resource: all, service: service) } override func run() { @@ -58,7 +56,7 @@ class FeedlyIngestStreamArticleIdsOperation: FeedlyOperation { } guard let continuation = streamIds.continuation else { - os_log(.debug, log: self.log, "Reached end of stream for %@", self.resource.id) + self.logger.debug("Reached end of stream: \(self.resource.id).") self.didFinish() return } diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyIngestUnreadArticleIdsOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyIngestUnreadArticleIdsOperation.swift index a06ebe0f5..72ec9f075 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyIngestUnreadArticleIdsOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyIngestUnreadArticleIdsOperation.swift @@ -7,7 +7,7 @@ // import Foundation -import os.log +import RSCore import RSParser import SyncDatabase import Secrets @@ -18,26 +18,24 @@ import Secrets /// When all the unread article ids are collected, a status is created for each. /// The article ids previously marked as unread but not collected become read. /// So this operation has side effects *for the entire account* it operates on. -final class FeedlyIngestUnreadArticleIdsOperation: FeedlyOperation { +final class FeedlyIngestUnreadArticleIdsOperation: FeedlyOperation, Logging { private let account: Account private let resource: FeedlyResourceId private let service: FeedlyGetStreamIdsService private let database: SyncDatabase private var remoteEntryIds = Set() - private let log: OSLog - convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?, log: OSLog) { + convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?) { let resource = FeedlyCategoryResourceId.Global.all(for: userId) - self.init(account: account, resource: resource, service: service, database: database, newerThan: newerThan, log: log) + self.init(account: account, resource: resource, service: service, database: database, newerThan: newerThan) } - init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?, log: OSLog) { + init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?) { self.account = account self.resource = resource self.service = service self.database = database - self.log = log } override func run() { diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyLogoutOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyLogoutOperation.swift index 6f412eafe..f4429fc03 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyLogoutOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyLogoutOperation.swift @@ -7,26 +7,24 @@ // import Foundation -import os.log +import RSCore protocol FeedlyLogoutService { func logout(completion: @escaping (Result) -> ()) } -final class FeedlyLogoutOperation: FeedlyOperation { +final class FeedlyLogoutOperation: FeedlyOperation, Logging { let service: FeedlyLogoutService let account: Account - let log: OSLog - init(account: Account, service: FeedlyLogoutService, log: OSLog) { + init(account: Account, service: FeedlyLogoutService) { self.service = service self.account = account - self.log = log } override func run() { - os_log("Requesting logout of %{public}@ account.", "\(account.type)") + self.logger.debug("Requesting logout of \(String(describing: self.account.type)).") service.logout(completion: didCompleteLogout(_:)) } @@ -34,7 +32,7 @@ final class FeedlyLogoutOperation: FeedlyOperation { assert(Thread.isMainThread) switch result { case .success: - os_log("Logged out of %{public}@ account.", log: log, "\(account.type)") + self.logger.debug("Logged out of \(String(describing: self.account.type)).") do { try account.removeCredentials(type: .oauthAccessToken) try account.removeCredentials(type: .oauthRefreshToken) @@ -44,7 +42,7 @@ final class FeedlyLogoutOperation: FeedlyOperation { didFinish() case .failure(let error): - os_log("Logout failed because %{public}@.", log: log, error as NSError) + self.logger.error("Logout failed because: \(error.localizedDescription)") didFinish(with: error) } } diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyMirrorCollectionsAsFoldersOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyMirrorCollectionsAsFoldersOperation.swift index 376459ff6..7baab0236 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyMirrorCollectionsAsFoldersOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyMirrorCollectionsAsFoldersOperation.swift @@ -7,25 +7,23 @@ // import Foundation -import os.log +import RSCore protocol FeedlyFeedsAndFoldersProviding { var feedsAndFolders: [([FeedlyFeed], Folder)] { get } } /// Reflect Collections from Feedly as Folders. -final class FeedlyMirrorCollectionsAsFoldersOperation: FeedlyOperation, FeedlyFeedsAndFoldersProviding { +final class FeedlyMirrorCollectionsAsFoldersOperation: FeedlyOperation, FeedlyFeedsAndFoldersProviding, Logging { let account: Account let collectionsProvider: FeedlyCollectionProviding - let log: OSLog private(set) var feedsAndFolders = [([FeedlyFeed], Folder)]() - init(account: Account, collectionsProvider: FeedlyCollectionProviding, log: OSLog) { + init(account: Account, collectionsProvider: FeedlyCollectionProviding) { self.collectionsProvider = collectionsProvider self.account = account - self.log = log } override func run() { @@ -46,8 +44,8 @@ final class FeedlyMirrorCollectionsAsFoldersOperation: FeedlyOperation, FeedlyFe return (collection.feeds, folder) } - os_log(.debug, log: log, "Ensured %i folders for %i collections.", feedsAndFolders.count, collections.count) - + self.logger.debug("Ensured \(self.feedsAndFolders.count) folders for \(collections.count) collections.") + // Remove folders without a corresponding collection let collectionFolders = Set(feedsAndFolders.map { $0.1 }) let foldersWithoutCollections = localFolders.subtracting(collectionFolders) @@ -57,7 +55,7 @@ final class FeedlyMirrorCollectionsAsFoldersOperation: FeedlyOperation, FeedlyFe account.removeFolder(unmatched) } - os_log(.debug, log: log, "Removed %i folders: %@", foldersWithoutCollections.count, foldersWithoutCollections.map { $0.externalID ?? $0.nameForDisplay }) + self.logger.debug("Removed \(foldersWithoutCollections.count) folders: \(foldersWithoutCollections.map({ $0.externalID ?? $0.nameForDisplay }))") } } } diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyOrganiseParsedItemsByFeedOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyOrganiseParsedItemsByFeedOperation.swift index a55ea1839..68637b82e 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyOrganiseParsedItemsByFeedOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyOrganiseParsedItemsByFeedOperation.swift @@ -8,7 +8,7 @@ import Foundation import RSParser -import os.log +import RSCore protocol FeedlyParsedItemsByFeedProviding { var parsedItemsByFeedProviderName: String { get } @@ -16,11 +16,10 @@ protocol FeedlyParsedItemsByFeedProviding { } /// Group articles by their feeds. -final class FeedlyOrganiseParsedItemsByFeedOperation: FeedlyOperation, FeedlyParsedItemsByFeedProviding { +final class FeedlyOrganiseParsedItemsByFeedOperation: FeedlyOperation, FeedlyParsedItemsByFeedProviding, Logging { private let account: Account private let parsedItemProvider: FeedlyParsedItemProviding - private let log: OSLog var parsedItemsByFeedProviderName: String { return name ?? String(describing: Self.self) @@ -33,10 +32,9 @@ final class FeedlyOrganiseParsedItemsByFeedOperation: FeedlyOperation, FeedlyPar private var itemsKeyedByFeedId = [String: Set]() - init(account: Account, parsedItemProvider: FeedlyParsedItemProviding, log: OSLog) { + init(account: Account, parsedItemProvider: FeedlyParsedItemProviding) { self.account = account self.parsedItemProvider = parsedItemProvider - self.log = log } override func run() { @@ -60,7 +58,7 @@ final class FeedlyOrganiseParsedItemsByFeedOperation: FeedlyOperation, FeedlyPar dict[key] = value } - os_log(.debug, log: log, "Grouped %i items by %i feeds for %@", items.count, dict.count, parsedItemProvider.parsedItemProviderName) + self.logger.debug("Grouped \(items.count) items by \(dict.count) feeds for \(self.parsedItemProvider.parsedItemProviderName).") itemsKeyedByFeedId = dict } diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyRefreshAccessTokenOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyRefreshAccessTokenOperation.swift index ad8271d12..a8c7731da 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyRefreshAccessTokenOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyRefreshAccessTokenOperation.swift @@ -7,22 +7,20 @@ // import Foundation -import os.log +import RSCore import RSWeb import Secrets -final class FeedlyRefreshAccessTokenOperation: FeedlyOperation { +final class FeedlyRefreshAccessTokenOperation: FeedlyOperation, Logging { let service: OAuthAccessTokenRefreshing let oauthClient: OAuthAuthorizationClient let account: Account - let log: OSLog - init(account: Account, service: OAuthAccessTokenRefreshing, oauthClient: OAuthAuthorizationClient, log: OSLog) { + init(account: Account, service: OAuthAccessTokenRefreshing, oauthClient: OAuthAuthorizationClient) { self.oauthClient = oauthClient self.service = service self.account = account - self.log = log } override func run() { @@ -30,7 +28,7 @@ final class FeedlyRefreshAccessTokenOperation: FeedlyOperation { do { guard let credentials = try account.retrieveCredentials(type: .oauthRefreshToken) else { - os_log(.debug, log: log, "Could not find a refresh token in the keychain. Check the refresh token is added to the Keychain, remove the account and add it again.") + self.logger.debug("Could not find a refresh token in the keychain. Check the refresh token is added to the Keychain, remove the account and add it again.") throw TransportError.httpError(status: 403) } @@ -41,7 +39,7 @@ final class FeedlyRefreshAccessTokenOperation: FeedlyOperation { return } - os_log(.debug, log: log, "Refreshing access token.") + self.logger.debug("Refreshing access token.") // Ignore cancellation after the request is resumed otherwise we may continue storing a potentially invalid token! service.refreshAccessToken(with: refreshToken.secret, client: oauthClient) { result in @@ -55,13 +53,13 @@ final class FeedlyRefreshAccessTokenOperation: FeedlyOperation { switch result { case .success(let grant): do { - os_log(.debug, log: log, "Storing refresh token.") + self.logger.debug("Storing refresh token.") // Store the refresh token first because it sends this token to the account delegate. if let token = grant.refreshToken { try account.storeCredentials(token) } - os_log(.debug, log: log, "Storing access token.") + self.logger.debug("Storing access token.") // Now store the access token because we want the account delegate to use it. try account.storeCredentials(grant.accessToken) diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyRequestStreamsOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyRequestStreamsOperation.swift index 688546abb..790f43fe7 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyRequestStreamsOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyRequestStreamsOperation.swift @@ -7,7 +7,7 @@ // import Foundation -import os.log +import RSCore protocol FeedlyRequestStreamsOperationDelegate: AnyObject { func feedlyRequestStreamsOperation(_ operation: FeedlyRequestStreamsOperation, enqueue collectionStreamOperation: FeedlyGetStreamContentsOperation) @@ -15,24 +15,22 @@ protocol FeedlyRequestStreamsOperationDelegate: AnyObject { /// Create one stream request operation for one Feedly collection. /// This is the start of the process of refreshing the entire contents of a Folder. -final class FeedlyRequestStreamsOperation: FeedlyOperation { +final class FeedlyRequestStreamsOperation: FeedlyOperation, Logging { weak var queueDelegate: FeedlyRequestStreamsOperationDelegate? let collectionsProvider: FeedlyCollectionProviding let service: FeedlyGetStreamContentsService let account: Account - let log: OSLog let newerThan: Date? let unreadOnly: Bool? - init(account: Account, collectionsProvider: FeedlyCollectionProviding, newerThan: Date?, unreadOnly: Bool?, service: FeedlyGetStreamContentsService, log: OSLog) { + init(account: Account, collectionsProvider: FeedlyCollectionProviding, newerThan: Date?, unreadOnly: Bool?, service: FeedlyGetStreamContentsService) { self.account = account self.service = service self.collectionsProvider = collectionsProvider self.newerThan = newerThan self.unreadOnly = unreadOnly - self.log = log } override func run() { @@ -50,11 +48,10 @@ final class FeedlyRequestStreamsOperation: FeedlyOperation { resource: resource, service: service, newerThan: newerThan, - unreadOnly: unreadOnly, - log: log) + unreadOnly: unreadOnly) queueDelegate?.feedlyRequestStreamsOperation(self, enqueue: operation) } - os_log(.debug, log: log, "Requested %i collection streams", collectionsProvider.collections.count) + self.logger.debug("Requested \(self.collectionsProvider.collections.count) collections streams.") } } diff --git a/Account/Sources/Account/Feedly/Operations/FeedlySendArticleStatusesOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlySendArticleStatusesOperation.swift index e5d71060d..6c1383537 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlySendArticleStatusesOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlySendArticleStatusesOperation.swift @@ -9,24 +9,22 @@ import Foundation import Articles import SyncDatabase -import os.log +import RSCore /// Take changes to statuses of articles locally and apply them to the corresponding the articles remotely. -final class FeedlySendArticleStatusesOperation: FeedlyOperation { +final class FeedlySendArticleStatusesOperation: FeedlyOperation, Logging { private let database: SyncDatabase - private let log: OSLog private let service: FeedlyMarkArticlesService - init(database: SyncDatabase, service: FeedlyMarkArticlesService, log: OSLog) { + init(database: SyncDatabase, service: FeedlyMarkArticlesService) { self.database = database self.service = service - self.log = log } override func run() { - os_log(.debug, log: log, "Sending article statuses...") + logger.debug("Sending article statuses...") database.selectForProcessing { result in if self.isCanceled { @@ -81,7 +79,7 @@ private extension FeedlySendArticleStatusesOperation { } group.notify(queue: DispatchQueue.main) { - os_log(.debug, log: self.log, "Done sending article statuses.") + self.logger.debug("Done sending article statuses.") self.didFinish() } } diff --git a/Account/Sources/Account/Feedly/Operations/FeedlySyncAllOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlySyncAllOperation.swift index 6cbde0443..452e01d11 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlySyncAllOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlySyncAllOperation.swift @@ -7,17 +7,15 @@ // import Foundation -import os.log import SyncDatabase import RSWeb import RSCore import Secrets /// Compose the operations necessary to get the entire set of articles, feeds and folders with the statuses the user expects between now and a certain date in the past. -final class FeedlySyncAllOperation: FeedlyOperation { +final class FeedlySyncAllOperation: FeedlyOperation, Logging { private let operationQueue = MainThreadOperationQueue() - private let log: OSLog let syncUUID: UUID var syncCompletionHandler: ((Result) -> ())? @@ -34,9 +32,8 @@ final class FeedlySyncAllOperation: FeedlyOperation { /// /// Download articles for statuses at the union of those statuses without its corresponding article and those included in 3 (changed since last successful sync). /// - init(account: Account, feedlyUserId: String, lastSuccessfulFetchStartDate: Date?, markArticlesService: FeedlyMarkArticlesService, getUnreadService: FeedlyGetStreamIdsService, getCollectionsService: FeedlyGetCollectionsService, getStreamContentsService: FeedlyGetStreamContentsService, getStarredService: FeedlyGetStreamIdsService, getStreamIdsService: FeedlyGetStreamIdsService, getEntriesService: FeedlyGetEntriesService, database: SyncDatabase, downloadProgress: DownloadProgress, log: OSLog) { + init(account: Account, feedlyUserId: String, lastSuccessfulFetchStartDate: Date?, markArticlesService: FeedlyMarkArticlesService, getUnreadService: FeedlyGetStreamIdsService, getCollectionsService: FeedlyGetCollectionsService, getStreamContentsService: FeedlyGetStreamContentsService, getStarredService: FeedlyGetStreamIdsService, getStreamIdsService: FeedlyGetStreamIdsService, getEntriesService: FeedlyGetEntriesService, database: SyncDatabase, downloadProgress: DownloadProgress) { self.syncUUID = UUID() - self.log = log self.operationQueue.suspend() super.init() @@ -44,38 +41,38 @@ final class FeedlySyncAllOperation: FeedlyOperation { self.downloadProgress = downloadProgress // Send any read/unread/starred article statuses to Feedly before anything else. - let sendArticleStatuses = FeedlySendArticleStatusesOperation(database: database, service: markArticlesService, log: log) + let sendArticleStatuses = FeedlySendArticleStatusesOperation(database: database, service: markArticlesService) sendArticleStatuses.delegate = self sendArticleStatuses.downloadProgress = downloadProgress self.operationQueue.add(sendArticleStatuses) // Get all the Collections the user has. - let getCollections = FeedlyGetCollectionsOperation(service: getCollectionsService, log: log) + let getCollections = FeedlyGetCollectionsOperation(service: getCollectionsService) getCollections.delegate = self getCollections.downloadProgress = downloadProgress getCollections.addDependency(sendArticleStatuses) self.operationQueue.add(getCollections) // Ensure a folder exists for each Collection, removing Folders without a corresponding Collection. - let mirrorCollectionsAsFolders = FeedlyMirrorCollectionsAsFoldersOperation(account: account, collectionsProvider: getCollections, log: log) + let mirrorCollectionsAsFolders = FeedlyMirrorCollectionsAsFoldersOperation(account: account, collectionsProvider: getCollections) mirrorCollectionsAsFolders.delegate = self mirrorCollectionsAsFolders.addDependency(getCollections) self.operationQueue.add(mirrorCollectionsAsFolders) // Ensure feeds are created and grouped by their folders. - let createFeedsOperation = FeedlyCreateFeedsForCollectionFoldersOperation(account: account, feedsAndFoldersProvider: mirrorCollectionsAsFolders, log: log) + let createFeedsOperation = FeedlyCreateFeedsForCollectionFoldersOperation(account: account, feedsAndFoldersProvider: mirrorCollectionsAsFolders) createFeedsOperation.delegate = self createFeedsOperation.addDependency(mirrorCollectionsAsFolders) self.operationQueue.add(createFeedsOperation) - let getAllArticleIds = FeedlyIngestStreamArticleIdsOperation(account: account, userId: feedlyUserId, service: getStreamIdsService, log: log) + let getAllArticleIds = FeedlyIngestStreamArticleIdsOperation(account: account, userId: feedlyUserId, service: getStreamIdsService) getAllArticleIds.delegate = self getAllArticleIds.downloadProgress = downloadProgress getAllArticleIds.addDependency(createFeedsOperation) self.operationQueue.add(getAllArticleIds) // Get each page of unread article ids in the global.all stream for the last 31 days (nil = Feedly API default). - let getUnread = FeedlyIngestUnreadArticleIdsOperation(account: account, userId: feedlyUserId, service: getUnreadService, database: database, newerThan: nil, log: log) + let getUnread = FeedlyIngestUnreadArticleIdsOperation(account: account, userId: feedlyUserId, service: getUnreadService, database: database, newerThan: nil) getUnread.delegate = self getUnread.addDependency(getAllArticleIds) getUnread.downloadProgress = downloadProgress @@ -83,21 +80,21 @@ final class FeedlySyncAllOperation: FeedlyOperation { // Get each page of the article ids which have been update since the last successful fetch start date. // If the date is nil, this operation provides an empty set (everything is new, nothing is updated). - let getUpdated = FeedlyGetUpdatedArticleIdsOperation(account: account, userId: feedlyUserId, service: getStreamIdsService, newerThan: lastSuccessfulFetchStartDate, log: log) + let getUpdated = FeedlyGetUpdatedArticleIdsOperation(account: account, userId: feedlyUserId, service: getStreamIdsService, newerThan: lastSuccessfulFetchStartDate) getUpdated.delegate = self getUpdated.downloadProgress = downloadProgress getUpdated.addDependency(createFeedsOperation) self.operationQueue.add(getUpdated) // Get each page of the article ids for starred articles. - let getStarred = FeedlyIngestStarredArticleIdsOperation(account: account, userId: feedlyUserId, service: getStarredService, database: database, newerThan: nil, log: log) + let getStarred = FeedlyIngestStarredArticleIdsOperation(account: account, userId: feedlyUserId, service: getStarredService, database: database, newerThan: nil) getStarred.delegate = self getStarred.downloadProgress = downloadProgress getStarred.addDependency(createFeedsOperation) self.operationQueue.add(getStarred) // Now all the possible article ids we need have a status, fetch the article ids for missing articles. - let getMissingIds = FeedlyFetchIdsForMissingArticlesOperation(account: account, log: log) + let getMissingIds = FeedlyFetchIdsForMissingArticlesOperation(account: account) getMissingIds.delegate = self getMissingIds.downloadProgress = downloadProgress getMissingIds.addDependency(getAllArticleIds) @@ -110,8 +107,7 @@ final class FeedlySyncAllOperation: FeedlyOperation { let downloadMissingArticles = FeedlyDownloadArticlesOperation(account: account, missingArticleEntryIdProvider: getMissingIds, updatedArticleEntryIdProvider: getUpdated, - getEntriesService: getEntriesService, - log: log) + getEntriesService: getEntriesService) downloadMissingArticles.delegate = self downloadMissingArticles.downloadProgress = downloadProgress downloadMissingArticles.addDependency(getMissingIds) @@ -126,17 +122,17 @@ final class FeedlySyncAllOperation: FeedlyOperation { self.operationQueue.add(finishOperation) } - convenience init(account: Account, feedlyUserId: String, caller: FeedlyAPICaller, database: SyncDatabase, lastSuccessfulFetchStartDate: Date?, downloadProgress: DownloadProgress, log: OSLog) { - self.init(account: account, feedlyUserId: feedlyUserId, lastSuccessfulFetchStartDate: lastSuccessfulFetchStartDate, markArticlesService: caller, getUnreadService: caller, getCollectionsService: caller, getStreamContentsService: caller, getStarredService: caller, getStreamIdsService: caller, getEntriesService: caller, database: database, downloadProgress: downloadProgress, log: log) + convenience init(account: Account, feedlyUserId: String, caller: FeedlyAPICaller, database: SyncDatabase, lastSuccessfulFetchStartDate: Date?, downloadProgress: DownloadProgress) { + self.init(account: account, feedlyUserId: feedlyUserId, lastSuccessfulFetchStartDate: lastSuccessfulFetchStartDate, markArticlesService: caller, getUnreadService: caller, getCollectionsService: caller, getStreamContentsService: caller, getStarredService: caller, getStreamIdsService: caller, getEntriesService: caller, database: database, downloadProgress: downloadProgress) } override func run() { - os_log(.debug, log: log, "Starting sync %{public}@", syncUUID.uuidString) + logger.debug("Starting sync \(self.syncUUID.uuidString).") operationQueue.resume() } override func didCancel() { - os_log(.debug, log: log, "Cancelling sync %{public}@", syncUUID.uuidString) + logger.debug("Cancelling sync \(self.syncUUID.uuidString).") self.operationQueue.cancelAllOperations() syncCompletionHandler = nil super.didCancel() @@ -147,7 +143,7 @@ extension FeedlySyncAllOperation: FeedlyCheckpointOperationDelegate { func feedlyCheckpointOperationDidReachCheckpoint(_ operation: FeedlyCheckpointOperation) { assert(Thread.isMainThread) - os_log(.debug, log: self.log, "Sync completed: %{public}@", syncUUID.uuidString) + logger.debug("Sync completed: \(self.syncUUID.uuidString).") syncCompletionHandler?(.success(())) syncCompletionHandler = nil @@ -162,7 +158,7 @@ extension FeedlySyncAllOperation: FeedlyOperationDelegate { assert(Thread.isMainThread) // Having this log is useful for debugging missing required JSON keys in the response from Feedly, for example. - os_log(.debug, log: log, "%{public}@ failed with error: %{public}@.", String(describing: operation), error as NSError) + logger.debug("\(String(describing: operation)) failed with error: \(error.localizedDescription).") syncCompletionHandler?(.failure(error)) syncCompletionHandler = nil diff --git a/Account/Sources/Account/Feedly/Operations/FeedlySyncStreamContentsOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlySyncStreamContentsOperation.swift index ef1770967..6a9bbaf5e 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlySyncStreamContentsOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlySyncStreamContentsOperation.swift @@ -7,13 +7,12 @@ // import Foundation -import os.log import RSParser import RSCore import RSWeb import Secrets -final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationDelegate, FeedlyGetStreamContentsOperationDelegate, FeedlyCheckpointOperationDelegate { +final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationDelegate, FeedlyGetStreamContentsOperationDelegate, FeedlyCheckpointOperationDelegate, Logging { private let account: Account private let resource: FeedlyResourceId @@ -21,17 +20,15 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD private let service: FeedlyGetStreamContentsService private let newerThan: Date? private let isPagingEnabled: Bool - private let log: OSLog private let finishOperation: FeedlyCheckpointOperation - init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamContentsService, isPagingEnabled: Bool, newerThan: Date?, log: OSLog) { + init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamContentsService, isPagingEnabled: Bool, newerThan: Date?) { self.account = account self.resource = resource self.service = service self.isPagingEnabled = isPagingEnabled self.operationQueue.suspend() self.newerThan = newerThan - self.log = log self.finishOperation = FeedlyCheckpointOperation() super.init() @@ -41,9 +38,9 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD enqueueOperations(for: nil) } - convenience init(account: Account, credentials: Credentials, service: FeedlyGetStreamContentsService, newerThan: Date?, log: OSLog) { + convenience init(account: Account, credentials: Credentials, service: FeedlyGetStreamContentsService, newerThan: Date?) { let all = FeedlyCategoryResourceId.Global.all(for: credentials.username) - self.init(account: account, resource: all, service: service, isPagingEnabled: true, newerThan: newerThan, log: log) + self.init(account: account, resource: all, service: service, isPagingEnabled: true, newerThan: newerThan) } override func run() { @@ -51,13 +48,13 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD } override func didCancel() { - os_log(.debug, log: log, "Canceling sync stream contents for %{public}@", resource.id) + self.logger.debug("Cancelling sync stream contents for \(self.resource.id).") operationQueue.cancelAllOperations() super.didCancel() } func enqueueOperations(for continuation: String?) { - os_log(.debug, log: log, "Requesting page for %{public}@", resource.id) + self.logger.debug("Requesting page for \(self.resource.id).") let operations = pageOperations(for: continuation) operationQueue.addOperations(operations) } @@ -67,13 +64,12 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD resource: resource, service: service, continuation: continuation, - newerThan: newerThan, - log: log) + newerThan: newerThan) - let organiseByFeed = FeedlyOrganiseParsedItemsByFeedOperation(account: account, parsedItemProvider: getPage, log: log) + let organiseByFeed = FeedlyOrganiseParsedItemsByFeedOperation(account: account, parsedItemProvider: getPage) - let updateAccount = FeedlyUpdateAccountFeedsWithItemsOperation(account: account, organisedItemsProvider: organiseByFeed, log: log) + let updateAccount = FeedlyUpdateAccountFeedsWithItemsOperation(account: account, organisedItemsProvider: organiseByFeed) getPage.delegate = self getPage.streamDelegate = self @@ -91,14 +87,14 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD func feedlyGetStreamContentsOperation(_ operation: FeedlyGetStreamContentsOperation, didGetContentsOf stream: FeedlyStream) { guard !isCanceled else { - os_log(.debug, log: log, "Cancelled requesting page for %{public}@", resource.id) + self.logger.debug("Cancelled requesting page for \(self.resource.id).") return } - os_log(.debug, log: log, "Ingesting %i items from %{public}@", stream.items.count, stream.id) + self.logger.debug("Ingesting \(stream.items.count) from \(stream.id).") guard isPagingEnabled, let continuation = stream.continuation else { - os_log(.debug, log: log, "Reached end of stream for %{public}@", stream.id) + self.logger.debug("Reached end of stream for \(stream.id).") return } @@ -106,7 +102,7 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD } func feedlyCheckpointOperationDidReachCheckpoint(_ operation: FeedlyCheckpointOperation) { - os_log(.debug, log: log, "Completed ingesting items from %{public}@", resource.id) + self.logger.debug("Completed ingesting items from \(self.resource.id).") didFinish() } diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyUpdateAccountFeedsWithItemsOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyUpdateAccountFeedsWithItemsOperation.swift index b15d17cf9..4218f15e5 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyUpdateAccountFeedsWithItemsOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyUpdateAccountFeedsWithItemsOperation.swift @@ -8,19 +8,17 @@ import Foundation import RSParser -import os.log +import RSCore /// Combine the articles with their feeds for a specific account. -final class FeedlyUpdateAccountFeedsWithItemsOperation: FeedlyOperation { +final class FeedlyUpdateAccountFeedsWithItemsOperation: FeedlyOperation, Logging { private let account: Account private let organisedItemsProvider: FeedlyParsedItemsByFeedProviding - private let log: OSLog - init(account: Account, organisedItemsProvider: FeedlyParsedItemsByFeedProviding, log: OSLog) { + init(account: Account, organisedItemsProvider: FeedlyParsedItemsByFeedProviding) { self.account = account self.organisedItemsProvider = organisedItemsProvider - self.log = log } override func run() { @@ -32,7 +30,7 @@ final class FeedlyUpdateAccountFeedsWithItemsOperation: FeedlyOperation { return } - os_log(.debug, log: self.log, "Updated %i feeds for \"%@\"", webFeedIDsAndItems.count, self.organisedItemsProvider.parsedItemsByFeedProviderName) + self.logger.debug("Updated \(webFeedIDsAndItems.count) feeds for \(self.organisedItemsProvider.parsedItemsByFeedProviderName).") self.didFinish() } } diff --git a/Account/Sources/Account/NewsBlur/Internals/NewsBlurAccountDelegate+Internal.swift b/Account/Sources/Account/NewsBlur/Internals/NewsBlurAccountDelegate+Internal.swift index f9ac2ad8b..23d1d8483 100644 --- a/Account/Sources/Account/NewsBlur/Internals/NewsBlurAccountDelegate+Internal.swift +++ b/Account/Sources/Account/NewsBlur/Internals/NewsBlurAccountDelegate+Internal.swift @@ -13,12 +13,12 @@ import RSDatabase import RSParser import RSWeb import SyncDatabase -import os.log extension NewsBlurAccountDelegate { func refreshFeeds(for account: Account, completion: @escaping (Result) -> Void) { - os_log(.debug, log: log, "Refreshing feeds...") + logger.debug("Refreshing feeds...") + caller.retrieveFeeds { result in switch result { @@ -39,7 +39,7 @@ extension NewsBlurAccountDelegate { guard let folders = folders else { return } assert(Thread.isMainThread) - os_log(.debug, log: log, "Syncing folders with %ld folders.", folders.count) + logger.debug("Syncing folders with \(folders.count) folders.") let folderNames = folders.map { $0.name } @@ -77,7 +77,7 @@ extension NewsBlurAccountDelegate { guard let feeds = feeds else { return } assert(Thread.isMainThread) - os_log(.debug, log: log, "Syncing feeds with %ld feeds.", feeds.count) + logger.debug("Syncing feeds with \(feeds.count) feeds.") let newsBlurFeedIds = feeds.map { String($0.feedID) } @@ -128,7 +128,7 @@ extension NewsBlurAccountDelegate { guard let folders = folders else { return } assert(Thread.isMainThread) - os_log(.debug, log: log, "Syncing folders with %ld folders.", folders.count) + logger.debug("Syncing folders with \(folders.count) folders.") // Set up some structures to make syncing easier let relationships = folders.map({ $0.asRelationships }).flatMap { $0 } @@ -251,7 +251,7 @@ extension NewsBlurAccountDelegate { } self.refreshUnreadStories(for: account, hashes: Array(hashes[numberOfStories...]), updateFetchDate: date) { result in - os_log(.debug, log: self.log, "Done refreshing stories.") + self.logger.debug("Done refreshing stories.") switch result { case .success: completion(.success(())) @@ -300,7 +300,7 @@ extension NewsBlurAccountDelegate { group.leave() case .failure(let error): errorOccurred = true - os_log(.error, log: self.log, "Story status sync call failed: %@.", error.localizedDescription) + self.logger.error("Story status sync call failed: \(error.localizedDescription)") self.database.resetSelectedForProcessing(storyHashGroup.map { String($0) } ) group.leave() } @@ -359,7 +359,7 @@ extension NewsBlurAccountDelegate { case .success(let pendingArticleIDs): process(pendingArticleIDs) case .failure(let error): - os_log(.error, log: self.log, "Sync Story Read Status failed: %@.", error.localizedDescription) + self.logger.error("Sync story read status failed: \(error.localizedDescription)") } } } @@ -407,7 +407,7 @@ extension NewsBlurAccountDelegate { case .success(let pendingArticleIDs): process(pendingArticleIDs) case .failure(let error): - os_log(.error, log: self.log, "Sync Story Starred Status failed: %@.", error.localizedDescription) + self.logger.error("Sync story starred status failed: \(error.localizedDescription)") } } } diff --git a/Account/Sources/Account/NewsBlur/NewsBlurAccountDelegate.swift b/Account/Sources/Account/NewsBlur/NewsBlurAccountDelegate.swift index b415d03d6..0281c1b03 100644 --- a/Account/Sources/Account/NewsBlur/NewsBlurAccountDelegate.swift +++ b/Account/Sources/Account/NewsBlur/NewsBlurAccountDelegate.swift @@ -12,10 +12,9 @@ import RSDatabase import RSParser import RSWeb import SyncDatabase -import os.log import Secrets -final class NewsBlurAccountDelegate: AccountDelegate { +final class NewsBlurAccountDelegate: AccountDelegate, Logging { var behaviors: AccountBehaviors = [] @@ -31,7 +30,6 @@ final class NewsBlurAccountDelegate: AccountDelegate { var refreshProgress = DownloadProgress(numberOfTasks: 0) let caller: NewsBlurAPICaller - let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "NewsBlur") let database: SyncDatabase init(dataFolder: String, transport: Transport?) { @@ -133,8 +131,7 @@ final class NewsBlurAccountDelegate: AccountDelegate { } func sendArticleStatus(for account: Account, completion: @escaping (Result) -> ()) { - os_log(.debug, log: log, "Sending story statuses...") - + logger.debug("Sending story statuses...") database.selectForProcessing { result in func processStatuses(_ syncStatuses: [SyncStatus]) { @@ -187,7 +184,7 @@ final class NewsBlurAccountDelegate: AccountDelegate { } group.notify(queue: DispatchQueue.main) { - os_log(.debug, log: self.log, "Done sending article statuses.") + self.logger.debug("Done sending article statuses.") if errorOccurred { completion(.failure(NewsBlurError.unknown)) } else { @@ -206,7 +203,7 @@ final class NewsBlurAccountDelegate: AccountDelegate { } func refreshArticleStatus(for account: Account, completion: @escaping (Result) -> ()) { - os_log(.debug, log: log, "Refreshing story statuses...") + logger.debug("Refreshing story statuses...") let group = DispatchGroup() var errorOccurred = false @@ -220,7 +217,7 @@ final class NewsBlurAccountDelegate: AccountDelegate { } case .failure(let error): errorOccurred = true - os_log(.info, log: self.log, "Retrieving unread stories failed: %@.", error.localizedDescription) + self.logger.error("Retrieving unread stories failed: \(error.localizedDescription)") group.leave() } } @@ -234,13 +231,13 @@ final class NewsBlurAccountDelegate: AccountDelegate { } case .failure(let error): errorOccurred = true - os_log(.info, log: self.log, "Retrieving starred stories failed: %@.", error.localizedDescription) + self.logger.error("Retrieving starred stories failed: \(error.localizedDescription)") group.leave() } } group.notify(queue: DispatchQueue.main) { - os_log(.debug, log: self.log, "Done refreshing article statuses.") + self.logger.debug("Done refreshing article statuses.") if errorOccurred { completion(.failure(NewsBlurError.unknown)) } else { @@ -250,9 +247,9 @@ final class NewsBlurAccountDelegate: AccountDelegate { } func refreshStories(for account: Account, completion: @escaping (Result) -> Void) { - os_log(.debug, log: log, "Refreshing stories...") - os_log(.debug, log: log, "Refreshing unread stories...") - + self.logger.debug("Refreshing stories...") + self.logger.debug("Refreshing unread stories...") + caller.retrieveUnreadStoryHashes { result in switch result { case .success(let storyHashes): @@ -269,7 +266,7 @@ final class NewsBlurAccountDelegate: AccountDelegate { } func refreshMissingStories(for account: Account, completion: @escaping (Result) -> Void) { - os_log(.debug, log: log, "Refreshing missing stories...") + self.logger.debug("Refreshing missing stories...") account.fetchArticleIDsForStatusesWithoutArticlesNewerThanCutoffDate { result in @@ -296,7 +293,7 @@ final class NewsBlurAccountDelegate: AccountDelegate { } case .failure(let error): errorOccurred = true - os_log(.error, log: self.log, "Refresh missing stories failed: %@.", error.localizedDescription) + self.logger.error("Refreshing missing stories failed: \(error.localizedDescription)") group.leave() } } @@ -304,7 +301,7 @@ final class NewsBlurAccountDelegate: AccountDelegate { group.notify(queue: DispatchQueue.main) { self.refreshProgress.completeTask() - os_log(.debug, log: self.log, "Done refreshing missing stories.") + self.logger.debug("Done refreshing stories.") if errorOccurred { completion(.failure(NewsBlurError.unknown)) } else { @@ -568,12 +565,12 @@ final class NewsBlurAccountDelegate: AccountDelegate { case .success: break case .failure(let error): - os_log(.error, log: self.log, "Restore folder feed error: %@.", error.localizedDescription) + self.logger.error("Restore folder feed error: \(error.localizedDescription)") } } } case .failure(let error): - os_log(.error, log: self.log, "Restore folder feed error: %@.", error.localizedDescription) + self.logger.error("Restore folder feed error: \(error.localizedDescription)") } } diff --git a/NetNewsWire.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/NetNewsWire.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 0f71953cd..4725e156b 100644 --- a/NetNewsWire.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/NetNewsWire.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -60,8 +60,8 @@ "repositoryURL": "https://github.com/Ranchero-Software/RSCore.git", "state": { "branch": null, - "revision": "814adfd956e5bd099b3b81b6680d0a4f6cd56130", - "version": "1.0.9" + "revision": "f50d5c2c0570f84d08d948a533510971e672a1c0", + "version": "1.0.11" } }, {