Add PostHog exception capture for crash reporting
Android: uncaught exception handler sends $exception events with stack trace to PostHog, flushes before delegating to default handler. iOS: NSSetUncaughtExceptionHandler captures crashes via PostHogSDK, avoids @MainActor deadlock by calling SDK directly. Common: captureException() available for non-fatal catches app-wide. Platform stubs for jvm/js/wasmJs.
This commit is contained in:
@@ -91,6 +91,47 @@ final class AnalyticsManager {
|
||||
PostHogSDK.shared.capture("screen_viewed", properties: props)
|
||||
}
|
||||
|
||||
// MARK: - Exception / Crash Capture
|
||||
|
||||
/// Capture a Swift Error as a PostHog `$exception` event.
|
||||
func captureException(_ error: Error, properties: [String: Any]? = nil) {
|
||||
guard isConfigured else { return }
|
||||
var props: [String: Any] = [
|
||||
"$exception_type": String(describing: type(of: error)),
|
||||
"$exception_message": error.localizedDescription,
|
||||
"$exception_stack_trace_raw": Thread.callStackSymbols.joined(separator: "\n")
|
||||
]
|
||||
if let properties { props.merge(properties) { _, new in new } }
|
||||
PostHogSDK.shared.capture("$exception", properties: props)
|
||||
}
|
||||
|
||||
/// Capture an NSException as a PostHog `$exception` event.
|
||||
func captureNSException(_ exception: NSException, isFatal: Bool = false) {
|
||||
guard isConfigured else { return }
|
||||
PostHogSDK.shared.capture("$exception", properties: [
|
||||
"$exception_type": exception.name.rawValue,
|
||||
"$exception_message": exception.reason ?? "No reason",
|
||||
"$exception_stack_trace_raw": exception.callStackSymbols.joined(separator: "\n"),
|
||||
"$exception_is_fatal": isFatal
|
||||
])
|
||||
}
|
||||
|
||||
/// Install an uncaught NSException handler that captures crashes to PostHog
|
||||
/// before the app terminates. Call this once after configure().
|
||||
func setupExceptionHandler() {
|
||||
NSSetUncaughtExceptionHandler { exception in
|
||||
// Cannot use AnalyticsManager.shared here (may deadlock on @MainActor),
|
||||
// so call PostHogSDK directly.
|
||||
PostHogSDK.shared.capture("$exception", properties: [
|
||||
"$exception_type": exception.name.rawValue,
|
||||
"$exception_message": exception.reason ?? "No reason",
|
||||
"$exception_stack_trace_raw": exception.callStackSymbols.joined(separator: "\n"),
|
||||
"$exception_is_fatal": true
|
||||
])
|
||||
PostHogSDK.shared.flush()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Flush & Reset
|
||||
|
||||
func flush() {
|
||||
|
||||
@@ -55,6 +55,9 @@ struct iOSApp: App {
|
||||
if !UITestRuntime.isEnabled {
|
||||
// Initialize PostHog Analytics (must use Swift AnalyticsManager, not the Kotlin stub)
|
||||
AnalyticsManager.shared.configure()
|
||||
|
||||
// Install uncaught exception handler to capture crashes to PostHog
|
||||
AnalyticsManager.shared.setupExceptionHandler()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user