前言

Android开发中,日志定制化打印是很重要的,下面是一种Kotlin日志打印封装,不需要手动每个类中定义TAG了,只要使用下面logelogvlogd等,让代码自动获取当前类名进行输出TAG。

懒人做法。

正文

代码1

只支持kotlin

import android.util.Log
import kotlin.reflect.KClass
private const val DEFAULT_TAG = "BiuApp_"//自定义
private const val MAX_TAG_LENGTH = 23
// 标记类,用于动态获取当前文件的包名
private class Pkg
private val SELF_PACKAGE: String = Pkg::class.java.`package`?.name ?: ""

private val SKIP_PREFIXES = listOf(
    SELF_PACKAGE, "kotlin.", "kotlinx.", "java.", "javax.",
    "sun.", "android.", "dalvik.", "com.android."
)

/**
 * 获取安全的 Tag(纯泛型解析,零性能开销)
 */
fun <T : Any> callerTag(clz: KClass<T>? = null): String {
    clz?.qualifiedName?.let { className ->
        if (!SKIP_PREFIXES.any { className.startsWith(it) }) {
            val simpleName = className.substringBefore("$").substringAfterLast('.')
            if (simpleName.isNotEmpty()) {
                val fullTag = DEFAULT_TAG + simpleName
                // 确保 Tag 不超过 Android 的 23 字符限制
                return if (fullTag.length > MAX_TAG_LENGTH) fullTag.take(MAX_TAG_LENGTH) else fullTag
            }
        }
    }
    // 兜底默认 Tag
    return DEFAULT_TAG
}

// ================= 扩展函数封装 =================

inline fun <reified T : Any> T.logv(msg: String, tr: Throwable? = null) {
    Log.v(callerTag(T::class), msg, tr)
}

inline fun <reified T : Any> T.logd(msg: String, tr: Throwable? = null) {
    Log.d(callerTag(T::class), msg, tr)
}

inline fun <reified T : Any> T.logi(msg: String, tr: Throwable? = null) {
    Log.i(callerTag(T::class), msg, tr)
}

inline fun <reified T : Any> T.logw(msg: String, tr: Throwable? = null) {
    Log.w(callerTag(T::class), msg, tr)
}

inline fun <reified T : Any> T.loge(msg: String, tr: Throwable? = null) {
    Log.e(callerTag(T::class), msg, tr)
}

代码2

支持kotlin和java

import android.util.Log
import kotlin.reflect.KClass

private const val DEFAULT_TAG = "BiuApp_"//自定义
private const val MAX_TAG_LENGTH = 23

// 标记类,用于动态获取当前文件的包名
private class Pkg

private val SELF_PACKAGE: String = Pkg::class.java.`package`?.name ?: ""

private val SKIP_PREFIXES = listOf(
    SELF_PACKAGE, "kotlin.", "kotlinx.", "java.", "javax.",
    "sun.", "android.", "dalvik.", "com.android."
)

/**
 * 获取安全的 Tag(纯泛型解析,零性能开销)
 */
fun <T : Any> callerTag(clz: KClass<T>? = null): String {
    clz?.qualifiedName?.let { className ->
        if (!SKIP_PREFIXES.any { className.startsWith(it) }) {
            val simpleName = className.substringBefore("$").substringAfterLast('.')
            if (simpleName.isNotEmpty()) {
                val fullTag = DEFAULT_TAG + simpleName
                // 确保 Tag 不超过 Android 的 23 字符限制
                return if (fullTag.length > MAX_TAG_LENGTH) fullTag.take(MAX_TAG_LENGTH) else fullTag
            }
        }
    }
    // 兜底默认 Tag
    return DEFAULT_TAG
}
// ================= 扩展函数封装 =================

inline fun <reified T : Any> T.logv(msg: String, tr: Throwable? = null) {
    Log.v(callerTag(T::class), msg, tr)
}

inline fun <reified T : Any> T.logd(msg: String, tr: Throwable? = null) {
    Log.d(callerTag(T::class), msg, tr)
}

inline fun <reified T : Any> T.logi(msg: String, tr: Throwable? = null) {
    Log.i(callerTag(T::class), msg, tr)
}

inline fun <reified T : Any> T.logw(msg: String, tr: Throwable? = null) {
    Log.w(callerTag(T::class), msg, tr)
}

inline fun <reified T : Any> T.loge(msg: String, tr: Throwable? = null) {
    Log.e(callerTag(T::class), msg, tr)
}

// ================= Java 友好顶层函数 =================
// Java 中通过 LogKt.xxx(...) 调用;TAG 自动取调用者类名。

fun logv(msg: String) {
    Log.v(callerTag(Throwable().stackTrace[1].className), msg)
}

fun logd(msg: String) {
    Log.d(callerTag(Throwable().stackTrace[1].className), msg)
}

fun logi(msg: String) {
    Log.i(callerTag(Throwable().stackTrace[1].className), msg)
}

fun logw(msg: String) {
    Log.w(callerTag(Throwable().stackTrace[1].className), msg)
}

fun loge(msg: String) {
    Log.e(callerTag(Throwable().stackTrace[1].className), msg)
}

/** 带 Throwable 的重载,对应 AppLog.e(msg, tr) */
fun loge(msg: String, tr: Throwable) {
    Log.e(callerTag(Throwable().stackTrace[1].className), msg, tr)
}

/** 仅 Throwable(msg 取异常信息),对应 AppLog.e(tr) */
fun loge(tr: Throwable) {
    Log.e(callerTag(Throwable().stackTrace[1].className), tr.message ?: "", tr)
}

private fun callerTag(className: String): String {
    if (className.isEmpty()) return DEFAULT_TAG
    val simple = className.substringBefore("$").substringAfterLast('.')
    val full = DEFAULT_TAG + simple
    return if (full.length > MAX_TAG_LENGTH) full.take(MAX_TAG_LENGTH) else full
}

参考文章

  1. AI 优化过

  2. 同事代码

相关文章