Cleanup VectorFileLogger.kt

This commit is contained in:
Benoit Marty 2021-02-19 18:04:26 +01:00
parent e12cbf92c3
commit 616b02cea8
2 changed files with 113 additions and 115 deletions

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2021 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.rageshake
import java.io.PrintWriter
import java.io.StringWriter
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.TimeZone
import java.util.logging.Formatter
import java.util.logging.LogRecord
class LogFormatter : Formatter() {
override fun format(r: LogRecord): String {
if (!mIsTimeZoneSet) {
DATE_FORMAT.timeZone = TimeZone.getTimeZone("UTC")
mIsTimeZoneSet = true
}
val thrown = r.thrown
if (thrown != null) {
val sw = StringWriter()
val pw = PrintWriter(sw)
sw.write(r.message)
sw.write(LINE_SEPARATOR)
thrown.printStackTrace(pw)
pw.flush()
return sw.toString()
} else {
val b = StringBuilder()
val date = DATE_FORMAT.format(Date(r.millis))
b.append(date)
b.append("Z ")
b.append(r.message)
b.append(LINE_SEPARATOR)
return b.toString()
}
}
companion object {
private val LINE_SEPARATOR = System.getProperty("line.separator") ?: "\n"
// private val DATE_FORMAT = SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US)
private val DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss*SSSZZZZ", Locale.US)
private var mIsTimeZoneSet = false
}
}

View File

