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:
Jorge Martin Espinosa 2025-04-02 13:21:53 +02:00 committed by GitHub
parent b2791d5aad
commit c3ff9c9bda
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 131 additions and 4 deletions

View file

@ -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
}

View file

@ -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
)
}

View file

@ -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
)

View file

@ -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,
)

View file

@ -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 = {

View file

@ -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>()