Skip to content

Commit 9614558

Browse files
authored
Merge pull request #702 from wordpress-mobile/add/spans-logger-toHTML
Add the ability to log Spans details in case of crashes
2 parents 2178541 + 2392943 commit 9614558

File tree

3 files changed

+108
-29
lines changed

3 files changed

+108
-29
lines changed

aztec/src/main/kotlin/org/wordpress/aztec/AztecExceptionHandler.kt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,21 @@ class AztecExceptionHandler(private val logHelper: ExceptionHandlerHelper?, priv
2424
try {
2525
shouldLog = logHelper?.shouldLog(ex) ?: true
2626
} catch (e: Throwable) {
27-
AppLog.w(AppLog.T.EDITOR, "There was an exception in the Logger Helper. Set the logging to true" )
27+
AppLog.w(AppLog.T.EDITOR, "There was an exception in the Logger Helper. Set the logging to true")
2828
}
2929

3030
if (shouldLog) {
31-
// Try to report the HTML code of the content, but do not report exceptions that can occur logging the content
31+
// Try to report the HTML code of the content, the spans details, but do not report exceptions that can occur logging the content
3232
try {
33-
AppLog.e(AppLog.T.EDITOR, "HTML Content of Aztec Editor before the crash " + visualEditor.toPlainHtml(false))
33+
AppLog.e(AppLog.T.EDITOR, "HTML content of Aztec Editor before the crash:")
34+
AppLog.e(AppLog.T.EDITOR, visualEditor.toPlainHtml(false))
3435
} catch (e: Throwable) {
35-
AppLog.e(AppLog.T.EDITOR, "HTML Content of Aztec Editor before the crash is unavailable, log the details instead")
36+
AppLog.e(AppLog.T.EDITOR, "Oops! There was an error logging the HTML code.")
37+
}
38+
try {
3639
AztecLog.logContentDetails(visualEditor)
40+
} catch (e: Throwable) {
41+
// nop
3742
}
3843
}
3944

aztec/src/main/kotlin/org/wordpress/aztec/AztecText.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,10 +1121,10 @@ open class AztecText : AppCompatEditText, TextWatcher, UnknownHtmlSpan.OnUnknown
11211121
val output: SpannableStringBuilder
11221122
try {
11231123
output = SpannableStringBuilder(text)
1124-
} catch (e: java.lang.ArrayIndexOutOfBoundsException) {
1124+
} catch (e: Exception) {
11251125
// FIXME: Remove this log once we've data to replicate the issue, and fix it in some way.
1126-
AppLog.e(AppLog.T.EDITOR, "There was an error creating SpannableStringBuilder. See #452 for details.")
1127-
// No need to log the exception here. The ExceptionHandler does this for us.
1126+
AppLog.e(AppLog.T.EDITOR, "There was an error creating SpannableStringBuilder. See #452 and #582 for details.")
1127+
// No need to log details here. The default AztecExceptionHandler does this for us.
11281128
throw e
11291129
}
11301130

Lines changed: 96 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package org.wordpress.aztec.util
22

3-
import android.text.Spannable
4-
import org.json.JSONArray
5-
import org.json.JSONException
6-
import org.json.JSONObject
3+
import android.text.Spanned
4+
import android.text.TextUtils
75
import org.wordpress.android.util.AppLog
86
import org.wordpress.aztec.AztecText
7+
import java.util.Arrays
8+
import java.util.Collections
99

1010
class AztecLog {
1111
interface ExternalLogger {
@@ -15,32 +15,106 @@ class AztecLog {
1515
}
1616

1717
companion object {
18+
private const val MARK = 1
19+
private const val POINT = 2
20+
private const val PARAGRAPH = 3
21+
1822
fun logContentDetails(aztecText: AztecText) {
1923
AppLog.d(AppLog.T.EDITOR, "Below are the details of the content in the editor:")
2024
logContentDetails(aztecText.text)
2125
}
2226

23-
fun logContentDetails(text: Spannable) {
27+
fun logContentDetails(text: Spanned) {
2428
try {
25-
val logContentJSON = JSONObject()
26-
logContentJSON.put("content", text.toString())
27-
logContentJSON.put("length", text.length)
28-
val spansJSON = JSONArray()
29-
val spans = text.getSpans(0, text.length, Any::class.java)
30-
spans.forEach {
31-
val currenSpanJSON = JSONObject()
32-
currenSpanJSON.put("clazz", it.javaClass.name)
33-
currenSpanJSON.put("start", text.getSpanStart(it))
34-
currenSpanJSON.put("end", text.getSpanEnd(it))
35-
currenSpanJSON.put("flags", text.getSpanFlags(it))
36-
spansJSON.put(currenSpanJSON)
37-
}
38-
logContentJSON.put("spans", spansJSON)
39-
AppLog.d(AppLog.T.EDITOR, logContentJSON.toString())
40-
} catch (e: JSONException) {
41-
AppLog.e(AppLog.T.EDITOR, "Uhh ohh! There was an error logging the content of the Editor. This should" +
29+
AppLog.d(AppLog.T.EDITOR, logSpansDetails(text))
30+
} catch (e: Exception) {
31+
AppLog.e(AppLog.T.EDITOR, "Uhh ohh! There was an error logging the spans details of the Editor. This should" +
4232
"never happen.", e)
4333
}
4434
}
35+
36+
private fun logSpansDetails(text: Spanned): String {
37+
val spans = text.getSpans(0, text.length, Any::class.java)
38+
val spansList = Arrays.asList<Any>(*spans)
39+
40+
val sb = StringBuilder()
41+
sb.append('\n').append(text.toString().replace('\n', '').replace('\u200B', '¬')) // ␤↵↭
42+
sb.append(" length = " + text.length)
43+
44+
for (span in spansList) {
45+
val start = text.getSpanStart(span)
46+
val end = text.getSpanEnd(span)
47+
48+
var gap = text.length + 5
49+
50+
sb.append('\n')
51+
52+
if (start > 0) {
53+
sb.append(spaces(start))
54+
gap -= start
55+
}
56+
57+
val spanMode = text.getSpanFlags(span) and Spanned.SPAN_POINT_MARK_MASK
58+
val leftMode = (spanMode and 0x30) ushr 4
59+
val rightMode = spanMode and 0x03
60+
61+
if (end - start > 0) {
62+
when (leftMode) {
63+
MARK -> sb.append('>')
64+
POINT -> sb.append('<')
65+
PARAGRAPH -> sb.append(if (start == 0) '<' else '>')
66+
}
67+
68+
gap--
69+
} else {
70+
if (spanMode == Spanned.SPAN_INCLUSIVE_INCLUSIVE) {
71+
sb.append('x')
72+
} else if (spanMode == Spanned.SPAN_INCLUSIVE_EXCLUSIVE) {
73+
sb.append('>')
74+
} else if (spanMode == Spanned.SPAN_EXCLUSIVE_INCLUSIVE) {
75+
sb.append('<')
76+
} else if (spanMode == Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) {
77+
sb.append('!')
78+
} else if (spanMode == Spanned.SPAN_PARAGRAPH) {
79+
if (start == 0) {
80+
sb.append('!')
81+
} else if (start == text.length) {
82+
sb.append('<')
83+
} else {
84+
sb.append('>')
85+
}
86+
}
87+
}
88+
89+
if (end - start - 1 > 0) {
90+
sb.append(spaces(end - start - 1, "-"))
91+
gap -= end - start - 1
92+
}
93+
94+
if (end - start > 0) {
95+
when (rightMode) {
96+
MARK -> sb.append('>')
97+
POINT -> sb.append('<')
98+
PARAGRAPH -> sb.append(if (end == text.length) '<' else '>')
99+
}
100+
gap--
101+
}
102+
103+
sb.append(spaces(gap))
104+
105+
sb.append(" ")
106+
.append(String.format("%03d", start))
107+
.append(" -> ")
108+
.append(String.format("%03d", end))
109+
.append(" : ")
110+
.append(span.javaClass.simpleName)
111+
}
112+
113+
return sb.toString()
114+
}
115+
116+
private fun spaces(count: Int, char: String = " "): String {
117+
return TextUtils.join("", Collections.nCopies(count, char))
118+
}
45119
}
46120
}

0 commit comments

Comments
 (0)