Fix tracing configuration in debug and nightlies (#3019)

* Fix tracing configuration in debug and nightlies:

- Debug will now write the logs to disk too.
- Nightly will be able to customise tracing filters.
- Improved the configure tracing and bug report screens.

* Update screenshots

* Add changelog

---------

Co-authored-by: ElementBot <benoitm+elementbot@element.io>
This commit is contained in:
Jorge Martin Espinosa
2024-06-12 12:20:43 +02:00
committed by GitHub
parent 9bbe6828f1
commit 54845866a6
9 changed files with 101 additions and 36 deletions

View File

@@ -22,7 +22,9 @@ import androidx.preference.PreferenceManager
import androidx.startup.Initializer
import io.element.android.features.preferences.impl.developer.tracing.SharedPreferencesTracingConfigurationStore
import io.element.android.features.preferences.impl.developer.tracing.TargetLogLevelMapBuilder
import io.element.android.features.rageshake.api.reporter.BugReporter
import io.element.android.libraries.architecture.bindings
import io.element.android.libraries.core.meta.BuildType
import io.element.android.libraries.matrix.api.tracing.TracingConfiguration
import io.element.android.libraries.matrix.api.tracing.TracingFilterConfigurations
import io.element.android.libraries.matrix.api.tracing.WriteToFilesConfiguration
@@ -36,31 +38,27 @@ class TracingInitializer : Initializer<Unit> {
val tracingService = appBindings.tracingService()
val bugReporter = appBindings.bugReporter()
Timber.plant(tracingService.createTimberTree())
val tracingConfiguration = if (BuildConfig.DEBUG) {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
val store = SharedPreferencesTracingConfigurationStore(prefs)
val builder = TargetLogLevelMapBuilder(store)
val tracingConfiguration = if (BuildConfig.BUILD_TYPE == BuildType.RELEASE.name) {
TracingConfiguration(
filterConfiguration = TracingFilterConfigurations.custom(builder.getCurrentMap()),
writesToLogcat = true,
writesToFilesConfiguration = WriteToFilesConfiguration.Disabled
filterConfiguration = TracingFilterConfigurations.release,
writesToLogcat = false,
writesToFilesConfiguration = defaultWriteToDiskConfiguration(bugReporter),
)
} else {
val config = if (BuildConfig.BUILD_TYPE == "nightly") {
TracingFilterConfigurations.nightly
} else {
TracingFilterConfigurations.release
}
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
val store = SharedPreferencesTracingConfigurationStore(prefs)
val builder = TargetLogLevelMapBuilder(
tracingConfigurationStore = store,
defaultConfig = if (BuildConfig.BUILD_TYPE == BuildType.NIGHTLY.name) {
TracingFilterConfigurations.nightly
} else {
TracingFilterConfigurations.debug
}
)
TracingConfiguration(
filterConfiguration = config,
writesToLogcat = false,
writesToFilesConfiguration = WriteToFilesConfiguration.Enabled(
directory = bugReporter.logDirectory().absolutePath,
filenamePrefix = "logs",
filenameSuffix = null,
// Keep a minimum of 1 week of log files.
numberOfFiles = 7 * 24,
)
filterConfiguration = TracingFilterConfigurations.custom(builder.getCurrentMap()),
writesToLogcat = BuildConfig.DEBUG,
writesToFilesConfiguration = defaultWriteToDiskConfiguration(bugReporter),
)
}
bugReporter.setCurrentTracingFilter(tracingConfiguration.filterConfiguration.filter)
@@ -69,5 +67,15 @@ class TracingInitializer : Initializer<Unit> {
Os.setenv("RUST_BACKTRACE", "1", true)
}
private fun defaultWriteToDiskConfiguration(bugReporter: BugReporter): WriteToFilesConfiguration.Enabled {
return WriteToFilesConfiguration.Enabled(
directory = bugReporter.logDirectory().absolutePath,
filenamePrefix = "logs",
filenameSuffix = null,
// Keep a minimum of 1 week of log files.
numberOfFiles = 7 * 24,
)
}
override fun dependencies(): List<Class<out Initializer<*>>> = mutableListOf()
}

5
changelog.d/3016.bugfix Normal file
View File

@@ -0,0 +1,5 @@
Fix tracing configuration in debug and nightlies:
- Debug will now write the logs to disk too.
- Nightly will be able to customise tracing filters.
- Improved the configure tracing and bug report screens.

View File

@@ -16,6 +16,7 @@
package io.element.android.features.preferences.impl.developer.tracing
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.WindowInsets
@@ -48,6 +49,7 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.aliasScreenTitle
import io.element.android.libraries.designsystem.theme.components.DropdownMenu
import io.element.android.libraries.designsystem.theme.components.DropdownMenuItem
import io.element.android.libraries.designsystem.theme.components.HorizontalDivider
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconButton
import io.element.android.libraries.designsystem.theme.components.ListItem
@@ -124,15 +126,17 @@ fun ConfigureTracingView(
.consumeWindowInsets(it)
.verticalScroll(state = rememberScrollState())
) {
CrateListContent(state)
ListItem(
headlineContent = {
Text(
text = "Kill and restart the app for the change to take effect.",
modifier = Modifier.clickable { Runtime.getRuntime().exit(0) },
text = "Tap here to kill the app and apply the changes. You'll have to re-open the app manually.",
style = ElementTheme.typography.fontHeadingSmMedium,
)
},
)
HorizontalDivider()
CrateListContent(state)
}
}
)

