I'm curious about the internal working of a coroutine when suspended on the main thread. The real question is how to log a suspended function which is a coroutine on the main thread. Where exactly the execution is taking place? Is it a virtual thread?
4 Answers
If you are talking about logging the coroutine name:
You can achieve this by
Give name to coroutine(if you want custom name):
launch(CoroutineName("My-Coroutine"))Enable the logging in IntelliJ toolbar menu: Run -> Edit Configuration and add
-Dkotlinx.coroutines.debug in VM options.
Then you can see @My-Coroutine in logcat.
Try below code after Edit Configuration change:
fun main() = runBlocking {
println(" 'runBlocking': I'm working in thread ${Thread.currentThread().name}")
val job = launch(CoroutineName("my-custom-name")) {
println(" 'runBlocking': I'm working in thread ${Thread.currentThread().name}")
}
job.join()}
2 Comments
The other answers don't answer the question directly "How to get the name of a coroutine in Kotlin?"; instead, they suggest how to name a coroutine.
If inside a coroutine, the name can be retrieved using currentCoroutineContext()[CoroutineName].
If outside a coroutine, there's no direct way to retrieve the name using a reference to a Job or Deferred (too bad). However, there's a reflection hack that can be used. Of course, the usual warnings come attached, which are, no type safety and hacking into internal APIs that may change anytime.
@Suppress("UNCHECKED_CAST")
val nameString = AbstractCoroutine::class.memberFunctions
.single { it.name == "nameString" } as Function1<AbstractCoroutine<*>, String>
val name = nameString(job as AbstractCoroutine<*>)
.replace("\"", "")
.takeWhile { it != '#' }
The method/function containing this code has to be marked with @InternalCoroutinesApi.
Comments
You can give name to coroutine using CoroutineName(name:String) method at the time of creating coroutine:
repeat(5) {
GlobalScope.launch(CoroutineName("$it")) {
displayGreetingsFor(it)
}
}
To retrive the name given to coroutine use coroutineContext[CoroutineName.Key] as shown below:
private suspend fun displayGreetingsFor(i: Int) {
delay(100)
println(
" ${coroutineContext[CoroutineName.Key]} is executing on thread : ${Thread.currentThread().name}"
)
}
This is will print following o/p on console:
CoroutineName(0) is executing on thread : DefaultDispatcher-worker-3
CoroutineName(1) is executing on thread : DefaultDispatcher-worker-2
CoroutineName(2) is executing on thread : DefaultDispatcher-worker-8
CoroutineName(3) is executing on thread : DefaultDispatcher-worker-6
CoroutineName(4) is executing on thread : DefaultDispatcher-worker-5
1 Comment
GlobalScope by including that in your answer.You can use CoroutineName("some name") as others have mentioned
To print CoroutineName, there are 3 ways:
Method A
System.setProperty("kotlinx.coroutines.debug", "on" ) will make Job.toString() include the name
e.g.
"my coroutine#4":StandaloneCoroutine{Active}@b735e2c
Method B
Inside each scope, printing the CoroutineContext.toString() will include the name
e.g.
CoroutineContext: [CoroutineName(my coroutine), StandaloneCoroutine{Active}@b735e2c, DefaultDispatcher]
Method C
Quite similar to method B, for Job objects, we can print (Job as CoroutineScope).coroutineContext.
Take note that (Job as CoroutineContext) does NOT work! (not sure why but (Job as CoroutineContext).get[CoroutineName] returns null)

