Enable Rust trace log packs (#4514)
* Enable Rust trace log packs This is a way to forcefully enable trace logs only for a few Rust crates in a safe way
This commit is contained in:
committed by
GitHub
parent
5d697711c0
commit
3d4b8c9b2a
@@ -37,6 +37,7 @@ class PlatformInitializer : Initializer<Unit> {
|
||||
writesToFilesConfiguration = defaultWriteToDiskConfiguration(bugReporter),
|
||||
logLevel = logLevel,
|
||||
extraTargets = listOf(ELEMENT_X_TARGET),
|
||||
traceLogPacks = runBlocking { preferencesStore.getTracingLogPacksFlow().first() },
|
||||
)
|
||||
bugReporter.setCurrentTracingLogLevel(logLevel.name)
|
||||
platformService.init(tracingConfiguration)
|
||||
|
||||
@@ -9,11 +9,13 @@ package io.element.android.features.preferences.impl.developer
|
||||
|
||||
import io.element.android.features.preferences.impl.developer.tracing.LogLevelItem
|
||||
import io.element.android.libraries.featureflag.ui.model.FeatureUiModel
|
||||
import io.element.android.libraries.matrix.api.tracing.TraceLogPack
|
||||
|
||||
sealed interface DeveloperSettingsEvents {
|
||||
data class UpdateEnabledFeature(val feature: FeatureUiModel, val isEnabled: Boolean) : DeveloperSettingsEvents
|
||||
data class SetCustomElementCallBaseUrl(val baseUrl: String?) : DeveloperSettingsEvents
|
||||
data class SetHideImagesAndVideos(val value: Boolean) : DeveloperSettingsEvents
|
||||
data class SetTracingLogLevel(val logLevel: LogLevelItem) : DeveloperSettingsEvents
|
||||
data class ToggleTracingLogPack(val logPack: TraceLogPack, val enabled: Boolean) : DeveloperSettingsEvents
|
||||
data object ClearCache : DeveloperSettingsEvents
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.runtime.mutableStateMapOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.snapshots.SnapshotStateMap
|
||||
@@ -34,9 +35,13 @@ import io.element.android.libraries.featureflag.api.Feature
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||
import io.element.android.libraries.featureflag.ui.model.FeatureUiModel
|
||||
import io.element.android.libraries.matrix.api.tracing.TraceLogPack
|
||||
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import java.net.URL
|
||||
@@ -77,6 +82,12 @@ class DeveloperSettingsPresenter @Inject constructor(
|
||||
appPreferencesStore.getTracingLogLevelFlow().map { AsyncData.Success(it.toLogLevelItem()) }
|
||||
}
|
||||
val tracingLogLevel by tracingLogLevelFlow.collectAsState(initial = AsyncData.Uninitialized)
|
||||
val tracingLogPacks by produceState(persistentListOf<TraceLogPack>()) {
|
||||
appPreferencesStore.getTracingLogPacksFlow()
|
||||
// Sort the entries alphabetically by its title
|
||||
.map { it.sortedBy { it.title }.toPersistentList() }
|
||||
.collectLatest { value = it }
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
FeatureFlags.entries
|
||||
@@ -121,6 +132,15 @@ class DeveloperSettingsPresenter @Inject constructor(
|
||||
is DeveloperSettingsEvents.SetTracingLogLevel -> coroutineScope.launch {
|
||||
appPreferencesStore.setTracingLogLevel(event.logLevel.toLogLevel())
|
||||
}
|
||||
is DeveloperSettingsEvents.ToggleTracingLogPack -> coroutineScope.launch {
|
||||
val currentPacks = tracingLogPacks.toMutableSet()
|
||||
if (currentPacks.contains(event.logPack)) {
|
||||
currentPacks.remove(event.logPack)
|
||||
} else {
|
||||
currentPacks.add(event.logPack)
|
||||
}
|
||||
appPreferencesStore.setTracingLogPacks(currentPacks)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,6 +155,7 @@ class DeveloperSettingsPresenter @Inject constructor(
|
||||
),
|
||||
hideImagesAndVideos = hideImagesAndVideos,
|
||||
tracingLogLevel = tracingLogLevel,
|
||||
tracingLogPacks = tracingLogPacks,
|
||||
eventSink = ::handleEvents
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import io.element.android.features.rageshake.api.preferences.RageshakePreference
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.featureflag.ui.model.FeatureUiModel
|
||||
import io.element.android.libraries.matrix.api.tracing.TraceLogPack
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
data class DeveloperSettingsState(
|
||||
@@ -22,6 +23,7 @@ data class DeveloperSettingsState(
|
||||
val customElementCallBaseUrlState: CustomElementCallBaseUrlState,
|
||||
val hideImagesAndVideos: Boolean,
|
||||
val tracingLogLevel: AsyncData<LogLevelItem>,
|
||||
val tracingLogPacks: ImmutableList<TraceLogPack>,
|
||||
val eventSink: (DeveloperSettingsEvents) -> Unit
|
||||
)
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ import io.element.android.features.rageshake.api.preferences.aRageshakePreferenc
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.featureflag.ui.model.aFeatureUiModelList
|
||||
import io.element.android.libraries.matrix.api.tracing.TraceLogPack
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
open class DeveloperSettingsStateProvider : PreviewParameterProvider<DeveloperSettingsState> {
|
||||
override val values: Sequence<DeveloperSettingsState>
|
||||
@@ -33,6 +35,7 @@ fun aDeveloperSettingsState(
|
||||
clearCacheAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
||||
customElementCallBaseUrlState: CustomElementCallBaseUrlState = aCustomElementCallBaseUrlState(),
|
||||
hideImagesAndVideos: Boolean = false,
|
||||
traceLogPacks: List<TraceLogPack> = emptyList(),
|
||||
eventSink: (DeveloperSettingsEvents) -> Unit = {},
|
||||
) = DeveloperSettingsState(
|
||||
features = aFeatureUiModelList(),
|
||||
@@ -42,6 +45,7 @@ fun aDeveloperSettingsState(
|
||||
customElementCallBaseUrlState = customElementCallBaseUrlState,
|
||||
hideImagesAndVideos = hideImagesAndVideos,
|
||||
tracingLogLevel = AsyncData.Success(LogLevelItem.INFO),
|
||||
tracingLogPacks = traceLogPacks.toPersistentList(),
|
||||
eventSink = eventSink,
|
||||
)
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
package io.element.android.features.preferences.impl.developer
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.progressSemantics
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
@@ -16,6 +17,7 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.features.preferences.impl.R
|
||||
import io.element.android.features.preferences.impl.developer.tracing.LogLevelItem
|
||||
import io.element.android.features.rageshake.api.preferences.RageshakePreferencesView
|
||||
@@ -32,6 +34,7 @@ import io.element.android.libraries.designsystem.theme.components.ListItem
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.featureflag.ui.FeatureListView
|
||||
import io.element.android.libraries.featureflag.ui.model.FeatureUiModel
|
||||
import io.element.android.libraries.matrix.api.tracing.TraceLogPack
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
@@ -56,6 +59,7 @@ fun DeveloperSettingsView(
|
||||
FeatureListContent(state)
|
||||
}
|
||||
ElementCallCategory(state = state)
|
||||
|
||||
PreferenceCategory(title = "Rust SDK") {
|
||||
PreferenceDropdown(
|
||||
title = "Tracing log level",
|
||||
@@ -67,6 +71,22 @@ fun DeveloperSettingsView(
|
||||
}
|
||||
)
|
||||
}
|
||||
PreferenceCategory(title = "Enable trace logs per SDK feature") {
|
||||
Text(
|
||||
text = "Requires app reboot",
|
||||
style = ElementTheme.typography.fontBodyMdRegular,
|
||||
color = ElementTheme.colors.textSecondary,
|
||||
modifier = Modifier.padding(start = 16.dp, end = 16.dp, bottom = 8.dp)
|
||||
)
|
||||
for (logPack in TraceLogPack.entries) {
|
||||
PreferenceSwitch(
|
||||
title = logPack.title,
|
||||
isChecked = state.tracingLogPacks.contains(logPack),
|
||||
onCheckedChange = { isChecked -> state.eventSink(DeveloperSettingsEvents.ToggleTracingLogPack(logPack, isChecked)) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
PreferenceCategory(title = "Showkase") {
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
|
||||
@@ -68,7 +68,7 @@ class DeveloperSettingsViewTest {
|
||||
eventsRecorder.assertSingle(DeveloperSettingsEvents.SetCustomElementCallBaseUrl("https://call.element.dev"))
|
||||
}
|
||||
|
||||
@Config(qualifiers = "h1024dp")
|
||||
@Config(qualifiers = "h1200dp")
|
||||
@Test
|
||||
fun `clicking on open showkase invokes the expected callback`() {
|
||||
val eventsRecorder = EventsRecorder<DeveloperSettingsEvents>(expectEvents = false)
|
||||
@@ -97,7 +97,7 @@ class DeveloperSettingsViewTest {
|
||||
eventsRecorder.assertSingle(DeveloperSettingsEvents.SetTracingLogLevel(LogLevelItem.DEBUG))
|
||||
}
|
||||
|
||||
@Config(qualifiers = "h1500dp")
|
||||
@Config(qualifiers = "h1700dp")
|
||||
@Test
|
||||
fun `clicking on clear cache emits the expected event`() {
|
||||
val eventsRecorder = EventsRecorder<DeveloperSettingsEvents>()
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2025 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
|
||||
|
||||
enum class TraceLogPack(val key: String) {
|
||||
EVENT_CACHE("event_cache") {
|
||||
override val title: String = "Event Cache"
|
||||
},
|
||||
SEND_QUEUE("send_queue") {
|
||||
override val title: String = "Send Queue"
|
||||
},
|
||||
TIMELINE("timeline") {
|
||||
override val title: String = "Timeline"
|
||||
};
|
||||
|
||||
abstract val title: String
|
||||
}
|
||||
@@ -10,6 +10,7 @@ package io.element.android.libraries.matrix.api.tracing
|
||||
data class TracingConfiguration(
|
||||
val logLevel: LogLevel,
|
||||
val extraTargets: List<String>,
|
||||
val traceLogPacks: Set<TraceLogPack>,
|
||||
val writesToLogcat: Boolean,
|
||||
val writesToFilesConfiguration: WriteToFilesConfiguration,
|
||||
)
|
||||
|
||||
@@ -51,7 +51,6 @@ fun TracingConfiguration.map(): org.matrix.rustcomponents.sdk.TracingConfigurati
|
||||
writeToStdoutOrSystem = writesToLogcat,
|
||||
logLevel = logLevel.toRustLogLevel(),
|
||||
extraTargets = extraTargets,
|
||||
// WARNING: this should be used only to debug issues, changes to this value should *never* be published
|
||||
traceLogPacks = emptyList(),
|
||||
traceLogPacks = traceLogPacks.map(),
|
||||
writeToFiles = writesToFilesConfiguration.toTracingFileConfiguration(),
|
||||
)
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2025 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.tracing
|
||||
|
||||
import io.element.android.libraries.matrix.api.tracing.TraceLogPack
|
||||
import org.matrix.rustcomponents.sdk.TraceLogPacks as RustTraceLogPack
|
||||
|
||||
fun TraceLogPack.map(): RustTraceLogPack = when (this) {
|
||||
TraceLogPack.SEND_QUEUE -> RustTraceLogPack.SEND_QUEUE
|
||||
TraceLogPack.EVENT_CACHE -> RustTraceLogPack.EVENT_CACHE
|
||||
TraceLogPack.TIMELINE -> RustTraceLogPack.TIMELINE
|
||||
}
|
||||
|
||||
fun Collection<TraceLogPack>.map(): List<RustTraceLogPack> {
|
||||
return map { it.map() }
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
package io.element.android.libraries.preferences.api.store
|
||||
|
||||
import io.element.android.libraries.matrix.api.tracing.LogLevel
|
||||
import io.element.android.libraries.matrix.api.tracing.TraceLogPack
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface AppPreferencesStore {
|
||||
@@ -26,5 +27,8 @@ interface AppPreferencesStore {
|
||||
suspend fun setTracingLogLevel(logLevel: LogLevel)
|
||||
fun getTracingLogLevelFlow(): Flow<LogLevel>
|
||||
|
||||
suspend fun setTracingLogPacks(targets: Set<TraceLogPack>)
|
||||
fun getTracingLogPacksFlow(): Flow<Set<TraceLogPack>>
|
||||
|
||||
suspend fun reset()
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ 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.matrix.api.tracing.TraceLogPack
|
||||
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
@@ -32,6 +33,7 @@ private val customElementCallBaseUrlKey = stringPreferencesKey("elementCallBaseU
|
||||
private val themeKey = stringPreferencesKey("theme")
|
||||
private val hideImagesAndVideosKey = booleanPreferencesKey("hideImagesAndVideos")
|
||||
private val logLevelKey = stringPreferencesKey("logLevel")
|
||||
private val traceLogPacksKey = stringPreferencesKey("traceLogPacks")
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultAppPreferencesStore @Inject constructor(
|
||||
@@ -105,6 +107,23 @@ class DefaultAppPreferencesStore @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setTracingLogPacks(targets: Set<TraceLogPack>) {
|
||||
val value = targets.joinToString(",") { it.key }
|
||||
store.edit { prefs ->
|
||||
prefs[traceLogPacksKey] = value
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTracingLogPacksFlow(): Flow<Set<TraceLogPack>> {
|
||||
return store.data.map { prefs ->
|
||||
prefs[traceLogPacksKey]
|
||||
?.split(",")
|
||||
?.mapNotNull { value -> TraceLogPack.entries.find { it.key == value } }
|
||||
?.toSet()
|
||||
?: emptySet()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun reset() {
|
||||
store.edit { it.clear() }
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
package io.element.android.libraries.preferences.test
|
||||
|
||||
import io.element.android.libraries.matrix.api.tracing.LogLevel
|
||||
import io.element.android.libraries.matrix.api.tracing.TraceLogPack
|
||||
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -19,6 +20,7 @@ class InMemoryAppPreferencesStore(
|
||||
theme: String? = null,
|
||||
simplifiedSlidingSyncEnabled: Boolean = false,
|
||||
logLevel: LogLevel = LogLevel.INFO,
|
||||
traceLockPacks: Set<TraceLogPack> = emptySet(),
|
||||
) : AppPreferencesStore {
|
||||
private val isDeveloperModeEnabled = MutableStateFlow(isDeveloperModeEnabled)
|
||||
private val hideImagesAndVideos = MutableStateFlow(hideImagesAndVideos)
|
||||
@@ -26,6 +28,7 @@ class InMemoryAppPreferencesStore(
|
||||
private val theme = MutableStateFlow(theme)
|
||||
private val simplifiedSlidingSyncEnabled = MutableStateFlow(simplifiedSlidingSyncEnabled)
|
||||
private val logLevel = MutableStateFlow(logLevel)
|
||||
private val tracingLogPacks = MutableStateFlow(traceLockPacks)
|
||||
|
||||
override suspend fun setDeveloperModeEnabled(enabled: Boolean) {
|
||||
isDeveloperModeEnabled.value = enabled
|
||||
@@ -67,6 +70,14 @@ class InMemoryAppPreferencesStore(
|
||||
return logLevel
|
||||
}
|
||||
|
||||
override suspend fun setTracingLogPacks(logPacks: Set<TraceLogPack>) {
|
||||
tracingLogPacks.value = logPacks
|
||||
}
|
||||
|
||||
override fun getTracingLogPacksFlow(): Flow<Set<TraceLogPack>> {
|
||||
return tracingLogPacks
|
||||
}
|
||||
|
||||
override suspend fun reset() {
|
||||
// No op
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user