From 544bbd3621c24189f02f54262e9c8dd89cde9093 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Wed, 5 Jun 2024 20:46:24 -0700 Subject: [PATCH] Debug log updates --- Meshtastic.xcodeproj/project.pbxproj | 4 + Meshtastic/Extensions/Logger.swift | 22 ++- Meshtastic/Helpers/BLEManager.swift | 8 +- Meshtastic/MeshtasticAppDelegate.swift | 2 +- Meshtastic/Views/Helpers/LogDetail.swift | 129 ++++++++++++++++++ .../Nodes/Helpers/Map/PositionPopover.swift | 1 + Meshtastic/Views/Settings/AppLog.swift | 35 +++-- Meshtastic/Views/Settings/Settings.swift | 2 +- 8 files changed, 174 insertions(+), 29 deletions(-) create mode 100644 Meshtastic/Views/Helpers/LogDetail.swift diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 13ea755d..59a1dd10 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -208,6 +208,7 @@ DDF45C372BC46A5A005ED5F2 /* TimeZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF45C362BC46A5A005ED5F2 /* TimeZone.swift */; }; DDF6B2482A9AEBF500BA6931 /* StoreForwardConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF6B2472A9AEBF500BA6931 /* StoreForwardConfig.swift */; }; DDF8E1F42C10125B0019C87E /* AppLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF8E1F32C10125B0019C87E /* AppLog.swift */; }; + DDF8E1F92C115CCE0019C87E /* LogDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF8E1F82C115CCE0019C87E /* LogDetail.swift */; }; DDF924CA26FBB953009FE055 /* ConnectedDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF924C926FBB953009FE055 /* ConnectedDevice.swift */; }; DDFEB3BB29900C1200EE7472 /* CurrentConditionsCompact.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFEB3BA29900C1200EE7472 /* CurrentConditionsCompact.swift */; }; DDFFA7472B3A7F3C004730DB /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFFA7462B3A7F3C004730DB /* Bundle.swift */; }; @@ -483,6 +484,7 @@ DDF6B2472A9AEBF500BA6931 /* StoreForwardConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreForwardConfig.swift; sourceTree = ""; }; DDF6B24B2A9C2FC800BA6931 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; DDF8E1F32C10125B0019C87E /* AppLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLog.swift; sourceTree = ""; }; + DDF8E1F82C115CCE0019C87E /* LogDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogDetail.swift; sourceTree = ""; }; DDF924C926FBB953009FE055 /* ConnectedDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectedDevice.swift; sourceTree = ""; }; DDFEB3BA29900C1200EE7472 /* CurrentConditionsCompact.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentConditionsCompact.swift; sourceTree = ""; }; DDFFA7462B3A7F3C004730DB /* Bundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bundle.swift; sourceTree = ""; }; @@ -894,6 +896,7 @@ DDB75A1D2A0B0CD0006ED576 /* LoRaSignalStrengthIndicator.swift */, DDB75A202A12B954006ED576 /* LoRaSignalStrength.swift */, DDB75A222A13CDA9006ED576 /* BatteryLevelCompact.swift */, + DDF8E1F82C115CCE0019C87E /* LogDetail.swift */, ); path = Helpers; sourceTree = ""; @@ -1197,6 +1200,7 @@ DD5E5208298EE33B00D21B61 /* rtttl.pb.swift in Sources */, DD6193792863875F00E59241 /* SerialConfig.swift in Sources */, DDDB263F2AABEE20003AFCB7 /* NodeList.swift in Sources */, + DDF8E1F92C115CCE0019C87E /* LogDetail.swift in Sources */, DDA0B6B2294CDC55001356EC /* Channels.swift in Sources */, DDE9659C2B1C3B6A00531070 /* RouteRecorder.swift in Sources */, B399E8A42B6F486400E4488E /* RetryButton.swift in Sources */, diff --git a/Meshtastic/Extensions/Logger.swift b/Meshtastic/Extensions/Logger.swift index 925da350..b15b0beb 100644 --- a/Meshtastic/Extensions/Logger.swift +++ b/Meshtastic/Extensions/Logger.swift @@ -37,14 +37,8 @@ extension Logger { try Task.checkCancellation() - if let log = entry as? OSLogEntryLog { - logs.append(log) -// logs.append(""" -// \(entry.date.formatted(.dateTime.hour(.twoDigits(amPM: .omitted)).minute().second().secondFraction(.fractional(3)))) \(log.level.description) \ -// \(log.category) \(entry.composedMessage)\n -// """) - } else { - // logs.append("\(entry.date): \(entry.composedMessage)\n") + if let log = entry as? OSLogEntryLog { + logs.append(log) } } @@ -54,14 +48,14 @@ extension Logger { } extension OSLogEntryLog.Level { - fileprivate var description: String { + var description: String { switch self { case .undefined: "undefined" - case .debug: "Debug" - case .info: "Info" - case .notice: "Notice" - case .error: "Error" - case .fault: "Fault" + case .debug: "🐛 Debug" + case .info: "â„šī¸ Info" + case .notice: "âš ī¸ Notice" + case .error: "🚨 Error" + case .fault: "đŸ’Ĩ Fault" @unknown default: "default" } } diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index 5885e375..42acd0a0 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -130,7 +130,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate let context = ["name": "\(peripheral.name ?? "Unknown")"] timeoutTimer = Timer.scheduledTimer(timeInterval: 1.5, target: self, selector: #selector(timeoutTimerFired), userInfo: context, repeats: true) RunLoop.current.add(timeoutTimer!, forMode: .common) - Logger.services.info("â„šī¸ BLE Connecting: \(peripheral.name ?? "Unknown")") + Logger.services.info("â„šī¸ BLE Connecting: \(peripheral.name ?? "Unknown", privacy: .public)") } // Disconnect Connected Peripheral @@ -259,12 +259,12 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate manager.schedule() } lastConnectionError = "🚨 \(e.localizedDescription)" - Logger.services.error("🚨 BLE Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode) Error: \(e.localizedDescription)") + Logger.services.error("đŸšĢ BLE Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode) Error: \(e.localizedDescription)") } } else { // Disconnected without error which indicates user intent to disconnect // Happens when swiping to disconnect - Logger.services.info("â„šī¸ BLE Disconnected: \(peripheral.name ?? "Unknown"): User Initiated Disconnect") + Logger.services.info("đŸšĢ BLE Disconnected: \(peripheral.name ?? "Unknown"): User Initiated Disconnect") } // Start a scan so the disconnected peripheral is moved to the peripherals[] if it is awake self.startScanning() @@ -3021,7 +3021,7 @@ extension BLEManager: CBCentralManagerDelegate { if self.automaticallyReconnect && peripheral.identifier.uuidString == UserDefaults.standard.object(forKey: "preferredPeripheralId") as? String ?? "" { self.connectTo(peripheral: peripheral) - Logger.services.info("BLE Reconnecting to prefered peripheral: \(peripheral.name ?? "Unknown")") + Logger.services.info("🔄 BLE Reconnecting to prefered peripheral: \(peripheral.name ?? "Unknown")") } let name = advertisementData[CBAdvertisementDataLocalNameKey] as? String let device = Peripheral(id: peripheral.identifier.uuidString, num: 0, name: name ?? "Unknown", shortName: "?", longName: name ?? "Unknown", firmwareVersion: "Unknown", rssi: RSSI.intValue, lastUpdate: Date(), peripheral: peripheral) diff --git a/Meshtastic/MeshtasticAppDelegate.swift b/Meshtastic/MeshtasticAppDelegate.swift index 1bfa73ed..cc5dc397 100644 --- a/Meshtastic/MeshtasticAppDelegate.swift +++ b/Meshtastic/MeshtasticAppDelegate.swift @@ -10,7 +10,7 @@ import OSLog class MeshtasticAppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, ObservableObject { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { - Logger.services.info("🚀 Meshtstic Apple App launched!") + Logger.services.info("🚀 Meshtastic Apple App launched!") // Default User Default Values UserDefaults.standard.register(defaults: ["meshMapRecentering": true]) UserDefaults.standard.register(defaults: ["meshMapShowNodeHistory": true]) diff --git a/Meshtastic/Views/Helpers/LogDetail.swift b/Meshtastic/Views/Helpers/LogDetail.swift new file mode 100644 index 00000000..085211d1 --- /dev/null +++ b/Meshtastic/Views/Helpers/LogDetail.swift @@ -0,0 +1,129 @@ +// +// LogDetail.swift +// Meshtastic +// +// Copyright(c) Garth Vander Houwen 6/5/24. +// + +import SwiftUI +import MapKit +import OSLog + +@available(iOS 17.0, macOS 14.0, *) +struct LogDetail: View { + + @Environment(\.dismiss) private var dismiss + var log: OSLogEntryLog + + var body: some View { + + VStack { + HStack { + Text("OS Log Entry Details") + .font(.largeTitle) + } + Divider() + HStack(alignment: .top) { + VStack(alignment: .leading) { + List { + /// Time + Label { + Text("time".localized + ":") + .font(.title) + LastHeardText(lastHeard: log.date) + .font(.title) + } icon: { + Image(systemName: "timer") + .symbolRenderingMode(.hierarchical) + .font(.title) + .frame(width: 35) + } + .padding(.bottom, 5) + /// Subsystem + Label { + Text("subsystem".localized + ":") + .font(.title) + Text(log.subsystem) + .font(.title) + } icon: { + Image(systemName: "gear") + .symbolRenderingMode(.hierarchical) + .font(.title) + .frame(width: 35) + } + .padding(.bottom, 5) + /// Process + Label { + Text("process".localized + ":") + .font(.title) + Text(log.process) + .font(.title) + } icon: { + Image(systemName: "tag") + .symbolRenderingMode(.hierarchical) + .font(.title) + .frame(width: 35) + } + .padding(.bottom, 5) + /// Category + Label { + Text("category".localized + ":") + .font(.title) + Text(log.category) + .font(.title) + } icon: { + Image(systemName: "rectangle.3.group") + .symbolRenderingMode(.hierarchical) + .font(.title) + .frame(width: 35) + } + .padding(.bottom, 5) + /// Level + Label { + Text("level".localized + ":") + .font(.title) + Text(log.level.description) + .font(.title) + } icon: { + Image(systemName: "shield") + .symbolRenderingMode(.hierarchical) + .font(.title) + .frame(width: 35) + } + .padding(.bottom, 5) + /// message + Label { + Text("message".localized + ":") + .font(.title) + Text(log.composedMessage) + .font(.title) + } icon: { + Image(systemName: "text.bubble") + .symbolRenderingMode(.hierarchical) + .font(.title) + .frame(width: 35) + } + .padding(.bottom, 5) + } + .listStyle(.plain) + } + Spacer() + } + .padding(.top) +#if targetEnvironment(macCatalyst) + Spacer() + Button { + dismiss() + } label: { + Label("close", systemImage: "xmark") + } + .buttonStyle(.bordered) + .buttonBorderShape(.capsule) + .controlSize(.large) + .padding(.bottom) +#endif + } + .presentationDetents([.fraction(0.65), .fraction(0.75), .fraction(0.85)]) + .presentationDragIndicator(.visible) + } +} diff --git a/Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift b/Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift index 48e71904..737020a7 100644 --- a/Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift +++ b/Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift @@ -18,6 +18,7 @@ struct PositionPopover: View { var popover: Bool = true let distanceFormatter = MKDistanceFormatter() var delay: Double = 0 + @State private var scale: CGFloat = 0.5 var body: some View { // Node Color from node.num diff --git a/Meshtastic/Views/Settings/AppLog.swift b/Meshtastic/Views/Settings/AppLog.swift index af6923e4..de925061 100644 --- a/Meshtastic/Views/Settings/AppLog.swift +++ b/Meshtastic/Views/Settings/AppLog.swift @@ -13,12 +13,11 @@ struct AppLog: View { @State private var logs: [OSLogEntryLog] = [] @State private var sortOrder = [KeyPathComparator(\OSLogEntryLog.date)] - @State private var selection = Set() + @State private var selection: OSLogEntry.ID? + @State private var selectedLog: OSLogEntryLog? + @State private var presentingErrorDetails: Bool = false private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } - let dateFormatStyle = Date.FormatStyle() - .year(.twoDigits) - .month(.defaultDigits) - .day(.defaultDigits) + private let dateFormatStyle = Date.FormatStyle() .hour(.twoDigits(amPM: .omitted)) .minute() .second() @@ -28,23 +27,41 @@ struct AppLog: View { Table(logs, selection: $selection, sortOrder: $sortOrder) { if idiom != .phone { - TableColumn("Date", value: \.date) { value in + TableColumn("Time", value: \.date) { value in Text(value.date.formatted(dateFormatStyle)) } - .width(min: 150, max: 200) + .width(min: 100, max: 125) TableColumn("Category", value: \.category) .width(min: 100, max: 125) + TableColumn("Level") { value in + Text(value.level.description) + } + .width(min: 50, max: 100) } TableColumn("Message", value: \.composedMessage) .width(ideal: 200, max: .infinity) + } .onChange(of: sortOrder) { _, sortOrder in - logs.sort(using: sortOrder) + withAnimation { + logs.sort(using: sortOrder) + } + } + .onChange(of: selection) { newSelection in + presentingErrorDetails = true + let log = logs.first { + $0.id == newSelection + } + selectedLog = log + } + .sheet(item: $selectedLog) { log in + LogDetail(log: log) + .padding() } .task { logs = await fetchLogs() } - .navigationTitle("Debug Logs") + .navigationBarTitle("Debug Logs", displayMode: .inline) } } diff --git a/Meshtastic/Views/Settings/Settings.swift b/Meshtastic/Views/Settings/Settings.swift index 115c66c2..77ca47ad 100644 --- a/Meshtastic/Views/Settings/Settings.swift +++ b/Meshtastic/Views/Settings/Settings.swift @@ -432,7 +432,7 @@ struct Settings: View { Label { Text("Debug Logs") } icon: { - Image(systemName: "building.columns") + Image(systemName: "ladybug") } } .tag(SettingsSidebar.appLog)