From 5dddf32689077e8084d5fc14006295d076365ef0 Mon Sep 17 00:00:00 2001 From: F0x1d Date: Tue, 6 Feb 2024 21:05:03 +0300 Subject: [PATCH] [hotfix]: save all logs feature --- app/build.gradle | 4 +- .../f0x1d/logfox/extensions/UriExtensions.kt | 1 + .../extensions/logline/LogLineExtensions.kt | 58 ++++++++++--------- .../repository/logging/LoggingRepository.kt | 6 +- .../logging/RecordingsRepository.kt | 38 +++++++----- .../recordings/RecordingsViewModel.kt | 3 + app/src/main/res/values-ru/strings.xml | 2 + app/src/main/res/values-zh-rCN/strings.xml | 3 + app/src/main/res/values/strings.xml | 2 + 9 files changed, 73 insertions(+), 44 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index f54b1042..08b7a0ed 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,8 +18,8 @@ android { applicationId "com.f0x1d.logfox" minSdk 24 targetSdk 34 - versionCode 57 - versionName "1.5.5" + versionCode 58 + versionName "1.5.6" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/java/com/f0x1d/logfox/extensions/UriExtensions.kt b/app/src/main/java/com/f0x1d/logfox/extensions/UriExtensions.kt index 19eb7068..e6f4b2fe 100644 --- a/app/src/main/java/com/f0x1d/logfox/extensions/UriExtensions.kt +++ b/app/src/main/java/com/f0x1d/logfox/extensions/UriExtensions.kt @@ -44,6 +44,7 @@ fun Uri?.readFileContentsAsFlow(context: Context) = flow { } ?: emit(emptyList()) } }.flowOn(Dispatchers.IO).catch { + it.printStackTrace() emit(emptyList()) } diff --git a/app/src/main/java/com/f0x1d/logfox/extensions/logline/LogLineExtensions.kt b/app/src/main/java/com/f0x1d/logfox/extensions/logline/LogLineExtensions.kt index ea878bb1..2a160fe0 100644 --- a/app/src/main/java/com/f0x1d/logfox/extensions/logline/LogLineExtensions.kt +++ b/app/src/main/java/com/f0x1d/logfox/extensions/logline/LogLineExtensions.kt @@ -6,7 +6,7 @@ import com.f0x1d.logfox.model.LogLevel import com.f0x1d.logfox.model.LogLine import com.f0x1d.logfox.utils.UIDS -private val logRegex = "(.{14}) (.{1,5}) (.{1,5}) (.{1,5}) (.) (.+?): (.+)".toRegex() +private val logRegex = "(.{14}) (.{5,}?) (.{1,5}) (.{1,5}) (.) (.+?): (.+)".toRegex() // time, uid, pid, tid, level, tag, message private val uidRegex = "u(.+?).*a(.+)".toRegex() @@ -16,37 +16,41 @@ fun LogLine( id: Long, line: String, context: Context -) = logRegex.find(line.trim())?.run { - val uid = groupValues[2].replace(" ", "") - val integerUid = uid.toIntOrNull() ?: UIDS.MAPPINGS[uid] ?: uidRegex.find(uid)?.run { - 100_000 * groupValues[1].toInt() + 10_000 + groupValues[2].toInt() - } +) = runCatching { + logRegex.find(line.trim())?.run { + val uid = groupValues[2].replace(" ", "") + val integerUid = uid.toIntOrNull() ?: UIDS.MAPPINGS[uid] ?: uidRegex.find(uid)?.run { + 100_000 * groupValues[1].toInt() + 10_000 + groupValues[2].toInt() + } - val packageName = uidsCache[uid] ?: integerUid?.let { - context.packageManager.getPackagesForUid(it)?.firstOrNull()?.also { packageName -> - uidsCache.put(uid, packageName) + val packageName = uidsCache[uid] ?: integerUid?.let { + runCatching { + context.packageManager.getPackagesForUid(it)?.firstOrNull()?.also { packageName -> + uidsCache.put(uid, packageName) + } + }.getOrNull() } - } - val time = groupValues[1].replace(" ", "").run { - indexOf(".").let { - substring(0, it).toLong() * 1000 + substring(it + 1).toLong() + val time = groupValues[1].replace(" ", "").run { + indexOf(".").let { + substring(0, it).toLong() * 1000 + substring(it + 1).toLong() + } } - } - LogLine( - id, - time, - uid, - groupValues[3].replace(" ", ""), - groupValues[4].replace(" ", ""), - packageName, - mapLevel(groupValues[5]), - groupValues[6].trim(), - groupValues[7], - groupValues[0] - ) -} + LogLine( + id, + time, + uid, + groupValues[3].replace(" ", ""), + groupValues[4].replace(" ", ""), + packageName, + mapLevel(groupValues[5]), + groupValues[6].trim(), + groupValues[7], + groupValues[0] + ) + } +}.getOrNull() private fun mapLevel(level: String) = LogLevel.entries.find { it.letter == level diff --git a/app/src/main/java/com/f0x1d/logfox/repository/logging/LoggingRepository.kt b/app/src/main/java/com/f0x1d/logfox/repository/logging/LoggingRepository.kt index 8aef469a..965a57ff 100644 --- a/app/src/main/java/com/f0x1d/logfox/repository/logging/LoggingRepository.kt +++ b/app/src/main/java/com/f0x1d/logfox/repository/logging/LoggingRepository.kt @@ -40,8 +40,10 @@ class LoggingRepository @Inject constructor( ): BaseRepository(), SharedPreferences.OnSharedPreferenceChangeListener { companion object { - private val COMMAND = arrayOf("logcat" , "-v", "uid", "-v", "epoch") - private val SHOW_LOGS_FROM_NOW_FLAGS = arrayOf("-T", "1") + val COMMAND = arrayOf("logcat" , "-v", "uid", "-v", "epoch") + + val DUMP_FLAG = arrayOf("-d") + val SHOW_LOGS_FROM_NOW_FLAGS = arrayOf("-T", "1") } val logsFlow = MutableStateFlow(emptyList()) diff --git a/app/src/main/java/com/f0x1d/logfox/repository/logging/RecordingsRepository.kt b/app/src/main/java/com/f0x1d/logfox/repository/logging/RecordingsRepository.kt index 47f8b350..5c78e405 100644 --- a/app/src/main/java/com/f0x1d/logfox/repository/logging/RecordingsRepository.kt +++ b/app/src/main/java/com/f0x1d/logfox/repository/logging/RecordingsRepository.kt @@ -4,6 +4,7 @@ import android.content.Context import com.f0x1d.logfox.R import com.f0x1d.logfox.database.AppDatabase import com.f0x1d.logfox.database.entity.LogRecording +import com.f0x1d.logfox.extensions.context.toast import com.f0x1d.logfox.extensions.notifications.cancelRecordingNotification import com.f0x1d.logfox.extensions.notifications.sendRecordingNotification import com.f0x1d.logfox.extensions.notifications.sendRecordingPausedNotification @@ -12,8 +13,9 @@ import com.f0x1d.logfox.extensions.runOnAppScope import com.f0x1d.logfox.model.LogLine import com.f0x1d.logfox.repository.logging.base.LoggingHelperItemsRepository import com.f0x1d.logfox.repository.logging.readers.recordings.RecordingWithFiltersReader -import com.f0x1d.logfox.repository.logging.readers.recordings.base.RecordingReader import com.f0x1d.logfox.utils.DateTimeFormatter +import com.f0x1d.logfox.utils.preferences.AppPreferences +import com.f0x1d.logfox.utils.terminal.base.Terminal import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -23,6 +25,7 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.update import kotlinx.coroutines.withContext import java.io.File +import java.io.FileOutputStream import javax.inject.Inject import javax.inject.Singleton @@ -32,20 +35,19 @@ class RecordingsRepository @Inject constructor( private val database: AppDatabase, private val dateTimeFormatter: DateTimeFormatter, private val recordingReader: RecordingWithFiltersReader, - private val allRecordingReader: RecordingReader + private val appPreferences: AppPreferences, + private val terminals: Array ): LoggingHelperItemsRepository() { val recordingStateFlow = MutableStateFlow(RecordingState.IDLE) override val readers = listOf( - recordingReader, - allRecordingReader + recordingReader ) private val recordingDir = File("${context.filesDir.absolutePath}/recordings").apply { if (!exists()) mkdirs() } - private val allRecordingFile = File(recordingDir, "all.log") private var filtersJob: Job? = null @@ -59,8 +61,7 @@ class RecordingsRepository @Inject constructor( } } - allRecordingFile.delete() - allRecordingReader.record(allRecordingFile) + File(recordingDir, "all.log").delete() } override suspend fun stop() { @@ -72,22 +73,33 @@ class RecordingsRepository @Inject constructor( recordingStateFlow.update { RecordingState.IDLE } recordingReader.clearLines() - allRecordingReader.updateRecording(false) - allRecordingReader.clearLines() - filtersJob?.cancel() } fun saveAll(recordingSaved: (LogRecording) -> Unit = {}) = runOnAppScope { - allRecordingReader.dumpLines() - val recordingTime = System.currentTimeMillis() val recordingFile = File( recordingDir, "${dateTimeFormatter.formatForExport(recordingTime)}.log" ) - allRecordingReader.copyFileTo(recordingFile) + val command = LoggingRepository.COMMAND + LoggingRepository.DUMP_FLAG + val process = terminals[appPreferences.selectedTerminalIndex].execute(*command) + + try { + FileOutputStream(recordingFile, true).use { out -> + process?.output?.bufferedReader()?.useLines { + for (line in it) { + out.write((line + "\n").encodeToByteArray()) + } + } + } + } catch (e: Exception) { + withContext(Dispatchers.Main) { + context.toast(R.string.error_saving_logs) + } + e.printStackTrace() + } val logRecording = LogRecording( "${context.getString(R.string.record_file)} ${database.logRecordingDao().count() + 1}", diff --git a/app/src/main/java/com/f0x1d/logfox/viewmodel/recordings/RecordingsViewModel.kt b/app/src/main/java/com/f0x1d/logfox/viewmodel/recordings/RecordingsViewModel.kt index a32caf76..464021e1 100644 --- a/app/src/main/java/com/f0x1d/logfox/viewmodel/recordings/RecordingsViewModel.kt +++ b/app/src/main/java/com/f0x1d/logfox/viewmodel/recordings/RecordingsViewModel.kt @@ -2,6 +2,7 @@ package com.f0x1d.logfox.viewmodel.recordings import android.app.Application import androidx.lifecycle.asLiveData +import com.f0x1d.logfox.R import com.f0x1d.logfox.database.AppDatabase import com.f0x1d.logfox.database.entity.LogRecording import com.f0x1d.logfox.extensions.sendEvent @@ -56,6 +57,8 @@ class RecordingsViewModel @Inject constructor( fun saveAll() = recordingsRepository.saveAll { sendEvent(EVENT_TYPE_RECORDING_SAVED, it) + }.also { + snackbar(R.string.saving_logs) } fun delete(logRecording: LogRecording) = recordingsRepository.delete(logRecording) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index e3ea810a..73d069dc 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -135,4 +135,6 @@ Сейчас фильтров нет Показывать только логи, появившиеся с момента запуска приложения Сохранить все логи + Сохраняем логи, это может занять много времени… + Ошибка при сохранении логов \ No newline at end of file diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index daf9bbec..819a1b3d 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -135,4 +135,7 @@ 目前没有录制 目前没有过滤器 只显示 app 启动后的日志 + 保存完整日志 + 正在保存日志,这可能需要一点时间… + 保存日志时发生错误 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b3554226..90469c34 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -145,4 +145,6 @@ There are currently no filters Show only logs which have appeared since the app launch Save all logs + Saving logs, this may take some time… + Error saving logs \ No newline at end of file