byte-buddy icon indicating copy to clipboard operation
byte-buddy copied to clipboard

Cannot resolve bytebuddy otel class when using a second Java Agent with ByteBuddy for Kafka instrumentation

Open lisong2010 opened this issue 7 months ago • 2 comments

I'm encountering a net.bytebuddy.pool.TypePool$Resolution$NoSuchTypeException when using a custom Java Agent based on ByteBuddy in conjunction with the OpenTelemetry Java Agent. The error occurs during transformation of KafkaConsumer:

Failed to handle org.apache.kafka.clients.consumer.KafkaConsumer for transformation on class loader org.springframework.boot.loader.LaunchedURLClassLoader@395065af net.bytebuddy.pool.TypePool$Resolution$NoSuchTypeException: Cannot resolve type description for io.opentelemetry.javaagent.bootstrap.field.VirtualFieldAccessor$org$apache$kafka$clients$consumer$Consumer$java$util$Map
	at shade.dependencies.pool.TypePool$Resolution$Illegal.resolve(TypePool.java:192)
	at shade.dependencies.pool.TypePool$Default$WithLazyResolution$LazyTypeDescription.delegate(TypePool.java:1170)
	at shade.dependencies.description.type.TypeDescription$AbstractBase$OfSimpleType$WithDelegation.getTypeVariables(TypeDescription.java:8532)
	at shade.dependencies.description.type.TypeDescription$AbstractBase.isGenerified(TypeDescription.java:8138)
	at shade.dependencies.description.type.TypeDescription$Generic$Visitor$Reifying.onNonGenericType(TypeDescription.java:1734)
	at shade.dependencies.description.type.TypeDescription$Generic$Visitor$Reifying$1.onNonGenericType(TypeDescription.java:1690)
	at shade.dependencies.description.type.TypeDescription$Generic$OfNonGenericType.accept(TypeDescription.java:3749)
	at shade.dependencies.dynamic.scaffold.MethodGraph$Compiler$Default.doAnalyze(MethodGraph.java:746)
	at shade.dependencies.dynamic.scaffold.MethodGraph$Compiler$Default.compile(MethodGraph.java:668)
	at shade.dependencies.dynamic.scaffold.MethodGraph$Compiler$AbstractBase.compile(MethodGraph.java:519)
	at shade.dependencies.dynamic.scaffold.MethodRegistry$Default.prepare(MethodRegistry.java:472)
	at shade.dependencies.dynamic.scaffold.inline.RedefinitionDynamicTypeBuilder.toTypeWriter(RedefinitionDynamicTypeBuilder.java:213)
	at shade.dependencies.dynamic.DynamicType$Builder$AbstractBase$UsingTypeWriter.make(DynamicType.java:4064)
	at shade.dependencies.agent.builder.AgentBuilder$Default$ExecutingTransformer.doTransform(AgentBuilder.java:12620)
	at shade.dependencies.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:12555)
	at shade.dependencies.agent.builder.AgentBuilder$Default$ExecutingTransformer.access$1800(AgentBuilder.java:12264)
	at shade.dependencies.agent.builder.AgentBuilder$Default$ExecutingTransformer$Java9CapableVmDispatcher.run(AgentBuilder.java:13046)
	at shade.dependencies.agent.builder.AgentBuilder$Default$ExecutingTransformer$Java9CapableVmDispatcher.run(AgentBuilder.java:12976)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
	at shade.dependencies.agent.builder.AgentBuilder$Default$ExecutingTransformer.doPrivileged(AgentBuilder.java)
	at shade.dependencies.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:12498)
	at shade.dependencies.agent.builder.AgentBuilder$Default$ExecutingTransformer$ByteBuddy$ModuleSupport.transform(Unknown Source)

It seems that my second agent is unable to resolve the VirtualFieldAccessor class injected by the OpenTelemetry agent

Important constraint My custom agent must be loaded last, due to architectural requirements and lifecycle constraints.

Expected behavior My second agent should be able to safely apply transformations to Kafka classes (e.g., Consumer) without encountering unresolved type exceptions related to OpenTelemetry's internal virtual field mechanism.

Request for guidance Is there a recommended way to access or safely bypass OpenTelemetry-injected types (e.g., VirtualFieldAccessor) in a multi-agent setup? Is it possible to avoid interference with OpenTelemetry's instrumentation when we need to augment the same target class?

my bytebuddy bulder is:

new Default().disableClassFormatChanges().installOn(instrumentation)

lisong2010 avatar Jun 17 '25 13:06 lisong2010

The OpenTelemetry agent likely appends the boot loader with additional types, and those types cannot be resolved by a class loader as their class file is not available. Basically, you only have two options:

  1. You add a resolver for a ClassFileLocator or TypePool that also looks up the classes from the other agent.
  2. You use a resolution strategy that does not imply a full resolution of type descriptions. For example, you could decorate classes, what however limits your own capability to add fields or methods.

What kind if transformations are you applying?

raphw avatar Jun 19 '25 07:06 raphw

I referred to https://github.com/raphw/byte-buddy/issues/1419, and that resolved the issue.

    public MethodGraph.Linked compile(TypeDefinition typeDefinition, TypeDescription viewPoint) {
        for (MethodDescription methodDescription : typeDefinition.getDeclaredMethods()
            .filter(
                // ignores all methods which refer to unknown types
                failSafe(
                    isVirtual()
                        .and(not(isBridge()))
                        .and(isVisibleTo(viewPoint))
                        .and(hasParameters(whereNone(hasType(not(isVisibleTo(viewPoint))))))
                )
            )
        ) {
            //todo something
        }
        return new MethodGraph.Linked.Delegation(.....);
    }

lisong2010 avatar Jun 20 '25 07:06 lisong2010