Skip to content

Commit

Permalink
feat: Option for uncaught NSExceptions on macOS (#4471)
Browse files Browse the repository at this point in the history
Add a new option, enableReportingUncaughtExceptions, for reporting
uncaught exceptions on macOS. AS SwiftUI applications on macOS can't
easily set a Principal class in the Info.plist, especially when using
the NSApplicationDelegate, our existing solution of the
SentryCrashExceptionApplication doesn't work for them. This new option
fixes that problem.
  • Loading branch information
philipphofmann authored Oct 29, 2024
1 parent 5c6ef23 commit df9fb5b
Show file tree
Hide file tree
Showing 21 changed files with 401 additions and 38 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

## Unreleased

### Fixes
## Feature

- Add option to report uncaught NSExceptions on macOS (#4471)
- Build visionOS project with static Sentry SDK (#4462)

### Improvements
Expand Down
3 changes: 1 addition & 2 deletions Samples/macOS-Swift/macOS-Swift/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import Sentry
class AppDelegate: NSObject, NSApplicationDelegate {

func applicationDidFinishLaunching(_ aNotification: Notification) {
UserDefaults.standard.register(defaults: ["NSApplicationCrashOnExceptions": true])


// Insert code here to initialize your application
SentrySDK.start { options in
options.dsn = "https://[email protected]/5428557"
Expand Down
46 changes: 35 additions & 11 deletions Samples/macOS-Swift/macOS-Swift/Base.lproj/Main.storyboard
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.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="23091" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="23094" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23091"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23094"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
Expand Down Expand Up @@ -710,10 +710,10 @@
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView distribution="fill" orientation="vertical" alignment="centerX" spacing="12" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" fixedFrame="YES" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fsa-9g-bf3">
<rect key="frame" x="161" y="136" width="224" height="404"/>
<rect key="frame" x="161" y="72" width="224" height="468"/>
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="nAm-U5-PON">
<rect key="frame" x="44" y="377" width="136" height="32"/>
<rect key="frame" x="44" y="441" width="136" height="32"/>
<buttonCell key="cell" type="push" title="Add Breadcrumb" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="zk9-d6-mm1">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
Expand All @@ -723,7 +723,7 @@
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="dzU-Gi-2VZ">
<rect key="frame" x="42" y="345" width="141" height="32"/>
<rect key="frame" x="42" y="409" width="141" height="32"/>
<buttonCell key="cell" type="push" title="Capture Message" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="EQH-kc-eDD">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
Expand All @@ -733,7 +733,7 @@
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="LiD-mH-Y7l">
<rect key="frame" x="54" y="313" width="116" height="32"/>
<rect key="frame" x="54" y="377" width="116" height="32"/>
<buttonCell key="cell" type="push" title="Capture Error" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Tlg-FD-XnA">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
Expand All @@ -743,7 +743,7 @@
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="zMq-8z-Bqi">
<rect key="frame" x="39" y="281" width="146" height="32"/>
<rect key="frame" x="39" y="345" width="146" height="32"/>
<buttonCell key="cell" type="push" title="Capture Exception" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="PwR-RA-ikK">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
Expand All @@ -753,7 +753,7 @@
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ocz-Nk-ZQ2">
<rect key="frame" x="23" y="249" width="178" height="32"/>
<rect key="frame" x="23" y="313" width="178" height="32"/>
<buttonCell key="cell" type="push" title="Capture User Feedback" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="nui-gg-F5o">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
Expand All @@ -763,15 +763,35 @@
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="GQW-jy-1TZ">
<rect key="frame" x="34" y="217" width="156" height="32"/>
<buttonCell key="cell" type="push" title="_crashOnException:" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="7rF-ep-EYR">
<rect key="frame" x="42" y="281" width="141" height="32"/>
<buttonCell key="cell" type="push" title="raiseNSException" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="7rF-ep-EYR">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<connections>
<action selector="crashOnException:" target="XfG-lQ-9wD" id="6mx-hG-Prh"/>
<action selector="raiseNSException:" target="XfG-lQ-9wD" id="6mx-hG-Prh"/>
</connections>
</buttonCell>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="TkR-L2-cU3" userLabel="reportNSException">
<rect key="frame" x="38" y="249" width="149" height="32"/>
<buttonCell key="cell" type="push" title="reportNSException" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="89W-TG-dLd">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="reportNSException:" target="XfG-lQ-9wD" id="aAF-y5-R3W"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="HXP-Is-MDM">
<rect key="frame" x="37" y="217" width="150" height="32"/>
<buttonCell key="cell" type="push" title="NSRangeException" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="f0L-i6-NLd">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="throwNSRangeException:" target="XfG-lQ-9wD" id="VqV-4q-Tzd"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="c5W-zA-19P">
<rect key="frame" x="37" y="185" width="150" height="32"/>
<buttonCell key="cell" type="push" title="captureTransaction" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="OVU-vi-LRM">
Expand Down Expand Up @@ -857,6 +877,8 @@
<integer value="1000"/>
<integer value="1000"/>
<integer value="1000"/>
<integer value="1000"/>
<integer value="1000"/>
</visibilityPriorities>
<customSpacing>
<real value="3.4028234663852886e+38"/>
Expand All @@ -872,6 +894,8 @@
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
</customSpacing>
</stackView>
</subviews>
Expand Down
1 change: 1 addition & 0 deletions Samples/macOS-Swift/macOS-Swift/CppWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
@interface CppWrapper : NSObject
- (void)throwCPPException;
- (void)rethrowNoActiveCPPException;
- (void)throwNSRangeException;
@end
6 changes: 6 additions & 0 deletions Samples/macOS-Swift/macOS-Swift/CppWrapper.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,10 @@ - (void)rethrowNoActiveCPPException
cppTool.rethrowNoActiveCPPException();
}

- (void)throwNSRangeException
{
NSArray *array = [NSArray array];
NSLog(@"%@", array[9]);
}

@end
2 changes: 1 addition & 1 deletion Samples/macOS-Swift/macOS-Swift/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
<key>NSMainStoryboardFile</key>
<string>Main</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<string>SentryCrashExceptionApplication</string>
<key>NSSupportsAutomaticTermination</key>
<true/>
<key>NSSupportsSuddenTermination</key>
Expand Down
14 changes: 12 additions & 2 deletions Samples/macOS-Swift/macOS-Swift/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,22 @@ class ViewController: NSViewController {
SentrySDK.capture(userFeedback: userFeedback)
}

@IBAction func crashOnException(_ sender: Any) {
@IBAction func raiseNSException(_ sender: Any) {
let userInfo: [String: String] = ["user-info-key-1": "user-info-value-1", "user-info-key-2": "user-info-value-2"]
let exception = NSException(name: NSExceptionName("My Custom exception"), reason: "User clicked the button", userInfo: userInfo)
let exception = NSException(name: NSExceptionName("NSException via NSException raise"), reason: "Raised NSException", userInfo: userInfo)
exception.raise()
}

@IBAction func reportNSException(_ sender: Any) {
let userInfo: [String: String] = ["user-info-key-1": "user-info-value-1", "user-info-key-2": "user-info-value-2"]
let exception = NSException(name: NSExceptionName("NSException via NSApplication report"), reason: "It doesn't work", userInfo: userInfo)
NSApplication.shared.reportException(exception)
}

@IBAction func throwNSRangeException(_ sender: Any) {
CppWrapper().throwNSRangeException()
}

@IBAction func captureTransaction(_ sender: Any) {
let transaction = SentrySDK.startTransaction(name: "Some Transaction", operation: "some operation")
DispatchQueue.main.asyncAfter(deadline: .now() + Double.random(in: 0.4...0.6), execute: {
Expand Down
22 changes: 16 additions & 6 deletions Samples/macOS-SwiftUI/macOS-SwiftUI/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ struct ContentView: View {
Text("Capture Error")
}

Button(action: uncaughtNSException) {
Text("Uncaught NSException")
Button(action: raiseNSException) {
Text("Raise NSException")
}

Button(action: reportNSException) {
Text("Report NSException")
}

Button(action: crash) {
Expand All @@ -24,10 +28,16 @@ struct ContentView: View {
SentrySDK.capture(error: error)
}

func uncaughtNSException() {
NSException(name: NSExceptionName(rawValue: "ExplodingPotato"),
reason: "Potato is exploding!",
userInfo: nil).raise()
func raiseNSException() {
let userInfo: [String: String] = ["user-info-key-1": "user-info-value-1", "user-info-key-2": "user-info-value-2"]
let exception = NSException(name: NSExceptionName("NSException via NSException raise"), reason: "Raised NSException", userInfo: userInfo)
exception.raise()
}

func reportNSException() {
let userInfo: [String: String] = ["user-info-key-1": "user-info-value-1", "user-info-key-2": "user-info-value-2"]
let exception = NSException(name: NSExceptionName("NSException via NSApplication report"), reason: "It doesn't work", userInfo: userInfo)
NSApplication.shared.reportException(exception)
}

func crash() {
Expand Down
1 change: 1 addition & 0 deletions Samples/macOS-SwiftUI/macOS-SwiftUI/macOS_SwiftUIApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class MyAppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
options.debug = true
options.tracesSampleRate = 1.0
options.profilesSampleRate = 1.0
options.enableUncaughtNSExceptionReporting = true
}
}

Expand Down
Loading

0 comments on commit df9fb5b

Please sign in to comment.