Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6411042f authored by Ashley's avatar Ashley
Browse files

Add Mail sync debug logging

parent 4509e2f6
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -4,5 +4,11 @@ import org.koin.dsl.module

val loggingModule = module {
    factory<ProcessExecutor> { RealProcessExecutor() }
    factory<LogFileWriter> { LogcatLogFileWriter(contentResolver = get(), processExecutor = get()) }
    factory<LogFileWriter> {
        MultiLogFileWriter(
            contentResolver = get(),
            processExecutor = get(),
            context = get(),
        )
    }
}
+30 −14
Original line number Diff line number Diff line
package net.thunderbird.core.android.logging

import android.content.ContentResolver
import android.content.Context
import android.net.Uri
import android.provider.OpenableColumns
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@@ -12,23 +14,35 @@ interface LogFileWriter {
    suspend fun writeLogTo(contentUri: Uri)
}

class LogcatLogFileWriter(
class MultiLogFileWriter(
    private val contentResolver: ContentResolver,
    private val processExecutor: ProcessExecutor,
    private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO,
    private val context: Context?,
) : LogFileWriter {
    override suspend fun writeLogTo(contentUri: Uri) {
        return withContext(coroutineDispatcher) {
            writeLogBlocking(contentUri)
            Timber.v("Writing output to content URI: %s", contentUri)
            var uriString = ""
            contentResolver.query(contentUri, null, null, null, null)?.use { cursor ->
                val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
                cursor.moveToFirst()
                uriString = cursor.getString(nameIndex)
            }
    }

    private fun writeLogBlocking(contentUri: Uri) {
        Timber.v("Writing logcat output to content URI: %s", contentUri)

            val outputStream = contentResolver.openOutputStream(contentUri, "wt")
                ?: error("Error opening contentUri for writing")

            if (uriString.contains("thunderbird-sync-logs")) {
                outputStream.use {
                    try {
                        context?.openFileInput("thunderbird-sync-logs.txt").use { inputStream ->
                            IOUtils.copy(inputStream, outputStream)
                        }
                    } catch (e: FileSystemException) {
                        println(e)
                    }
                }
                context?.openFileOutput("thunderbird-sync-logs.txt", Context.MODE_PRIVATE)?.bufferedWriter()?.write("")
            } else {
                outputStream.use {
                    processExecutor.exec("logcat -d").use { inputStream ->
                        IOUtils.copy(inputStream, outputStream)
@@ -36,3 +50,5 @@ class LogcatLogFileWriter(
                }
            }
        }
    }
}
+6 −3
Original line number Diff line number Diff line
@@ -23,10 +23,11 @@ class LogcatLogFileWriterTest {
    @Test
    fun `write log to contentUri`() = runBlocking {
        val logData = "a".repeat(10_000)
        val logFileWriter = LogcatLogFileWriter(
        val logFileWriter = MultiLogFileWriter(
            contentResolver = createContentResolver(),
            processExecutor = createProcessExecutor(logData),
            coroutineDispatcher = Dispatchers.Unconfined,
            context = null,
        )

        logFileWriter.writeLogTo(contentUri)
@@ -36,10 +37,11 @@ class LogcatLogFileWriterTest {

    @Test(expected = FileNotFoundException::class)
    fun `contentResolver throws`() = runBlocking {
        val logFileWriter = LogcatLogFileWriter(
        val logFileWriter = MultiLogFileWriter(
            contentResolver = createThrowingContentResolver(FileNotFoundException()),
            processExecutor = createProcessExecutor("irrelevant"),
            coroutineDispatcher = Dispatchers.Unconfined,
            context = null,
        )

        logFileWriter.writeLogTo(contentUri)
@@ -47,10 +49,11 @@ class LogcatLogFileWriterTest {

    @Test(expected = IOException::class)
    fun `processExecutor throws`() = runBlocking {
        val logFileWriter = LogcatLogFileWriter(
        val logFileWriter = MultiLogFileWriter(
            contentResolver = createContentResolver(),
            processExecutor = ThrowingProcessExecutor(IOException()),
            coroutineDispatcher = Dispatchers.Unconfined,
            context = null,
        )

        logFileWriter.writeLogTo(contentUri)
+2 −1
Original line number Diff line number Diff line
@@ -24,7 +24,8 @@ androidxAutofill = "1.3.0-rc01"
androidxBiometric = "1.1.0"
androidxCamera = "1.4.2"
# https://developer.android.com/jetpack/compose/bom/bom-mapping
androidxComposeBom = "2025.04.01"
androidxComposeBom = "2025.02.00"
androidxComposeUi = "1.8.0-rc02"
androidxConstraintLayout = "2.2.1"
androidxCoordinatorLayout = "1.3.0"
androidxCore = "1.16.0"
+65 −0
Original line number Diff line number Diff line
package com.fsck.k9

import android.content.Context
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicReference
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import timber.log.Timber

class FileLoggerTree(private val context: Context) : Timber.Tree() {
    private val coroutineContext: CoroutineContext = Dispatchers.IO
    private val coroutineScope = CoroutineScope(coroutineContext + SupervisorJob())

    private val writeFile = AtomicReference<File>()
    private val accumulatedLogs = ConcurrentHashMap<String, String>()

    override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
        if (message.contains("sync")) {
            try {
                accumulatedLogs[convertLongToTime(System.currentTimeMillis())] = "priority = $priority, $message"
                createLogFile()
            } catch (e: FileSystemException) {
                Timber.e(" Error while logging into file: $e")
            }
        }
    }

    private fun createLogFile() =
        coroutineScope.launch {
            writeFile.lazySet(
                context.createFile(fileName = "$DEFAULT_SYNC_FILENAME.txt"),
            )
            writeToLogFile()
        }

    private suspend fun writeToLogFile() {
        val result = runCatching {
            writeFile.get().bufferedWriter().use { it.write(accumulatedLogs.toString()) }
        }
        if (result.isFailure) {
            result.exceptionOrNull()?.printStackTrace()
        }
    }

    private fun convertLongToTime(long: Long): String {
        val date = Date(long)
        val format = SimpleDateFormat(ANDROID_LOG_TIME_FORMAT, Locale.US)
        return format.format(date)
    }
    companion object {
        private const val ANDROID_LOG_TIME_FORMAT = "MM-dd-yy kk:mm:ss.SSS"
        const val DEFAULT_SYNC_FILENAME = "thunderbird-sync-logs"
    }

    private fun Context.createFile(fileName: String): File {
        return File(filesDir, fileName)
    }
}
Loading