From 5ebe8410c7d8f20abde217a03b521b5399ffded4 Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Mon, 17 Dec 2018 22:44:06 -0800 Subject: [PATCH] Start work on crash reporter. --- NetNewsWire.xcodeproj/project.pbxproj | 13 ++++ NetNewsWire/CrashReporter/CrashReporter.swift | 72 +++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 NetNewsWire/CrashReporter/CrashReporter.swift diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 0fa7801c6..e214a628c 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -214,6 +214,7 @@ 8472058120142E8900AD578B /* FeedInspectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8472058020142E8900AD578B /* FeedInspectorViewController.swift */; }; 84754C8A213E471B009CFDFB /* GeneralPrefencesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84754C89213E471B009CFDFB /* GeneralPrefencesViewController.swift */; }; 847FA121202BA34100BB56C8 /* SidebarContextualMenuDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847FA120202BA34100BB56C8 /* SidebarContextualMenuDelegate.swift */; }; + 848B937221C8C5540038DC0D /* CrashReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848B937121C8C5540038DC0D /* CrashReporter.swift */; }; 848D578E21543519005FFAD5 /* PasteboardFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848D578D21543519005FFAD5 /* PasteboardFeed.swift */; }; 848F6AE51FC29CFB002D422E /* FaviconDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848F6AE41FC29CFA002D422E /* FaviconDownloader.swift */; }; 849A97431ED9EAA9007D329B /* AddFolderWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97421ED9EAA9007D329B /* AddFolderWindowController.swift */; }; @@ -891,6 +892,7 @@ 847FA120202BA34100BB56C8 /* SidebarContextualMenuDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarContextualMenuDelegate.swift; sourceTree = ""; }; 848B930921C8B0BF0038DC0D /* Subscribe-to-Feed-MAS-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "Subscribe-to-Feed-MAS-Info.plist"; sourceTree = ""; }; 848B934321C8B8A00038DC0D /* CrashReporter.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CrashReporter.xcodeproj; path = submodules/CrashReporter/CrashReporter.xcodeproj; sourceTree = ""; }; + 848B937121C8C5540038DC0D /* CrashReporter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CrashReporter.swift; sourceTree = ""; }; 848D578D21543519005FFAD5 /* PasteboardFeed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasteboardFeed.swift; sourceTree = ""; }; 848F6AE41FC29CFA002D422E /* FaviconDownloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FaviconDownloader.swift; sourceTree = ""; }; 849A97421ED9EAA9007D329B /* AddFolderWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddFolderWindowController.swift; sourceTree = ""; }; @@ -1316,6 +1318,15 @@ name = Products; sourceTree = ""; }; + 848B937021C8C5540038DC0D /* CrashReporter */ = { + isa = PBXGroup; + children = ( + 848B937121C8C5540038DC0D /* CrashReporter.swift */, + ); + name = CrashReporter; + path = NetNewsWire/CrashReporter; + sourceTree = ""; + }; 848F6AE31FC29CFA002D422E /* Favicons */ = { isa = PBXGroup; children = ( @@ -1522,6 +1533,7 @@ 849A97961ED9EFAA007D329B /* Extensions */, D5907D6F2004AB67005947E5 /* Scriptability */, D5558FD6200227E60066386B /* AppleEvents */, + 848B937021C8C5540038DC0D /* CrashReporter */, 849A97991ED9EFB6007D329B /* Resources */, 84F9EACF213660A100CF2DE4 /* NetNewsWireTests */, 840D617D2029031C009BC708 /* NetNewsWire-iOS */, @@ -2642,6 +2654,7 @@ files = ( 84F204E01FAACBB30076E152 /* ArticleArray.swift in Sources */, 849C64641ED37A5D003D8FC0 /* AppDelegate.swift in Sources */, + 848B937221C8C5540038DC0D /* CrashReporter.swift in Sources */, 84BBB12E20142A4700F054F5 /* InspectorWindowController.swift in Sources */, 84E46C7D1F75EF7B005ECFB3 /* AppDefaults.swift in Sources */, D5907D972004B7EB005947E5 /* Account+Scriptability.swift in Sources */, diff --git a/NetNewsWire/CrashReporter/CrashReporter.swift b/NetNewsWire/CrashReporter/CrashReporter.swift new file mode 100644 index 000000000..c969ea660 --- /dev/null +++ b/NetNewsWire/CrashReporter/CrashReporter.swift @@ -0,0 +1,72 @@ +// +// CrashReporter.swift +// NetNewsWire +// +// Created by Brent Simmons on 12/17/18. +// Copyright © 2018 Ranchero Software. All rights reserved. +// + +import Foundation + +// Based originally on Uli Kusterer's UKCrashReporter: http://www.zathras.de/angelweb/blog-ukcrashreporter-oh-one.htm +// Then based on the crash reporter included in NetNewsWire 3 and NetNewsWire Lite 4. +// Displays a window that shows the crash log — gives the user the chance to add data. +// (Or just decide not to send it.) +// This code is not included in the MAS build. +// At some point this code should probably move into RSCore, so Rainier and any other +// future apps can use it. + + +struct CrashReporter { + + /// Look in ~/Library/Logs/DiagnosticReports/ for a new crash log for this app. + /// Show a crash log catcher window if found. + static func check(appName: String) throws { + let folder = ("~/Library/Logs/DiagnosticReports/" as NSString).expandingTildeInPath + let crashSuffix = ".crash" + let lowerAppName = appName.lowercased() + let filenames = try FileManager.default.contentsOfDirectory(atPath: folder) + + var mostRecentFilePath: String? = nil + var mostRecentFileDate = NSDate.distantPast + for filename in filenames { + if !filename.lowercased().hasPrefix(lowerAppName) { + continue + } + if !filename.hasSuffix(crashSuffix) { + continue + } + + let path = (folder as NSString).appendingPathComponent(filename) + let fileAttributes = try FileManager.default.attributesOfItem(atPath: path) + if let fileModificationDate = fileAttributes[.modificationDate] as? Date { + if fileModificationDate > mostRecentFileDate { + mostRecentFileDate = fileModificationDate + mostRecentFilePath = path + } + } + } + + guard let crashLogPath = mostRecentFilePath else { + return + } + guard let crashLog = try? NSString(contentsOfFile: crashLogPath, usedEncoding: nil) else { + return + } + + // Check to see if we’ve already reported this crash log. This should be common. + let hashOfLog = crashLog.rs_md5Hash() + let hashOfLastReportedCrashLogKey = "hashOfLastReportedCrashLog" + if let lastLogHash = UserDefaults.standard.string(forKey: hashOfLastReportedCrashLogKey) { + if hashOfLog == lastLogHash { + return // Don’t report this crash log again. + } + } + UserDefaults.standard.set(hashOfLog, forKey: hashOfLastReportedCrashLogKey) + + + + } +} + +