From 94cfaeeaa04d88146f340b39037f062b66264ea9 Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Tue, 25 Apr 2023 14:48:20 +0300 Subject: [PATCH] Structured logging (#831) * Structured logging support * Bump the SDK, fix breaking changes * Enabled more logging of timeline diffs * Keep only source file last path components in logs * Bump the SDK, tweaks following code review --- .../xcshareddata/swiftpm/Package.resolved | 13 +- .../Sources/Application/AppCoordinator.swift | 23 +- .../Sources/Application/Application.swift | 12 +- ElementX/Sources/Other/Logging/MXLog.swift | 255 ++++++++++-------- ElementX/Sources/Other/Logging/MXLogger.swift | 16 +- .../Sources/Other/Logging/RustTracing.swift | 27 +- .../AuthenticationServiceProxy.swift | 2 +- .../Services/Media/Provider/MediaLoader.swift | 2 +- .../RoomSummary/RoomSummaryProvider.swift | 10 +- .../Timeline/RoomTimelineProvider.swift | 77 +++++- .../Services/Timeline/TimelineItemProxy.swift | 2 +- ElementX/SupportingFiles/target.yml | 1 - IntegrationTests/SupportingFiles/target.yml | 1 - NSE/Sources/Other/NSELogger.swift | 19 +- NSE/SupportingFiles/target.yml | 1 - UITests/SupportingFiles/target.yml | 1 - UnitTests/Sources/LoggingTests.swift | 61 ++--- .../MediaProvider/MediaLoaderTests.swift | 8 +- .../Sources/MessageTimelineItemTests.swift | 2 +- project.yml | 5 +- 20 files changed, 286 insertions(+), 252 deletions(-) diff --git a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 49928f96b..b13bbbc87 100644 --- a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -111,8 +111,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/matrix-org/matrix-rust-components-swift", "state" : { - "revision" : "8ce08eb804c449f4e7472e66edd7e80b4e8e9ded", - "version" : "1.0.54-alpha" + "revision" : "1febfb02005fca9cf99264be72c6383c103085c5", + "version" : "1.0.56-alpha" } }, { @@ -214,15 +214,6 @@ "version" : "0.2.3" } }, - { - "identity" : "swiftybeaver", - "kind" : "remoteSourceControl", - "location" : "https://github.com/SwiftyBeaver/SwiftyBeaver", - "state" : { - "revision" : "1080914828ef1c9ca9cd2bad50667b3d847dabff", - "version" : "2.0.0" - } - }, { "identity" : "version", "kind" : "remoteSourceControl", diff --git a/ElementX/Sources/Application/AppCoordinator.swift b/ElementX/Sources/Application/AppCoordinator.swift index ba6f2f5fe..6c2605769 100644 --- a/ElementX/Sources/Application/AppCoordinator.swift +++ b/ElementX/Sources/Application/AppCoordinator.swift @@ -51,10 +51,11 @@ class AppCoordinator: AppCoordinatorProtocol { @Consumable private var storedAppRoute: AppRoute? init() { + MXLog.configure() + navigationRootCoordinator = NavigationRootCoordinator() Self.setupServiceLocator(navigationRootCoordinator: navigationRootCoordinator) - Self.setupLogging() ServiceLocator.shared.analytics.startIfEnabled() @@ -118,26 +119,6 @@ class AppCoordinator: AppCoordinatorProtocol { ServiceLocator.shared.register(analytics: Analytics(client: PostHogAnalyticsClient())) } - private static func setupLogging() { - let loggerConfiguration = MXLogConfiguration() - loggerConfiguration.maxLogFilesCount = 10 - - #if DEBUG - setupTracing(configuration: .debug) - loggerConfiguration.logLevel = .debug - #else - setupTracing(configuration: .release) - loggerConfiguration.logLevel = .info - #endif - - // Avoid redirecting NSLogs to files if we are attached to a debugger. - if isatty(STDERR_FILENO) == 0 { - loggerConfiguration.redirectLogsToFiles = true - } - - MXLog.configure(loggerConfiguration) - } - /// Perform any required migrations for the app to function correctly. private func performMigrationsIfNecessary(from oldVersion: Version, to newVersion: Version) { guard oldVersion != newVersion else { return } diff --git a/ElementX/Sources/Application/Application.swift b/ElementX/Sources/Application/Application.swift index 4f0f2e899..c3bd641b0 100644 --- a/ElementX/Sources/Application/Application.swift +++ b/ElementX/Sources/Application/Application.swift @@ -19,13 +19,15 @@ import SwiftUI @main struct Application: App { @UIApplicationDelegateAdaptor(AppDelegate.self) private var applicationDelegate - private let applicationCoordinator: AppCoordinatorProtocol + private let appCoordinator: AppCoordinatorProtocol! init() { if Tests.isRunningUITests { - applicationCoordinator = UITestsAppCoordinator() + appCoordinator = UITestsAppCoordinator() + } else if Tests.isRunningUnitTests { + appCoordinator = nil } else { - applicationCoordinator = AppCoordinator() + appCoordinator = AppCoordinator() } } @@ -34,9 +36,9 @@ struct Application: App { if Tests.isRunningUnitTests { EmptyView() } else { - applicationCoordinator.toPresentable() + appCoordinator.toPresentable() .task { - applicationCoordinator.start() + appCoordinator.start() } .statusBarHidden(shouldHideStatusBar) } diff --git a/ElementX/Sources/Other/Logging/MXLog.swift b/ElementX/Sources/Other/Logging/MXLog.swift index bbc015e60..6abd0b4a5 100644 --- a/ElementX/Sources/Other/Logging/MXLog.swift +++ b/ElementX/Sources/Other/Logging/MXLog.swift @@ -15,87 +15,119 @@ // import Foundation -import SwiftyBeaver - -/// Various MXLog configuration options. Used in conjunction with `MXLog.configure()` -public class MXLogConfiguration: NSObject { - /// the desired log level. `.verbose` by default. - public var logLevel = MXLogLevel.verbose - - /// whether logs should be written directly to files. `false` by default. - public var redirectLogsToFiles = false - - /// the maximum total space to use for log files in bytes. `100MB` by default. - public var logFilesSizeLimit: UInt = 100 * 1024 * 1024 // 100MB - - /// the maximum number of log files to use before rolling. `50` by default. - public var maxLogFilesCount: UInt = 50 - - /// the subname for log files. Files will be named as 'console-[subLogName].log'. `nil` by default - public var subLogName: String? -} - -/// MXLog logging levels. Use .none to disable logging entirely. -public enum MXLogLevel: UInt { - case none - case verbose - case debug - case info - case warning - case error -} - -private var logger: SwiftyBeaver.Type = { - let logger = SwiftyBeaver.self - MXLog.configureLogger(logger, withConfiguration: MXLogConfiguration()) - return logger -}() +import MatrixRustSDK /** Logging utility that provies multiple logging levels as well as file output and rolling. Its purpose is to provide a common entry for customizing logging and should be used throughout the code. - Please see `MXLog.h` for Objective-C options. */ -public class MXLog: NSObject { - /// Method used to customize MXLog's behavior. - /// Called automatically when first accessing the logger with the default values. - /// Please see `MXLogConfiguration` for all available options. - /// - Parameters: - /// - configuration: the `MXLogConfiguration` instance to use - public static func configure(_ configuration: MXLogConfiguration) { - configureLogger(logger, withConfiguration: configuration) +enum MXLog { + private enum Constants { + static let target = "elementx" + + // Avoid redirecting NSLogs to files if we are attached to a debugger. + static let redirectToFiles = isatty(STDERR_FILENO) == 0 + + /// the maximum number of log files to use before rolling. `10` by default. + static let maxLogFileCount: UInt = 10 + + /// the maximum total space to use for log files in bytes. `100MB` by default. + static let logFilesSizeLimit: UInt = 100 * 1024 * 1024 // 100MB } - public static func verbose(_ message: @autoclosure () -> Any, - file: String = #file, - function: String = #function, - line: Int = #line, - context: Any? = nil) { - logger.verbose(message(), file: file, function: function, line: line, context: context) + // Rust side crashes if invoking setupTracing multiple times + private static var didConfigureOnce = false + + private static var rootSpan: Span! + private static var target: String! + + static func configure(target: String? = nil, + logLevel: TracingConfiguration.LogLevel? = nil, + redirectToFiles: Bool = Constants.redirectToFiles, + maxLogFileCount: UInt = Constants.maxLogFileCount, + logFileSizeLimit: UInt = Constants.logFilesSizeLimit) { + guard didConfigureOnce == false else { + if let target { + MXLogger.setSubLogName(target) + } + + // SubLogName needs to be set before calling configure in order to be applied + MXLogger.configure(redirectToFiles: redirectToFiles, + maxLogFileCount: maxLogFileCount, + logFileSizeLimit: logFileSizeLimit) + return + } + + if let logLevel { + setupTracing(configuration: .custom(logLevel: logLevel)) + } else { + #if DEBUG + setupTracing(configuration: .debug) + #else + setupTracing(configuration: .release) + #endif + } + + if let target { + self.target = target + MXLogger.setSubLogName(target) + } else { + self.target = Constants.target + } + + rootSpan = Span(file: #file, line: #line, column: #column, level: .info, target: self.target, name: "root") + + rootSpan.enter() + + MXLogger.configure(redirectToFiles: redirectToFiles, + maxLogFileCount: maxLogFileCount, + logFileSizeLimit: logFileSizeLimit) + + didConfigureOnce = true } - public static func debug(_ message: @autoclosure () -> Any, - file: String = #file, - function: String = #function, - line: Int = #line, - context: Any? = nil) { - logger.debug(message(), file: file, function: function, line: line, context: context) + static func createSpan(_ name: String, + file: String = #file, + function: String = #function, + line: Int = #line, + column: Int = #column) -> Span { + createSpan(name, level: .info, file: file, function: function, line: line, column: column) } - public static func info(_ message: @autoclosure () -> Any, - file: String = #file, - function: String = #function, - line: Int = #line, - context: Any? = nil) { - logger.info(message(), file: file, function: function, line: line, context: context) + static func verbose(_ message: Any, + file: String = #file, + function: String = #function, + line: Int = #line, + column: Int = #column, + context: Any? = nil) { + log(message, level: .trace, file: file, function: function, line: line, column: column, context: context) } - public static func warning(_ message: @autoclosure () -> Any, - file: String = #file, - function: String = #function, - line: Int = #line, - context: Any? = nil) { - logger.warning(message(), file: file, function: function, line: line, context: context) + static func debug(_ message: Any, + file: String = #file, + function: String = #function, + line: Int = #line, + column: Int = #column, + context: Any? = nil) { + log(message, level: .debug, file: file, function: function, line: line, column: column, context: context) + } + + static func info(_ message: Any, + file: String = #file, + function: String = #function, + line: Int = #line, + column: Int = #column, + context: Any? = nil) { + log(message, level: .info, file: file, function: function, line: line, column: column, context: context) + } + + static func warning(_ message: Any, + file: String = #file, + function: String = #function, + line: Int = #line, + column: Int = #column, + context: Any? = nil) { + log(message, level: .warn, file: file, function: function, line: line, column: column, context: context) } /// Log error with additional details @@ -103,12 +135,13 @@ public class MXLog: NSObject { /// - Parameters: /// - message: Description of the error without any variables (this is to improve error aggregations by type) /// - context: Additional context-dependent details about the issue - public static func error(_ message: @autoclosure () -> Any, - file: String = #file, - function: String = #function, - line: Int = #line, - context: Any? = nil) { - logger.error(message(), file: file, function: function, line: line, context: context) + static func error(_ message: Any, + file: String = #file, + function: String = #function, + line: Int = #line, + column: Int = #column, + context: Any? = nil) { + log(message, level: .error, file: file, function: function, line: line, column: column, context: context) } /// Log failure with additional details @@ -119,12 +152,14 @@ public class MXLog: NSObject { /// - Parameters: /// - message: Description of the error without any variables (this is to improve error aggregations by type) /// - context: Additional context-dependent details about the issue - public static func failure(_ message: String, - file: String = #file, - function: String = #function, - line: Int = #line, - context: Any? = nil) { - logger.error(message, file: file, function: function, line: line, context: context) + static func failure(_ message: Any, + file: String = #file, + function: String = #function, + line: Int = #line, + column: Int = #column, + context: Any? = nil) { + log(message, level: .error, file: file, function: function, line: line, column: column, context: context) + #if DEBUG assertionFailure("\(message)") #endif @@ -132,46 +167,38 @@ public class MXLog: NSObject { // MARK: - Private - fileprivate static func configureLogger(_ logger: SwiftyBeaver.Type, withConfiguration configuration: MXLogConfiguration) { - if let subLogName = configuration.subLogName { - MXLogger.setSubLogName(subLogName) + private static func createSpan(_ name: String, + level: LogLevel, + file: String = #file, + function: String = #function, + line: Int = #line, + column: Int = #column) -> Span { + guard didConfigureOnce else { + fatalError() } - MXLogger.redirectNSLog(toFiles: configuration.redirectLogsToFiles, - numberOfFiles: configuration.maxLogFilesCount, - sizeLimit: configuration.logFilesSizeLimit) + if Span.current().isNone() { + rootSpan.enter() + } - guard configuration.logLevel != .none else { - logger.removeAllDestinations() + return Span(file: file, line: UInt32(line), column: UInt32(column), level: level, target: target, name: name) + } + + private static func log(_ message: Any, + level: LogLevel, + file: String = #file, + function: String = #function, + line: Int = #line, + column: Int = #column, + context: Any? = nil) { + guard didConfigureOnce else { return } - logger.removeAllDestinations() - - let consoleDestination = ConsoleDestination() - consoleDestination.useNSLog = true - consoleDestination.asynchronously = false - consoleDestination.format = "$C$N.$F:$l $M $X$c" // See https://docs.swiftybeaver.com/article/20-custom-format - consoleDestination.levelColor.verbose = "" - consoleDestination.levelColor.debug = "" - consoleDestination.levelColor.info = "" - consoleDestination.levelColor.warning = "⚠️ " - consoleDestination.levelColor.error = "🚨 " - - switch configuration.logLevel { - case .verbose: - consoleDestination.minLevel = .verbose - case .debug: - consoleDestination.minLevel = .debug - case .info: - consoleDestination.minLevel = .info - case .warning: - consoleDestination.minLevel = .warning - case .error: - consoleDestination.minLevel = .error - case .none: - break + if Span.current().isNone() { + rootSpan.enter() } - logger.addDestination(consoleDestination) + + logEvent(file: (file as NSString).lastPathComponent, line: UInt32(line), column: UInt32(column), level: level, target: target, message: "\(message)") } } diff --git a/ElementX/Sources/Other/Logging/MXLogger.swift b/ElementX/Sources/Other/Logging/MXLogger.swift index edb943f4e..81e907767 100644 --- a/ElementX/Sources/Other/Logging/MXLogger.swift +++ b/ElementX/Sources/Other/Logging/MXLogger.swift @@ -37,14 +37,16 @@ class MXLogger { /// /// - Parameters: /// - redirectToFiles: `true` to enable the redirection. - /// - numberOfFiles: number of files to keep (default is 10). - /// - sizeLimit: size limit of log files in bytes. 0 means no limitation, the default value for other methods - static func redirectNSLog(toFiles redirectToFiles: Bool, numberOfFiles: UInt = 10, sizeLimit: UInt = 0) { + /// - maxLogFileCount: number of files to keep (default is 10). + /// - logFileSizeLimit: size limit of log files in bytes. 0 means no limitation, the default value for other methods + static func configure(redirectToFiles: Bool, + maxLogFileCount: UInt, + logFileSizeLimit: UInt) { if redirectToFiles { var tempLog = "" // Do a circular buffer based on X files - for index in (0...(numberOfFiles - 2)).reversed() { + for index in (0...(maxLogFileCount - 2)).reversed() { rotateLog(at: index, tempLog: &tempLog) } @@ -60,10 +62,10 @@ class MXLogger { MXLog.info(tempLog) } - removeExtraFiles(from: numberOfFiles) + removeExtraFiles(from: maxLogFileCount) - if sizeLimit > 0 { - removeFiles(after: sizeLimit) + if logFileSizeLimit > 0 { + removeFiles(after: logFileSizeLimit) } } else if stderrSave > 0 { // Flush before restoring stderr diff --git a/ElementX/Sources/Other/Logging/RustTracing.swift b/ElementX/Sources/Other/Logging/RustTracing.swift index 4634b0e9e..f3660e7bb 100644 --- a/ElementX/Sources/Other/Logging/RustTracing.swift +++ b/ElementX/Sources/Other/Logging/RustTracing.swift @@ -22,11 +22,30 @@ import MatrixRustSDK // https://docs.rs/tracing-subscriber/0.2.7/tracing_subscriber/filter/struct.EnvFilter.html#examples struct TracingConfiguration { static var release = TracingConfiguration(overrides: [.common: .info]) - static var debug = TracingConfiguration(overrides: [.common: .info]) + + static var debug = TracingConfiguration(overrides: [.matrix_sdk_crypto: .info, + .matrix_sdk_http_client: .info, + .matrix_sdk_sliding_sync: .info, + .matrix_sdk_base_sliding_sync: .info]) + + /// Configure tracing with certain overrides in place + /// - Parameter overrides: the desired overrides + /// - Returns: a custom tracing configuration static func custom(overrides: [Target: LogLevel]) -> TracingConfiguration { TracingConfiguration(overrides: overrides) } + /// Sets the same log level for all Targets + /// - Parameter logLevel: the desired log level + /// - Returns: a custom tracing configuration + static func custom(logLevel: LogLevel) -> TracingConfiguration { + let overrides = targets.keys.reduce(into: [Target: LogLevel]()) { partialResult, target in + partialResult[target] = logLevel + } + + return TracingConfiguration(overrides: overrides) + } + enum LogLevel: String { case error, warn, info, debug, trace } enum Target: String { @@ -41,8 +60,8 @@ struct TracingConfiguration { case matrix_sdk_room_timeline = "matrix_sdk::room::timeline" } - let targets: OrderedDictionary = [ - .common: .warn, + static let targets: OrderedDictionary = [ + .common: .info, .hyper: .warn, .sled: .warn, .matrix_sdk_sled: .warn, @@ -56,7 +75,7 @@ struct TracingConfiguration { var overrides = [Target: LogLevel]() var filter: String { - var newTargets = targets + var newTargets = Self.targets for (target, logLevel) in overrides { newTargets.updateValue(logLevel, forKey: target) } diff --git a/ElementX/Sources/Services/Authentication/AuthenticationServiceProxy.swift b/ElementX/Sources/Services/Authentication/AuthenticationServiceProxy.swift index df5788f54..7e5c3de70 100644 --- a/ElementX/Sources/Services/Authentication/AuthenticationServiceProxy.swift +++ b/ElementX/Sources/Services/Authentication/AuthenticationServiceProxy.swift @@ -93,7 +93,7 @@ class AuthenticationServiceProxy: AuthenticationServiceProxyProtocol { let client = try authenticationService.restoreWithAccessToken(token: token, deviceId: deviceID) return await userSession(for: client) } catch { - MXLog.error(error) + MXLog.error("Failed restoring with access token: \(error)") return .failure(.failedLoggingIn) } } diff --git a/ElementX/Sources/Services/Media/Provider/MediaLoader.swift b/ElementX/Sources/Services/Media/Provider/MediaLoader.swift index bb047264b..48d5640e3 100644 --- a/ElementX/Sources/Services/Media/Provider/MediaLoader.swift +++ b/ElementX/Sources/Services/Media/Provider/MediaLoader.swift @@ -48,7 +48,7 @@ actor MediaLoader: MediaLoaderProtocol { func loadMediaFileForSource(_ source: MediaSourceProxy) async throws -> MediaFileHandleProxy { let result = try await Task.dispatch(on: clientQueue) { - try self.client.getMediaFile(source: source.underlyingSource, mimeType: source.mimeType ?? "application/octet-stream") + try self.client.getMediaFile(mediaSource: source.underlyingSource, mimeType: source.mimeType ?? "application/octet-stream") } return MediaFileHandleProxy(handle: result) diff --git a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift index 06eed03b9..1c2ccc88b 100644 --- a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift +++ b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift @@ -80,7 +80,13 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol { // MARK: - Private fileprivate func updateRoomsWithDiffs(_ diffs: [SlidingSyncListRoomsListDiff]) { - MXLog.info("Received \(diffs.count) diffs") + let span = MXLog.createSpan("process_room_list_diffs") + span.enter() + defer { + span.exit() + } + + MXLog.verbose("Received \(diffs.count) diffs") rooms = diffs .reduce(rooms) { currentItems, diff in @@ -101,7 +107,7 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol { detectDuplicatesInRoomList(rooms) - MXLog.info("Finished applying \(diffs.count) diffs, new count: \(rooms.count)") + MXLog.verbose("Finished applying \(diffs.count) diffs, new count: \(rooms.count)") } private func buildRoomSummaryForIdentifier(_ identifier: String, invalidated: Bool) -> RoomSummary { diff --git a/ElementX/Sources/Services/Timeline/RoomTimelineProvider.swift b/ElementX/Sources/Services/Timeline/RoomTimelineProvider.swift index 93ae724d3..4763428a8 100644 --- a/ElementX/Sources/Services/Timeline/RoomTimelineProvider.swift +++ b/ElementX/Sources/Services/Timeline/RoomTimelineProvider.swift @@ -60,6 +60,7 @@ class RoomTimelineProvider: RoomTimelineProviderProtocol { switch await roomProxy.addTimelineListener(listener: roomTimelineListener) { case .success(let items): itemProxies = items.map(TimelineItemProxy.init) + MXLog.info("Added timeline listener, current items (\(items.count)) : \(items.map(\.debugIdentifier))") case .failure: let roomID = await roomProxy.id MXLog.error("Failed adding timeline listener on room with identifier: \(roomID)") @@ -70,7 +71,13 @@ class RoomTimelineProvider: RoomTimelineProviderProtocol { // MARK: - Private private func updateItemsWithDiffs(_ diffs: [TimelineDiff]) { - MXLog.verbose("Received timeline diff") + let span = MXLog.createSpan("process_timeline_list_diffs") + span.enter() + defer { + span.exit() + } + + MXLog.info("Received timeline diff") itemProxies = diffs .reduce(itemProxies) { currentItems, diff in @@ -84,12 +91,10 @@ class RoomTimelineProvider: RoomTimelineProviderProtocol { return currentItems } - MXLog.verbose("Applied diff \(collectionDiff), new count: \(updatedItems.count)") - return updatedItems } - MXLog.verbose("Finished applying diff") + MXLog.info("Finished applying diffs, current items (\(itemProxies.count)) : \(itemProxies.map(\.debugIdentifier))") } // swiftlint:disable:next cyclomatic_complexity function_body_length @@ -100,60 +105,64 @@ class RoomTimelineProvider: RoomTimelineProviderProtocol { case .pushFront: guard let item = diff.pushFront() else { fatalError() } - MXLog.verbose("Push Front") + MXLog.info("Push Front: \(item.debugIdentifier)") let itemProxy = TimelineItemProxy(item: item) changes.append(.insert(offset: 0, element: itemProxy, associatedWith: nil)) case .pushBack: guard let item = diff.pushBack() else { fatalError() } - MXLog.verbose("Push Back") + MXLog.info("Push Back \(item.debugIdentifier)") let itemProxy = TimelineItemProxy(item: item) changes.append(.insert(offset: Int(itemProxies.count), element: itemProxy, associatedWith: nil)) case .insert: guard let update = diff.insert() else { fatalError() } - MXLog.verbose("Insert at \(update.index), current total count: \(itemProxies.count)") + MXLog.info("Insert \(update.item.debugIdentifier) at \(update.index)") let itemProxy = TimelineItemProxy(item: update.item) changes.append(.insert(offset: Int(update.index), element: itemProxy, associatedWith: nil)) case .append: guard let items = diff.append() else { fatalError() } - MXLog.verbose("Append new items with count: \(items.count), to current total count: \(itemProxies.count)") + MXLog.info("Append \(items.map(\.debugIdentifier))") for (index, item) in items.enumerated() { changes.append(.insert(offset: Int(itemProxies.count) + index, element: TimelineItemProxy(item: item), associatedWith: nil)) } case .set: guard let update = diff.set() else { fatalError() } - MXLog.verbose("Update \(update.index), current total count: \(itemProxies.count)") + MXLog.info("Set \(update.item.debugIdentifier) at index \(update.index)") let itemProxy = TimelineItemProxy(item: update.item) changes.append(.remove(offset: Int(update.index), element: itemProxy, associatedWith: nil)) changes.append(.insert(offset: Int(update.index), element: itemProxy, associatedWith: nil)) case .popFront: - MXLog.verbose("Pop Front, current total count: \(itemProxies.count)") guard let itemProxy = itemProxies.first else { fatalError() } + MXLog.info("Pop Front \(itemProxy.debugIdentifier)") + changes.append(.remove(offset: 0, element: itemProxy, associatedWith: nil)) case .popBack: - MXLog.verbose("Pop Back, current total count: \(itemProxies.count)") guard let itemProxy = itemProxies.last else { fatalError() } + MXLog.info("Pop Back \(itemProxy.debugIdentifier)") + changes.append(.remove(offset: itemProxies.count - 1, element: itemProxy, associatedWith: nil)) case .remove: guard let index = diff.remove() else { fatalError() } - MXLog.verbose("Remove item at: \(index), current total count: \(itemProxies.count)") let itemProxy = itemProxies[Int(index)] + + MXLog.info("Remove \(itemProxy.debugIdentifier) at: \(index)") + changes.append(.remove(offset: Int(index), element: itemProxy, associatedWith: nil)) case .clear: - MXLog.verbose("Clear all items, current total count: \(itemProxies.count)") + MXLog.info("Clear all items") for (index, itemProxy) in itemProxies.enumerated() { changes.append(.remove(offset: index, element: itemProxy, associatedWith: nil)) } case .reset: guard let items = diff.reset() else { fatalError() } - MXLog.verbose("Replace all items with new count: \(items.count), current total count: \(itemProxies.count)") + MXLog.info("Replace all items with \(items.map(\.debugIdentifier))") for (index, itemProxy) in itemProxies.enumerated() { changes.append(.remove(offset: index, element: itemProxy, associatedWith: nil)) } @@ -166,3 +175,43 @@ class RoomTimelineProvider: RoomTimelineProviderProtocol { return CollectionDifference(changes) } } + +private extension TimelineItem { + var debugIdentifier: String { + if let virtualTimelineItem = asVirtual() { + return virtualTimelineItem.debugIdentifier + } else if let eventTimelineItem = asEvent() { + return eventTimelineItem.uniqueIdentifier() + } + + return "UnknownTimelineItem" + } +} + +private extension TimelineItemProxy { + var debugIdentifier: String { + switch self { + case .event(let eventTimelineItem): + return eventTimelineItem.item.uniqueIdentifier() + case .virtual(let virtualTimelineItem): + return virtualTimelineItem.debugIdentifier + case .unknown: + return "UnknownTimelineItem" + } + } +} + +private extension VirtualTimelineItem { + var debugIdentifier: String { + switch self { + case .dayDivider(let timestamp): + return "DayDiviver(\(timestamp))" + case .loadingIndicator: + return "LoadingIndicator" + case .readMarker: + return "ReadMarker" + case .timelineStart: + return "TimelineStart" + } + } +} diff --git a/ElementX/Sources/Services/Timeline/TimelineItemProxy.swift b/ElementX/Sources/Services/Timeline/TimelineItemProxy.swift index eb92317a0..56962932f 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItemProxy.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItemProxy.swift @@ -106,7 +106,7 @@ struct EventTimelineItemProxy { } var reactions: [Reaction] { - item.reactions() ?? [] + item.reactions() } var timestamp: Date { diff --git a/ElementX/SupportingFiles/target.yml b/ElementX/SupportingFiles/target.yml index 3d1842928..9774b1899 100644 --- a/ElementX/SupportingFiles/target.yml +++ b/ElementX/SupportingFiles/target.yml @@ -140,7 +140,6 @@ targets: - package: Kingfisher - package: KZFileWatchers - package: PostHog - - package: SwiftyBeaver - package: SwiftState - package: GZIP - package: Sentry diff --git a/IntegrationTests/SupportingFiles/target.yml b/IntegrationTests/SupportingFiles/target.yml index 90092169d..7c81c12ff 100644 --- a/IntegrationTests/SupportingFiles/target.yml +++ b/IntegrationTests/SupportingFiles/target.yml @@ -36,7 +36,6 @@ targets: - package: DTCoreText - package: KeychainAccess - package: Kingfisher - - package: SwiftyBeaver - package: SwiftState - package: GZIP - package: Sentry diff --git a/NSE/Sources/Other/NSELogger.swift b/NSE/Sources/Other/NSELogger.swift index 3a7669653..3b25f6482 100644 --- a/NSE/Sources/Other/NSELogger.swift +++ b/NSE/Sources/Other/NSELogger.swift @@ -81,24 +81,7 @@ class NSELogger { } isConfigured = true - let configuration = MXLogConfiguration() - configuration.maxLogFilesCount = 10 - configuration.subLogName = "nse" - - #if DEBUG - setupTracing(configuration: .debug) - configuration.logLevel = .debug - #else - setupTracing(configuration: .release) - configuration.logLevel = .info - #endif - - // Avoid redirecting NSLogs to files if we are attached to a debugger. - if isatty(STDERR_FILENO) == 0 { - configuration.redirectLogsToFiles = true - } - - MXLog.configure(configuration) + MXLog.configure(target: "nse") } static func logMemory(with tag: String) { diff --git a/NSE/SupportingFiles/target.yml b/NSE/SupportingFiles/target.yml index f423f9bb6..8fed7e120 100644 --- a/NSE/SupportingFiles/target.yml +++ b/NSE/SupportingFiles/target.yml @@ -33,7 +33,6 @@ targets: dependencies: - package: MatrixRustSDK - - package: SwiftyBeaver - package: KeychainAccess - package: Kingfisher - package: Collections diff --git a/UITests/SupportingFiles/target.yml b/UITests/SupportingFiles/target.yml index 7240ace23..bf615d31f 100644 --- a/UITests/SupportingFiles/target.yml +++ b/UITests/SupportingFiles/target.yml @@ -36,7 +36,6 @@ targets: - package: Kingfisher - package: KZFileWatchers - package: PostHog - - package: SwiftyBeaver - package: SwiftState - package: GZIP - package: Sentry diff --git a/UnitTests/Sources/LoggingTests.swift b/UnitTests/Sources/LoggingTests.swift index 3147753d6..2782b38c9 100644 --- a/UnitTests/Sources/LoggingTests.swift +++ b/UnitTests/Sources/LoggingTests.swift @@ -36,9 +36,8 @@ class LoggingTests: XCTestCase { let log = UUID().uuidString - let configuration = MXLogConfiguration() - configuration.redirectLogsToFiles = true - MXLog.configure(configuration) + MXLog.configure(redirectToFiles: true) + MXLog.info(log) guard let logFile = MXLogger.logFiles.first else { XCTFail(Constants.genericFailure) @@ -56,9 +55,7 @@ class LoggingTests: XCTestCase { // When launching the app 5 times. let launchCount = 5 for index in 0.. String { fatalError() } - func getMediaFile(source: MatrixRustSDK.MediaSource, mimeType: String) throws -> MatrixRustSDK.MediaFileHandle { fatalError() } + func getMediaFile(mediaSource: MatrixRustSDK.MediaSource, mimeType: String) throws -> MatrixRustSDK.MediaFileHandle { fatalError() } func getProfile(userId: String) throws -> MatrixRustSDK.UserProfile { fatalError() } @@ -129,10 +129,6 @@ private class MockMediaLoadingClient: ClientProtocol { fatalError() } - func searchUsers(searchTerm: String, limit: UInt64) throws -> MatrixRustSDK.SearchUsersResults { - fatalError() - } - func unignoreUser(userId: String) throws { fatalError() } @@ -146,4 +142,6 @@ private class MockMediaLoadingClient: ClientProtocol { lang: String) throws { fatalError() } + + func searchUsers(searchTerm: String, limit: UInt64) throws -> MatrixRustSDK.SearchUsersResults { fatalError() } } diff --git a/UnitTests/Sources/MessageTimelineItemTests.swift b/UnitTests/Sources/MessageTimelineItemTests.swift index ba45b0754..ea3bb4b84 100644 --- a/UnitTests/Sources/MessageTimelineItemTests.swift +++ b/UnitTests/Sources/MessageTimelineItemTests.swift @@ -156,7 +156,7 @@ private struct MockEventTimelineItem: EventTimelineItemProtocol { func raw() -> String? { nil } - func reactions() -> [MatrixRustSDK.Reaction]? { nil } + func reactions() -> [MatrixRustSDK.Reaction] { [] } func sender() -> String { "@user:server.com" } diff --git a/project.yml b/project.yml index 62fb54825..9f1ba8856 100644 --- a/project.yml +++ b/project.yml @@ -42,7 +42,7 @@ include: packages: MatrixRustSDK: url: https://github.com/matrix-org/matrix-rust-components-swift - exactVersion: 1.0.54-alpha + exactVersion: 1.0.56-alpha # path: ../matrix-rust-sdk DesignKit: path: DesignKit @@ -83,9 +83,6 @@ packages: PostHog: url: https://github.com/PostHog/posthog-ios minorVersion: 2.0.0 - SwiftyBeaver: - url: https://github.com/SwiftyBeaver/SwiftyBeaver - minorVersion: 2.0.0 SwiftState: url: https://github.com/ReactKit/SwiftState minorVersion: 6.0.0