@ -22,45 +22,41 @@ import im.vector.app.features.settings.VectorPreferences
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.extensions.tryOrNull
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
import java.io.PrintWriter import java.io.PrintWriter
import java.io.StringWriter import java.io.StringWriter
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.TimeZone
import java.util.logging.FileHandler import java.util.logging.FileHandler
import java.util.logging.Formatter
import java.util.logging.Level import java.util.logging.Level
import java.util.logging.LogRecord
import java.util.logging.Logger import java.util.logging.Logger
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton
class VectorFileLogger @Inject constructor(
context: Context,
private val vectorPreferences: VectorPreferences
) : Timber.Tree() {
companion object {
private const val SIZE_20MB = 20 * 1024 * 1024 private const val SIZE_20MB = 20 * 1024 * 1024
private const val SIZE_50MB = 50 * 1024 * 1024 private const val SIZE_50MB = 50 * 1024 * 1024
}
@Singleton private val maxLogSizeByte = if (vectorPreferences.labAllowedExtendedLogging()) SIZE_50MB else SIZE_20MB
class VectorFileLogger @Inject constructor(val context: Context, private val vectorPreferences: VectorPreferences) : Timber.Tree() { private val logRotationCount = if (vectorPreferences.labAllowedExtendedLogging()) 15 else 7
private val maxLogSizeByte: Int private val logger = Logger.getLogger(context.packageName).apply {
private val logRotationCount: Int tryOrNull {
useParentHandlers = false
init { level = Level.ALL
if (vectorPreferences.labAllowedExtendedLogging()) {
maxLogSizeByte = SIZE_50MB
logRotationCount = 15
} else {
maxLogSizeByte = SIZE_20MB
logRotationCount = 7
} }
} }
private val sLogger = Logger.getLogger("im.vector.app") private val fileHandler: FileHandler?
private var sFileHandler: FileHandler? = null private val cacheDirectory = File(context.cacheDir, "logs")
private var sCacheDirectory: File? = null private var fileNamePrefix = "logs"
private var sFileName = "elementLogs"
private val prioPrefixes = mapOf( private val prioPrefixes = mapOf(
Log.VERBOSE to "V/ ", Log.VERBOSE to "V/ ",
@ -72,24 +68,29 @@ class VectorFileLogger @Inject constructor(val context: Context, private val vec
) )
init { init {
val logsDirectoryFile = context.cacheDir.absolutePath + "/logs" if (!cacheDirectory.exists()) {
setLogDirectory(File(logsDirectoryFile)) cacheDirectory.mkdirs()
try {
if (sCacheDirectory != null) {
sFileHandler = FileHandler(sCacheDirectory!!.absolutePath + "/" + sFileName + ".%g.txt", maxLogSizeByte, logRotationCount)
sFileHandler?.formatter = LogFormatter()
sLogger.useParentHandlers = false
sLogger.level = Level.ALL
sFileHandler?.let { sLogger.addHandler(it) }
} }
} catch (e: Throwable) {
Timber.e(e, "Failed to initialize FileLogger") for (i in 0..15) {
val file = File(cacheDirectory, "elementLogs.$i.txt")
tryOrNull { file.delete() }
}
fileHandler = tryOrNull("Failed to initialize FileLogger") {
FileHandler(
cacheDirectory.absolutePath + "/" + fileNamePrefix + ".%g.txt",
maxLogSizeByte,
logRotationCount
)
.also { it.formatter = LogFormatter() }
.also { logger.addHandler(it) }
} }
} }
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
fileHandler ?: return
GlobalScope.launch(Dispatchers.IO) { GlobalScope.launch(Dispatchers.IO) {
if (sFileHandler == null) return@launch
if (skipLog(priority)) return@launch if (skipLog(priority)) return@launch
if (t != null) { if (t != null) {
logToFile(t) logToFile(t)
@ -107,84 +108,22 @@ class VectorFileLogger @Inject constructor(val context: Context, private val vec
} }
} }
/**
* Set the directory to put log files.
*
* @param cacheDir The directory, usually [android.content.ContextWrapper.getCacheDir]
*/
private fun setLogDirectory(cacheDir: File) {
if (!cacheDir.exists()) {
cacheDir.mkdirs()
}
sCacheDirectory = cacheDir
}
/** /**
* Adds our own log files to the provided list of files. * Adds our own log files to the provided list of files.
* *
* @param files The list of files to add to. * @return The list of files with logs.
* @return The same list with more files added.
*/ */
fun getLogFiles(): List<File> { fun getLogFiles(): List<File> {
val files = ArrayList<File>() return tryOrNull("## getLogFiles() failed") {
fileHandler
try { ?.flush()
// reported by GA ?.let { 0 until logRotationCount }
if (null != sFileHandler) { ?.mapNotNull { index ->
sFileHandler!!.flush() File(cacheDirectory, "$fileNamePrefix.$index.txt")
val absPath = sCacheDirectory?.absolutePath ?: return emptyList() .takeIf { it.exists() }
for (i in 0..logRotationCount) {
val filepath = "$absPath/$sFileName.$i.txt"
val file = File(filepath)
if (file.exists()) {
files.add(file)
} }
} }
} .orEmpty()
} catch (e: Exception) {
Timber.e(e, "## addLogFiles() failed")
}
return files
}
class LogFormatter : Formatter() {
override fun format(r: LogRecord): String {
if (!mIsTimeZoneSet) {
DATE_FORMAT.timeZone = TimeZone.getTimeZone("UTC")
mIsTimeZoneSet = true
}
val thrown = r.thrown
if (thrown != null) {
val sw = StringWriter()
val pw = PrintWriter(sw)
sw.write(r.message)
sw.write(LINE_SEPARATOR)
thrown.printStackTrace(pw)
pw.flush()
return sw.toString()
} else {
val b = StringBuilder()
val date = DATE_FORMAT.format(Date(r.millis))
b.append(date)
b.append("Z ")
b.append(r.message)
b.append(LINE_SEPARATOR)
return b.toString()
}
}
companion object {
private val LINE_SEPARATOR = System.getProperty("line.separator") ?: "\n"
// private val DATE_FORMAT = SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US)
private val DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss*SSSZZZZ", Locale.US)
private var mIsTimeZoneSet = false
}
} }
/** /**
@ -193,20 +132,15 @@ class VectorFileLogger @Inject constructor(val context: Context, private val vec
* @param throwable the throwable to log * @param throwable the throwable to log
*/ */
private fun logToFile(throwable: Throwable?) { private fun logToFile(throwable: Throwable?) {
if (null == sCacheDirectory || throwable == null) { throwable ?: return
return
}
val errors = StringWriter() val errors = StringWriter()
throwable.printStackTrace(PrintWriter(errors)) throwable.printStackTrace(PrintWriter(errors))
sLogger.info(errors.toString()) logger.info(errors.toString())
} }
private fun logToFile(level: String, tag: String, content: String) { private fun logToFile(level: String, tag: String, content: String) {
if (null == sCacheDirectory) {
return
}
val b = StringBuilder() val b = StringBuilder()
b.append(Thread.currentThread().id) b.append(Thread.currentThread().id)
b.append(" ") b.append(" ")
@ -215,6 +149,6 @@ class VectorFileLogger @Inject constructor(val context: Context, private val vec
b.append(tag) b.append(tag)
b.append(": ") b.append(": ")
b.append(content) b.append(content)
sLogger.info(b.toString()) logger.info(b.toString())
} }
} }