简体   繁体   English

如何拦截 Kotlin 协程?

[英]How to intercept Kotlin Coroutines?

I'm trying to instrument Kotlin coroutines, similar to what's done here using a Javaagent.我正在尝试检测 Kotlin 协程,类似于这里使用 Javaagent 所做的。 I don't want a Javaagent.我不想要 Javaagent。

The first step is to intercept the creation, suspension and resumption of Coroutines defined in the DebugProbes .第一步是拦截DebugProbes中定义的Coroutines的创建、暂停和恢复。 The code for that is as follows:代码如下:

public class Instrumentor {
    private static final Logger LOG = LoggerFactory.getLogger(Instrumentor.class);

    public static void install() {
        TypeDescription typeDescription = TypePool.Default.ofSystemLoader()
                .describe("kotlin.coroutines.jvm.internal.DebugProbesKt")
                .resolve();
        new ByteBuddy()
                .redefine(typeDescription, ClassFileLocator.ForClassLoader.ofSystemLoader())
                .method(ElementMatchers.named("probeCoroutineCreated").and(ElementMatchers.takesArguments(1)))
                .intercept(MethodDelegation.to(CoroutineCreatedAdvice.class))
                .method(ElementMatchers.named("probeCoroutineResumed").and(ElementMatchers.takesArguments(1)))
                .intercept(MethodDelegation.to(CoroutineResumedAdvice.class))
                .method(ElementMatchers.named("probeCoroutineSuspended").and(ElementMatchers.takesArguments(1)))
                .intercept(MethodDelegation.to(CoroutineSuspendedAdvice.class))
                .make()
                .load(ClassLoader.getSystemClassLoader(), ClassLoadingStrategy.Default.INJECTION);

        DebugProbes.INSTANCE.install();
    }

    public static void uninstall() {
        DebugProbes.INSTANCE.uninstall();
    }

    public static class CoroutineCreatedAdvice {
        @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
        public static Continuation<Object> exit(@Advice.Return(readOnly = false) Continuation<Object> retVal) {
            LOG.info("Coroutine created: {}", retVal);
           
            return retVal;
        }
    }

    public static class CoroutineResumedAdvice {
        @Advice.OnMethodEnter(suppress = Throwable.class)
        public static void enter(@Advice.Argument(0) final Continuation<Object> continuation) {
            LOG.info("Coroutine resumed: {}", continuation);
        }
    }

    public static class CoroutineSuspendedAdvice {
        @Advice.OnMethodEnter(suppress = Throwable.class)
        public static void enter(@Advice.Argument(0) final Continuation<Object> continuation) {
            LOG.info("Coroutine suspended: {}", continuation);
        }
    }
}

JUnit5 test to trigger interception: JUnit5 测试触发拦截:

class CoroutineInstrumentationTest {
    companion object {
        @JvmStatic
        @BeforeAll
        fun beforeAll() {
            Instrumentor.install()
        }

        @JvmStatic
        @AfterAll
        fun afterAll() {
            Instrumentor.uninstall()
        }
    }

    @Test
    fun testInterception() {
        runBlocking {
            println("Test")
        }
    }
}

However, no interception happens (confirmed by the absence of log statements and by using a debugger).但是,不会发生拦截(通过没有日志语句和使用调试器确认)。 I'm new to Byte Buddy, so it's possible I'm missing something.我是 Byte Buddy 的新手,所以我可能遗漏了一些东西。 Any ideas?有任何想法吗?

Kotlin v1.4.10, Kotlin Coroutines v1.3.9, Byte Buddy v1.10.17. Kotlin v1.4.10、Kotlin Coroutines v1.3.9、Byte Buddy v1.10.17。

Are you sure the class is not yet loaded at this point?您确定该类此时尚未加载吗? Try setting a breakpoint in ClassInjector.UsingReflection to see if you acutally walk through or of the injection is aborted due to a previously loaded class.尝试在ClassInjector.UsingReflection设置一个断点,以查看您是否真的通过或由于先前加载的类而中止了注入。

The cleaner solution would be a Java agent.更干净的解决方案是 Java 代理。 You can use byte-buddy-agent to create one dynamically by ByteBuddyAgent.install() and then register an AgentBuilder on it.您可以使用byte-buddy-agent通过ByteBuddyAgent.install()动态创建一个,然后在其上注册一个AgentBuilder

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM