203 lines
7.7 KiB
Swift
203 lines
7.7 KiB
Swift
|
//
|
||
|
// LogView.swift
|
||
|
// Monal
|
||
|
//
|
||
|
// Created by Zain Ashraf on 3/23/24.
|
||
|
// Copyright © 2024 monal-im.org. All rights reserved.
|
||
|
//
|
||
|
|
||
|
class DebugDefaultDB: ObservableObject {
|
||
|
@defaultsDB("udpLoggerEnabled")
|
||
|
var udpLoggerEnabled: Bool
|
||
|
|
||
|
@defaultsDB("udpLoggerPort")
|
||
|
var udpLoggerPort: String
|
||
|
|
||
|
@defaultsDB("udpLoggerHostname")
|
||
|
var udpLoggerHostname: String
|
||
|
|
||
|
@defaultsDB("udpLoggerKey")
|
||
|
var udpLoggerKey: String
|
||
|
|
||
|
@defaultsDB("hasCompletedOnboarding")
|
||
|
var hasCompletedOnboarding: Bool
|
||
|
}
|
||
|
|
||
|
struct LogFilesView: View {
|
||
|
@State private var sortedLogFileInfos: [DDLogFileInfo] = []
|
||
|
@State private var showShareSheet:Bool = false
|
||
|
@State private var fileURL: URL?
|
||
|
@State private var showingDBExportFailedAlert = false
|
||
|
|
||
|
func refreshSortedLogfiles() {
|
||
|
if let sortedLogFileInfos = HelperTools.fileLogger?.logFileManager.sortedLogFileInfos {
|
||
|
self.sortedLogFileInfos = sortedLogFileInfos
|
||
|
}
|
||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 4.0) {
|
||
|
refreshSortedLogfiles()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var body: some View {
|
||
|
VStack(alignment: .leading) {
|
||
|
Text("This can be used to export logfiles.\n[Learn how to read them](https://github.com/monal-im/Monal/wiki/Introduction-to-Monal-Logging#view-the-log).")
|
||
|
List {
|
||
|
Section(header: Text("Logfiles")) {
|
||
|
ForEach(sortedLogFileInfos, id: \.self) { logFileInfo in
|
||
|
Button(logFileInfo.fileName) {
|
||
|
fileURL = URL(fileURLWithPath: logFileInfo.filePath)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
Section(header: Text("Database Files")) {
|
||
|
Button("Main Database") {
|
||
|
if let dbFile = DataLayer.sharedInstance().exportDB() {
|
||
|
self.fileURL = URL(fileURLWithPath: dbFile)
|
||
|
} else {
|
||
|
showingDBExportFailedAlert = true
|
||
|
}
|
||
|
}
|
||
|
Button("IPC Database") {
|
||
|
if let dbFile = HelperTools.exportIPCDatabase() {
|
||
|
self.fileURL = URL(fileURLWithPath: dbFile)
|
||
|
} else {
|
||
|
showingDBExportFailedAlert = true
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
.listStyle(.grouped)
|
||
|
}
|
||
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||
|
.background(.interpolatedWindowBackground)
|
||
|
.alert(isPresented: $showingDBExportFailedAlert) {
|
||
|
Alert(title: Text("Database Export Failed"), message: Text("Failed to export the database, please check the logfile for errors and try again."), dismissButton: .default(Text("Close")))
|
||
|
}
|
||
|
.sheet(isPresented:$fileURL.optionalMappedToBool()) {
|
||
|
if let fileURL = fileURL {
|
||
|
ActivityViewController(activityItems: [fileURL])
|
||
|
}
|
||
|
}
|
||
|
.onAppear {
|
||
|
refreshSortedLogfiles()
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
struct UDPConfigView: View {
|
||
|
@ObservedObject var defaultDB = DebugDefaultDB()
|
||
|
|
||
|
var body: some View {
|
||
|
VStack(alignment: .leading) {
|
||
|
Text("The UDP logger allows you to livestream the log to the configured IP. Please use a secure key when streaming over the internet!\n[Learn how to receive the log stream](https://github.com/monal-im/Monal/wiki/Introduction-to-Monal-Logging#stream-the-log).")
|
||
|
Form {
|
||
|
Section(header: Text("UDP Logger Configuration")) {
|
||
|
Toggle(isOn: $defaultDB.udpLoggerEnabled) {
|
||
|
Text("Enable")
|
||
|
}
|
||
|
LabeledContent("Logserver IP:") {
|
||
|
TextField("Logserver IP", text: $defaultDB.udpLoggerHostname, prompt: Text("Required"))
|
||
|
}
|
||
|
LabeledContent("Logserver Port:") {
|
||
|
TextField("Logserver Port", text: $defaultDB.udpLoggerPort, prompt: Text("Required"))
|
||
|
}.keyboardType(.numberPad)
|
||
|
LabeledContent("AES Encryption Key:") {
|
||
|
TextField("AES Encryption Key", text: $defaultDB.udpLoggerKey, prompt: Text("Required"))
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
.padding(0)
|
||
|
.textFieldStyle(.roundedBorder)
|
||
|
}
|
||
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||
|
.background(.interpolatedWindowBackground)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
struct CrashTestingView: View {
|
||
|
@ObservedObject var defaultDB = DebugDefaultDB()
|
||
|
|
||
|
var body: some View {
|
||
|
VStack(alignment:.leading, spacing: 25) {
|
||
|
Section(header: Text("Some debug settings.")) {
|
||
|
Toggle(isOn: $defaultDB.hasCompletedOnboarding) {
|
||
|
Text("Don't show onboarding")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Text("The following buttons allow you to forcefully crash the app using several different methods to test the crash handling.")
|
||
|
|
||
|
Group {
|
||
|
Button("Try to call unknown handler method") {
|
||
|
DispatchQueue.global(qos: .default).async(execute: {
|
||
|
HelperTools.flushLogs(withTimeout: 0.100)
|
||
|
let handler = MLHandler(delegate: self, handlerName: "IDontKnowThis", andBoundArguments: [:])
|
||
|
handler.call(withArguments: nil)
|
||
|
})
|
||
|
}
|
||
|
Button("Bad Access Crash") {
|
||
|
HelperTools.flushLogs(withTimeout: 0.100)
|
||
|
let delegate: AnyClass? = NSClassFromString("MonalAppDelegate")
|
||
|
print(delegate.unsafelyUnwrapped.audiovisualTypes())
|
||
|
|
||
|
}
|
||
|
Button("Assertion Crash") {
|
||
|
HelperTools.flushLogs(withTimeout: 0.100)
|
||
|
assert(false)
|
||
|
}
|
||
|
Button("Fatal Error Crash") {
|
||
|
HelperTools.flushLogs(withTimeout: 0.100)
|
||
|
fatalError("fatalError_example")
|
||
|
}
|
||
|
Button("Nil Crash") {
|
||
|
HelperTools.flushLogs(withTimeout: 0.100)
|
||
|
let crasher:Int? = nil
|
||
|
print(crasher!)
|
||
|
}
|
||
|
}.foregroundColor(.red)
|
||
|
Spacer()
|
||
|
}
|
||
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||
|
.background(.interpolatedWindowBackground)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
struct DebugView: View {
|
||
|
@StateObject private var overlay = LoadingOverlayState()
|
||
|
|
||
|
var body: some View {
|
||
|
TabView {
|
||
|
LogFilesView()
|
||
|
.tabItem {
|
||
|
Image(systemName: "list.bullet")
|
||
|
Text("Logs")
|
||
|
}
|
||
|
UDPConfigView()
|
||
|
.tabItem {
|
||
|
Image(systemName: "gear")
|
||
|
Text("UDP Logger")
|
||
|
}
|
||
|
CrashTestingView()
|
||
|
.tabItem {
|
||
|
Image(systemName: "bolt.fill")
|
||
|
Text("Crash Testing")
|
||
|
}
|
||
|
}
|
||
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||
|
.padding()
|
||
|
.addLoadingOverlay(overlay)
|
||
|
.navigationBarItems(trailing:Button("Reconnect All") {
|
||
|
showLoadingOverlay(overlay, headline: "Reconnecting", description: "Will log out and reconnect all (connected) accounts.") {
|
||
|
MLXMPPManager.sharedInstance().reconnectAll()
|
||
|
return after(seconds:3.0)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#Preview {
|
||
|
NavigationStack {
|
||
|
DebugView()
|
||
|
}
|
||
|
}
|