Displays detailed error log in-app with Quick Look

This commit is contained in:
Riley Testut
2023-12-08 18:15:48 -06:00
committed by Magesh K
parent 1fbec33719
commit 4514fe1c2c
2 changed files with 46 additions and 30 deletions

View File

@@ -8,6 +8,7 @@
import UIKit import UIKit
import SafariServices import SafariServices
import QuickLook
import AltStoreCore import AltStoreCore
import Roxas import Roxas
@@ -37,6 +38,8 @@ final class ErrorLogViewController: UITableViewController
@IBOutlet private var exportLogButton: UIBarButtonItem! @IBOutlet private var exportLogButton: UIBarButtonItem!
@IBOutlet private var clearLogButton: UIBarButtonItem! @IBOutlet private var clearLogButton: UIBarButtonItem!
private var _exportedLogURL: URL?
override var preferredStatusBarStyle: UIStatusBarStyle { override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent return .lightContent
} }
@@ -286,10 +289,10 @@ private extension ErrorLogViewController
// All logs since the app launched. // All logs since the app launched.
let position = store.position(timeIntervalSinceLatestBoot: 0) let position = store.position(timeIntervalSinceLatestBoot: 0)
let predicate = NSPredicate(format: "subsystem == %@", Logger.altstoreSubsystem)
let entries = try store.getEntries(at: position) let entries = try store.getEntries(at: position, matching: predicate)
.compactMap { $0 as? OSLogEntryLog } .compactMap { $0 as? OSLogEntryLog }
.filter { $0.subsystem.contains(Logger.altstoreSubsystem) }
.map { "[\($0.date.formatted())] [\($0.category)] [\($0.level.localizedName)] \($0.composedMessage)" } .map { "[\($0.date.formatted())] [\($0.category)] [\($0.level.localizedName)] \($0.composedMessage)" }
let outputText = entries.joined(separator: "\n") let outputText = entries.joined(separator: "\n")
@@ -297,35 +300,17 @@ private extension ErrorLogViewController
let outputDirectory = FileManager.default.uniqueTemporaryURL() let outputDirectory = FileManager.default.uniqueTemporaryURL()
try FileManager.default.createDirectory(at: outputDirectory, withIntermediateDirectories: true) try FileManager.default.createDirectory(at: outputDirectory, withIntermediateDirectories: true)
defer { let outputURL = outputDirectory.appendingPathComponent("altstore.log")
do
{
try FileManager.default.removeItem(at: outputDirectory)
}
catch
{
Logger.main.error("Failed to remove temporary log directory \(outputDirectory.lastPathComponent, privacy: .public). \(error.localizedDescription, privacy: .public)")
}
}
let outputURL = outputDirectory.appendingPathComponent("altlog.txt")
try outputText.write(to: outputURL, atomically: true, encoding: .utf8) try outputText.write(to: outputURL, atomically: true, encoding: .utf8)
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, Error>) in await MainActor.run {
Task<Void, Never> { @MainActor in self._exportedLogURL = outputURL
let activityViewController = UIActivityViewController(activityItems: [outputURL], applicationActivities: nil)
activityViewController.completionWithItemsHandler = { (activityType, completed, _, error) in let previewController = QLPreviewController()
if let error previewController.delegate = self
{ previewController.dataSource = self
continuation.resume(throwing: error) previewController.view.tintColor = .altPrimary
} self.present(previewController, animated: true)
else
{
continuation.resume()
}
}
self.present(activityViewController, animated: true)
}
} }
} }
catch catch
@@ -448,3 +433,34 @@ extension ErrorLogViewController
} }
} }
} }
extension ErrorLogViewController: QLPreviewControllerDataSource, QLPreviewControllerDelegate
{
func numberOfPreviewItems(in controller: QLPreviewController) -> Int
{
return 1
}
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem
{
return (_exportedLogURL as? NSURL) ?? NSURL()
}
func previewControllerDidDismiss(_ controller: QLPreviewController)
{
guard let exportedLogURL = _exportedLogURL else { return }
let parentDirectory = exportedLogURL.deletingLastPathComponent()
do
{
try FileManager.default.removeItem(at: parentDirectory)
}
catch
{
Logger.main.error("Failed to remove temporary log directory \(parentDirectory.lastPathComponent, privacy: .public). \(error.localizedDescription, privacy: .public)")
}
_exportedLogURL = nil
}
}

View File

@@ -10,7 +10,7 @@
public extension Logger public extension Logger
{ {
static let altstoreSubsystem = Bundle.main.bundleIdentifier! static let altstoreSubsystem = "com.rileytestut.AltStore" // Hardcoded because Bundle.main.bundleIdentifier is different for every user
static let main = Logger(subsystem: altstoreSubsystem, category: "Main") static let main = Logger(subsystem: altstoreSubsystem, category: "Main")
static let sideload = Logger(subsystem: altstoreSubsystem, category: "Sideload") static let sideload = Logger(subsystem: altstoreSubsystem, category: "Sideload")