Created
October 31, 2023 12:24
-
-
Save megaacheyounes/e1121e5275818492310e8dcab012737f to your computer and use it in GitHub Desktop.
Tree for Timber Android logger with persistent storage to txt file
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.megaache.myapp.util | |
import android.os.Environment | |
import android.util.Log | |
import com.megaache.myapp.BuildConfig | |
import com.megaache.myapp.FmtApp | |
import timber.log.Timber | |
import timber.log.Timber.DebugTree | |
import java.io.File | |
import java.io.FileInputStream | |
import java.io.FileOutputStream | |
import java.io.IOException | |
import java.math.BigDecimal | |
import java.math.RoundingMode | |
/** | |
* Created by YounesMegaacheY84154336 on 9/9/2020. | |
*/ | |
class VSLogTree : DebugTree() { | |
init { | |
try { | |
val p = File(getDir()) | |
if (!p.exists()) | |
p.mkdirs() | |
Log.println(Log.DEBUG, "timber", "log dir created => ${p.absolutePath}") | |
} catch (e: Exception) { | |
if (BuildConfig.DEBUG) | |
throw e | |
Log.println(Log.ERROR, "timber", " $e") | |
} | |
} | |
override fun createStackElementTag(element: StackTraceElement): String { | |
element.apply { | |
val methodFirst10 = methodName.substring( | |
0, | |
if (methodName.length > 10) | |
10 | |
else | |
methodName.length | |
) | |
return String.format( | |
"Timber(%s:%s)#%s", | |
element.fileName, | |
element.lineNumber, | |
methodFirst10 | |
) | |
} | |
} | |
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { | |
if (BuildConfig.DEBUG) | |
super.log( | |
priority, | |
tag, | |
"[${timeSinceStarted()}s] ${formatMessage(priority, message)}", | |
t | |
) | |
try { | |
val file = File(getPath()) | |
if (!file.exists()) { | |
val success = file.createNewFile() | |
Log.d("timber", "is log file created => $success") | |
} | |
val log = "->[${timeSinceStarted()}s] $tag ${formatMessage(priority, message)}" | |
//SharedPrefHelper.saveLog(log) | |
FileOutputStream(file, true).bufferedWriter().use { writer -> | |
writer.appendLine(log) | |
writer.flush() | |
} | |
} catch (e: IOException) { | |
//app may not have permission to write log file, so ignore it | |
} | |
} | |
private fun formatMessage(priority: Int, msg: String) = when (priority) { | |
Log.ERROR -> """${"\n"} | |
|*********************************************UNCAUGHT EXCEPTION:START*************************************************** | |
|*$msg | |
|*********************************************UNCAUGHT EXCEPTION:END*****************************************************""" | |
.trimMargin() | |
Log.WARN -> """${"\n"} | |
|********************************************* WARNING *************************************************** | |
|*$msg""" | |
.trimMargin() | |
else -> msg | |
} | |
private fun timeSinceStarted() = | |
BigDecimal((System.currentTimeMillis() - START_TIME.toDouble()) / 1000).setScale( | |
4, | |
RoundingMode.HALF_EVEN | |
) | |
companion object { | |
val START_TIME = System.currentTimeMillis() | |
//clear logs afte 1 day | |
const val LOG_PURGE_DAYS = 1 | |
const val TAG = "MyApp" | |
//current time millis is 13 digits, we only keep the last 3 days logs, | |
//mean the start time for logs will be different in the last 9 digits (day), the first 5 digits will always be equal (ex: month year) | |
//so we remove to static part keep the name short | |
//this is valid until Nov 20th 2286, we have enough time | |
private var DAY_MILLIS = START_TIME.toString().substring(5) //pick only last 9 digits | |
private fun getName() = | |
"$TAG${BuildConfig.VERSION_NAME}(${BuildConfig.BUILD_TYPE})_$DAY_MILLIS.txt" | |
private fun getDir() = | |
"${FmtApp.instance.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)}${File.separator }${TAG}_Logs" | |
fun getPath() = getDir() + File.separator + getName() | |
fun getLogs() = | |
FileInputStream(File(getPath())).bufferedReader().use { reader -> | |
reader.readLines().toList() | |
} | |
//delete log files older than 24 hours | |
fun cleanOldLogs() = try { | |
var deleted = 0 | |
Timber.d("CLEANING log files older than ${LOG_PURGE_DAYS * 24} hours...") | |
val directory = File(getDir()) | |
if (directory.exists()) { | |
val listFiles = directory.listFiles() | |
if (listFiles == null) { | |
Timber.d("0 logs files found") | |
} else { | |
Timber.d("Found ${listFiles.size} log files") | |
val purgeTime = System.currentTimeMillis() - LOG_PURGE_DAYS * 24 * 60 * 60 * 1000 | |
for (listFile in listFiles) { | |
if (listFile.lastModified() < purgeTime) { | |
if (listFile.delete()) { | |
deleted++ | |
} else { | |
Timber.w("Unable to delete log file: $listFile") | |
} | |
} | |
} | |
} | |
Timber.d("cleaned $deleted log files") | |
} else { | |
Timber.w("logs dir does not exist") | |
} | |
true | |
} catch (e: Exception) { | |
if (BuildConfig.DEBUG) throw e | |
Timber.w("$e") | |
false | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment