经过长时间的调查,我发现:
android.util.Log
默认使用java.util.logging.Logger
- LogCat使用名称为
""
的logger
,要获取它的实例,请使用LogManager.getLogManager().getLogger("")
- 在运行调试应用程序后,Android设备将向LogCat添加
com.android.internal.logging.AndroidHandler
的logger
实例
- 但是!!!
com.android.internal.logging.AndroidHandler
仅将消息打印到logcat中,当级别大于java.util.logging.Level.INFO
时,例如(Level.INFO, Level.WARNING, Level.SEVERE, Level.OFF
)
因此,要将日志写入文件,只需简单地向rootLogger
""
添加一个java.util.logging.FileHandler
即可:
class App : Application{
override fun onCreate() {
super.onCreate()
Log.d(TAG, printLoggers("before setup"))
val rootLogger = java.util.logging.LogManager.getLogManager().getLogger("")
val dirFile = destinationFolder
val file = File(dirFile,"logFile.txt")
val handler = java.util.logging.FileHandler(file.absolutePath, 5* 1024 * 1024, 1, true)
handler.formatter = AndroidLogFormatter(filePath = file.absolutePath)
rootLogger?.addHandler(handler)
Log.d(TAG, printLoggers("after setup"))
}
}
val destinationFolder: File
get() {
val parent =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absoluteFile
val destinationFolder = File(parent, "MyApp")
if (!destinationFolder.exists()) {
destinationFolder.mkdirs()
destinationFolder.mkdir()
}
return destinationFolder
}
class AndroidLogFormatter(val filePath: String = "", var tagPrefix: String = "") : Formatter() {
override fun format(record: LogRecord): String {
val tag = record.getTag(tagPrefix)
val date = record.getDate()
val level = record.getLogCatLevel()
val message = record.getLogCatMessage()
return "$date $level$tag: $message\n"
}
}
fun LogRecord.getTag(tagPrefix: String): String {
val name = loggerName
val maxLength = 30
val tag = tagPrefix + (if (name.length > maxLength) name.substring(name.length - maxLength) else name)
return tag
}
fun LogRecord.getDate(): String? {
return Date(millis).formatedBy("yyyy-MM-dd HH:mm:ss.SSS")
}
fun Date?.formatedBy(dateFormat: String): String? {
val date = this
date ?: return null
val writeFormat = SimpleDateFormat(dateFormat, Locale.getDefault())
return writeFormat.format(date)
}
fun LogRecord.getLogCatMessage(): String {
var message = message
if (thrown != null) {
message += Log.getStackTraceString(thrown)
}
return message
}
fun Int.getAndroidLevel(): Int {
return when {
this >= Level.SEVERE.intValue() -> {
Log.ERROR
}
this >= Level.WARNING.intValue() -> {
Log.WARN
}
this >= Level.INFO.intValue() -> {
Log.INFO
}
else -> {
Log.DEBUG
}
}
}
fun LogRecord.getLogCatLevel(): String {
return when (level.intValue().getAndroidLevel()) {
Log.ERROR -> {
"E/"
}
Log.WARN -> {
"W/"
}
Log.INFO -> {
"I/"
}
Log.DEBUG -> {
"D/"
}
else -> {
"D/"
}
}
}
fun getLoggerLevel(level: Int): Level {
return when (level) {
Log.ERROR -> {
Level.SEVERE
}
Log.WARN -> {
Level.WARNING
}
Log.INFO -> {
Level.INFO
}
Log.DEBUG -> {
Level.FINE
}
else -> {
Level.FINEST
}
}
}
要打印应用程序中的所有记录器,请使用以下命令:
Log.e(TAG, printLoggers("before setup"))
private fun printLoggers(caller: String, printIfEmpty: Boolean = true): String {
val builder = StringBuilder()
val loggerNames = LogManager.getLogManager().loggerNames
builder.appendln("--------------------------------------------------------------")
builder.appendln("printLoggers: $caller")
while (loggerNames.hasMoreElements()) {
val element = loggerNames.nextElement()
val logger = LogManager.getLogManager().getLogger(element)
val parentLogger: Logger? = logger.parent
val handlers = logger.handlers
val level = logger?.level
if (!printIfEmpty && handlers.isEmpty()) {
continue
}
val handlersNames = handlers.map {
val handlerName = it.javaClass.simpleName
val formatter: Formatter? = it.formatter
val formatterName = if (formatter is AndroidLogFormatter) {
"${formatter.javaClass.simpleName}(${formatter.filePath})"
} else {
formatter?.javaClass?.simpleName
}
"$handlerName($formatterName)"
}
builder.appendln("level: $level logger: \"$element\" handlers: $handlersNames parentLogger: ${parentLogger?.name}")
}
builder.appendln("--------------------------------------------------------------")
return builder.toString()
}
buf.close()
放在finally
块内。 - William Price