mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 02:34:39 +00:00
fix: Add modified version of RollingFileLogWriter
This commit is contained in:
parent
5fa5815541
commit
d7160db53a
5 changed files with 175 additions and 50 deletions
|
@ -56,21 +56,19 @@ import eu.kanade.tachiyomi.util.system.GLUtil
|
|||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import eu.kanade.tachiyomi.util.system.launchIO
|
||||
import eu.kanade.tachiyomi.util.system.localeContext
|
||||
import eu.kanade.tachiyomi.util.system.nameWithoutExtension
|
||||
import eu.kanade.tachiyomi.util.system.notification
|
||||
import eu.kanade.tachiyomi.util.system.setToDefault
|
||||
import eu.kanade.tachiyomi.util.system.setupFileLog
|
||||
import java.security.Security
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.io.files.Path
|
||||
import org.conscrypt.Conscrypt
|
||||
import org.koin.core.context.startKoin
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import yokai.core.CrashlyticsLogWriter
|
||||
import yokai.core.RollingUniFileLogWriter
|
||||
import yokai.core.di.appModule
|
||||
import yokai.core.di.domainModule
|
||||
import yokai.core.di.preferenceModule
|
||||
|
@ -113,7 +111,7 @@ open class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.F
|
|||
|
||||
val scope = ProcessLifecycleOwner.get().lifecycleScope
|
||||
|
||||
Logger.setToDefault(buildLogWritersToAdd(storageManager.getLogsFile()))
|
||||
Logger.setToDefault(buildLogWritersToAdd(storageManager.getLogsDirectory()))
|
||||
|
||||
basePreferences.crashReport().changes()
|
||||
.onEach {
|
||||
|
@ -284,18 +282,11 @@ open class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.F
|
|||
}
|
||||
|
||||
fun buildLogWritersToAdd(
|
||||
logFile: UniFile?,
|
||||
logPath: UniFile?,
|
||||
) = buildList {
|
||||
if (!BuildConfig.DEBUG) add(CrashlyticsLogWriter())
|
||||
|
||||
//val fileName = logFile?.nameWithoutExtension
|
||||
//val filePath = logFile?.parentFile?.filePath?.let { path -> Path(path) }
|
||||
//if (filePath != null && fileName != null) add(
|
||||
// Logger.setupFileLog(
|
||||
// logFileName = fileName,
|
||||
// logPath = filePath,
|
||||
// )
|
||||
//)
|
||||
if (logPath != null) add(RollingUniFileLogWriter(logPath))
|
||||
}
|
||||
|
||||
private const val ACTION_DISABLE_INCOGNITO_MODE = "tachi.action.DISABLE_INCOGNITO_MODE"
|
||||
|
|
160
app/src/main/java/yokai/core/RollingUniFileLogWriter.kt
Normal file
160
app/src/main/java/yokai/core/RollingUniFileLogWriter.kt
Normal file
|
@ -0,0 +1,160 @@
|
|||
package yokai.core
|
||||
|
||||
import co.touchlab.kermit.DefaultFormatter
|
||||
import co.touchlab.kermit.LogWriter
|
||||
import co.touchlab.kermit.Message
|
||||
import co.touchlab.kermit.MessageStringFormatter
|
||||
import co.touchlab.kermit.Severity
|
||||
import co.touchlab.kermit.Tag
|
||||
import com.hippo.unifile.UniFile
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.util.system.launchIO
|
||||
import eu.kanade.tachiyomi.util.system.withIOContext
|
||||
import java.io.IOException
|
||||
import java.text.DateFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.CoroutineName
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.trySendBlocking
|
||||
import kotlinx.coroutines.currentCoroutineContext
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.newSingleThreadContext
|
||||
|
||||
/**
|
||||
* Copyright (c) 2024 Touchlab
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Kermit's RollingFileLogWriter, modified to use UniFile since using KotlinX IO's FileSystem keep throwing
|
||||
* "Permission Denied". Also added try-catch, in case "Permission Denied" is back to haunt me
|
||||
*
|
||||
* REF: https://github.com/touchlab/Kermit/blob/c9af0b7d3344b430f4ed2668e74d02f34ba1905a/kermit-io/src/commonMain/kotlin/co/touchlab/kermit/io/RollingFileLogWriter.kt
|
||||
*/
|
||||
class RollingUniFileLogWriter(
|
||||
private val logPath: UniFile,
|
||||
private val rollOnSize: Long = 10 * 1024 * 1024, // 10MB
|
||||
private val maxLogFiles: Int = 5,
|
||||
private val messageStringFormatter: MessageStringFormatter = DefaultFormatter,
|
||||
private val messageDateFormat: DateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault())
|
||||
) : LogWriter() {
|
||||
@OptIn(DelicateCoroutinesApi::class, ExperimentalCoroutinesApi::class)
|
||||
private val coroutineScope = CoroutineScope(
|
||||
newSingleThreadContext("RollingUniFileLogWriter") +
|
||||
SupervisorJob() +
|
||||
CoroutineName("RollingUniFileLogWriter") +
|
||||
CoroutineExceptionHandler { _, throwable ->
|
||||
println("RollingUniFileLogWriter: Uncaught exception in writer coroutine")
|
||||
throwable.printStackTrace()
|
||||
}
|
||||
)
|
||||
|
||||
private val loggingChannel: Channel<ByteArray> = Channel()
|
||||
|
||||
init {
|
||||
coroutineScope.launchIO {
|
||||
writer()
|
||||
}
|
||||
}
|
||||
|
||||
override fun log(severity: Severity, message: String, tag: String, throwable: Throwable?) {
|
||||
bufferLog(
|
||||
formatMessage(
|
||||
severity = severity,
|
||||
tag = Tag(tag),
|
||||
message = Message(message),
|
||||
), throwable
|
||||
)
|
||||
}
|
||||
|
||||
private fun bufferLog(message: String, throwable: Throwable?) {
|
||||
val log = buildString {
|
||||
append(messageDateFormat.format(Date()))
|
||||
append(" ")
|
||||
appendLine(message)
|
||||
if (throwable != null) {
|
||||
appendLine(throwable.stackTraceToString())
|
||||
}
|
||||
}
|
||||
loggingChannel.trySendBlocking(log.toByteArray())
|
||||
}
|
||||
|
||||
private fun formatMessage(severity: Severity, tag: Tag?, message: Message): String =
|
||||
messageStringFormatter.formatMessage(severity, tag, message)
|
||||
|
||||
private fun maybeRollLogs(size: Long): Boolean {
|
||||
return if (size > rollOnSize) {
|
||||
rollLogs()
|
||||
true
|
||||
} else false
|
||||
}
|
||||
|
||||
private fun rollLogs() {
|
||||
if (pathForLogIndex(maxLogFiles - 1)?.exists() == true) {
|
||||
pathForLogIndex(maxLogFiles - 1)?.delete()
|
||||
}
|
||||
|
||||
(0..<(maxLogFiles - 1)).reversed().forEach {
|
||||
val sourcePath = pathForLogIndex(it)
|
||||
val targetFileName = fileNameForLogIndex(it + 1)
|
||||
if (sourcePath?.exists() == true) {
|
||||
try {
|
||||
sourcePath.renameTo(targetFileName)
|
||||
} catch (e: Exception) {
|
||||
println("RollingUniFileLogWriter: Failed to roll log file ${sourcePath.filePath} to $targetFileName (sourcePath exists=${sourcePath.exists()})")
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fileNameForLogIndex(index: Int): String {
|
||||
val date = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date())
|
||||
return if (index == 0) "${date}-${BuildConfig.BUILD_TYPE}.log" else "${date}-${BuildConfig.BUILD_TYPE} (${index}).log"
|
||||
}
|
||||
|
||||
private fun pathForLogIndex(index: Int, create: Boolean = false): UniFile? {
|
||||
return if (create) logPath.createFile(fileNameForLogIndex(index)) else logPath.findFile(fileNameForLogIndex(index))
|
||||
}
|
||||
|
||||
private suspend fun writer() = withIOContext {
|
||||
val logFilePath = pathForLogIndex(0)
|
||||
|
||||
if (logFilePath?.exists() == true) {
|
||||
maybeRollLogs(fileSize(logFilePath))
|
||||
}
|
||||
|
||||
fun openNewOutput() = pathForLogIndex(0, true)?.openOutputStream(true)
|
||||
|
||||
var currentLogSink = openNewOutput()
|
||||
|
||||
while (currentCoroutineContext().isActive) {
|
||||
val result = loggingChannel.receiveCatching()
|
||||
|
||||
val rolled = maybeRollLogs(fileSize(logFilePath))
|
||||
if (rolled) {
|
||||
currentLogSink?.close()
|
||||
currentLogSink = openNewOutput()
|
||||
}
|
||||
|
||||
result.getOrNull()?.let {
|
||||
try {
|
||||
currentLogSink?.write(it)
|
||||
} catch (e: IOException) {
|
||||
// Probably "Permission Denied" is back to haunt me
|
||||
println("RollingUniFileLogWriter: Failed to write to log file")
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
currentLogSink?.flush()
|
||||
}
|
||||
}
|
||||
|
||||
private fun fileSize(path: UniFile?) = path?.length() ?: -1L
|
||||
}
|
|
@ -4,13 +4,9 @@ import android.content.Context
|
|||
import androidx.core.net.toUri
|
||||
import co.touchlab.kermit.Logger
|
||||
import com.hippo.unifile.UniFile
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.buildLogWritersToAdd
|
||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
import eu.kanade.tachiyomi.util.system.setToDefault
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
|
@ -21,7 +17,6 @@ import kotlinx.coroutines.flow.launchIn
|
|||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
import kotlinx.io.files.Path
|
||||
|
||||
class StorageManager(
|
||||
private val context: Context,
|
||||
|
@ -50,15 +45,15 @@ class StorageManager(
|
|||
}
|
||||
parent.createDirectory(COVERS_PATH)
|
||||
parent.createDirectory(PAGES_PATH)
|
||||
parent.createDirectory(LOGS_PATH)
|
||||
}
|
||||
|
||||
try {
|
||||
Logger.setToDefault(buildLogWritersToAdd(getLogsFile()))
|
||||
} catch (e: Exception) {
|
||||
// Just in case something went horribly wrong
|
||||
Logger.setToDefault(buildLogWritersToAdd(null))
|
||||
Logger.e(e) { "Something went wrong while trying to setup log file" }
|
||||
parent.createDirectory(LOGS_PATH)?.also {
|
||||
try {
|
||||
Logger.setToDefault(buildLogWritersToAdd(it))
|
||||
} catch (e: Exception) {
|
||||
// Just in case something went horribly wrong
|
||||
Logger.setToDefault(buildLogWritersToAdd(null))
|
||||
Logger.e(e) { "Something went wrong while trying to setup log file" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_changes.send(Unit)
|
||||
|
@ -98,11 +93,6 @@ class StorageManager(
|
|||
fun getLogsDirectory(): UniFile? {
|
||||
return baseDir?.createDirectory(LOGS_PATH)
|
||||
}
|
||||
|
||||
fun getLogsFile(): UniFile? {
|
||||
val date = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date())
|
||||
return getLogsDirectory()?.createFile("${date}-${BuildConfig.BUILD_TYPE}.log")
|
||||
}
|
||||
}
|
||||
|
||||
private const val BACKUPS_PATH = "backup"
|
||||
|
|
|
@ -2,27 +2,12 @@ package eu.kanade.tachiyomi.util.system
|
|||
|
||||
import co.touchlab.kermit.LogWriter
|
||||
import co.touchlab.kermit.Logger
|
||||
import co.touchlab.kermit.io.RollingFileLogWriter
|
||||
import co.touchlab.kermit.io.RollingFileLogWriterConfig
|
||||
import co.touchlab.kermit.platformLogWriter
|
||||
import kotlinx.io.files.Path
|
||||
|
||||
fun Logger.w(e: Throwable) = w(e) { "Something is not right..." }
|
||||
fun Logger.e(e: Throwable) = e(e) { "Something went wrong!" }
|
||||
|
||||
fun Logger.setToDefault(
|
||||
writersToAdd: List<LogWriter>,
|
||||
) {
|
||||
fun Logger.setToDefault(writersToAdd: List<LogWriter>) {
|
||||
Logger.setLogWriters(listOf(platformLogWriter()) + writersToAdd)
|
||||
Logger.setTag("Yokai")
|
||||
}
|
||||
|
||||
fun Logger.setupFileLog(logFileName: String, logPath: Path): LogWriter {
|
||||
return RollingFileLogWriter(
|
||||
config = RollingFileLogWriterConfig(
|
||||
logFileName = logFileName,
|
||||
logFilePath = logPath,
|
||||
maxLogFiles = 1,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -44,7 +44,6 @@ flexible-adapter = { module = "com.github.arkon.FlexibleAdapter:flexible-adapter
|
|||
image-decoder = { module = "com.github.tachiyomiorg:image-decoder", version = "41c059e540" }
|
||||
|
||||
kermit = { module = "co.touchlab:kermit", version.ref = "kermit" }
|
||||
kermit-io = { module = "co.touchlab:kermit-io", version.ref = "kermit" }
|
||||
|
||||
koin-bom = { module = "io.insert-koin:koin-bom", version.ref = "koin" }
|
||||
koin-core = { module = "io.insert-koin:koin-core" }
|
||||
|
@ -114,7 +113,7 @@ sqldelight = { id = "app.cash.sqldelight", version.ref = "sqldelight" }
|
|||
db = [ "sqldelight-coroutines" ]
|
||||
db-android = [ "sqldelight-android-driver", "sqldelight-android-paging" ]
|
||||
coil = [ "coil3", "coil3-svg", "coil3-gif", "coil3-okhttp" ]
|
||||
logging = [ "kermit", "kermit-io" ]
|
||||
logging = [ "kermit" ]
|
||||
# FIXME: Uncomment once SQLDelight support KMP AndroidX SQLiteDriver
|
||||
#sqlite = [ "sqlite", "sqlite-ktx" ]
|
||||
sqlite = [ "sqlite-ktx" ]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue