首页 > 解决方案 > 使用 ByteBuddy 检测另一个 java 代理

问题描述

我正在使用Elastic APM 代理作为 Java 代理来监控我的 Spring Boot 微服务中各种方法的使用情况。这一切都很好,我们能够在 Kibana 中绘制各种指标。不幸的是,它没有做的是始终将相同的标签附加到事务中的所有跨度,例如发出原始请求的用户的详细信息。

为了解决这个问题,我认为我可以使用 ByteBuddy(我以前从未使用过)来包装 APM Span 类的任何用法并将该信息(因为它可以从 ThreadLocal 中轻松获得)附加到每个实例。但是,我在访问 Span 类时遇到问题,因为它位于 APM Java 代理中,并且使用以下代码,我得到以下日志,其中似乎无法找到 Span 类...

        Instrumentation instrumentation = ByteBuddyAgent.install();
        new AgentBuilder.Default()
                .with(debuggingListener)
                .ignore(ElementMatchers.nameStartsWith("net.bytebuddy."))
                .type(ElementMatchers.named("co.elastic.apm.agent.impl.transaction.Span"), ElementMatchers.isBootstrapClassLoader())
                .transform((builder, type, classLoader, module) -> builder.visit(Advice.to(SpanAdvice.class).on(ElementMatchers.hasMethodName("start"))))
                .installOn(instrumentation);
[Byte Buddy] DISCOVERY co.elastic.apm.agent.impl.transaction.Transaction [null, unnamed module @758a34ce, loaded=false]
[Byte Buddy] IGNORE co.elastic.apm.agent.impl.transaction.Transaction [null, unnamed module @758a34ce, loaded=false]
[Byte Buddy] COMPLETE co.elastic.apm.agent.impl.transaction.Transaction [null, unnamed module @758a34ce, loaded=false]
[Byte Buddy] DISCOVERY co.elastic.apm.agent.impl.transaction.Transaction$1 [null, unnamed module @758a34ce, loaded=false]
[Byte Buddy] IGNORE co.elastic.apm.agent.impl.transaction.Transaction$1 [null, unnamed module @758a34ce, loaded=false]
[Byte Buddy] COMPLETE co.elastic.apm.agent.impl.transaction.Transaction$1 [null, unnamed module @758a34ce, loaded=false]
[Byte Buddy] DISCOVERY co.elastic.apm.agent.impl.transaction.AbstractSpan$ChildDurationTimer [null, unnamed module @758a34ce, loaded=false]
[Byte Buddy] IGNORE co.elastic.apm.agent.impl.transaction.AbstractSpan$ChildDurationTimer [null, unnamed module @758a34ce, loaded=false]
[Byte Buddy] COMPLETE co.elastic.apm.agent.impl.transaction.AbstractSpan$ChildDurationTimer [null, unnamed module @758a34ce, loaded=false]
[Byte Buddy] DISCOVERY co.elastic.apm.agent.impl.transaction.SpanCount [null, unnamed module @758a34ce, loaded=false]
[Byte Buddy] IGNORE co.elastic.apm.agent.impl.transaction.SpanCount [null, unnamed module @758a34ce, loaded=false]
[Byte Buddy] COMPLETE co.elastic.apm.agent.impl.transaction.SpanCount [null, unnamed module @758a34ce, loaded=false]
[Byte Buddy] DISCOVERY co.elastic.apm.agent.impl.transaction.TraceState$TextTracestateAppender [null, unnamed module @758a34ce, loaded=false]
[Byte Buddy] IGNORE co.elastic.apm.agent.impl.transaction.TraceState$TextTracestateAppender [null, unnamed module @758a34ce, loaded=false]
[Byte Buddy] COMPLETE co.elastic.apm.agent.impl.transaction.TraceState$TextTracestateAppender [null, unnamed module @758a34ce, loaded=false]

我已经尝试将 ByteBuddy 用于我自己的类,并且一切正常,但我对哪个类加载器加载了什么以及如何将 ByteBuddy 指向它们感到非常困惑。

标签: javabyte-buddyelastic-apm

解决方案


免责声明:这个答案现在是一个存根。

您应该首先尝试像里卡多建议的那样探索一种更规范的做事方式。如果由于某种原因不起作用,那么我们可以探索检测代理类的方法 - 不是因为我认为这是一个好主意,而是因为它在技术上很有趣。

基本上,我们必须确定在您的 ByteBuddy 代理激活之前是否已经加载了您想要检测的类。那么你将不得不使用类重新转换而不是重新定义。您必须确保您应用的建议可以完成其工作,而无需更改有关方法签名和字段的类结构。

  .disableClassFormatChanges()
  .with(RETRANSFORMATION)

您还需要确保通知和 ByteBuddy 对其他代理的类加载器可见,例如通过将两者都放在引导类路径上。但是,我们不要超越自己。请先探索里卡多的想法。


推荐阅读