You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android自定义Log函数如何打印协程ID或名称?

解决日志中打印协程ID/名称的问题

方案一:利用kotlinx.coroutines.debug探针获取协程信息

该方案需要依赖kotlinx-coroutines-debug库(建议仅在Debug编译环境引入,避免增加生产包体积),通过探针直接获取当前线程关联的协程详情。

修改后的日志函数代码

import kotlinx.coroutines.debug.DebugProbes

@JvmInline
value class MyLogger(private val tag: String) {       
    fun log(level: Level, e: Throwable? = null, message: String) {
        if (isLoggingEnabled(level)) {
            val threadName = Thread.currentThread().name
            // 尝试获取当前线程绑定的协程信息
            val coroutineInfo = runCatching {
                DebugProbes.getCoroutineInfo(Thread.currentThread())
            }.getOrNull()?.firstOrNull()
            
            // 拼接协程ID和名称
            val coroutineSuffix = coroutineInfo?.let { info ->
                val coroutineId = info.context[Job]?.id ?: "-"
                val coroutineName = info.context[CoroutineName]?.name ?: "coroutine"
                " @$coroutineName#$coroutineId"
            } ?: ""
            
            val fullThreadInfo = "[$threadName$coroutineSuffix]"
            val messageWithCoroutineInfo = "Running on: $fullThreadInfo | $message"
            
            when (level) {
                Level.VERBOSE -> Log.v(tag, messageWithCoroutineInfo, e)
                Level.DEBUG -> Log.d(tag, messageWithCoroutineInfo, e)
                Level.INFO -> Log.i(tag, messageWithCoroutineInfo, e)
                Level.WARN -> Log.w(tag, messageWithCoroutineInfo, e)
                Level.ERROR -> Log.e(tag, messageWithCoroutineInfo, e)
                Level.ASSERT -> Log.wtf(tag, messageWithCoroutineInfo, e)
            }
        }
    }
    // ... 保留原有其他方法
}

额外初始化步骤

在Application或Activity的onCreate中(仅Debug环境)初始化探针:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val isDebug = !BuildTypes.isProduction
    System.setProperty("kotlinx.coroutines.debug", if(isDebug) "on" else "off")
    // 仅Debug环境安装探针
    if (isDebug) {
        DebugProbes.install()
    }
}

方案二:直接从协程上下文获取信息

该方案无需额外依赖,但要求日志调用必须在协程上下文内执行,通过currentCoroutineContext()直接读取协程的Job ID和名称。

修改后的代码实现

import kotlin.coroutines.coroutineContext

@JvmInline
value class MyLogger(private val tag: String) {       
    // 新增带协程上下文参数的日志方法
    private fun logWithContext(level: Level, e: Throwable? = null, message: String, context: CoroutineContext) {
        if (isLoggingEnabled(level)) {
            val threadName = Thread.currentThread().name
            val job = context[Job]
            val coroutineName = context[CoroutineName]?.name ?: "coroutine"
            val coroutineId = job?.id ?: "-"
            
            val coroutineSuffix = job?.let { " @$coroutineName#$coroutineId" } ?: ""
            val fullThreadInfo = "[$threadName$coroutineSuffix]"
            val messageWithCoroutineInfo = "Running on: $fullThreadInfo | $message"
            
            when (level) {
                Level.VERBOSE -> Log.v(tag, messageWithCoroutineInfo, e)
                Level.DEBUG -> Log.d(tag, messageWithCoroutineInfo, e)
                Level.INFO -> Log.i(tag, messageWithCoroutineInfo, e)
                Level.WARN -> Log.w(tag, messageWithCoroutineInfo, e)
                Level.ERROR -> Log.e(tag, messageWithCoroutineInfo, e)
                Level.ASSERT -> Log.wtf(tag, messageWithCoroutineInfo, e)
            }
        }
    }
    
    // 修改原有扩展函数,自动传入当前协程上下文
    fun i(messageProvider: () -> String) {
        logWithContext(Level.INFO, message = messageProvider(), context = coroutineContext)
    }
    
    // 同理修改其他日志级别扩展函数(d/w/e等)
}

关键注意事项

  • 方案一的Debug探针仅在Debug环境使用,生产环境务必关闭,避免性能开销和潜在安全风险
  • 方案二要求所有日志调用必须在协程内部执行,若在普通线程调用则只会打印线程名称
  • 两种方案最终都能输出类似[AWT-EventQueue-0 @coroutine#40]的格式

内容的提问来源于stack exchange,提问作者Cindy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 12:07:27