Coverage Summary for Class: MNetLoggerAndroid (com.greybox.projectmesh)
| Class |
Class, %
|
Method, %
|
Branch, %
|
Line, %
|
| MNetLoggerAndroid |
0%
(0/1)
|
0%
(0/5)
|
0%
(0/18)
|
0%
(0/45)
|
package com.greybox.projectmesh
import android.content.Context
import android.util.Log
import com.greybox.projectmesh.extension.deviceInfo
import com.ustadmobile.meshrabiya.MeshrabiyaConstants
import com.ustadmobile.meshrabiya.ext.trimIfExceeds
import com.ustadmobile.meshrabiya.log.LogLine
import com.ustadmobile.meshrabiya.log.MNetLogger
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import java.io.File
import java.text.DateFormat
import java.util.Date
class MNetLoggerAndroid(
private val deviceInfo: String,
private val minLogLevel: Int = Log.VERBOSE,
private val logHistoryLines: Int = 300,
private val logFile: File? = null,
): MNetLogger() {
val epochTime = System.currentTimeMillis()
private val _recentLogs = MutableStateFlow(emptyList<LogLine>())
val recentLogs: Flow<List<LogLine>> = _recentLogs.asStateFlow()
private val logScope = CoroutineScope(Dispatchers.IO + Job())
private val logChannel = Channel<LogLine>(Channel.UNLIMITED)
init {
logScope.launch {
logFile?.parentFile?.takeIf { !it.exists() }?.mkdirs()
val startTime = DateFormat.getTimeInstance().format(Date())
logFile?.appendText("Meshrabiya Session start: $startTime\n$deviceInfo\n")
for(logLine in logChannel) {
val time = (System.currentTimeMillis() - epochTime) / 1000.toFloat()
val rounded = (time * 100).toInt() / 100.toFloat()
logFile?.appendText("${priorityLabel(logLine.priority)}: t+${rounded}s : ${logLine.line}\n")
}
}
}
private fun doLog(priority: Int, message: String, exception: Exception?) {
when (priority) {
Log.VERBOSE -> Log.v(MeshrabiyaConstants.LOG_TAG, message, exception)
Log.DEBUG -> Log.d(MeshrabiyaConstants.LOG_TAG, message, exception)
Log.INFO -> Log.i(MeshrabiyaConstants.LOG_TAG, message, exception)
Log.WARN -> Log.w(MeshrabiyaConstants.LOG_TAG, message, exception)
Log.ERROR -> Log.e(MeshrabiyaConstants.LOG_TAG, message, exception)
Log.ASSERT -> Log.wtf(MeshrabiyaConstants.LOG_TAG, message, exception)
}
val logDisplay = buildString {
append(message)
if (exception != null) {
append(" Exception: ")
append(exception.toString())
}
}
val logLine = LogLine(logDisplay, priority, System.currentTimeMillis())
_recentLogs.update { prev ->
buildList {
add(logLine)
addAll(prev.trimIfExceeds(logHistoryLines - 1))
}
}
logChannel.takeIf { logFile != null }?.trySend(logLine)
}
override fun invoke(priority: Int, message: () -> String, exception: Exception?) {
if(priority >= minLogLevel)
doLog(priority, message(), exception)
}
override fun invoke(priority: Int, message: String, exception: Exception?) {
if(priority >= minLogLevel)
doLog(priority, message, exception)
}
/**
* Export logs with time/date stamp, device info, etc.
*/
fun exportAsString(context: Context): String {
return buildString {
append(context.deviceInfo())
append("==Logs==\n")
_recentLogs.value.reversed().forEach {
append(it.toString(epochTime))
append("\n")
}
}
}
}