mirror of
https://github.com/nextcloud/android.git
synced 2024-11-24 14:15:44 +03:00
Merge pull request #8805 from nextcloud/stacktrace
Add stacktrace directly to github issue
This commit is contained in:
commit
5b964994d1
5 changed files with 68 additions and 59 deletions
|
@ -30,8 +30,6 @@ import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import com.owncloud.android.BuildConfig
|
import com.owncloud.android.BuildConfig
|
||||||
import com.owncloud.android.R
|
import com.owncloud.android.R
|
||||||
import java.io.PrintWriter
|
|
||||||
import java.io.StringWriter
|
|
||||||
|
|
||||||
class ExceptionHandler(
|
class ExceptionHandler(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
|
@ -40,15 +38,14 @@ class ExceptionHandler(
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val LINE_SEPARATOR = "\n"
|
private const val LINE_SEPARATOR = "\n"
|
||||||
|
private const val EXCEPTION_FORMAT_MAX_RECURSIVITY = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun uncaughtException(thread: Thread, exception: Throwable) {
|
override fun uncaughtException(thread: Thread, exception: Throwable) {
|
||||||
|
|
||||||
@Suppress("TooGenericExceptionCaught") // this is exactly what we want here
|
@Suppress("TooGenericExceptionCaught") // this is exactly what we want here
|
||||||
try {
|
try {
|
||||||
val stackTrace = StringWriter()
|
val errorReport = generateErrorReport(formatException(thread, exception))
|
||||||
exception.printStackTrace(PrintWriter(stackTrace))
|
|
||||||
val errorReport = generateErrorReport(stackTrace.toString())
|
|
||||||
val intent = Intent(context, ShowErrorActivity::class.java)
|
val intent = Intent(context, ShowErrorActivity::class.java)
|
||||||
intent.putExtra(ShowErrorActivity.EXTRA_ERROR_TEXT, errorReport)
|
intent.putExtra(ShowErrorActivity.EXTRA_ERROR_TEXT, errorReport)
|
||||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
@ -63,55 +60,60 @@ class ExceptionHandler(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun formatException(thread: Thread, exception: Throwable): String {
|
||||||
|
fun formatExceptionRecursive(thread: Thread, exception: Throwable, count: Int = 0): String {
|
||||||
|
if (count > EXCEPTION_FORMAT_MAX_RECURSIVITY) {
|
||||||
|
return "Max number of recursive exception causes exceeded!"
|
||||||
|
}
|
||||||
|
// print exception
|
||||||
|
val stringBuilder = StringBuilder()
|
||||||
|
val stackTrace = exception.stackTrace
|
||||||
|
stringBuilder.appendLine("Exception in thread \"${thread.name}\" $exception")
|
||||||
|
// print available stacktrace
|
||||||
|
for (element in stackTrace) {
|
||||||
|
stringBuilder.appendLine(" at $element")
|
||||||
|
}
|
||||||
|
// print cause recursively
|
||||||
|
exception.cause?.let {
|
||||||
|
stringBuilder.append("Caused by: ")
|
||||||
|
stringBuilder.append(formatExceptionRecursive(thread, it, count + 1))
|
||||||
|
}
|
||||||
|
return stringBuilder.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatExceptionRecursive(thread, exception, 0)
|
||||||
|
}
|
||||||
|
|
||||||
private fun generateErrorReport(stackTrace: String): String {
|
private fun generateErrorReport(stackTrace: String): String {
|
||||||
val buildNumber = context.resources.getString(R.string.buildNumber)
|
val buildNumber = context.resources.getString(R.string.buildNumber)
|
||||||
|
|
||||||
var buildNumberString = ""
|
val buildNumberString = when {
|
||||||
if (buildNumber.isNotEmpty()) {
|
buildNumber.isNotEmpty() -> " (build #$buildNumber)"
|
||||||
buildNumberString = " (build #$buildNumber)"
|
else -> ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return "************ CAUSE OF ERROR ************\n\n" +
|
return """
|
||||||
stackTrace +
|
|### Cause of error
|
||||||
"\n************ APP INFORMATION ************" +
|
|```java
|
||||||
LINE_SEPARATOR +
|
${stackTrace.prependIndent("|")}
|
||||||
"ID: " +
|
|```
|
||||||
BuildConfig.APPLICATION_ID +
|
|
|
||||||
LINE_SEPARATOR +
|
|### App information
|
||||||
"Version: " +
|
|* ID: `${BuildConfig.APPLICATION_ID}`
|
||||||
BuildConfig.VERSION_CODE +
|
|* Version: `${BuildConfig.VERSION_CODE}$buildNumberString`
|
||||||
buildNumberString +
|
|* Build flavor: `${BuildConfig.FLAVOR}`
|
||||||
LINE_SEPARATOR +
|
|
|
||||||
"Build flavor: " +
|
|### Device information
|
||||||
BuildConfig.FLAVOR +
|
|* Brand: `${Build.BRAND}`
|
||||||
LINE_SEPARATOR +
|
|* Device: `${Build.DEVICE}`
|
||||||
"\n************ DEVICE INFORMATION ************" +
|
|* Model: `${Build.MODEL}`
|
||||||
LINE_SEPARATOR +
|
|* Id: `${Build.ID}`
|
||||||
"Brand: " +
|
|* Product: `${Build.PRODUCT}`
|
||||||
Build.BRAND +
|
|
|
||||||
LINE_SEPARATOR +
|
|### Firmware
|
||||||
"Device: " +
|
|* SDK: `${Build.VERSION.SDK_INT}`
|
||||||
Build.DEVICE +
|
|* Release: `${Build.VERSION.RELEASE}`
|
||||||
LINE_SEPARATOR +
|
|* Incremental: `${Build.VERSION.INCREMENTAL}`
|
||||||
"Model: " +
|
""".trimMargin("|")
|
||||||
Build.MODEL +
|
|
||||||
LINE_SEPARATOR +
|
|
||||||
"Id: " +
|
|
||||||
Build.ID +
|
|
||||||
LINE_SEPARATOR +
|
|
||||||
"Product: " +
|
|
||||||
Build.PRODUCT +
|
|
||||||
LINE_SEPARATOR +
|
|
||||||
"\n************ FIRMWARE ************" +
|
|
||||||
LINE_SEPARATOR +
|
|
||||||
"SDK: " +
|
|
||||||
Build.VERSION.SDK_INT +
|
|
||||||
LINE_SEPARATOR +
|
|
||||||
"Release: " +
|
|
||||||
Build.VERSION.RELEASE +
|
|
||||||
LINE_SEPARATOR +
|
|
||||||
"Incremental: " +
|
|
||||||
Build.VERSION.INCREMENTAL +
|
|
||||||
LINE_SEPARATOR
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import com.owncloud.android.R
|
||||||
import com.owncloud.android.databinding.ActivityShowErrorBinding
|
import com.owncloud.android.databinding.ActivityShowErrorBinding
|
||||||
import com.owncloud.android.utils.ClipboardUtil
|
import com.owncloud.android.utils.ClipboardUtil
|
||||||
import com.owncloud.android.utils.DisplayUtils
|
import com.owncloud.android.utils.DisplayUtils
|
||||||
|
import java.net.URLEncoder
|
||||||
|
|
||||||
class ShowErrorActivity : AppCompatActivity() {
|
class ShowErrorActivity : AppCompatActivity() {
|
||||||
private lateinit var binding: ActivityShowErrorBinding
|
private lateinit var binding: ActivityShowErrorBinding
|
||||||
|
@ -66,7 +67,12 @@ class ShowErrorActivity : AppCompatActivity() {
|
||||||
ClipboardUtil.copyToClipboard(this, binding.textViewError.text.toString(), false)
|
ClipboardUtil.copyToClipboard(this, binding.textViewError.text.toString(), false)
|
||||||
val issueLink = getString(R.string.report_issue_link)
|
val issueLink = getString(R.string.report_issue_link)
|
||||||
if (issueLink.isNotEmpty()) {
|
if (issueLink.isNotEmpty()) {
|
||||||
val uriUrl = Uri.parse(issueLink)
|
val uriUrl = Uri.parse(
|
||||||
|
String.format(
|
||||||
|
issueLink,
|
||||||
|
URLEncoder.encode(binding.textViewError.text.toString())
|
||||||
|
)
|
||||||
|
)
|
||||||
val intent = Intent(Intent.ACTION_VIEW, uriUrl)
|
val intent = Intent(Intent.ACTION_VIEW, uriUrl)
|
||||||
DisplayUtils.startIntentIfAppAvailable(intent, this, R.string.no_browser_available)
|
DisplayUtils.startIntentIfAppAvailable(intent, this, R.string.no_browser_available)
|
||||||
}
|
}
|
||||||
|
@ -80,7 +86,9 @@ class ShowErrorActivity : AppCompatActivity() {
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
return when (item.itemId) {
|
return when (item.itemId) {
|
||||||
R.id.error_share -> { onClickedShare(); true }
|
R.id.error_share -> {
|
||||||
|
onClickedShare(); true
|
||||||
|
}
|
||||||
else -> super.onOptionsItemSelected(item)
|
else -> super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,9 +231,8 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
|
||||||
// we don't want to handle crashes occurring inside crash reporter activity/process;
|
// we don't want to handle crashes occurring inside crash reporter activity/process;
|
||||||
// let the platform deal with those
|
// let the platform deal with those
|
||||||
final boolean isCrashReportingProcess = getAppProcessName().endsWith(":crash");
|
final boolean isCrashReportingProcess = getAppProcessName().endsWith(":crash");
|
||||||
final boolean useExceptionHandler = !appInfo.isDebugBuild();
|
|
||||||
|
|
||||||
if (!isCrashReportingProcess && useExceptionHandler) {
|
if (!isCrashReportingProcess) {
|
||||||
Thread.UncaughtExceptionHandler defaultPlatformHandler = Thread.getDefaultUncaughtExceptionHandler();
|
Thread.UncaughtExceptionHandler defaultPlatformHandler = Thread.getDefaultUncaughtExceptionHandler();
|
||||||
final ExceptionHandler crashReporter = new ExceptionHandler(this,
|
final ExceptionHandler crashReporter = new ExceptionHandler(this,
|
||||||
defaultPlatformHandler);
|
defaultPlatformHandler);
|
||||||
|
|
|
@ -58,7 +58,7 @@ public final class StringUtils {
|
||||||
matcher.group(),
|
matcher.group(),
|
||||||
String.format(Locale.getDefault(), "<font color='%d'><b>%s</b></font>", color,
|
String.format(Locale.getDefault(), "<font color='%d'><b>%s</b></font>", color,
|
||||||
matcher.group())
|
matcher.group())
|
||||||
);
|
);
|
||||||
matcher.appendReplacement(stringBuffer, Matcher.quoteReplacement(replacement));
|
matcher.appendReplacement(stringBuffer, Matcher.quoteReplacement(replacement));
|
||||||
}
|
}
|
||||||
matcher.appendTail(stringBuffer);
|
matcher.appendTail(stringBuffer);
|
||||||
|
@ -70,9 +70,9 @@ public final class StringUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static
|
public static
|
||||||
@NonNull String removePrefix(@NonNull String s, @NonNull String prefix)
|
@NonNull
|
||||||
{
|
String removePrefix(@NonNull String s, @NonNull String prefix) {
|
||||||
if (s.startsWith(prefix)){
|
if (s.startsWith(prefix)) {
|
||||||
return s.substring(prefix.length());
|
return s.substring(prefix.length());
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
|
|
|
@ -97,7 +97,7 @@
|
||||||
<string name="help_link" translatable="false">https://help.nextcloud.com/c/clients/android</string>
|
<string name="help_link" translatable="false">https://help.nextcloud.com/c/clients/android</string>
|
||||||
<string name="translation_link" translatable="false">https://www.transifex.com/nextcloud/nextcloud/android/</string>
|
<string name="translation_link" translatable="false">https://www.transifex.com/nextcloud/nextcloud/android/</string>
|
||||||
<string name="contributing_link" translatable="false">https://github.com/nextcloud/android/blob/master/CONTRIBUTING.md</string>
|
<string name="contributing_link" translatable="false">https://github.com/nextcloud/android/blob/master/CONTRIBUTING.md</string>
|
||||||
<string name="report_issue_link" translatable="false">https://github.com/nextcloud/android/issues/new/choose</string>
|
<string name="report_issue_link" translatable="false">https://github.com/nextcloud/android/issues/new?labels=bug&body=%1$s</string>
|
||||||
|
|
||||||
<!-- login data links -->
|
<!-- login data links -->
|
||||||
<string name="login_data_own_scheme" translatable="false">nc</string>
|
<string name="login_data_own_scheme" translatable="false">nc</string>
|
||||||
|
|
Loading…
Reference in a new issue