From 61c9e34488cf57ab67ebe34b40bc8a25b9845f9c Mon Sep 17 00:00:00 2001 From: Tim Bert <5411131+timbms@users.noreply.github.com> Date: Thu, 31 Oct 2024 15:29:30 +0100 Subject: [PATCH 1/2] Add log viewer to watch app Signed-off-by: Tim Bert <5411131+timbms@users.noreply.github.com> --- openHAB.xcodeproj/project.pbxproj | 4 + openHABWatch/OpenHABWatch.swift | 4 + openHABWatch/Views/LogsViewer.swift | 111 +++++++++++++++++++++++ openHABWatch/Views/Rows/LogsViewer.swift | 43 +++++++++ 4 files changed, 162 insertions(+) create mode 100644 openHABWatch/Views/LogsViewer.swift create mode 100644 openHABWatch/Views/Rows/LogsViewer.swift diff --git a/openHAB.xcodeproj/project.pbxproj b/openHAB.xcodeproj/project.pbxproj index ae72cb94..3fc9f5af 100644 --- a/openHAB.xcodeproj/project.pbxproj +++ b/openHAB.xcodeproj/project.pbxproj @@ -79,6 +79,7 @@ DA0776F0234788010086C685 /* UserData.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA0776EF234788010086C685 /* UserData.swift */; }; DA0F37D023D4ACC7007EAB48 /* SliderRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA0F37CF23D4ACC7007EAB48 /* SliderRow.swift */; }; DA15BFBD23C6726400BD8ADA /* ObservableOpenHABDataObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA15BFBC23C6726400BD8ADA /* ObservableOpenHABDataObject.swift */; }; + DA162BEC2CD3B53E0040DAE5 /* LogsViewer.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA162BEB2CD3B53E0040DAE5 /* LogsViewer.swift */; }; DA19E25B22FD801D002F8F2F /* OpenHABGeneralTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA19E25A22FD801D002F8F2F /* OpenHABGeneralTests.swift */; }; DA21EAE22339621C001AB415 /* Throttler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA21EAE12339621C001AB415 /* Throttler.swift */; }; DA242C622C83588600AFB10D /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA242C612C83588600AFB10D /* SettingsView.swift */; }; @@ -346,6 +347,7 @@ DA0776EF234788010086C685 /* UserData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserData.swift; sourceTree = ""; }; DA0F37CF23D4ACC7007EAB48 /* SliderRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SliderRow.swift; sourceTree = ""; }; DA15BFBC23C6726400BD8ADA /* ObservableOpenHABDataObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObservableOpenHABDataObject.swift; sourceTree = ""; }; + DA162BEB2CD3B53E0040DAE5 /* LogsViewer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogsViewer.swift; sourceTree = ""; }; DA19E25A22FD801D002F8F2F /* OpenHABGeneralTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenHABGeneralTests.swift; sourceTree = ""; }; DA1C2E4B230DC28F00FACFB0 /* Appfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Appfile; sourceTree = ""; }; DA1C2E4C230DC28F00FACFB0 /* SnapshotHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnapshotHelper.swift; sourceTree = ""; }; @@ -775,6 +777,7 @@ isa = PBXGroup; children = ( DA0775262346705F0086C685 /* ContentView.swift */, + DA162BEB2CD3B53E0040DAE5 /* LogsViewer.swift */, DAC6608C236F771600F4501E /* PreferencesSwiftUIView.swift */, DAF457A323DB7A820018B495 /* Rows */, DAF457A723DBA2C40018B495 /* Utils */, @@ -1460,6 +1463,7 @@ DA32D1B42C8C98C40018D974 /* IconWithAction.swift in Sources */, DA07764A234683BC0086C685 /* SwitchRow.swift in Sources */, DA2E0AA423DC96E9009B0A99 /* ImageWithAction.swift in Sources */, + DA162BEC2CD3B53E0040DAE5 /* LogsViewer.swift in Sources */, DAF4578723D798A50018B495 /* TextLabelView.swift in Sources */, DA0749DE23E0B5950057FA83 /* ColorPickerRow.swift in Sources */, DA7224D223828D3400712D20 /* PreviewConstants.swift in Sources */, diff --git a/openHABWatch/OpenHABWatch.swift b/openHABWatch/OpenHABWatch.swift index 3a207800..0aaf26ed 100644 --- a/openHABWatch/OpenHABWatch.swift +++ b/openHABWatch/OpenHABWatch.swift @@ -32,6 +32,10 @@ struct OpenHABWatch: App { .tabItem { Label("Preferences", systemSymbol: .circleFill) } + LogsViewer() + .tabItem { + Label("Debug", systemSymbol: .circleFill) + } } .tabViewStyle(.page) .environmentObject(settings) diff --git a/openHABWatch/Views/LogsViewer.swift b/openHABWatch/Views/LogsViewer.swift new file mode 100644 index 00000000..d4ac8cbc --- /dev/null +++ b/openHABWatch/Views/LogsViewer.swift @@ -0,0 +1,111 @@ +// +// LogView.swift +// openHABWatch +// +// Created by Tim Müller-Seydlitz on 31.10.24. +// Copyright © 2024 openHAB e.V. All rights reserved. +// + +import Foundation +import OSLog +import SwiftUI + +// Thanks to https://useyourloaf.com/blog/fetching-oslog-messages-in-swift/ + +extension OSLogEntryLog.Level { + fileprivate var description: String { + switch self { + case .undefined: "undefined" + case .debug: "debug" + case .info: "info" + case .notice: "notice" + case .error: "error" + case .fault: "fault" + @unknown default: "default" + } + } +} + +extension Logger { + static public func fetch(since date: Date, + predicateFormat: String) async throws -> [String] { + let store = try OSLogStore(scope: .currentProcessIdentifier) + let position = store.position(date: date) + let predicate = NSPredicate(format: predicateFormat) + let entries = try store.getEntries( + at: position, + matching: predicate + ) + + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" + + var logs: [String] = [] + for entry in entries { + try Task.checkCancellation() + if let log = entry as? OSLogEntryLog { + var attributedMessage = AttributedString(dateFormatter.string(from: entry.date)) + attributedMessage.font = .headline + + logs.append(""" + \(dateFormatter.string(from: entry.date)): \ + \(log.category):\(log.level.description): \ + \(entry.composedMessage)\n + """) + } else { + logs.append("\(entry.date): \(entry.composedMessage)\n") + } + } + + if logs.isEmpty { logs = ["Nothing found"] } + return logs + } +} + +struct LogsViewer: View { + @State private var text = "Loading..." + + static private let template = NSPredicate(format: + "(subsystem BEGINSWITH $PREFIX)") + + let myFont = Font + .system(size: 10) + .monospaced() + + private func fetchLogs() async -> String { + let calendar = Calendar.current + guard let dayAgo = calendar.date(byAdding: .day, + value: -1, to: Date.now) else { + return "Invalid calendar" + } + + do { + let predicate = Self.template.withSubstitutionVariables( + [ + "PREFIX": "org.openhab" + ]) + + let logs = try await Logger.fetch(since: dayAgo, + predicateFormat: predicate.predicateFormat) + return logs.joined() + } catch { + return error.localizedDescription + } + } + + var body: some View { + + ScrollView { + Text(text) + .font(myFont) + .padding() + } + .task { + text = await fetchLogs() + } + } +} + +#Preview { + LogsViewer() +} diff --git a/openHABWatch/Views/Rows/LogsViewer.swift b/openHABWatch/Views/Rows/LogsViewer.swift new file mode 100644 index 00000000..4a0944d8 --- /dev/null +++ b/openHABWatch/Views/Rows/LogsViewer.swift @@ -0,0 +1,43 @@ +// +// LogView.swift +// openHABWatch +// +// Created by Tim Müller-Seydlitz on 31.10.24. +// Copyright © 2024 openHAB e.V. All rights reserved. +// + +import Foundation +import OSLog +import SwiftUI + +struct LogsViewer: View { + let logs: [OSLogEntryLog] + + init() { + let logStore = try! OSLogStore(scope: .currentProcessIdentifier) + self.logs = try! logStore.getEntries().compactMap { entry in + guard let logEntry = entry as? OSLogEntryLog, + logEntry.subsystem.starts(with: "com.donnywals") == true else { + return nil + } + + return logEntry + } + } + + var body: some View { + List(logs, id: \.self) { log in + VStack(alignment: .leading) { + Text(log.composedMessage) + HStack { + Text(log.subsystem) + Text(log.date, format: .dateTime) + }.bold() + } + } + } +} + +#Preview { + LogsViewer() +} From 1575a8c9c508bf67314e419ab0407e48c197b32d Mon Sep 17 00:00:00 2001 From: Tim Bert <5411131+timbms@users.noreply.github.com> Date: Thu, 31 Oct 2024 15:59:39 +0100 Subject: [PATCH 2/2] Remove LogsViewer.swift in openHABWatch/Views/Rows Signed-off-by: Tim Bert <5411131+timbms@users.noreply.github.com> --- openHABWatch/Views/Rows/LogsViewer.swift | 43 ------------------------ 1 file changed, 43 deletions(-) delete mode 100644 openHABWatch/Views/Rows/LogsViewer.swift diff --git a/openHABWatch/Views/Rows/LogsViewer.swift b/openHABWatch/Views/Rows/LogsViewer.swift deleted file mode 100644 index 4a0944d8..00000000 --- a/openHABWatch/Views/Rows/LogsViewer.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// LogView.swift -// openHABWatch -// -// Created by Tim Müller-Seydlitz on 31.10.24. -// Copyright © 2024 openHAB e.V. All rights reserved. -// - -import Foundation -import OSLog -import SwiftUI - -struct LogsViewer: View { - let logs: [OSLogEntryLog] - - init() { - let logStore = try! OSLogStore(scope: .currentProcessIdentifier) - self.logs = try! logStore.getEntries().compactMap { entry in - guard let logEntry = entry as? OSLogEntryLog, - logEntry.subsystem.starts(with: "com.donnywals") == true else { - return nil - } - - return logEntry - } - } - - var body: some View { - List(logs, id: \.self) { log in - VStack(alignment: .leading) { - Text(log.composedMessage) - HStack { - Text(log.subsystem) - Text(log.date, format: .dateTime) - }.bold() - } - } - } -} - -#Preview { - LogsViewer() -}