package com.beantechs.beanphone.common.utils.log
import android.app.ActivityManager
import android.app.Application
import android.content.Context
import android.content.pm.ApplicationInfo
import android.os.Handler
import android.os.HandlerThread
import android.os.Process.myPid
import android.util.Log
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.io.File
import java.io.RandomAccessFile
import java.nio.ByteBuffer
import java.nio.channels.FileChannel
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.LinkedBlockingDeque
object LogUtils {
private const val V = "V"
private const val D = "D"
private const val I = "I"
private const val W = "W"
private const val E = "E"
private const val WTF = "WTF"
private const val JSON = "JSON"
private const val SYSO = "SYSO"
//堆栈的索引
private var stakeIndex = 4
private const val JSON_INDENT = 4
private val LINE_SEPARATOR: String = System.getProperty("line.separator")
private const val MAX_LENGTH = 4000
private const val TAG_DEFAULT = "Bean_"
private var isShowLog = true
private var isLogIntoFile = true
internal lateinit var logPathDir: String
internal var logfile: String = "main_log.txt"
private val logFileHandlerThread by lazy {
var result = LogFileHandlerThread("LogFile")
result.start()
result
}
@JvmStatic
fun init(application: Application) {
try {
isShowLog = (application.applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) != 0
if (!isShowLog)
return
logPathDir = application.getExternalFilesDir("").toString() + "/bean_log"
var activityManager = application.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
activityManager.runningAppProcesses.forEach {
if (myPid() == it.pid && it.processName.contains(":")) {
var index = it.processName.indexOf(":")
logfile = "${it.processName.substring(index + 1)}_log.txt"
return@forEach
}
}
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
}
@JvmStatic
fun setIsShowLog(value: Boolean) {
isShowLog = value
}
@JvmStatic
fun setIsLogIntoFile(value: Boolean) {
isLogIntoFile = value
}
@JvmStatic
fun v(vararg msg: CharSequence?) {
printLog(V, *msg)
}
@JvmStatic
fun d(vararg msg: CharSequence?) {
printLog(D, *msg)
}
@JvmStatic
fun i(vararg msg: CharSequence?) {
printLog(I, *msg)
}
@JvmStatic
fun w(vararg msg: CharSequence?) {
printLog(W, *msg)
}
@JvmStatic
fun wtf(vararg msg: CharSequence?) {
printLog(WTF, *msg)
}
@JvmStatic
fun e(vararg msg: CharSequence?) {
printLog(E, *msg)
}
@JvmStatic
fun syso(text: CharSequence?) {
printLog(SYSO, text)
}
@JvmStatic
fun json(jsonFormat: CharSequence?) {
printLog(JSON, jsonFormat)
}
private fun getObjectsString(vararg objArgs: CharSequence?): String {
return when (objArgs.size) {
0 -> "Empty Params"
1 -> objArgs[0]?.toString() ?: "params is null"
else -> {
val sb = StringBuilder()
for (i in objArgs.indices) {
sb.append("${objArgs[i]} ")
}
sb.toString()
}
}
}
private fun printLine(tag: String, isTop: Boolean, type: String = D) {
if (!isShowLog) {
return
}
val line: String = if (isTop) {
"╔═══════════════════════════════════════════════════════════════════════════════════════"
} else {
"╚═══════════════════════════════════════════════════════════════════════════════════════"
}
when (type) {
I -> Log.i(tag, line)
D -> Log.d(tag, line)
V -> Log.v(tag, line)
W -> Log.w(tag, line)
E -> Log.e(tag, line)
WTF -> Log.wtf(tag, line)
}
}
private fun printJson(tag: String, headString: String, msg: String) {
if (!isShowLog) {
return
}
var message: String
message = try {
if (msg.startsWith("{")) {
val jsonObject = JSONObject(msg)
jsonObject.toString(JSON_INDENT)
} else if (msg.startsWith("[")) {
val jsonArray = JSONArray(msg)
jsonArray.toString(JSON_INDENT)
} else {
msg
}
} catch (e: JSONException) {
msg
}
printLine(tag, true)
message = headString + LINE_SEPARATOR + message
val lines = message.split(LINE_SEPARATOR.toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
for (line in lines) {
Log.d(tag, "║ $line")
}
printLine(tag, false)
}
private fun printDefault(type: String, tag: String, msg: String) {
if (!isShowLog) {
return
}
var index = 0
val length = msg.length
val countOfSub = length / MAX_LENGTH
if (countOfSub > 0) {
for (i in 0 until countOfSub) {
val sub = msg.substring(index, index + MAX_LENGTH)
printSub(type, tag, sub)
index += MAX_LENGTH
}
printSub(type, tag, msg.substring(index, length))
} else {
printSub(type, tag, msg)
}
}
private fun printLog(type: String, vararg objects: CharSequence?) {
if (!isShowLog) {
return
}
val targetElement = Thread.currentThread().stackTrace[stakeIndex]
val tag = TAG_DEFAULT + targetElement.fileName
val headString = "[(%s:%s).%s()] ".format(
targetElement.fileName, targetElement.lineNumber, targetElement.methodName)
val msg: String = getObjectsString(*objects)
if (isShowLog) {
when (type) {
JSON -> printJson(tag, headString, msg)
// V, D, I, W, E, WTF,SYSO,
else -> printDefault(type, tag, headString + msg)
}
if (isLogIntoFile) {
logFileHandlerThread.log2File(type, tag, msg)
}
}
}
private fun printSub(type: String, tag: String, sub: String) {
if (!isShowLog) {
return
}
when (type) {
V -> Log.v(tag, sub)
D -> Log.d(tag, sub)
I -> Log.i(tag, sub)
W -> Log.w(tag, sub)
E -> Log.e(tag, sub)
WTF -> Log.wtf(tag, sub)
SYSO -> println(sub)
}
}
}
private data class LogInfo(val type: String, val tag: String, val sub: String)
private class LogFileHandlerThread(threadName: String) : HandlerThread(threadName) {
private val maxSize = 6 * 1024 * 1024.toLong()
private var logHandler: Handler? = null
private val queue = LinkedBlockingDeque<LogInfo>(258)
private val logFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
private var fileChannel: FileChannel? = null
override fun onLooperPrepared() {
super.onLooperPrepared()
logHandler = Handler(looper)
logHandler?.post {
try {
val logFile = File(LogUtils.logPathDir, LogUtils.logfile)
logFile.parentFile.mkdirs()
if (logFile.exists() && logFile.length() > 100) {
logFile.delete()
logFile.createNewFile()
}
if (fileChannel == null) {
var randomAccessFile = RandomAccessFile(logFile, "rws")
randomAccessFile.seek(randomAccessFile.length())
fileChannel = randomAccessFile.channel
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
fun log2File(type: String, tag: String, sub: String) {
if (null != logHandler) {
logHandler?.post {
try {
while (!queue.isEmpty()) {
var logInfo = queue.poll()
val log = "${logFormat.format(Date())} ${myPid()} ${logInfo.type}/${logInfo.tag}: ${logInfo.sub}\n"
fileChannel?.write(ByteBuffer.wrap(log.toByteArray()))
}
val log = "${logFormat.format(Date())} ${myPid()} ${type}/${tag}: ${sub}\n"
fileChannel?.write(ByteBuffer.wrap(log.toByteArray()))
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
}
} else {
queue.offer(LogInfo(type, tag, sub))
}
}
}
Kotlin Log工具2020-11-16
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 版本记录 前言 我们在做app的时候,不是做完功能就结束了,很多时候是需要进行检查和优化的,而xcode自带了一个...
- 版本记录 前言 我们在做app的时候,不是做完功能就结束了,很多时候是需要进行检查和优化的,而xcode自带了一个...
- 版本记录 前言 我们在做app的时候,不是做完功能就结束了,很多时候是需要进行检查和优化的,而xcode自带了一个...
- 5月以来,哪怕对市场风向再不敏感的人,也感觉到阵阵凉意。二级市场连续下挫,一级市场融资环境恶化,不论企业融资数量还...