Handle new session in log file appender (#191)

* Remove getValue log with base URL when app starts

* Print time when session starts

* Flush log file when an Activity is paused
This commit is contained in:
Kirill Kamakin
2023-12-27 10:41:34 +01:00
committed by GitHub
parent 36a72b63de
commit ffdac4c616
2 changed files with 53 additions and 11 deletions

View File

@@ -2,7 +2,7 @@ package gq.kirmanak.mealient.data.baseurl.impl
import androidx.core.net.toUri import androidx.core.net.toUri
import gq.kirmanak.mealient.architecture.configuration.AppDispatchers import gq.kirmanak.mealient.architecture.configuration.AppDispatchers
import gq.kirmanak.mealient.data.baseurl.ServerInfoStorage import gq.kirmanak.mealient.data.storage.PreferencesStorage
import gq.kirmanak.mealient.logging.LogRedactor import gq.kirmanak.mealient.logging.LogRedactor
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
@@ -14,11 +14,13 @@ import javax.inject.Singleton
@Singleton @Singleton
class BaseUrlLogRedactor @Inject constructor( class BaseUrlLogRedactor @Inject constructor(
private val serverInfoStorageProvider: Provider<ServerInfoStorage>, private val preferencesStorageProvider: Provider<PreferencesStorage>,
private val dispatchers: AppDispatchers, private val dispatchers: AppDispatchers,
) : LogRedactor { ) : LogRedactor {
private val hostState = MutableStateFlow<String?>(null) private val hostState = MutableStateFlow<String?>(null)
private val preferencesStorage: PreferencesStorage
get() = preferencesStorageProvider.get()
init { init {
setInitialBaseUrl() setInitialBaseUrl()
@@ -27,10 +29,9 @@ class BaseUrlLogRedactor @Inject constructor(
private fun setInitialBaseUrl() { private fun setInitialBaseUrl() {
val scope = CoroutineScope(dispatchers.default + SupervisorJob()) val scope = CoroutineScope(dispatchers.default + SupervisorJob())
scope.launch { scope.launch {
val serverInfoStorage = serverInfoStorageProvider.get()
hostState.compareAndSet( hostState.compareAndSet(
expect = null, expect = null,
update = serverInfoStorage.getBaseURL()?.extractHost(), update = preferencesStorage.getValue(preferencesStorage.baseUrlKey)
) )
} }
} }
@@ -41,8 +42,12 @@ class BaseUrlLogRedactor @Inject constructor(
override fun redact(message: String): String { override fun redact(message: String): String {
val host = hostState.value ?: return message val host = hostState.value
return message.replace(host, "<host>") return when {
host == null && message.contains(preferencesStorage.baseUrlKey.name) -> "<redacted>"
host == null -> message
else -> message.replace(host, "<host>")
}
} }
} }

View File

@@ -1,6 +1,9 @@
package gq.kirmanak.mealient.logging package gq.kirmanak.mealient.logging
import android.app.Activity
import android.app.Application import android.app.Application
import android.app.Application.ActivityLifecycleCallbacks
import android.os.Bundle
import gq.kirmanak.mealient.architecture.configuration.AppDispatchers import gq.kirmanak.mealient.architecture.configuration.AppDispatchers
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
@@ -13,7 +16,6 @@ import java.io.FileWriter
import java.io.IOException import java.io.IOException
import java.io.Writer import java.io.Writer
import java.time.Instant import java.time.Instant
import java.time.ZoneId
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@@ -42,11 +44,24 @@ internal class FileAppender @Inject constructor(
private val coroutineScope = CoroutineScope(dispatchers.io + SupervisorJob()) private val coroutineScope = CoroutineScope(dispatchers.io + SupervisorJob())
private val dateTimeFormatter =
DateTimeFormatter.ISO_LOCAL_DATE_TIME.withZone(ZoneId.systemDefault())
init { init {
startLogWriter() startLogWriter()
startLifecycleObserver()
}
private fun startLifecycleObserver() {
val observer = object : DefaultActivityLifecycleCallbacks() {
override fun onActivityPaused(activity: Activity) {
super.onActivityPaused(activity)
try {
fileWriter?.flush()
} catch (e: IOException) {
// Ignore
}
}
}
application.registerActivityLifecycleCallbacks(observer)
} }
private fun createFileWriter(): Writer? { private fun createFileWriter(): Writer? {
@@ -70,8 +85,10 @@ internal class FileAppender @Inject constructor(
} }
coroutineScope.launch { coroutineScope.launch {
fileWriter.appendLine("Session started at ${Instant.now().formatted()}")
for (logInfo in logChannel) { for (logInfo in logChannel) {
val time = dateTimeFormatter.format(logInfo.logTime) val time = logInfo.logTime.formatted()
val level = logInfo.logLevel.name.first() val level = logInfo.logLevel.name.first()
logInfo.message.lines().forEach { logInfo.message.lines().forEach {
try { try {
@@ -84,6 +101,8 @@ internal class FileAppender @Inject constructor(
} }
} }
private fun Instant.formatted(): String = DateTimeFormatter.ISO_INSTANT.format(this)
override fun isLoggable(logLevel: LogLevel): Boolean = true override fun isLoggable(logLevel: LogLevel): Boolean = true
override fun isLoggable(logLevel: LogLevel, tag: String): Boolean = true override fun isLoggable(logLevel: LogLevel, tag: String): Boolean = true
@@ -106,4 +125,22 @@ internal class FileAppender @Inject constructor(
// Ignore // Ignore
} }
} }
}
private open class DefaultActivityLifecycleCallbacks : ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) = Unit
override fun onActivityStarted(activity: Activity) = Unit
override fun onActivityResumed(activity: Activity) = Unit
override fun onActivityPaused(activity: Activity) = Unit
override fun onActivityStopped(activity: Activity) = Unit
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) = Unit
override fun onActivityDestroyed(activity: Activity) = Unit
} }