Skip to content

Commit

Permalink
Include exceptions in the logs (#69)
Browse files Browse the repository at this point in the history
* Fix memory leak in readInBackgroundAndNotify method

* Make the layout bigger

* Catch exceptions in the logs

* Enable exception logging
  • Loading branch information
AvdLee authored May 27, 2020
1 parent ad8702e commit 0e7e1b7
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15510"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
Expand All @@ -22,11 +22,29 @@
<action selector="sendDiagnostics:" destination="BYZ-38-t0r" eventType="touchUpInside" id="9M3-6U-Ewz"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="WIU-ba-HLD">
<rect key="frame" x="155.5" y="772" width="103" height="30"/>
<state key="normal" title="Trigger a crash"/>
<connections>
<action selector="crashTriggerButtonTapped:" destination="BYZ-38-t0r" eventType="touchUpInside" id="Uii-kB-MjN"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Trigger a crash to see how it ends up in the report" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sdk-GT-eTr">
<rect key="frame" x="60" y="730" width="294" height="34"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleFootnote"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstItem="BEa-uA-oUu" firstAttribute="centerY" secondItem="6Tk-OE-BBY" secondAttribute="centerY" id="8Dh-z9-7qe"/>
<constraint firstItem="WIU-ba-HLD" firstAttribute="centerX" secondItem="6Tk-OE-BBY" secondAttribute="centerX" id="8jb-X9-Gt4"/>
<constraint firstItem="WIU-ba-HLD" firstAttribute="top" secondItem="sdk-GT-eTr" secondAttribute="bottom" constant="8" id="BKG-65-OcU"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="bottom" secondItem="WIU-ba-HLD" secondAttribute="bottom" constant="60" id="Bfb-vo-yeh"/>
<constraint firstItem="sdk-GT-eTr" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="60" id="JpG-Uu-CKP"/>
<constraint firstItem="BEa-uA-oUu" firstAttribute="centerX" secondItem="6Tk-OE-BBY" secondAttribute="centerX" id="gp0-3e-aM6"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="sdk-GT-eTr" secondAttribute="trailing" constant="60" id="j3D-tG-nc3"/>
</constraints>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
Expand Down
9 changes: 7 additions & 2 deletions Example/Diagnostics-Example/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import UIKit
import MessageUI
import Diagnostics

class ViewController: UIViewController {
final class ViewController: UIViewController {

@IBAction func sendDiagnostics(_ sender: UIButton) {
@IBAction private func sendDiagnostics(_ sender: UIButton) {
/// Create the report.
var reporters = DiagnosticsReporter.DefaultReporter.allReporters
reporters.insert(CustomReporter.self, at: 1)
Expand All @@ -37,6 +37,11 @@ class ViewController: UIViewController {
present(mail, animated: true)
}

@IBAction private func crashTriggerButtonTapped(_ sender: Any) {
/// Swift exceptions can't be catched yet, unfortunately.
let array = NSArray(array: ["Antoine", "Boris", "Kaira"])
print(array.object(at: 4)) // Classic index out of bounds crash
}
}

extension ViewController: MFMailComposeViewControllerDelegate {
Expand Down
66 changes: 49 additions & 17 deletions Sources/DiagnosticsLogger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,23 +82,8 @@ public final class DiagnosticsLogger {
}
}

// MARK: - Setup & Logging
// MARK: - Setup
extension DiagnosticsLogger {
/// Reads the log and converts it to a `Data` object.
func readLog() -> Data? {
guard isSetup else {
assertionFailure("Trying to read the log while not set up")
return nil
}

return queue.sync { try? Data(contentsOf: logFileLocation) }
}

/// Removes the log file. Should only be used for testing purposes.
func deleteLogs() throws {
guard FileManager.default.fileExists(atPath: logFileLocation.path) else { return }
try? FileManager.default.removeItem(atPath: logFileLocation.path)
}

private func setup() throws {
if !FileManager.default.fileExists(atPath: logFileLocation.path) {
Expand All @@ -113,11 +98,42 @@ extension DiagnosticsLogger {
logFileHandle!.seekToEndOfFile()
logSize = Int64(logFileHandle!.offsetInFile)
setupPipe()
setupCrashMonitoring()
isSetup = true
startNewSession()
}

internal func startNewSession() {
private func setupCrashMonitoring() {
NSSetUncaughtExceptionHandler { exception in
DiagnosticsLogger.logExceptionUsingCallStackSymbols(exception, description: "Uncaught Exception")
}
}

/// Creates a new log section with the current thread call stack symbols.
private static func logExceptionUsingCallStackSymbols(_ exception: NSException, description: String) {
let message = """
---
🚨 CRASH:
Description: \(description)
Exception name: \(exception.name.rawValue)
Reason: \(exception.reason ?? "nil")
\(Thread.callStackSymbols.joined(separator: "\n"))
---
"""
standard.log(message)
}
}

// MARK: - Setup & Logging
extension DiagnosticsLogger {

/// Creates a new section in the overall logs with data about the session start and system information.
func startNewSession() {
queue.async { [unowned self] in
let date = self.formatter.string(from: Date())
let appVersion = "\(Bundle.appVersion) (\(Bundle.appBuildNumber))"
Expand All @@ -134,6 +150,22 @@ extension DiagnosticsLogger {
}
}

/// Reads the log and converts it to a `Data` object.
func readLog() -> Data? {
guard isSetup else {
assertionFailure("Trying to read the log while not set up")
return nil
}

return queue.sync { try? Data(contentsOf: logFileLocation) }
}

/// Removes the log file. Should only be used for testing purposes.
func deleteLogs() throws {
guard FileManager.default.fileExists(atPath: logFileLocation.path) else { return }
try? FileManager.default.removeItem(atPath: logFileLocation.path)
}

private func log(message: String, file: String = #file, function: String = #function, line: UInt = #line) {
guard isSetup else { return assertionFailure("Trying to log a message while not set up") }

Expand Down
2 changes: 1 addition & 1 deletion Sources/DiagnosticsReporter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ extension DiagnosticsReporter {
static func style() -> HTML {
/// To add Swift Package Manager support we're adding the CSS directly here. This is because we can't add resources to packages in SPM.
return """
<style>body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:1em;line-height:1.3em;margin:50px 50px 20px;color:#17181a}h1{margin:10px 0 20px;font-weight:400}h3{display:block;font-weight:400;font-size:20px;margin:0 0 10px}p{font-size:14px;margin:0 0 10px;display:block}p:last-child,ul:last-child{margin-bottom:0}pre{overflow:scroll}.container{display:flex;justify-content:space-between;flex-direction:row-reverse;max-width:960px;margin:0 auto}.main-content{width:calc(100% - 190px)}.nav-container{width:180px}.nav-container nav{position:fixed;border-radius:4px}.nav-container nav ul{margin:0}.nav-container nav ul li{margin-bottom:5px;display:block}.nav-container nav ul li:last-child{margin-bottom:0}.nav-container nav ul li a{font-size:14px;color:#444;text-decoration:none}.nav-container nav ul li a:hover{color:#000;text-decoration:underline}.chapter{position:relative;margin-bottom:20px;padding-bottom:20px;border-bottom:1px solid #ccc}.chapter:last-child{border-bottom:0}.chapter .anchor{position:absolute;top:-20px}table th{text-align:left;padding:0 5px 0 0;font-weight:500}table td,table th{font-size:14px}footer{text-align:center;font-size:14px}footer a{color:#111}.footer-logo{width:20px;display:inline-block;vertical-align:middle}@media(max-width:768px){body{margin:20px}.container{margin:0}header h1{font-size:24px}.main-content{width:100%}.nav-container{display:none}table td,table th{display:block}table td{margin-bottom:5px}}@media (prefers-color-scheme:dark){body{background:#111;color:#f7f7f7}.chapter{border-bottom-color:rgba(255,255,255,.3)}.nav-container nav ul li a{color:rgba(255,255,255,.6)}.nav-container nav ul li a:hover{color:#fff}footer a{color:rgba(255,255,255,.85)}footer a:hover{color:#fff}.footer-logo path{fill:#f7f7f7}}</style>
<style>body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:1em;line-height:1.3em;margin:50px 50px 20px;color:#17181a}h1{margin:10px 0 20px;font-weight:400}h3{display:block;font-weight:400;font-size:20px;margin:0 0 10px}p{font-size:14px;margin:0 0 10px;display:block}p:last-child,ul:last-child{margin-bottom:0}pre{overflow:scroll}.container{display:flex;justify-content:space-between;flex-direction:row-reverse;margin:0 auto}.main-content{width:calc(100% - 190px)}.nav-container{width:180px}.nav-container nav{position:fixed;border-radius:4px}.nav-container nav ul{margin:0}.nav-container nav ul li{margin-bottom:5px;display:block}.nav-container nav ul li:last-child{margin-bottom:0}.nav-container nav ul li a{font-size:14px;color:#444;text-decoration:none}.nav-container nav ul li a:hover{color:#000;text-decoration:underline}.chapter{position:relative;margin-bottom:20px;padding-bottom:20px;border-bottom:1px solid #ccc}.chapter:last-child{border-bottom:0}.chapter .anchor{position:absolute;top:-20px}table th{text-align:left;padding:0 5px 0 0;font-weight:500}table td,table th{font-size:14px}footer{text-align:center;font-size:14px}footer a{color:#111}.footer-logo{width:20px;display:inline-block;vertical-align:middle}@media(max-width:768px){body{margin:20px}.container{margin:0}header h1{font-size:24px}.main-content{width:100%}.nav-container{display:none}table td,table th{display:block}table td{margin-bottom:5px}}@media (prefers-color-scheme:dark){body{background:#111;color:#f7f7f7}.chapter{border-bottom-color:rgba(255,255,255,.3)}.nav-container nav ul li a{color:rgba(255,255,255,.6)}.nav-container nav ul li a:hover{color:#fff}footer a{color:rgba(255,255,255,.85)}footer a:hover{color:#fff}.footer-logo path{fill:#f7f7f7}}</style>
"""
}

Expand Down
1 change: 0 additions & 1 deletion Sources/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ pre {
display: flex;
justify-content: space-between;
flex-direction: row-reverse;
max-width: 960px;
margin: 0 auto;
}

Expand Down

0 comments on commit 0e7e1b7

Please sign in to comment.