mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-19 19:53:25 +01:00
Supports exporting OSLogs from ErrorLogViewController
This commit is contained in:
@@ -33,6 +33,9 @@ class ErrorLogViewController: UITableViewController
|
|||||||
return dateFormatter
|
return dateFormatter
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@IBOutlet private var exportLogButton: UIBarButtonItem!
|
||||||
|
@IBOutlet private var clearLogButton: UIBarButtonItem!
|
||||||
|
|
||||||
override var preferredStatusBarStyle: UIStatusBarStyle {
|
override var preferredStatusBarStyle: UIStatusBarStyle {
|
||||||
return .lightContent
|
return .lightContent
|
||||||
}
|
}
|
||||||
@@ -43,6 +46,14 @@ class ErrorLogViewController: UITableViewController
|
|||||||
|
|
||||||
self.tableView.dataSource = self.dataSource
|
self.tableView.dataSource = self.dataSource
|
||||||
self.tableView.prefetchDataSource = self.dataSource
|
self.tableView.prefetchDataSource = self.dataSource
|
||||||
|
|
||||||
|
self.exportLogButton.activityIndicatorView.color = .white
|
||||||
|
|
||||||
|
if #unavailable(iOS 15)
|
||||||
|
{
|
||||||
|
// Assign just clearLogButton to hide export button.
|
||||||
|
self.navigationItem.rightBarButtonItems = [self.clearLogButton]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
|
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
|
||||||
@@ -260,6 +271,77 @@ private extension ErrorLogViewController
|
|||||||
{
|
{
|
||||||
self.performSegue(withIdentifier: "showErrorDetails", sender: loggedError)
|
self.performSegue(withIdentifier: "showErrorDetails", sender: loggedError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(iOS 15, *)
|
||||||
|
@IBAction func exportDetailedLog(_ sender: UIBarButtonItem)
|
||||||
|
{
|
||||||
|
self.exportLogButton.isIndicatingActivity = true
|
||||||
|
|
||||||
|
Task<Void, Never>.detached(priority: .userInitiated) {
|
||||||
|
do
|
||||||
|
{
|
||||||
|
let store = try OSLogStore(scope: .currentProcessIdentifier)
|
||||||
|
|
||||||
|
// All logs since the app launched.
|
||||||
|
let position = store.position(timeIntervalSinceLatestBoot: 0)
|
||||||
|
|
||||||
|
let entries = try store.getEntries(at: position)
|
||||||
|
.compactMap { $0 as? OSLogEntryLog }
|
||||||
|
.filter { $0.subsystem.contains(Logger.altstoreSubsystem) }
|
||||||
|
.map { "[\($0.date.formatted())] [\($0.category)] [\($0.level.localizedName)] \($0.composedMessage)" }
|
||||||
|
|
||||||
|
let outputText = entries.joined(separator: "\n")
|
||||||
|
|
||||||
|
let outputDirectory = FileManager.default.uniqueTemporaryURL()
|
||||||
|
try FileManager.default.createDirectory(at: outputDirectory, withIntermediateDirectories: true)
|
||||||
|
|
||||||
|
defer {
|
||||||
|
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 await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, Error>) in
|
||||||
|
Task<Void, Never> { @MainActor in
|
||||||
|
let activityViewController = UIActivityViewController(activityItems: [outputURL], applicationActivities: nil)
|
||||||
|
activityViewController.completionWithItemsHandler = { (activityType, completed, _, error) in
|
||||||
|
if let error
|
||||||
|
{
|
||||||
|
continuation.resume(throwing: error)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
continuation.resume()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.present(activityViewController, animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Logger.main.error("Failed to export OSLog entries. \(error.localizedDescription, privacy: .public)")
|
||||||
|
|
||||||
|
await MainActor.run {
|
||||||
|
let alertController = UIAlertController(title: NSLocalizedString("Unable to Export Detailed Log", comment: ""), message: error.localizedDescription, preferredStyle: .alert)
|
||||||
|
alertController.addAction(.ok)
|
||||||
|
self.present(alertController, animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await MainActor.run {
|
||||||
|
self.exportLogButton.isIndicatingActivity = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ErrorLogViewController
|
extension ErrorLogViewController
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="5Rz-4h-jJ8">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="5Rz-4h-jJ8">
|
||||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
|
||||||
<capability name="Named colors" minToolsVersion="9.0"/>
|
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||||
@@ -1095,13 +1095,22 @@ Settings by i cons from the Noun Project</string>
|
|||||||
</connections>
|
</connections>
|
||||||
</tableView>
|
</tableView>
|
||||||
<navigationItem key="navigationItem" title="Error Log" largeTitleDisplayMode="never" id="a1p-3W-bSi">
|
<navigationItem key="navigationItem" title="Error Log" largeTitleDisplayMode="never" id="a1p-3W-bSi">
|
||||||
<barButtonItem key="rightBarButtonItem" systemItem="trash" id="BnQ-Eh-1gC">
|
<rightBarButtonItems>
|
||||||
<connections>
|
<barButtonItem systemItem="trash" id="BnQ-Eh-1gC">
|
||||||
<action selector="clearLoggedErrors:" destination="g8a-Rf-zWa" id="faq-89-H5j"/>
|
<connections>
|
||||||
</connections>
|
<action selector="clearLoggedErrors:" destination="g8a-Rf-zWa" id="faq-89-H5j"/>
|
||||||
</barButtonItem>
|
</connections>
|
||||||
|
</barButtonItem>
|
||||||
|
<barButtonItem systemItem="action" id="BNj-HE-KHr">
|
||||||
|
<connections>
|
||||||
|
<action selector="exportDetailedLog:" destination="g8a-Rf-zWa" id="Kbw-Q5-9WO"/>
|
||||||
|
</connections>
|
||||||
|
</barButtonItem>
|
||||||
|
</rightBarButtonItems>
|
||||||
</navigationItem>
|
</navigationItem>
|
||||||
<connections>
|
<connections>
|
||||||
|
<outlet property="clearLogButton" destination="BnQ-Eh-1gC" id="MHl-Kh-ick"/>
|
||||||
|
<outlet property="exportLogButton" destination="BNj-HE-KHr" id="w9g-yA-0Yx"/>
|
||||||
<segue destination="7gm-d1-zWK" kind="presentation" identifier="showErrorDetails" id="9vz-y6-evp"/>
|
<segue destination="7gm-d1-zWK" kind="presentation" identifier="showErrorDetails" id="9vz-y6-evp"/>
|
||||||
</connections>
|
</connections>
|
||||||
</tableViewController>
|
</tableViewController>
|
||||||
|
|||||||
Reference in New Issue
Block a user