175 lines
5.4 KiB
Kotlin
175 lines
5.4 KiB
Kotlin
package jp.juggler.util.log
|
|
|
|
import android.util.Log
|
|
import jp.juggler.base.BuildConfig
|
|
import jp.juggler.util.data.notEmpty
|
|
import java.io.PrintWriter
|
|
import java.io.StringWriter
|
|
import kotlin.math.min
|
|
|
|
object AdbLog {
|
|
private const val APP_TAG = "AppTag_PushReceiver"
|
|
private const val MAX_LOG_LENGTH = 4000
|
|
|
|
@Suppress("RegExpSimplifiable")
|
|
val reAnonymousClass = """(\.\$[0-9]+)+$""".toRegex()
|
|
|
|
private val callStackTag: String
|
|
get() {
|
|
// DO NOT switch this to Thread.getCurrentThread().getStackTrace(). The test will pass
|
|
// because Robolectric runs them on the JVM but on Android the elements are different.
|
|
@Suppress("ThrowingExceptionsWithoutMessageOrCause")
|
|
val trace = Throwable().stackTrace
|
|
val stackTraceElement = trace.elementAtOrNull(4)
|
|
?: error("callStackTag: stacktrace didn't have enough elements: are you using proguard?")
|
|
|
|
stackTraceElement.fileName.notEmpty()
|
|
?.let {
|
|
when (val lastDotPos = it.lastIndexOf('.')) {
|
|
-1 -> it
|
|
else -> it.substring(0, lastDotPos)
|
|
}
|
|
}
|
|
?.let { return it }
|
|
|
|
return reAnonymousClass.replace(stackTraceElement.className, "")
|
|
.let { it.substring(it.lastIndexOf('.') + 1) }
|
|
}
|
|
|
|
private fun Throwable.dump(): String {
|
|
// Don't replace this with Log.getStackTraceString() - it hides
|
|
// UnknownHostException, which is not what we want.
|
|
val sw = StringWriter(256)
|
|
val pw = PrintWriter(sw, false)
|
|
this.printStackTrace(pw)
|
|
pw.flush()
|
|
return sw.toString()
|
|
}
|
|
|
|
private fun printlnOrWtf(priority: Int, message: String) {
|
|
try {
|
|
if (priority == Log.ASSERT) {
|
|
Log.wtf(APP_TAG, message)
|
|
} else {
|
|
Log.println(priority, APP_TAG, message)
|
|
}
|
|
} catch (ignored: Throwable) {
|
|
// 単体テストで呼ばれた?
|
|
println(message)
|
|
}
|
|
}
|
|
|
|
private inline fun splitLines(
|
|
prefix: String,
|
|
message: CharSequence,
|
|
block: (CharSequence) -> Unit,
|
|
) {
|
|
val limit = MAX_LOG_LENGTH - prefix.length
|
|
if (message.length < limit) {
|
|
block(prefix + message)
|
|
} else {
|
|
// Split by line, then ensure each line can fit into Log's maximum length.
|
|
val length = message.length
|
|
var i = 0
|
|
while (i < length) {
|
|
val newline = message.indexOf('\n', i).takeIf { it >= 0 } ?: length
|
|
do {
|
|
val end = min(newline, i + limit)
|
|
val part = message.subSequence(i, end)
|
|
block(prefix + part)
|
|
i = end
|
|
} while (i < newline)
|
|
// skip \n
|
|
++i
|
|
}
|
|
}
|
|
}
|
|
|
|
fun log(
|
|
priority: Int,
|
|
ex: Throwable? = null,
|
|
messageArg: String? = null,
|
|
prefixArg: String? = null,
|
|
) {
|
|
if (priority < Log.INFO && !BuildConfig.DEBUG) return
|
|
|
|
// 本文の先頭に付与するprefix
|
|
val tag = (prefixArg ?: callStackTag)
|
|
val prefix = when {
|
|
tag.isBlank() -> ""
|
|
else -> "$tag: "
|
|
}
|
|
|
|
val stackTrace = ex?.dump()
|
|
|
|
// 本文とスタックトレース
|
|
val sb = StringBuilder()
|
|
val message = messageArg?.takeIf { it.isNotEmpty() }?.also { sb.append(it) }
|
|
if (stackTrace != null) {
|
|
if (message != null) sb.append("\n")
|
|
sb.append(stackTrace)
|
|
}
|
|
|
|
splitLines(prefix, sb) {
|
|
printlnOrWtf(priority, it.toString())
|
|
}
|
|
// LogEntity.saveLog(priority, tag, message, stackTrace)
|
|
}
|
|
|
|
@JvmStatic
|
|
fun v(msg: String) = log(Log.VERBOSE, messageArg = msg)
|
|
|
|
@JvmStatic
|
|
fun d(msg: String) = log(Log.DEBUG, messageArg = msg)
|
|
|
|
@JvmStatic
|
|
fun i(msg: String) = log(Log.INFO, messageArg = msg)
|
|
|
|
@JvmStatic
|
|
fun w(msg: String) = log(Log.WARN, messageArg = msg)
|
|
|
|
@JvmStatic
|
|
fun e(msg: String) = log(Log.ERROR, messageArg = msg)
|
|
|
|
@JvmStatic
|
|
fun wtf(msg: String) = log(Log.ASSERT, messageArg = msg)
|
|
|
|
@JvmStatic
|
|
fun recordFirebaseCrashlytics(ex: Throwable?) {
|
|
try {
|
|
ex ?: return
|
|
// FirebaseCrashlytics.getInstance().recordException(ex)
|
|
} catch (ignored: Throwable) {
|
|
// 単体テストで FirebaseCrashlytics.getInstance() が例外を出す
|
|
}
|
|
}
|
|
|
|
@JvmStatic
|
|
@JvmOverloads
|
|
fun i(ex: Throwable?, msg: String? = null) {
|
|
recordFirebaseCrashlytics(ex)
|
|
log(Log.INFO, ex = ex, messageArg = msg)
|
|
}
|
|
|
|
@JvmStatic
|
|
@JvmOverloads
|
|
fun w(ex: Throwable?, msg: String? = null) {
|
|
recordFirebaseCrashlytics(ex)
|
|
log(Log.WARN, ex = ex, messageArg = msg)
|
|
}
|
|
|
|
@JvmStatic
|
|
@JvmOverloads
|
|
fun e(ex: Throwable?, msg: String? = null) {
|
|
recordFirebaseCrashlytics(ex)
|
|
log(Log.ERROR, ex = ex, messageArg = msg)
|
|
}
|
|
|
|
@JvmStatic
|
|
@JvmOverloads
|
|
fun wtf(ex: Throwable?, msg: String? = null) {
|
|
recordFirebaseCrashlytics(ex)
|
|
log(Log.ASSERT, ex = ex, messageArg = msg)
|
|
}
|
|
}
|