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:
@@ -80,6 +80,9 @@ class MainActivity : FragmentActivity(), SingletonImageLoader.Factory {
|
||||
// Initialize PostHog Analytics
|
||||
PostHogAnalytics.initialize(application, debug = true) // Set debug=false for release
|
||||
|
||||
// Install uncaught exception handler to capture crashes to PostHog
|
||||
PostHogAnalytics.setupExceptionHandler()
|
||||
|
||||
// Handle deep link, notification navigation, and file import from intent
|
||||
handleDeepLink(intent)
|
||||
handleNotificationNavigation(intent)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.tt.honeyDue.analytics
|
||||
|
||||
import android.app.Application
|
||||
import android.util.Log
|
||||
import com.posthog.PostHog
|
||||
import com.posthog.android.PostHogAndroid
|
||||
import com.posthog.android.PostHogAndroidConfig
|
||||
@@ -13,6 +14,8 @@ actual object PostHogAnalytics {
|
||||
private const val API_KEY = "YOUR_POSTHOG_API_KEY"
|
||||
private const val HOST = "https://us.i.posthog.com"
|
||||
|
||||
private const val TAG = "PostHogAnalytics"
|
||||
|
||||
private var isInitialized = false
|
||||
private var application: Application? = null
|
||||
|
||||
@@ -57,6 +60,28 @@ actual object PostHogAnalytics {
|
||||
PostHog.capture(event, properties = properties)
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture an exception/crash as a PostHog `$exception` event.
|
||||
* Uses PostHog's standard exception property names so exceptions
|
||||
* appear correctly in the PostHog Errors dashboard.
|
||||
*/
|
||||
actual fun captureException(throwable: Throwable, properties: Map<String, Any>?) {
|
||||
if (!isInitialized) return
|
||||
try {
|
||||
val exceptionProps = mutableMapOf<String, Any>(
|
||||
"\$exception_type" to (throwable::class.simpleName ?: "Unknown"),
|
||||
"\$exception_message" to (throwable.message ?: "No message"),
|
||||
"\$exception_stack_trace_raw" to throwable.stackTraceToString()
|
||||
)
|
||||
if (properties != null) {
|
||||
exceptionProps.putAll(properties)
|
||||
}
|
||||
PostHog.capture("\$exception", properties = exceptionProps)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to capture exception to PostHog", e)
|
||||
}
|
||||
}
|
||||
|
||||
actual fun screen(screenName: String, properties: Map<String, Any>?) {
|
||||
if (!isInitialized) return
|
||||
PostHog.screen(screenName, properties = properties)
|
||||
@@ -71,4 +96,36 @@ actual object PostHogAnalytics {
|
||||
if (!isInitialized) return
|
||||
PostHog.flush()
|
||||
}
|
||||
|
||||
/**
|
||||
* Install an uncaught exception handler that captures crashes to PostHog
|
||||
* before delegating to the default handler (which shows the crash dialog).
|
||||
* Call this after initialize() in MainActivity.onCreate().
|
||||
*/
|
||||
actual fun setupExceptionHandler() {
|
||||
if (!isInitialized) return
|
||||
|
||||
val defaultHandler = Thread.getDefaultUncaughtExceptionHandler()
|
||||
Thread.setDefaultUncaughtExceptionHandler { thread, throwable ->
|
||||
try {
|
||||
PostHog.capture(
|
||||
event = "\$exception",
|
||||
properties = mapOf(
|
||||
"\$exception_type" to (throwable::class.simpleName ?: "Unknown"),
|
||||
"\$exception_message" to (throwable.message ?: "No message"),
|
||||
"\$exception_stack_trace_raw" to throwable.stackTraceToString(),
|
||||
"\$exception_thread" to thread.name,
|
||||
"\$exception_is_fatal" to true
|
||||
)
|
||||
)
|
||||
// Flush to ensure the event is sent before the process dies
|
||||
PostHog.flush()
|
||||
} catch (_: Exception) {
|
||||
// Don't let our crash handler crash
|
||||
}
|
||||
// Call the default handler so the system crash dialog still appears
|
||||
defaultHandler?.uncaughtException(thread, throwable)
|
||||
}
|
||||
Log.d(TAG, "Uncaught exception handler installed")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user