diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9644d056cb..2d10257dfe 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -366,6 +366,7 @@ dependencies { implementation(deps.googlePlay.advertising) coreLibraryDesugaring(deps.desugar) implementation(deps.timber) + implementation(deps.kermit) implementation(deps.reKotlin) implementation(deps.zxing.qrCore) implementation(deps.coil) diff --git a/app/src/main/java/com/tangem/tap/common/log/TangemAppLoggerInitializer.kt b/app/src/main/java/com/tangem/tap/common/log/TangemAppLoggerInitializer.kt index 924cbede00..8eaafd7505 100644 --- a/app/src/main/java/com/tangem/tap/common/log/TangemAppLoggerInitializer.kt +++ b/app/src/main/java/com/tangem/tap/common/log/TangemAppLoggerInitializer.kt @@ -1,11 +1,17 @@ package com.tangem.tap.common.log +import android.os.Build import android.util.Log +import co.touchlab.kermit.BaseLogger +import co.touchlab.kermit.LogWriter +import co.touchlab.kermit.Logger +import co.touchlab.kermit.Severity import com.orhanobut.logger.AndroidLogAdapter -import com.orhanobut.logger.Logger import com.tangem.datasource.local.logs.AppLogsStore import com.tangem.wallet.BuildConfig import timber.log.Timber +import java.util.regex.Pattern +import com.orhanobut.logger.Logger as PrettyLogger /** * Tangem app logger @@ -21,32 +27,102 @@ class TangemAppLoggerInitializer( /** Initialize */ fun initialize() { if (IS_LOG_ENABLED) { - Logger.addLogAdapter(AndroidLogAdapter(TimberFormatStrategy())) + PrettyLogger.addLogAdapter(AndroidLogAdapter(TimberFormatStrategy())) } Timber.plant(tree = createTimberTree()) + Logger.setLogWriters(KermitLogWriter(::finalLogOutput)) } private fun createTimberTree(): Timber.Tree { return object : Timber.DebugTree() { override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { - if (IS_LOG_ENABLED) { - Logger.log(priority, tag, message, t) - } - - if (PERMITTED_PRIORITY.contains(priority)) { - appLogsStore.saveLogMessage( - tag = tag ?: "TangemAppLogger", - message = message, - ) - } + finalLogOutput(priority = priority, tag = tag, message = message, t = t) } } } + private fun finalLogOutput(priority: Int, tag: String?, message: String, t: Throwable?) { + if (IS_LOG_ENABLED) { + PrettyLogger.log(priority, tag, message, t) + } + + if (PERMITTED_PRIORITY.contains(priority)) { + appLogsStore.saveLogMessage( + tag = tag ?: "TangemAppLogger", + message = message, + ) + } + } + @Suppress("BooleanPropertyNaming") private companion object { val IS_LOG_ENABLED: Boolean = BuildConfig.LOG_ENABLED val PERMITTED_PRIORITY = listOf(Log.ERROR, Log.INFO) } +} + +private class KermitLogWriter( + private val finalLogOutput: (priority: Int, tag: String?, message: String, t: Throwable?) -> Unit, +) : LogWriter() { + + private val fqcnIgnore = setOf( + LogWriter::class.java.name, + KermitLogWriter::class.java.name, + BaseLogger::class.java.name, + Logger::class.java.name, + ) + + override fun log(severity: Severity, message: String, tag: String, throwable: Throwable?) { + val priority = when (severity) { + Severity.Verbose -> PrettyLogger.VERBOSE + Severity.Debug -> PrettyLogger.DEBUG + Severity.Info -> PrettyLogger.INFO + Severity.Warn -> PrettyLogger.WARN + Severity.Error -> PrettyLogger.ERROR + Severity.Assert -> PrettyLogger.ASSERT + } + + val finalTag = if (tag != KERMIT_LOGGER_DEFAULT_TAG) { + tag + } else { + /** + * like in [Timber.DebugTree.tag] + */ + @Suppress("UnnecessaryLet", "ThrowingExceptionsWithoutMessageOrCause") + Throwable().stackTrace + .first { it.className !in fqcnIgnore } + .let(::createStackElementTag) + } + + finalLogOutput(priority, finalTag, message, throwable) + } + + /** + * copy from [Timber.DebugTree.createStackElementTag] + */ + @Suppress("MagicNumber") + private fun createStackElementTag(element: StackTraceElement): String? { + var tag = element.className.substringAfterLast('.') + val m = ANONYMOUS_CLASS.matcher(tag) + if (m.find()) { + tag = m.replaceAll("") + } + // Tag length limit was removed in API 26. + return if (tag.length <= MAX_TAG_LENGTH || Build.VERSION.SDK_INT >= 26) { + tag + } else { + tag.substring(0, MAX_TAG_LENGTH) + } + } + + private companion object { + private const val KERMIT_LOGGER_DEFAULT_TAG = "" + + /** + * copy from [Timber.DebugTree.Companion] + */ + private const val MAX_TAG_LENGTH = 23 + private val ANONYMOUS_CLASS = Pattern.compile("(\\$\\d+)+$") + } } \ No newline at end of file diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 759030eecc..4cde3e5c09 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -78,6 +78,7 @@ retrofit = "2.11.0" retrofitMoshiConverter = "2.9.0" spongycastleCryptoCore = "1.58.0.0" timber = "4.7.1" +kermit = "2.1.0" viewBindingDelegate = "1.5.9" xmlShimmer = "1.1.3" zxingQrCode = "3.5.1" @@ -284,6 +285,7 @@ retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit retrofit-response-type-keeper = { module = "com.squareup.retrofit2:response-type-keeper", version.ref = "retrofit" } retrofit-moshi = { module = "com.squareup.retrofit2:converter-moshi", version.ref = "retrofitMoshiConverter" } timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" } +kermit = { module = "co.touchlab:kermit", version.ref = "kermit" } viewBindingDelegate = { module = "com.github.kirich1409:viewbindingpropertydelegate-noreflection", version.ref = "viewBindingDelegate" } xmlShimmer = { module = "com.github.skydoves:androidveil", version.ref = "xmlShimmer" } zxing-qrCore = { module = "com.google.zxing:core", version.ref = "zxingQrCode" }