mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 13:37:11 +00:00
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
This commit is contained in:
parent
0d3e823b69
commit
be8adb19b5
@ -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",
|
||||
|
@ -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 }
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)")
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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<Target, LogLevel> = [
|
||||
.common: .warn,
|
||||
static let targets: OrderedDictionary<Target, LogLevel> = [
|
||||
.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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ struct EventTimelineItemProxy {
|
||||
}
|
||||
|
||||
var reactions: [Reaction] {
|
||||
item.reactions() ?? []
|
||||
item.reactions()
|
||||
}
|
||||
|
||||
var timestamp: Date {
|
||||
|
@ -140,7 +140,6 @@ targets:
|
||||
- package: Kingfisher
|
||||
- package: KZFileWatchers
|
||||
- package: PostHog
|
||||
- package: SwiftyBeaver
|
||||
- package: SwiftState
|
||||
- package: GZIP
|
||||
- package: Sentry
|
||||
|
@ -36,7 +36,6 @@ targets:
|
||||
- package: DTCoreText
|
||||
- package: KeychainAccess
|
||||
- package: Kingfisher
|
||||
- package: SwiftyBeaver
|
||||
- package: SwiftState
|
||||
- package: GZIP
|
||||
- package: Sentry
|
||||
|
@ -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) {
|
||||
|
@ -33,7 +33,6 @@ targets:
|
||||
|
||||
dependencies:
|
||||
- package: MatrixRustSDK
|
||||
- package: SwiftyBeaver
|
||||
- package: KeychainAccess
|
||||
- package: Kingfisher
|
||||
- package: Collections
|
||||
|
@ -36,7 +36,6 @@ targets:
|
||||
- package: Kingfisher
|
||||
- package: KZFileWatchers
|
||||
- package: PostHog
|
||||
- package: SwiftyBeaver
|
||||
- package: SwiftState
|
||||
- package: GZIP
|
||||
- package: Sentry
|
||||
|
@ -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..<launchCount {
|
||||
let configuration = MXLogConfiguration()
|
||||
configuration.redirectLogsToFiles = true
|
||||
MXLog.configure(configuration) // This call is only made at app launch.
|
||||
MXLog.configure(redirectToFiles: true)
|
||||
MXLog.info("Launch \(index + 1)")
|
||||
}
|
||||
|
||||
@ -77,10 +74,7 @@ class LoggingTests: XCTestCase {
|
||||
let launchCount = 10
|
||||
let logFileCount = 5
|
||||
for index in 0..<launchCount {
|
||||
let configuration = MXLogConfiguration()
|
||||
configuration.maxLogFilesCount = UInt(logFileCount)
|
||||
configuration.redirectLogsToFiles = true
|
||||
MXLog.configure(configuration) // This call is only made at app launch.
|
||||
MXLog.configure(redirectToFiles: true, maxLogFileCount: UInt(logFileCount))
|
||||
MXLog.info("Launch \(index + 1)")
|
||||
}
|
||||
|
||||
@ -97,12 +91,9 @@ class LoggingTests: XCTestCase {
|
||||
|
||||
// When launching the app 10 times, with a max total log size of 25KB and logging ~5KB data each time.
|
||||
let launchCount = 10
|
||||
let logFileSizeLimit = 25 * 1024
|
||||
let logFileSizeLimit: UInt = 25 * 1024
|
||||
for index in 0..<launchCount {
|
||||
let configuration = MXLogConfiguration()
|
||||
configuration.logFilesSizeLimit = UInt(logFileSizeLimit)
|
||||
configuration.redirectLogsToFiles = true
|
||||
MXLog.configure(configuration) // This call is only made at app launch.
|
||||
MXLog.configure(redirectToFiles: true, logFileSizeLimit: logFileSizeLimit)
|
||||
MXLog.info("Launch \(index + 1)")
|
||||
|
||||
// Add ~5KB of logs
|
||||
@ -142,11 +133,9 @@ class LoggingTests: XCTestCase {
|
||||
|
||||
let log = UUID().uuidString
|
||||
|
||||
let configuration = MXLogConfiguration()
|
||||
configuration.logLevel = .error
|
||||
configuration.redirectLogsToFiles = true
|
||||
MXLog.configure(configuration)
|
||||
MXLog.info(log)
|
||||
MXLog.configure(redirectToFiles: true)
|
||||
|
||||
MXLog.verbose(log)
|
||||
guard let logFile = MXLogger.logFiles.first else {
|
||||
XCTFail(Constants.genericFailure)
|
||||
return
|
||||
@ -159,19 +148,17 @@ class LoggingTests: XCTestCase {
|
||||
func testSubLogName() {
|
||||
XCTAssert(MXLogger.logFiles.isEmpty)
|
||||
|
||||
let subLogName = "nse"
|
||||
let target = "nse"
|
||||
|
||||
let configuration = MXLogConfiguration()
|
||||
configuration.subLogName = subLogName
|
||||
configuration.redirectLogsToFiles = true
|
||||
MXLog.configure(configuration)
|
||||
MXLog.configure(target: target, redirectToFiles: true)
|
||||
|
||||
MXLog.info(UUID().uuidString)
|
||||
guard let logFile = MXLogger.logFiles.first else {
|
||||
XCTFail(Constants.genericFailure)
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssertTrue(logFile.lastPathComponent.contains(subLogName))
|
||||
XCTAssertTrue(logFile.lastPathComponent.contains(target))
|
||||
}
|
||||
|
||||
func testRoomSummaryContentIsRedacted() throws {
|
||||
@ -189,10 +176,9 @@ class LoggingTests: XCTestCase {
|
||||
|
||||
// When logging that value
|
||||
XCTAssert(MXLogger.logFiles.isEmpty)
|
||||
let configuration = MXLogConfiguration()
|
||||
configuration.logLevel = .info
|
||||
configuration.redirectLogsToFiles = true
|
||||
MXLog.configure(configuration)
|
||||
|
||||
MXLog.configure(redirectToFiles: true)
|
||||
|
||||
MXLog.info(roomSummary)
|
||||
|
||||
// Then the log file should not include the sensitive information
|
||||
@ -207,7 +193,6 @@ class LoggingTests: XCTestCase {
|
||||
XCTAssertFalse(content.contains(lastMessage))
|
||||
}
|
||||
|
||||
// swiftlint:disable:next function_body_length
|
||||
func testTimelineContentIsRedacted() throws {
|
||||
// Given timeline items that contain text
|
||||
let textAttributedString = "TextAttributed"
|
||||
@ -235,10 +220,9 @@ class LoggingTests: XCTestCase {
|
||||
|
||||
// When logging that value
|
||||
XCTAssert(MXLogger.logFiles.isEmpty)
|
||||
let configuration = MXLogConfiguration()
|
||||
configuration.logLevel = .info
|
||||
configuration.redirectLogsToFiles = true
|
||||
MXLog.configure(configuration)
|
||||
|
||||
MXLog.configure(redirectToFiles: true)
|
||||
|
||||
MXLog.info(textMessage)
|
||||
MXLog.info(noticeMessage)
|
||||
MXLog.info(emoteMessage)
|
||||
@ -294,10 +278,9 @@ class LoggingTests: XCTestCase {
|
||||
|
||||
// When logging that value
|
||||
XCTAssert(MXLogger.logFiles.isEmpty)
|
||||
let configuration = MXLogConfiguration()
|
||||
configuration.logLevel = .info
|
||||
configuration.redirectLogsToFiles = true
|
||||
MXLog.configure(configuration)
|
||||
|
||||
MXLog.configure(redirectToFiles: true)
|
||||
|
||||
MXLog.info(textMessage)
|
||||
MXLog.info(noticeMessage)
|
||||
MXLog.info(emoteMessage)
|
||||
|
@ -95,7 +95,7 @@ private class MockMediaLoadingClient: ClientProtocol {
|
||||
|
||||
func uploadMedia(mimeType: String, data content: [UInt8]) throws -> 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() }
|
||||
}
|
||||
|
@ -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" }
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user