Kotlin -3. Kotlin Log工具

  1 package com.beantechs.beanphone.common.utils.log
  2 
  3 import android.app.ActivityManager
  4 import android.app.Application
  5 import android.content.Context
  6 import android.content.pm.ApplicationInfo
  7 import android.os.Handler
  8 import android.os.HandlerThread
  9 import android.os.Process.myPid
 10 import android.util.Log
 11 import org.json.JSONArray
 12 import org.json.JSONException
 13 import org.json.JSONObject
 14 import java.io.File
 15 import java.io.RandomAccessFile
 16 import java.nio.ByteBuffer
 17 import java.nio.channels.FileChannel
 18 import java.text.SimpleDateFormat
 19 import java.util.*
 20 import java.util.concurrent.LinkedBlockingDeque
 21 
 22 object LogUtils {
 23     private const val V = "V"
 24     private const val D = "D"
 25     private const val I = "I"
 26     private const val W = "W"
 27     private const val E = "E"
 28     private const val WTF = "WTF"
 29     private const val JSON = "JSON"
 30     private const val SYSO = "SYSO"
 31 
 32     //堆栈的索引
 33     private var stakeIndex = 4
 34 
 35     private const val JSON_INDENT = 4
 36     private val LINE_SEPARATOR: String = System.getProperty("line.separator")
 37 
 38     private const val MAX_LENGTH = 4000
 39 
 40     private const val TAG_DEFAULT = "Bean_"
 41 
 42     private var isShowLog = true
 43 
 44     private var isLogIntoFile = true
 45 
 46     internal lateinit var logPathDir: String
 47 
 48     internal var logfile: String = "main_log.txt"
 49 
 50     private val logFileHandlerThread by lazy {
 51         var result = LogFileHandlerThread("LogFile")
 52         result.start()
 53         result
 54     }
 55 
 56     @JvmStatic
 57     fun init(application: Application) {
 58         try {
 59             isShowLog = (application.applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) != 0
 60 
 61             if (!isShowLog)
 62                 return
 63 
 64             logPathDir = application.getExternalFilesDir("").toString() + "/bean_log"
 65             var activityManager = application.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
 66             activityManager.runningAppProcesses.forEach {
 67                 if (myPid() == it.pid && it.processName.contains(":")) {
 68                     var index = it.processName.indexOf(":")
 69                     logfile = "${it.processName.substring(index + 1)}_log.txt"
 70                     return@forEach
 71                 }
 72             }
 73 
 74         } catch (e: java.lang.Exception) {
 75             e.printStackTrace()
 76         }
 77     }
 78 
 79     @JvmStatic
 80     fun setIsShowLog(value: Boolean) {
 81         isShowLog = value
 82     }
 83 
 84     @JvmStatic
 85     fun setIsLogIntoFile(value: Boolean) {
 86         isLogIntoFile = value
 87     }
 88 
 89     @JvmStatic
 90     fun v(vararg msg: CharSequence?) {
 91         printLog(V, *msg)
 92     }
 93 
 94     @JvmStatic
 95     fun d(vararg msg: CharSequence?) {
 96         printLog(D, *msg)
 97     }
 98 
 99     @JvmStatic
100     fun i(vararg msg: CharSequence?) {
101         printLog(I, *msg)
102     }
103 
104     @JvmStatic
105     fun w(vararg msg: CharSequence?) {
106         printLog(W, *msg)
107     }
108 
109     @JvmStatic
110     fun wtf(vararg msg: CharSequence?) {
111         printLog(WTF, *msg)
112     }
113 
114     @JvmStatic
115     fun e(vararg msg: CharSequence?) {
116         printLog(E, *msg)
117     }
118 
119 
120     @JvmStatic
121     fun syso(text: CharSequence?) {
122         printLog(SYSO, text)
123     }
124 
125     @JvmStatic
126     fun json(jsonFormat: CharSequence?) {
127         printLog(JSON, jsonFormat)
128     }
129 
130 
131     private fun getObjectsString(vararg objArgs: CharSequence?): String {
132         return when (objArgs.size) {
133             0 -> "Empty Params"
134             1 -> objArgs[0]?.toString() ?: "params is null"
135             else -> {
136                 val sb = StringBuilder()
137                 for (i in objArgs.indices) {
138                     sb.append("${objArgs[i]} ")
139                 }
140                 sb.toString()
141             }
142         }
143     }
144 
145 
146     private fun printLine(tag: String, isTop: Boolean, type: String = D) {
147         if (!isShowLog) {
148             return
149         }
150         val line: String = if (isTop) {
151             "╔═══════════════════════════════════════════════════════════════════════════════════════"
152         } else {
153             "╚═══════════════════════════════════════════════════════════════════════════════════════"
154         }
155         when (type) {
156             I -> Log.i(tag, line)
157             D -> Log.d(tag, line)
158             V -> Log.v(tag, line)
159             W -> Log.w(tag, line)
160             E -> Log.e(tag, line)
161             WTF -> Log.wtf(tag, line)
162         }
163     }
164 
165     private fun printJson(tag: String, headString: String, msg: String) {
166         if (!isShowLog) {
167             return
168         }
169         var message: String
170         message = try {
171             if (msg.startsWith("{")) {
172                 val jsonObject = JSONObject(msg)
173                 jsonObject.toString(JSON_INDENT)
174             } else if (msg.startsWith("[")) {
175                 val jsonArray = JSONArray(msg)
176                 jsonArray.toString(JSON_INDENT)
177             } else {
178                 msg
179             }
180         } catch (e: JSONException) {
181             msg
182         }
183         printLine(tag, true)
184         message = headString + LINE_SEPARATOR + message
185         val lines = message.split(LINE_SEPARATOR.toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
186         for (line in lines) {
187             Log.d(tag, "║ $line")
188         }
189         printLine(tag, false)
190     }
191 
192 
193     private fun printDefault(type: String, tag: String, msg: String) {
194         if (!isShowLog) {
195             return
196         }
197         var index = 0
198         val length = msg.length
199         val countOfSub = length / MAX_LENGTH
200         if (countOfSub > 0) {
201             for (i in 0 until countOfSub) {
202                 val sub = msg.substring(index, index + MAX_LENGTH)
203                 printSub(type, tag, sub)
204                 index += MAX_LENGTH
205             }
206             printSub(type, tag, msg.substring(index, length))
207         } else {
208             printSub(type, tag, msg)
209         }
210 
211     }
212 
213 
214     private fun printLog(type: String, vararg objects: CharSequence?) {
215         if (!isShowLog) {
216             return
217         }
218         val targetElement = Thread.currentThread().stackTrace[stakeIndex]
219         val tag = TAG_DEFAULT + targetElement.fileName
220         val headString = "[(%s:%s).%s()] ".format(
221                 targetElement.fileName, targetElement.lineNumber, targetElement.methodName)
222 
223         val msg: String = getObjectsString(*objects)
224         if (isShowLog) {
225             when (type) {
226                 JSON -> printJson(tag, headString, msg)
227                 //            V, D, I, W, E, WTF,SYSO,
228                 else -> printDefault(type, tag, headString + msg)
229             }
230 
231             if (isLogIntoFile) {
232                 logFileHandlerThread.log2File(type, tag, msg)
233             }
234         }
235     }
236 
237 
238     private fun printSub(type: String, tag: String, sub: String) {
239         if (!isShowLog) {
240             return
241         }
242         when (type) {
243             V -> Log.v(tag, sub)
244             D -> Log.d(tag, sub)
245             I -> Log.i(tag, sub)
246             W -> Log.w(tag, sub)
247             E -> Log.e(tag, sub)
248             WTF -> Log.wtf(tag, sub)
249             SYSO -> println(sub)
250         }
251     }
252 
253 
254 }
255 
256 private data class LogInfo(val type: String, val tag: String, val sub: String)
257 
258 private class LogFileHandlerThread(threadName: String) : HandlerThread(threadName) {
259     private val maxSize = 6 * 1024 * 1024.toLong()
260     private var logHandler: Handler? = null
261     private val queue = LinkedBlockingDeque<LogInfo>(258)
262     private val logFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
263 
264     private var fileChannel: FileChannel? = null
265 
266     override fun onLooperPrepared() {
267         super.onLooperPrepared()
268         logHandler = Handler(looper)
269         logHandler?.post {
270             try {
271                 val logFile = File(LogUtils.logPathDir, LogUtils.logfile)
272                 logFile.parentFile.mkdirs()
273                 if (logFile.exists() && logFile.length() > 100) {
274                     logFile.delete()
275                     logFile.createNewFile()
276                 }
277                 if (fileChannel == null) {
278                     var randomAccessFile = RandomAccessFile(logFile, "rws")
279                     randomAccessFile.seek(randomAccessFile.length())
280                     fileChannel = randomAccessFile.channel
281                 }
282             } catch (e: Exception) {
283                 e.printStackTrace()
284             }
285         }
286     }
287 
288     fun log2File(type: String, tag: String, sub: String) {
289         if (null != logHandler) {
290             logHandler?.post {
291                 try {
292                     while (!queue.isEmpty()) {
293                         var logInfo = queue.poll()
294                         val log = "${logFormat.format(Date())} ${myPid()} ${logInfo.type}/${logInfo.tag}: ${logInfo.sub}\n"
295                         fileChannel?.write(ByteBuffer.wrap(log.toByteArray()))
296                     }
297 
298                     val log = "${logFormat.format(Date())} ${myPid()} ${type}/${tag}: ${sub}\n"
299                     fileChannel?.write(ByteBuffer.wrap(log.toByteArray()))
300 
301                 } catch (e: java.lang.Exception) {
302                     e.printStackTrace()
303                 }
304             }
305         } else {
306             queue.offer(LogInfo(type, tag, sub))
307         }
308     }
309 }

 

上一篇:Kotlin协程- 协程的出现意味着什么?


下一篇:Android Jetpack系列之MVVM使用及封装