美文网首页
Kotlin Log工具2020-11-16

Kotlin Log工具2020-11-16

作者: orgcheng | 来源:发表于2020-11-16 11:33 被阅读0次
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

      本文链接:https://www.haomeiwen.com/subject/orbabktx.html