-
Notifications
You must be signed in to change notification settings - Fork 879
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add capability for invokedynamic InstrumentationModules to inject pro…
…xies (#9565)
- Loading branch information
Showing
16 changed files
with
456 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
...metry/javaagent/extension/instrumentation/internal/ExperimentalInstrumentationModule.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.extension.instrumentation.internal; | ||
|
||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; | ||
import io.opentelemetry.javaagent.extension.instrumentation.internal.injection.ClassInjector; | ||
|
||
/** | ||
* This class is internal and is hence not for public use. Its APIs are unstable and can change at | ||
* any time. | ||
*/ | ||
public interface ExperimentalInstrumentationModule { | ||
|
||
/** | ||
* Only functional for Modules where {@link InstrumentationModule#isIndyModule()} returns {@code | ||
* true}. | ||
* | ||
* <p>Normally, helper and advice classes are loaded in a child classloader of the instrumented | ||
* classloader. This method allows to inject classes directly into the instrumented classloader | ||
* instead. | ||
* | ||
* @param injector the builder for injecting classes | ||
*/ | ||
default void injectClasses(ClassInjector injector) {} | ||
} |
39 changes: 39 additions & 0 deletions
39
...o/opentelemetry/javaagent/extension/instrumentation/internal/injection/ClassInjector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.extension.instrumentation.internal.injection; | ||
|
||
/** | ||
* This class is internal and is hence not for public use. Its APIs are unstable and can change at | ||
* any time. | ||
*/ | ||
public interface ClassInjector { | ||
|
||
/** | ||
* Create a builder for a proxy class which will be injected into the instrumented {@link | ||
* ClassLoader}. The generated proxy will delegate to the original class, which is loaded in a | ||
* separate classloader. | ||
* | ||
* <p>This removes the need for the proxied class and its dependencies to be visible (just like | ||
* Advices) to the instrumented ClassLoader. | ||
* | ||
* @param classToProxy the fully qualified name of the class for which a proxy will be generated | ||
* @param newProxyName the fully qualified name to use for the generated proxy | ||
* @return a builder for further customizing the proxy. {@link | ||
* ProxyInjectionBuilder#inject(InjectionMode)} must be called to actually inject the proxy. | ||
*/ | ||
ProxyInjectionBuilder proxyBuilder(String classToProxy, String newProxyName); | ||
|
||
/** | ||
* Same as invoking {@link #proxyBuilder(String, String)}, but the resulting proxy will have the | ||
* same name as the proxied class. | ||
* | ||
* @param classToProxy the fully qualified name of the class for which a proxy will be generated | ||
* @return a builder for further customizing and injecting the proxy | ||
*/ | ||
default ProxyInjectionBuilder proxyBuilder(String classToProxy) { | ||
return proxyBuilder(classToProxy, classToProxy); | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
...o/opentelemetry/javaagent/extension/instrumentation/internal/injection/InjectionMode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.extension.instrumentation.internal.injection; | ||
|
||
/** | ||
* This class is internal and is hence not for public use. Its APIs are unstable and can change at | ||
* any time. | ||
*/ | ||
public enum InjectionMode { | ||
CLASS_ONLY | ||
// TODO: implement the modes RESOURCE_ONLY and CLASS_AND_RESOURCE | ||
// This will require a custom URL implementation for byte arrays, similar to how bytebuddy's | ||
// ByteArrayClassLoader does it | ||
|
||
} |
15 changes: 15 additions & 0 deletions
15
...lemetry/javaagent/extension/instrumentation/internal/injection/ProxyInjectionBuilder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.extension.instrumentation.internal.injection; | ||
|
||
/** | ||
* This class is internal and is hence not for public use. Its APIs are unstable and can change at | ||
* any time. | ||
*/ | ||
public interface ProxyInjectionBuilder { | ||
|
||
void inject(InjectionMode mode); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
65 changes: 65 additions & 0 deletions
65
.../main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/ClassInjectorImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.tooling.instrumentation.indy; | ||
|
||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; | ||
import io.opentelemetry.javaagent.extension.instrumentation.internal.injection.ClassInjector; | ||
import io.opentelemetry.javaagent.extension.instrumentation.internal.injection.InjectionMode; | ||
import io.opentelemetry.javaagent.extension.instrumentation.internal.injection.ProxyInjectionBuilder; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.function.Function; | ||
import net.bytebuddy.description.type.TypeDescription; | ||
import net.bytebuddy.pool.TypePool; | ||
|
||
public class ClassInjectorImpl implements ClassInjector { | ||
|
||
private final InstrumentationModule instrumentationModule; | ||
|
||
private final Map<String, Function<ClassLoader, byte[]>> classesToInject; | ||
|
||
private final IndyProxyFactory proxyFactory; | ||
|
||
public ClassInjectorImpl(InstrumentationModule module) { | ||
instrumentationModule = module; | ||
classesToInject = new HashMap<>(); | ||
proxyFactory = IndyBootstrap.getProxyFactory(module); | ||
} | ||
|
||
public Map<String, Function<ClassLoader, byte[]>> getClassesToInject() { | ||
return classesToInject; | ||
} | ||
|
||
@Override | ||
public ProxyInjectionBuilder proxyBuilder(String classToProxy, String newProxyName) { | ||
return new ProxyBuilder(classToProxy, newProxyName); | ||
} | ||
|
||
private class ProxyBuilder implements ProxyInjectionBuilder { | ||
|
||
private final String classToProxy; | ||
private final String proxyClassName; | ||
|
||
ProxyBuilder(String classToProxy, String proxyClassName) { | ||
this.classToProxy = classToProxy; | ||
this.proxyClassName = proxyClassName; | ||
} | ||
|
||
@Override | ||
public void inject(InjectionMode mode) { | ||
if (mode != InjectionMode.CLASS_ONLY) { | ||
throw new UnsupportedOperationException("Not yet implemented"); | ||
} | ||
classesToInject.put( | ||
proxyClassName, | ||
cl -> { | ||
TypePool typePool = IndyModuleTypePool.get(cl, instrumentationModule); | ||
TypeDescription proxiedType = typePool.describe(classToProxy).resolve(); | ||
return proxyFactory.generateProxy(proxiedType, proxyClassName).getBytes(); | ||
}); | ||
} | ||
} | ||
} |
Oops, something went wrong.