forked from shadowfacts/Tusker
Include log data in issue/crash reports
This commit is contained in:
parent
afa1a733f4
commit
d661870401
|
@ -2,6 +2,22 @@
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>OSLogPreferences</key>
|
||||||
|
<dict>
|
||||||
|
<key>$(PRODUCT_BUNDLE_IDENTIFIER)</key>
|
||||||
|
<dict>
|
||||||
|
<key>DEFAULT-OPTIONS</key>
|
||||||
|
<dict>
|
||||||
|
<key>Level</key>
|
||||||
|
<dict>
|
||||||
|
<key>Persist</key>
|
||||||
|
<string>Debug</string>
|
||||||
|
<key>Enable</key>
|
||||||
|
<string>Debug</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
|
@ -16,19 +32,6 @@
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>$(MARKETING_VERSION)</string>
|
<string>$(MARKETING_VERSION)</string>
|
||||||
<key>CFBundleURLTypes</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleTypeRole</key>
|
|
||||||
<string>Editor</string>
|
|
||||||
<key>CFBundleURLName</key>
|
|
||||||
<string>net.shadowfacts.Tusker</string>
|
|
||||||
<key>CFBundleURLSchemes</key>
|
|
||||||
<array>
|
|
||||||
<string>tusker</string>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
<key>LSApplicationCategoryType</key>
|
<key>LSApplicationCategoryType</key>
|
||||||
|
@ -56,7 +59,7 @@
|
||||||
<key>NSMicrophoneUsageDescription</key>
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
<string>Post videos from the camera.</string>
|
<string>Post videos from the camera.</string>
|
||||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||||
<string>Save photos directly from other people's posts.</string>
|
<string>Save photos directly from other people's posts.</string>
|
||||||
<key>NSPhotoLibraryUsageDescription</key>
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
<string>Post photos from the photo library.</string>
|
<string>Post photos from the photo library.</string>
|
||||||
<key>NSUserActivityTypes</key>
|
<key>NSUserActivityTypes</key>
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
import UIKit
|
import UIKit
|
||||||
import CrashReporter
|
import CrashReporter
|
||||||
import MessageUI
|
import MessageUI
|
||||||
|
import OSLog
|
||||||
|
|
||||||
class IssueReporterViewController: UIViewController {
|
class IssueReporterViewController: UIViewController {
|
||||||
|
|
||||||
|
@ -34,6 +35,8 @@ class IssueReporterViewController: UIViewController {
|
||||||
"Tusker Error Report"
|
"Tusker Error Report"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let logDataTask: Task<Data?, Never>
|
||||||
|
|
||||||
@IBOutlet weak var crashReportTextView: UITextView!
|
@IBOutlet weak var crashReportTextView: UITextView!
|
||||||
@IBOutlet weak var sendReportButton: UIButton!
|
@IBOutlet weak var sendReportButton: UIButton!
|
||||||
|
|
||||||
|
@ -41,6 +44,15 @@ class IssueReporterViewController: UIViewController {
|
||||||
self.reportText = reportText
|
self.reportText = reportText
|
||||||
self.reportFilename = reportFilename
|
self.reportFilename = reportFilename
|
||||||
self.dismiss = dismiss
|
self.dismiss = dismiss
|
||||||
|
|
||||||
|
self.logDataTask = Task(priority: .userInitiated) {
|
||||||
|
return await withCheckedContinuation({ continuation in
|
||||||
|
DispatchQueue.global().async {
|
||||||
|
continuation.resume(returning: getLogData())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
super.init(nibName: "IssueReporterViewController", bundle: .main)
|
super.init(nibName: "IssueReporterViewController", bundle: .main)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,15 +119,22 @@ class IssueReporterViewController: UIViewController {
|
||||||
@IBAction func sendReportTouchUpInside(_ sender: Any) {
|
@IBAction func sendReportTouchUpInside(_ sender: Any) {
|
||||||
updateSendReportButtonColor(lightened: false, animate: true)
|
updateSendReportButtonColor(lightened: false, animate: true)
|
||||||
|
|
||||||
let composeVC = MFMailComposeViewController()
|
Task {
|
||||||
composeVC.mailComposeDelegate = self
|
let composeVC = MFMailComposeViewController()
|
||||||
composeVC.setToRecipients(["me@shadowfacts.net"])
|
composeVC.mailComposeDelegate = self
|
||||||
composeVC.setSubject(subject)
|
composeVC.setToRecipients(["me@shadowfacts.net"])
|
||||||
|
composeVC.setSubject(subject)
|
||||||
|
|
||||||
let data = reportText.data(using: .utf8)!
|
let data = reportText.data(using: .utf8)!
|
||||||
composeVC.addAttachmentData(data, mimeType: "text/plain", fileName: reportFilename)
|
composeVC.addAttachmentData(data, mimeType: "text/plain", fileName: reportFilename)
|
||||||
|
|
||||||
self.present(composeVC, animated: true)
|
if let logData = await logDataTask.value {
|
||||||
|
let timestamp = ISO8601DateFormatter().string(from: Date())
|
||||||
|
composeVC.addAttachmentData(logData, mimeType: "text/plain", fileName: "Tusker-\(timestamp).log")
|
||||||
|
}
|
||||||
|
|
||||||
|
self.present(composeVC, animated: true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func sendReportButtonLongPressed() {
|
@objc func sendReportButtonLongPressed() {
|
||||||
|
@ -139,3 +158,29 @@ extension IssueReporterViewController: MFMailComposeViewControllerDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fileprivate func getLogData() -> Data? {
|
||||||
|
do {
|
||||||
|
let store = try OSLogStore(scope: .currentProcessIdentifier)
|
||||||
|
// past hour
|
||||||
|
let position = store.position(date: Date().addingTimeInterval(-60 * 60))
|
||||||
|
let entries = try store.getEntries(at: position, matching: NSPredicate(format: "subsystem = %@", Bundle.main.bundleIdentifier!))
|
||||||
|
var data = Data()
|
||||||
|
for entry in entries {
|
||||||
|
guard let entry = entry as? OSLogEntryLog else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
data.append(contentsOf: entry.date.formatted(.iso8601).utf8)
|
||||||
|
data.append(32) // ' '
|
||||||
|
data.append(91) // '['
|
||||||
|
data.append(contentsOf: entry.category.utf8)
|
||||||
|
data.append(93) // ']'
|
||||||
|
data.append(32) // ' '
|
||||||
|
data.append(contentsOf: entry.composedMessage.utf8)
|
||||||
|
data.append(10) // '\n'
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
} catch {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue