change(tracing) : change how tracing is configured (ui and logic)

This commit is contained in:
ganfra 2025-01-17 09:52:32 +01:00
parent fd3b99765d
commit 7d27e6581b
38 changed files with 220 additions and 886 deletions

View file

@ -0,0 +1,19 @@
/*
* Copyright 2022-2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.matrix.api.tracing
/**
* Log levels for tracing in the SDK.
*/
enum class LogLevel {
ERROR,
WARN,
INFO,
DEBUG,
TRACE,
}

View file

@ -8,7 +8,8 @@
package io.element.android.libraries.matrix.api.tracing
data class TracingConfiguration(
val filterConfiguration: TracingFilterConfiguration,
val logLevel: LogLevel,
val extraTargets: List<String>,
val writesToLogcat: Boolean,
val writesToFilesConfiguration: WriteToFilesConfiguration,
)

View file

@ -1,102 +0,0 @@
/*
* Copyright 2022-2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.matrix.api.tracing
data class TracingFilterConfiguration(
val overrides: Map<Target, LogLevel> = emptyMap(),
) {
private val defaultLogLevel = LogLevel.INFO
// Order should matters
private val targetsToLogLevel: Map<Target, LogLevel> = mapOf(
Target.HYPER to LogLevel.WARN,
Target.MATRIX_SDK_CRYPTO to LogLevel.DEBUG,
Target.MATRIX_SDK_CRYPTO_ACCOUNT to LogLevel.TRACE,
Target.MATRIX_SDK_HTTP_CLIENT to LogLevel.DEBUG,
Target.MATRIX_SDK_SLIDING_SYNC to LogLevel.INFO,
Target.MATRIX_SDK_BASE_SLIDING_SYNC to LogLevel.INFO,
Target.MATRIX_SDK_UI_TIMELINE to LogLevel.INFO,
Target.MATRIX_SDK_BASE_CLIENT to LogLevel.TRACE,
// To debug OIDC logouts
Target.MATRIX_SDK_OIDC to LogLevel.TRACE,
)
fun getLogLevel(target: Target): LogLevel {
return overrides[target] ?: targetsToLogLevel[target] ?: defaultLogLevel
}
val filter: String
get() {
val fullMap = Target.entries.associateWith {
overrides[it] ?: targetsToLogLevel[it] ?: defaultLogLevel
}
return fullMap.map {
if (it.key.filter.isEmpty()) {
it.value.filter
} else {
"${it.key.filter}=${it.value.filter}"
}
}.joinToString(separator = ",")
}
}
enum class Target(open val filter: String) {
// COMMON(""),
ELEMENT("elementx"),
HYPER("hyper"),
MATRIX_SDK_FFI("matrix_sdk_ffi"),
MATRIX_SDK_UNIFFI_API("matrix_sdk_ffi::uniffi_api"),
MATRIX_SDK_CRYPTO("matrix_sdk_crypto"),
MATRIX_SDK_CRYPTO_ACCOUNT("matrix_sdk_crypto::olm::account"),
MATRIX_SDK("matrix_sdk"),
MATRIX_SDK_HTTP_CLIENT("matrix_sdk::http_client"),
MATRIX_SDK_CLIENT("matrix_sdk::client"),
MATRIX_SDK_OIDC("matrix_sdk::oidc"),
MATRIX_SDK_SEND_QUEUE("matrix_sdk::send_queue"),
MATRIX_SDK_SLIDING_SYNC("matrix_sdk::sliding_sync"),
MATRIX_SDK_BASE_SLIDING_SYNC("matrix_sdk_base::sliding_sync"),
MATRIX_SDK_UI_TIMELINE("matrix_sdk_ui::timeline"),
MATRIX_SDK_BASE_READ_RECEIPTS("matrix_sdk_base::read_receipts"),
MATRIX_SDK_BASE_CLIENT("matrix_sdk_base"),
}
enum class LogLevel(open val filter: String) {
ERROR("error"),
WARN("warn"),
INFO("info"),
DEBUG("debug"),
TRACE("trace"),
}
object TracingFilterConfigurations {
val release = TracingFilterConfiguration(
overrides = mapOf(
Target.ELEMENT to LogLevel.DEBUG
),
)
val nightly = TracingFilterConfiguration(
overrides = mapOf(
Target.ELEMENT to LogLevel.TRACE,
),
)
val debug = TracingFilterConfiguration(
overrides = mapOf(
Target.ELEMENT to LogLevel.TRACE
)
)
/**
* Use this method to create a custom configuration where all targets will have the same log level.
*/
fun custom(logLevel: LogLevel) = TracingFilterConfiguration(overrides = Target.entries.associateWith { logLevel })
/**
* Use this method to override the log level of specific targets.
*/
fun custom(overrides: Map<Target, LogLevel>) = TracingFilterConfiguration(overrides)
}

View file

@ -11,5 +11,5 @@ import timber.log.Timber
interface TracingService {
fun setupTracing(tracingConfiguration: TracingConfiguration)
fun createTimberTree(): Timber.Tree
fun createTimberTree(target: String): Timber.Tree
}

View file

@ -1,30 +0,0 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.matrix.impl.di
import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.Provides
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.core.meta.BuildType
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.matrix.api.tracing.TracingFilterConfiguration
import io.element.android.libraries.matrix.api.tracing.TracingFilterConfigurations
@Module
@ContributesTo(AppScope::class)
object TracingMatrixModule {
@Provides
fun providesTracingFilterConfiguration(buildMeta: BuildMeta): TracingFilterConfiguration {
return when (buildMeta.buildType) {
BuildType.DEBUG -> TracingFilterConfigurations.debug
BuildType.NIGHTLY -> TracingFilterConfigurations.nightly
BuildType.RELEASE -> TracingFilterConfigurations.release
}
}
}

View file

@ -10,6 +10,7 @@ package io.element.android.libraries.matrix.impl.tracing
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.matrix.api.tracing.LogLevel
import io.element.android.libraries.matrix.api.tracing.TracingConfiguration
import io.element.android.libraries.matrix.api.tracing.TracingService
import io.element.android.libraries.matrix.api.tracing.WriteToFilesConfiguration
@ -20,21 +21,28 @@ import javax.inject.Inject
@ContributesBinding(AppScope::class)
class RustTracingService @Inject constructor(private val buildMeta: BuildMeta) : TracingService {
override fun setupTracing(tracingConfiguration: TracingConfiguration) {
/*
val filter = tracingConfiguration.filterConfiguration
val rustTracingConfiguration = org.matrix.rustcomponents.sdk.TracingConfiguration(
filter = tracingConfiguration.filterConfiguration.filter,
writeToStdoutOrSystem = tracingConfiguration.writesToLogcat,
logLevel = tracingConfiguration.logLevel.toRustLogLevel(),
extraTargets = tracingConfiguration.extraTargets,
writeToFiles = tracingConfiguration.writesToFilesConfiguration.toTracingFileConfiguration(),
)
org.matrix.rustcomponents.sdk.setupTracing(rustTracingConfiguration)
Timber.v("Tracing config filter = $filter: ${filter.filter}")
*/
Timber.d("setupTracing: $rustTracingConfiguration")
}
override fun createTimberTree(): Timber.Tree {
return RustTracingTree(retrieveFromStackTrace = buildMeta.isDebuggable)
override fun createTimberTree(target: String): Timber.Tree {
return RustTracingTree(target = target, retrieveFromStackTrace = buildMeta.isDebuggable)
}
}
private fun LogLevel.toRustLogLevel(): org.matrix.rustcomponents.sdk.LogLevel {
return when (this) {
LogLevel.ERROR -> org.matrix.rustcomponents.sdk.LogLevel.ERROR
LogLevel.WARN -> org.matrix.rustcomponents.sdk.LogLevel.WARN
LogLevel.INFO -> org.matrix.rustcomponents.sdk.LogLevel.INFO
LogLevel.DEBUG -> org.matrix.rustcomponents.sdk.LogLevel.DEBUG
LogLevel.TRACE -> org.matrix.rustcomponents.sdk.LogLevel.TRACE
}
}

View file

@ -8,7 +8,6 @@
package io.element.android.libraries.matrix.impl.tracing
import android.util.Log
import io.element.android.libraries.matrix.api.tracing.Target
import org.matrix.rustcomponents.sdk.LogLevel
import org.matrix.rustcomponents.sdk.logEvent
import timber.log.Timber
@ -26,7 +25,10 @@ private val fqcnIgnore = listOf(
/**
* A Timber tree that passes logs to the Rust SDK.
*/
internal class RustTracingTree(private val retrieveFromStackTrace: Boolean) : Timber.Tree() {
internal class RustTracingTree(
private val target: String,
private val retrieveFromStackTrace: Boolean,
) : Timber.Tree() {
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
val location = if (retrieveFromStackTrace) {
getLogEventLocationFromStackTrace()
@ -38,7 +40,7 @@ internal class RustTracingTree(private val retrieveFromStackTrace: Boolean) : Ti
file = location.file,
line = location.line,
level = logLevel,
target = Target.ELEMENT.filter,
target = target,
message = if (tag != null) "[$tag] $message" else message,
)
}

View file

@ -1,34 +0,0 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.matrix.impl.di
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.core.meta.BuildType
import io.element.android.libraries.matrix.api.tracing.TracingFilterConfigurations
import io.element.android.libraries.matrix.test.core.aBuildMeta
import org.junit.Test
class TracingMatrixModuleTest {
@Test
fun `providesTracingFilterConfiguration returns debug config for debug build`() {
assertThat(TracingMatrixModule.providesTracingFilterConfiguration(aBuildMeta(BuildType.DEBUG)))
.isEqualTo(TracingFilterConfigurations.debug)
}
@Test
fun `providesTracingFilterConfiguration returns nightly config for nightly build`() {
assertThat(TracingMatrixModule.providesTracingFilterConfiguration(aBuildMeta(BuildType.NIGHTLY)))
.isEqualTo(TracingFilterConfigurations.nightly)
}
@Test
fun `providesTracingFilterConfiguration returns release config for release build`() {
assertThat(TracingMatrixModule.providesTracingFilterConfiguration(aBuildMeta(BuildType.RELEASE)))
.isEqualTo(TracingFilterConfigurations.release)
}
}

View file

@ -7,6 +7,7 @@
package io.element.android.libraries.preferences.api.store
import io.element.android.libraries.matrix.api.tracing.LogLevel
import kotlinx.coroutines.flow.Flow
interface AppPreferencesStore {
@ -25,5 +26,8 @@ interface AppPreferencesStore {
suspend fun setHideImagesAndVideos(value: Boolean)
fun doesHideImagesAndVideosFlow(): Flow<Boolean>
suspend fun setTracingLogLevel(logLevel: LogLevel)
fun getTracingLogLevelFlow(): Flow<LogLevel>
suspend fun reset()
}

View file

@ -19,6 +19,7 @@ import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.core.meta.BuildType
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.matrix.api.tracing.LogLevel
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
@ -31,6 +32,7 @@ private val customElementCallBaseUrlKey = stringPreferencesKey("elementCallBaseU
private val themeKey = stringPreferencesKey("theme")
private val simplifiedSlidingSyncKey = booleanPreferencesKey("useSimplifiedSlidingSync")
private val hideImagesAndVideosKey = booleanPreferencesKey("hideImagesAndVideos")
private val logLevelKey = stringPreferencesKey("logLevel")
@ContributesBinding(AppScope::class)
class DefaultAppPreferencesStore @Inject constructor(
@ -104,7 +106,27 @@ class DefaultAppPreferencesStore @Inject constructor(
}
}
override suspend fun setTracingLogLevel(logLevel: LogLevel) {
store.edit { prefs ->
prefs[logLevelKey] = logLevel.name
}
}
override fun getTracingLogLevelFlow(): Flow<LogLevel> {
return store.data.map { prefs ->
prefs[logLevelKey]?.let { LogLevel.valueOf(it) } ?: buildMeta.defaultLogLevel()
}
}
override suspend fun reset() {
store.edit { it.clear() }
}
}
private fun BuildMeta.defaultLogLevel(): LogLevel {
return when (buildType) {
BuildType.DEBUG -> LogLevel.TRACE
BuildType.NIGHTLY -> LogLevel.DEBUG
BuildType.RELEASE -> LogLevel.INFO
}
}

View file

@ -7,6 +7,7 @@
package io.element.android.libraries.preferences.test
import io.element.android.libraries.matrix.api.tracing.LogLevel
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@ -16,13 +17,15 @@ class InMemoryAppPreferencesStore(
hideImagesAndVideos: Boolean = false,
customElementCallBaseUrl: String? = null,
theme: String? = null,
simplifiedSlidingSyncEnabled: Boolean = false
simplifiedSlidingSyncEnabled: Boolean = false,
logLevel: LogLevel = LogLevel.INFO,
) : AppPreferencesStore {
private val isDeveloperModeEnabled = MutableStateFlow(isDeveloperModeEnabled)
private val hideImagesAndVideos = MutableStateFlow(hideImagesAndVideos)
private val customElementCallBaseUrl = MutableStateFlow(customElementCallBaseUrl)
private val theme = MutableStateFlow(theme)
private val simplifiedSlidingSyncEnabled = MutableStateFlow(simplifiedSlidingSyncEnabled)
private val logLevel = MutableStateFlow(logLevel)
override suspend fun setDeveloperModeEnabled(enabled: Boolean) {
isDeveloperModeEnabled.value = enabled
@ -64,6 +67,14 @@ class InMemoryAppPreferencesStore(
return hideImagesAndVideos
}
override suspend fun setTracingLogLevel(logLevel: LogLevel) {
this.logLevel.value = logLevel
}
override fun getTracingLogLevelFlow(): Flow<LogLevel> {
return logLevel
}
override suspend fun reset() {
// No op
}