View File

@@ -18,14 +18,13 @@ package io.element.android.features.preferences.impl.developer.tracing
import io.element.android.libraries.matrix.api.tracing.LogLevel
import io.element.android.libraries.matrix.api.tracing.Target
import io.element.android.libraries.matrix.api.tracing.TracingFilterConfigurations
import io.element.android.libraries.matrix.api.tracing.TracingFilterConfiguration
import javax.inject.Inject
class TargetLogLevelMapBuilder @Inject constructor(
private val tracingConfigurationStore: TracingConfigurationStore,
private val defaultConfig: TracingFilterConfiguration,
) {
private val defaultConfig = TracingFilterConfigurations.debug
fun getDefaultMap(): Map<Target, LogLevel> {
return Target.entries.associateWith { target ->
defaultConfig.getLogLevel(target)

View File

@@ -22,6 +22,7 @@ import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.matrix.api.tracing.LogLevel
import io.element.android.libraries.matrix.api.tracing.Target
import io.element.android.libraries.matrix.api.tracing.TracingFilterConfigurations
import io.element.android.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.waitForPredicate
import kotlinx.coroutines.test.runTest
@@ -37,7 +38,7 @@ class ConfigureTracingPresenterTest {
val store = InMemoryTracingConfigurationStore()
val presenter = ConfigureTracingPresenter(
store,
TargetLogLevelMapBuilder(store),
TargetLogLevelMapBuilder(store, TracingFilterConfigurations.debug),
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
@@ -54,7 +55,7 @@ class ConfigureTracingPresenterTest {
store.givenLogLevel(LogLevel.ERROR)
val presenter = ConfigureTracingPresenter(
store,
TargetLogLevelMapBuilder(store),
TargetLogLevelMapBuilder(store, TracingFilterConfigurations.debug),
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
@@ -70,7 +71,7 @@ class ConfigureTracingPresenterTest {
val store = InMemoryTracingConfigurationStore()
val presenter = ConfigureTracingPresenter(
store,
TargetLogLevelMapBuilder(store),
TargetLogLevelMapBuilder(store, TracingFilterConfigurations.debug),
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
@@ -89,7 +90,7 @@ class ConfigureTracingPresenterTest {
val store = InMemoryTracingConfigurationStore()
val presenter = ConfigureTracingPresenter(
store,
TargetLogLevelMapBuilder(store),
TargetLogLevelMapBuilder(store, TracingFilterConfigurations.debug),
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()

View File

@@ -21,6 +21,7 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@@ -28,6 +29,8 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardCapitalization
@@ -51,6 +54,7 @@ import io.element.android.libraries.designsystem.preview.debugPlaceholderBackgro
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.onTabOrEnterKeyFocusNext
import io.element.android.libraries.ui.strings.CommonStrings
@Composable
@@ -68,6 +72,7 @@ fun BugReportView(
title = stringResource(id = CommonStrings.common_report_a_problem),
onBackClick = onBackClick
) {
val keyboardController = LocalSoftwareKeyboardController.current
val isFormEnabled = state.sending !is AsyncAction.Loading
var descriptionFieldState by textFieldState(
stateValue = state.formState.description
@@ -76,7 +81,8 @@ fun BugReportView(
PreferenceRow {
OutlinedTextField(
value = descriptionFieldState,
modifier = Modifier.fillMaxWidth(),
modifier = Modifier.fillMaxWidth()
.onTabOrEnterKeyFocusNext(LocalFocusManager.current),
enabled = isFormEnabled,
label = {
Text(text = stringResource(id = R.string.screen_bug_report_editor_placeholder))
@@ -91,8 +97,11 @@ fun BugReportView(
keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Sentences,
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
imeAction = ImeAction.Next,
),
keyboardActions = KeyboardActions(onNext = {
keyboardController?.hide()
}),
minLines = 3,
isError = state.isDescriptionInError,
)

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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
}
}
}