Feature/fga/rust sdk tracing (#1036)
* Align TracingConfiguration with iOS * Create TracingTree from rust sdk * tracing: create a working configuration with RustTracingTree * Tracing: WIP implementation of new api * Tracing: clean up * Tracing: use the latest api * Tracing: some more clean up * Remove generated logcat file after compressing it --------- Co-authored-by: ganfra <francoisg@element.io> Co-authored-by: Jorge Martín <jorgem@element.io>
This commit is contained in:
parent
f15817447c
commit
3f1d241b48
19 changed files with 455 additions and 162 deletions
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package io.element.android.features.rageshake.api.reporter
|
||||
|
||||
import java.io.File
|
||||
|
||||
interface BugReporter {
|
||||
/**
|
||||
* Send a bug report.
|
||||
|
|
@ -43,4 +45,14 @@ interface BugReporter {
|
|||
customFields: Map<String, String>? = null,
|
||||
listener: BugReporterListener?
|
||||
)
|
||||
|
||||
/**
|
||||
* Clean the log files if needed to avoid wasting disk space.
|
||||
*/
|
||||
fun cleanLogDirectoryIfNeeded()
|
||||
|
||||
/**
|
||||
* Provide the log directory.
|
||||
*/
|
||||
fun logDirectory(): File
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ anvil {
|
|||
dependencies {
|
||||
implementation(projects.anvilannotations)
|
||||
anvil(projects.anvilcodegen)
|
||||
implementation(projects.services.toolbox.api)
|
||||
implementation(projects.libraries.androidutils)
|
||||
implementation(projects.libraries.core)
|
||||
implementation(projects.libraries.network)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package io.element.android.features.rageshake.impl.reporter
|
|||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.text.format.DateUtils.DAY_IN_MILLIS
|
||||
import androidx.core.net.toFile
|
||||
import androidx.core.net.toUri
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
|
|
@ -27,10 +28,10 @@ import io.element.android.features.rageshake.api.reporter.BugReporterListener
|
|||
import io.element.android.features.rageshake.api.reporter.ReportType
|
||||
import io.element.android.features.rageshake.api.screenshot.ScreenshotHolder
|
||||
import io.element.android.features.rageshake.impl.R
|
||||
import io.element.android.features.rageshake.impl.logs.VectorFileLogger
|
||||
import io.element.android.libraries.androidutils.file.compressFile
|
||||
import io.element.android.libraries.androidutils.file.safeDelete
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.core.data.tryOrNull
|
||||
import io.element.android.libraries.core.extensions.toOnOff
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.core.mimetype.MimeTypes
|
||||
|
|
@ -38,7 +39,10 @@ import io.element.android.libraries.di.AppScope
|
|||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.network.useragent.UserAgentProvider
|
||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.Call
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
|
|
@ -65,6 +69,8 @@ class DefaultBugReporter @Inject constructor(
|
|||
@ApplicationContext private val context: Context,
|
||||
private val screenshotHolder: ScreenshotHolder,
|
||||
private val crashDataStore: CrashDataStore,
|
||||
private val coroutineScope: CoroutineScope,
|
||||
private val systemClock: SystemClock,
|
||||
private val coroutineDispatchers: CoroutineDispatchers,
|
||||
private val okHttpClient: Provider<OkHttpClient>,
|
||||
private val userAgentProvider: UserAgentProvider,
|
||||
|
|
@ -87,6 +93,7 @@ class DefaultBugReporter @Inject constructor(
|
|||
// filenames
|
||||
private const val LOG_CAT_ERROR_FILENAME = "logcatError.log"
|
||||
private const val LOG_CAT_FILENAME = "logcat.log"
|
||||
private const val LOG_DIRECTORY_NAME = "logs"
|
||||
// private const val KEY_REQUESTS_FILENAME = "keyRequests.log"
|
||||
|
||||
private const val BUFFER_SIZE = 1024 * 1024 * 50
|
||||
|
|
@ -158,9 +165,8 @@ class DefaultBugReporter @Inject constructor(
|
|||
|
||||
val gzippedFiles = ArrayList<File>()
|
||||
|
||||
val vectorFileLogger = VectorFileLogger.getFromTimber()
|
||||
if (withDevicesLogs && vectorFileLogger != null) {
|
||||
val files = vectorFileLogger.getLogFiles()
|
||||
if (withDevicesLogs) {
|
||||
val files = getLogFiles()
|
||||
files.mapNotNullTo(gzippedFiles) { f ->
|
||||
if (!mIsCancelled) {
|
||||
compressFile(f)
|
||||
|
|
@ -168,6 +174,7 @@ class DefaultBugReporter @Inject constructor(
|
|||
null
|
||||
}
|
||||
}
|
||||
files.deleteAllExceptMostRecent()
|
||||
}
|
||||
|
||||
if (!mIsCancelled && (withCrashLogs || withDevicesLogs)) {
|
||||
|
|
@ -458,6 +465,54 @@ class DefaultBugReporter @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
override fun logDirectory(): File {
|
||||
return File(context.cacheDir, LOG_DIRECTORY_NAME)
|
||||
}
|
||||
|
||||
override fun cleanLogDirectoryIfNeeded() {
|
||||
coroutineScope.launch(coroutineDispatchers.io) {
|
||||
// delete the log files older than 1 day, except the most recent one
|
||||
deleteOldLogFiles(systemClock.epochMillis() - DAY_IN_MILLIS)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the files on the log directory.
|
||||
*/
|
||||
private fun getLogFiles(): List<File> {
|
||||
return tryOrNull(
|
||||
onError = { Timber.e(it, "## getLogFiles() failed") }
|
||||
) {
|
||||
val logDirectory = logDirectory()
|
||||
logDirectory.listFiles()?.toList()
|
||||
}.orEmpty()
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the log files older than the given time except the most recent one.
|
||||
* @param time the time in ms
|
||||
*/
|
||||
private fun deleteOldLogFiles(time: Long) {
|
||||
val logFiles = getLogFiles()
|
||||
val oldLogFiles = logFiles.filter { it.lastModified() < time }
|
||||
oldLogFiles.deleteAllExceptMostRecent()
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all the log files except the most recent one.
|
||||
*
|
||||
*/
|
||||
private fun List<File>.deleteAllExceptMostRecent() {
|
||||
if (size > 1) {
|
||||
val mostRecentFile = maxByOrNull { it.lastModified() }
|
||||
forEach { file ->
|
||||
if (file != mostRecentFile) {
|
||||
file.safeDelete()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================================================================================
|
||||
// Logcat management
|
||||
// ==============================================================================================================
|
||||
|
|
@ -485,6 +540,10 @@ class DefaultBugReporter @Inject constructor(
|
|||
Timber.e(error, "## saveLogCat() : fail to write logcat OOM")
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## saveLogCat() : fail to write logcat")
|
||||
} finally {
|
||||
if (logCatErrFile.exists()) {
|
||||
logCatErrFile.safeDelete()
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import io.element.android.features.rageshake.api.reporter.BugReporterListener
|
|||
import io.element.android.features.rageshake.api.reporter.ReportType
|
||||
import io.element.android.libraries.matrix.test.A_FAILURE_REASON
|
||||
import kotlinx.coroutines.delay
|
||||
import java.io.File
|
||||
|
||||
class FakeBugReporter(val mode: FakeBugReporterMode = FakeBugReporterMode.Success) : BugReporter {
|
||||
override suspend fun sendBugReport(
|
||||
|
|
@ -55,6 +56,14 @@ class FakeBugReporter(val mode: FakeBugReporterMode = FakeBugReporterMode.Succes
|
|||
delay(100)
|
||||
listener?.onUploadSucceed(null)
|
||||
}
|
||||
|
||||
override fun cleanLogDirectoryIfNeeded() {
|
||||
// No op
|
||||
}
|
||||
|
||||
override fun logDirectory(): File {
|
||||
return File("fake")
|
||||
}
|
||||
}
|
||||
|
||||
enum class FakeBugReporterMode {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue