parent
f02021709a
commit
8434e23014
|
@ -72,7 +72,8 @@ class ZcashWalletApp : Application(), CameraXConfig.Provider {
|
|||
inner class ExceptionReporter(private val ogHandler: Thread.UncaughtExceptionHandler) : Thread.UncaughtExceptionHandler {
|
||||
override fun uncaughtException(t: Thread?, e: Throwable?) {
|
||||
twig("Uncaught Exception: $e caused by: ${e?.cause}")
|
||||
coordinator.feedback.report(e)
|
||||
// these are the only reported crashes that are considered fatal
|
||||
coordinator.feedback.report(e, true)
|
||||
coordinator.flush()
|
||||
// can do this if necessary but first verify that we need it
|
||||
runBlocking {
|
||||
|
|
|
@ -3,6 +3,27 @@ package cash.z.ecc.android.feedback
|
|||
import cash.z.ecc.android.ZcashWalletApp
|
||||
|
||||
object Report {
|
||||
object Send {
|
||||
class SubmitFailure(private val errorCode: Int?, private val errorMessage: String?) : Feedback.Funnel("send.failure.submit") {
|
||||
override fun toMap(): MutableMap<String, Any> {
|
||||
return super.toMap().apply {
|
||||
put("error.code", errorCode ?: -1)
|
||||
put("error.message", errorMessage ?: "None")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class EncodingFailure(private val errorCode: Int?, private val errorMessage: String?) : Feedback.Funnel("send.failure.submit") {
|
||||
override fun toMap(): MutableMap<String, Any> {
|
||||
return super.toMap().apply {
|
||||
put("error.code", errorCode ?: -1)
|
||||
put("error.message", errorMessage ?: "None")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum class NonUserAction(override val key: String, val description: String) : Feedback.Action {
|
||||
FEEDBACK_STARTED("action.feedback.start", "feedback started"),
|
||||
FEEDBACK_STOPPED("action.feedback.stop", "feedback stopped"),
|
||||
|
|
|
@ -44,7 +44,7 @@ class SendFinalFragment : BaseFragment<FragmentSendFinalBinding>() {
|
|||
}
|
||||
binding.textConfirmation.text =
|
||||
"Sending ${sendViewModel.zatoshiAmount.convertZatoshiToZecString(8)} ZEC to ${sendViewModel.toAddress.toAbbreviatedAddress()}"
|
||||
sendViewModel.memo?.trim()?.isNotEmpty()?.let { hasMemo ->
|
||||
sendViewModel.memo.trim().isNotEmpty().let { hasMemo ->
|
||||
binding.radioIncludeAddress.isChecked = hasMemo
|
||||
binding.radioIncludeAddress.goneIf(!hasMemo)
|
||||
}
|
||||
|
@ -91,6 +91,15 @@ class SendFinalFragment : BaseFragment<FragmentSendFinalBinding>() {
|
|||
pendingTransaction.isCreating() -> "Creating transaction . . ."
|
||||
else -> "Transaction updated!".also { twig("Unhandled TX state: $pendingTransaction") }
|
||||
}
|
||||
|
||||
// TODO: make this error tracking easier to use and more spiffy
|
||||
if (pendingTransaction?.isFailedSubmit() == true) {
|
||||
sendViewModel.feedback.report(Report.Send.SubmitFailure(pendingTransaction?.errorCode, pendingTransaction?.errorMessage))
|
||||
}
|
||||
if (pendingTransaction?.isFailedEncoding() == true) {
|
||||
sendViewModel.feedback.report(Report.Send.EncodingFailure(pendingTransaction?.errorCode, pendingTransaction?.errorMessage))
|
||||
}
|
||||
|
||||
twig("Pending TX (id: ${pendingTransaction?.id} Updated with message: $message")
|
||||
binding.textStatus.apply {
|
||||
text = "$message"
|
||||
|
@ -106,7 +115,9 @@ class SendFinalFragment : BaseFragment<FragmentSendFinalBinding>() {
|
|||
sendViewModel.reset()
|
||||
}
|
||||
} catch(t: Throwable) {
|
||||
twig("ERROR: error while handling pending transaction update! $t")
|
||||
val message = "ERROR: error while handling pending transaction update! $t"
|
||||
twig(message)
|
||||
Crashlytics.log(message)
|
||||
Crashlytics.logException(t)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,8 @@ import kotlinx.coroutines.*
|
|||
import kotlinx.coroutines.channels.BroadcastChannel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import java.io.OutputStreamWriter
|
||||
import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
import java.lang.StringBuilder
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
class Feedback(capacity: Int = 256) {
|
||||
|
@ -145,8 +143,8 @@ class Feedback(capacity: Int = 256) {
|
|||
*
|
||||
* @param error the uncaught exception that occurred.
|
||||
*/
|
||||
fun report(error: Throwable?): Feedback {
|
||||
return report(Crash(error))
|
||||
fun report(error: Throwable?, fatal: Boolean = false): Feedback {
|
||||
return report(Crash(error, fatal))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -199,6 +197,14 @@ class Feedback(capacity: Int = 256) {
|
|||
}
|
||||
}
|
||||
|
||||
abstract class Funnel(override val key: String) : Action {
|
||||
override fun toMap(): MutableMap<String, Any> {
|
||||
return mutableMapOf(
|
||||
"key" to key
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
interface Keyed<T> {
|
||||
val key: T
|
||||
}
|
||||
|
@ -225,17 +231,19 @@ class Feedback(capacity: Int = 256) {
|
|||
}
|
||||
}
|
||||
|
||||
data class Crash(val error: Throwable?) : Action {
|
||||
data class Crash(val error: Throwable? = null, val fatal: Boolean = true) : Action {
|
||||
override val key: String = "crash"
|
||||
override fun toMap(): Map<String, Any> {
|
||||
return mutableMapOf<String, Any>(
|
||||
"fatal" to fatal,
|
||||
"message" to (error?.message ?: "None"),
|
||||
"cause" to (error?.cause?.toString() ?: "None"),
|
||||
"cause.cause" to (error?.cause?.cause?.toString() ?: "None"),
|
||||
"cause.cause.cause" to (error?.cause?.cause?.cause?.toString() ?: "None")
|
||||
).apply { putAll(super.toMap()); putAll(error.stacktraceToMap()) }
|
||||
}
|
||||
override fun toString() = "App crashed due to: $error"
|
||||
|
||||
override fun toString() = "App ${if (fatal) "crashed due to" else "caught error"}: $error"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue