Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit a7f83ca2 authored by Rafael Tonholo's avatar Rafael Tonholo Committed by GitHub
Browse files

Merge pull request #9359 from rafaeltonholo/fix/add-auto-log-tagging-for-android

Logging - Add log auto tagging
parents 638ed81b df7a7215
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -4,6 +4,10 @@ plugins {

android {
    namespace = "net.thunderbird.app.common"

    buildFeatures {
        buildConfig = true
    }
}

dependencies {
+2 −1
Original line number Diff line number Diff line
package net.thunderbird.app.common.core

import net.thunderbird.app.common.BuildConfig
import net.thunderbird.core.logging.DefaultLogger
import net.thunderbird.core.logging.LogLevel
import net.thunderbird.core.logging.LogSink
@@ -11,7 +12,7 @@ import org.koin.dsl.module

val appCommonCoreModule: Module = module {
    single<LogLevel> {
        LogLevel.INFO
        if (BuildConfig.DEBUG) LogLevel.VERBOSE else LogLevel.INFO
    }

    single<List<LogSink>> {
+13 −0
Original line number Diff line number Diff line
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi

plugins {
    id(ThunderbirdPlugins.Library.kmp)
}
@@ -7,7 +9,18 @@ android {
}

kotlin {
    @OptIn(ExperimentalKotlinGradlePluginApi::class)
    applyDefaultHierarchyTemplate {
        common {
            group("commonJvm") {
                withAndroidTarget()
                withJvm()
            }
        }
    }
    sourceSets {
        val commonJvmMain by getting

        commonMain.dependencies {
            implementation(projects.core.logging.api)
        }
+14 −1
Original line number Diff line number Diff line
@@ -11,7 +11,9 @@ private class AndroidConsoleLogSink(
) : ConsoleLogSink {

    override fun log(event: LogEvent) {
        val timber = event.tag?.let { Timber.tag(it) } ?: Timber
        val timber = event.tag
            ?.let { Timber.tag(it) }
            ?: Timber.tag(event.composeTag(ignoredClasses = IGNORE_CLASSES) ?: this::class.java.name)

        when (event.level) {
            LogLevel.VERBOSE -> timber.v(event.throwable, event.message)
@@ -21,4 +23,15 @@ private class AndroidConsoleLogSink(
            LogLevel.ERROR -> timber.e(event.throwable, event.message)
        }
    }

    companion object {
        private val IGNORE_CLASSES = setOf(
            Timber::class.java.name,
            Timber.Forest::class.java.name,
            Timber.Tree::class.java.name,
            Timber.DebugTree::class.java.name,
            AndroidConsoleLogSink::class.java.name,
            // Add other classes to ignore if needed
        )
    }
}
+67 −0
Original line number Diff line number Diff line
package net.thunderbird.core.logging.console

import net.thunderbird.core.logging.DefaultLogger
import net.thunderbird.core.logging.LogEvent
import net.thunderbird.core.logging.Logger

/**
 * Composes a tag for the given [LogEvent].
 *
 * If the event has a tag, it is used; otherwise, a tag is extracted from the stack trace.
 * The tag is processed using the [processTag] method before being returned.
 *
 * @receiver The [LogEvent] to compose a tag for.
 * @param ignoredClasses The set of Class full name to be ignored.
 * @param processTag Processes a tag before it is used for logging.
 * @return The composed tag, or null if no tag could be determined.
 */
internal fun LogEvent.composeTag(
    ignoredClasses: Set<String>,
    processTag: (String) -> String? = { it },
): String? {
    // If a tag is provided, use it; otherwise, extract it from the stack trace
    val rawTag = tag ?: extractTagFromStackTrace(ignoredClasses)
    // Process the tag before returning it
    return rawTag?.let { processTag(it) }
}

/**
 * Extracts a tag from the stack trace.
 *
 * @return The extracted tag, or null if no suitable tag could be found.
 */
private fun extractTagFromStackTrace(ignoredClasses: Set<String>): String? {
    // Some classes are not available to this module, and we don't want
    // to add the dependency just for class filtering.
    val ignoredClasses = ignoredClasses + setOf(
        "net.thunderbird.core.logging.console.ComposeLogTagKt",
        "net.thunderbird.core.logging.composite.DefaultCompositeLogSink",
        "net.thunderbird.core.logging.legacy.Log",
        Logger::class.java.name,
        DefaultLogger::class.java.name,
    )

    @Suppress("ThrowingExceptionsWithoutMessageOrCause")
    val stackTrace = Throwable().stackTrace

    return stackTrace
        .firstOrNull { element ->
            ignoredClasses.none { element.className.startsWith(it) }
        }
        ?.let(::createStackElementTag)
}

/**
 * Creates a tag from a stack trace element.
 *
 * @param element The stack trace element to create a tag from.
 * @return The created tag.
 */
private fun createStackElementTag(element: StackTraceElement): String {
    var tag = element.className.substringAfterLast('.')
    val regex = "(\\$\\d+)+$".toRegex()
    if (regex.containsMatchIn(input = tag)) {
        tag = regex.replace(input = tag, replacement = "")
    }
    return tag
}
Loading