diff --git a/appconfig/src/main/kotlin/io/element/android/appconfig/ApplicationConfig.kt b/appconfig/src/main/kotlin/io/element/android/appconfig/ApplicationConfig.kt index 21af158ad6..e8a8a2b33a 100644 --- a/appconfig/src/main/kotlin/io/element/android/appconfig/ApplicationConfig.kt +++ b/appconfig/src/main/kotlin/io/element/android/appconfig/ApplicationConfig.kt @@ -40,4 +40,9 @@ object ApplicationConfig { * For Element, the value is "Element". We use the same name for desktop and mobile for now. */ const val DESKTOP_APPLICATION_NAME: String = "Element" + + /** + * The maximum size of the upload request. Default value is just below CloudFlare's max request size. + */ + const val MAX_LOG_UPLOAD_SIZE = 50 * 1024 * 1024L } diff --git a/changelog.d/2825.bugfix b/changelog.d/2825.bugfix new file mode 100644 index 0000000000..786464f40d --- /dev/null +++ b/changelog.d/2825.bugfix @@ -0,0 +1 @@ +Make log less verbose, make sure we upload as many log files as possible before reaching the request size limit of the bug reporting service, discard older logs if they don't fit. diff --git a/features/rageshake/impl/build.gradle.kts b/features/rageshake/impl/build.gradle.kts index fdc8e803f7..6ac0776d0a 100644 --- a/features/rageshake/impl/build.gradle.kts +++ b/features/rageshake/impl/build.gradle.kts @@ -38,6 +38,7 @@ anvil { dependencies { implementation(projects.anvilannotations) anvil(projects.anvilcodegen) + implementation(projects.appconfig) implementation(projects.services.toolbox.api) implementation(projects.libraries.androidutils) implementation(projects.libraries.core) diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenter.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenter.kt index 1fd8526458..5eeb078275 100644 --- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenter.kt +++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenter.kt @@ -96,6 +96,7 @@ class BugReportPresenter @Inject constructor( if (formState.value.description.length < 10) { sendingAction.value = AsyncAction.Failure(BugReportFormError.DescriptionTooShort) } else { + sendingAction.value = AsyncAction.Loading appCoroutineScope.sendBugReport(formState.value, crashInfo.isNotEmpty(), uploadListener) } } diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporter.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporter.kt index f81a755bd0..468d9bc1f4 100755 --- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporter.kt +++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporter.kt @@ -21,6 +21,7 @@ import android.os.Build import androidx.core.net.toFile import androidx.core.net.toUri import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.appconfig.ApplicationConfig import io.element.android.features.rageshake.api.crash.CrashDataStore import io.element.android.features.rageshake.api.reporter.BugReporter import io.element.android.features.rageshake.api.reporter.BugReporterListener @@ -83,7 +84,6 @@ class DefaultBugReporter @Inject constructor( // filenames private const val LOG_CAT_FILENAME = "logcat.log" private const val LOG_DIRECTORY_NAME = "logs" - private const val BUFFER_SIZE = 1024 * 1024 * 50 } // the pending bug report call @@ -120,7 +120,7 @@ class DefaultBugReporter @Inject constructor( val gzippedFiles = ArrayList() if (withDevicesLogs) { - val files = getLogFiles() + val files = getLogFiles().sortedByDescending { it.lastModified() } files.mapNotNullTo(gzippedFiles) { f -> when { isCancelled -> null @@ -135,7 +135,7 @@ class DefaultBugReporter @Inject constructor( saveLogCat() val gzippedLogcat = compressFile(logCatErrFile) if (null != gzippedLogcat) { - if (gzippedFiles.size == 0) { + if (gzippedFiles.isEmpty()) { gzippedFiles.add(gzippedLogcat) } else { gzippedFiles.add(0, gzippedLogcat) @@ -166,10 +166,18 @@ class DefaultBugReporter @Inject constructor( } // add the gzipped files, don't cancel the whole upload if only some file failed to upload + var totalUploadedSize = 0L var uploadedSomeLogs = false for (file in gzippedFiles) { try { - builder.addFormDataPart("compressed-log", file.name, file.asRequestBody(MimeTypes.OctetStream.toMediaTypeOrNull())) + val requestBody = file.asRequestBody(MimeTypes.OctetStream.toMediaTypeOrNull()) + totalUploadedSize += requestBody.contentLength() + // If we are about to upload more than the max request size, stop here + if (totalUploadedSize > ApplicationConfig.MAX_LOG_UPLOAD_SIZE) { + Timber.e("Could not upload file ${file.name} because it would exceed the max request size") + break + } + builder.addFormDataPart("compressed-log", file.name, requestBody) uploadedSomeLogs = true } catch (e: CancellationException) { throw e @@ -411,7 +419,7 @@ class DefaultBugReporter @Inject constructor( val separator = System.getProperty("line.separator") logcatProc.inputStream .reader() - .buffered(BUFFER_SIZE) + .buffered(ApplicationConfig.MAX_LOG_UPLOAD_SIZE.toInt()) .forEachLine { line -> streamWriter.append(line) streamWriter.append(separator) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/tracing/TracingFilterConfiguration.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/tracing/TracingFilterConfiguration.kt index 222017255a..84d4d61da5 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/tracing/TracingFilterConfiguration.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/tracing/TracingFilterConfiguration.kt @@ -27,9 +27,9 @@ data class TracingFilterConfiguration( 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.TRACE, - Target.MATRIX_SDK_BASE_SLIDING_SYNC to LogLevel.TRACE, - Target.MATRIX_SDK_UI_TIMELINE to LogLevel.TRACE, + 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, ) fun getLogLevel(target: Target): LogLevel {