Skip to content

Commit 5ff7901

Browse files
authored
Versioned helper resources, part 2 (#3880)
* Versioned helper resources, part 2 * Remove accidentally added javadoc param * Spotless * Fix test
1 parent c96af0d commit 5ff7901

File tree

8 files changed

+81
-39
lines changed

8 files changed

+81
-39
lines changed

javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/InstrumentationModuleInstaller.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,15 @@ AgentBuilder install(
5858
return parentAgentBuilder;
5959
}
6060
List<String> helperClassNames = instrumentationModule.getMuzzleHelperClassNames();
61-
HelperResourceBuilderImpl helperResources = new HelperResourceBuilderImpl();
61+
HelperResourceBuilderImpl helperResourceBuilder = new HelperResourceBuilderImpl();
6262
List<String> helperResourceNames = instrumentationModule.helperResourceNames();
6363
for (String helperResourceName : helperResourceNames) {
64-
helperResources.register(helperResourceName);
64+
helperResourceBuilder.register(helperResourceName);
6565
}
66-
instrumentationModule.registerHelperResources(helperResources);
66+
instrumentationModule.registerHelperResources(helperResourceBuilder);
6767
List<TypeInstrumentation> typeInstrumentations = instrumentationModule.typeInstrumentations();
6868
if (typeInstrumentations.isEmpty()) {
69-
if (!helperClassNames.isEmpty() || !helperResources.getResourcePathMappings().isEmpty()) {
69+
if (!helperClassNames.isEmpty() || !helperResourceBuilder.getResources().isEmpty()) {
7070
logger.warn(
7171
"Helper classes and resources won't be injected if no types are instrumented: {}",
7272
instrumentationModule.instrumentationName());
@@ -82,7 +82,7 @@ AgentBuilder install(
8282
new HelperInjector(
8383
instrumentationModule.instrumentationName(),
8484
helperClassNames,
85-
helperResources.getResourcePathMappings(),
85+
helperResourceBuilder.getResources(),
8686
Utils.getExtensionsClassLoader(),
8787
instrumentation);
8888
InstrumentationContextProvider contextProvider =

javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/test/HelperInjectionTest.groovy

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class HelperInjectionTest extends Specification {
2828
ClassLoader helpersSourceLoader = new URLClassLoader(helpersSourceUrls)
2929

3030
String helperClassName = HelperInjectionTest.getPackage().getName() + '.HelperClass'
31-
HelperInjector injector = new HelperInjector("test", [helperClassName], [:], helpersSourceLoader, null)
31+
HelperInjector injector = new HelperInjector("test", [helperClassName], [], helpersSourceLoader, null)
3232
AtomicReference<URLClassLoader> emptyLoader = new AtomicReference<>(new URLClassLoader(new URL[0], (ClassLoader) null))
3333

3434
when:
@@ -60,7 +60,7 @@ class HelperInjectionTest extends Specification {
6060
ByteBuddyAgent.install()
6161
AgentInstaller.installBytebuddyAgent(ByteBuddyAgent.getInstrumentation())
6262
String helperClassName = HelperInjectionTest.getPackage().getName() + '.HelperClass'
63-
HelperInjector injector = new HelperInjector("test", [helperClassName], [:], this.class.classLoader, ByteBuddyAgent.getInstrumentation())
63+
HelperInjector injector = new HelperInjector("test", [helperClassName], [], this.class.classLoader, ByteBuddyAgent.getInstrumentation())
6464
URLClassLoader bootstrapChild = new URLClassLoader(new URL[0], (ClassLoader) null)
6565

6666
when:

muzzle/build.gradle.kts

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ dependencies {
99
// Only used during compilation by bytebuddy plugin
1010
compileOnly("com.google.guava:guava")
1111

12+
compileOnly("com.google.auto.value:auto-value-annotations")
13+
annotationProcessor("com.google.auto.value:auto-value")
14+
1215
api("net.bytebuddy:byte-buddy")
1316

1417
implementation(project(":javaagent-bootstrap"))

muzzle/src/main/java/io/opentelemetry/javaagent/tooling/HelperInjector.java

+14-12
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import io.opentelemetry.instrumentation.api.caching.Cache;
99
import io.opentelemetry.javaagent.bootstrap.HelperResources;
10+
import io.opentelemetry.javaagent.tooling.muzzle.HelperResource;
1011
import java.io.File;
1112
import java.io.IOException;
1213
import java.lang.instrument.Instrumentation;
@@ -63,7 +64,7 @@ public String toString() {
6364
private final String requestingName;
6465

6566
private final Set<String> helperClassNames;
66-
private final Map<String, String> helperResourcePathMappings;
67+
private final List<HelperResource> helperResources;
6768
@Nullable private final ClassLoader helpersSource;
6869
@Nullable private final Instrumentation instrumentation;
6970
private final Map<String, byte[]> dynamicTypeMap = new LinkedHashMap<>();
@@ -87,14 +88,14 @@ public String toString() {
8788
public HelperInjector(
8889
String requestingName,
8990
List<String> helperClassNames,
90-
Map<String, String> helperResourcePathMappings,
91+
List<HelperResource> helperResources,
9192
// TODO can this be replaced with the context classloader?
9293
ClassLoader helpersSource,
9394
Instrumentation instrumentation) {
9495
this.requestingName = requestingName;
9596

9697
this.helperClassNames = new LinkedHashSet<>(helperClassNames);
97-
this.helperResourcePathMappings = helperResourcePathMappings;
98+
this.helperResources = helperResources;
9899
this.helpersSource = helpersSource;
99100
this.instrumentation = instrumentation;
100101
}
@@ -106,7 +107,7 @@ private HelperInjector(
106107
this.helperClassNames = helperMap.keySet();
107108
this.dynamicTypeMap.putAll(helperMap);
108109

109-
this.helperResourcePathMappings = Collections.emptyMap();
110+
this.helperResources = Collections.emptyList();
110111
this.helpersSource = null;
111112
this.instrumentation = instrumentation;
112113
}
@@ -149,19 +150,20 @@ public DynamicType.Builder<?> transform(
149150
classLoader = injectHelperClasses(typeDescription, classLoader, module);
150151
}
151152

152-
if (helpersSource != null && !helperResourcePathMappings.isEmpty()) {
153-
for (Map.Entry<String, String> entry : helperResourcePathMappings.entrySet()) {
154-
String agentResourcePath = entry.getValue();
155-
String applicationResourcePath = entry.getKey();
156-
URL resource = helpersSource.getResource(agentResourcePath);
153+
if (helpersSource != null && !helperResources.isEmpty()) {
154+
for (HelperResource helperResource : helperResources) {
155+
URL resource = helpersSource.getResource(helperResource.getAgentPath());
157156
if (resource == null) {
158-
logger.debug("Helper resource {} requested but not found.", agentResourcePath);
157+
logger.debug(
158+
"Helper resource {} requested but not found.", helperResource.getAgentPath());
159159
continue;
160160
}
161161

162162
logger.debug(
163-
"Injecting resource onto classloader {} -> {}", classLoader, applicationResourcePath);
164-
HelperResources.register(classLoader, applicationResourcePath, resource);
163+
"Injecting resource onto classloader {} -> {}",
164+
classLoader,
165+
helperResource.getApplicationPath());
166+
HelperResources.register(classLoader, helperResource.getApplicationPath(), resource);
165167
}
166168
}
167169

muzzle/src/main/java/io/opentelemetry/javaagent/tooling/muzzle/ClassLoaderMatcher.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -82,17 +82,17 @@ private static List<Mismatch> checkHelperInjection(
8282
try {
8383
// verify helper injector works
8484
List<String> allHelperClasses = instrumentationModule.getMuzzleHelperClassNames();
85-
HelperResourceBuilderImpl helperResources = new HelperResourceBuilderImpl();
85+
HelperResourceBuilderImpl helperResourceBuilder = new HelperResourceBuilderImpl();
8686
List<String> helperResourceNames = instrumentationModule.helperResourceNames();
8787
for (String helperResourceName : helperResourceNames) {
88-
helperResources.register(helperResourceName);
88+
helperResourceBuilder.register(helperResourceName);
8989
}
90-
instrumentationModule.registerHelperResources(helperResources);
90+
instrumentationModule.registerHelperResources(helperResourceBuilder);
9191
if (!allHelperClasses.isEmpty()) {
9292
new HelperInjector(
9393
instrumentationModule.instrumentationName(),
9494
allHelperClasses,
95-
helperResources.getResourcePathMappings(),
95+
helperResourceBuilder.getResources(),
9696
Thread.currentThread().getContextClassLoader(),
9797
null)
9898
.transform(null, null, classLoader, null);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.tooling.muzzle;
7+
8+
import com.google.auto.value.AutoValue;
9+
10+
@AutoValue
11+
public abstract class HelperResource {
12+
13+
/**
14+
* Create a new helper resource object.
15+
*
16+
* @param applicationPath The path in the user's class loader at which to inject the resource.
17+
* @param agentPath The path in the agent class loader from which to get the content for the
18+
* resource.
19+
*/
20+
public static HelperResource create(String applicationPath, String agentPath) {
21+
return new AutoValue_HelperResource(applicationPath, agentPath);
22+
}
23+
24+
/** The path in the user's class loader at which to inject the resource. */
25+
public abstract String getApplicationPath();
26+
27+
/** The path in the agent class loader from which to get the content for the resource. */
28+
public abstract String getAgentPath();
29+
}

muzzle/src/main/java/io/opentelemetry/javaagent/tooling/muzzle/HelperResourceBuilderImpl.java

+7-13
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,24 @@
66
package io.opentelemetry.javaagent.tooling.muzzle;
77

88
import io.opentelemetry.javaagent.extension.instrumentation.HelperResourceBuilder;
9-
import java.util.HashMap;
10-
import java.util.Map;
9+
import java.util.ArrayList;
10+
import java.util.List;
1111

1212
public class HelperResourceBuilderImpl implements HelperResourceBuilder {
1313

14-
private final Map<String, String> resourcePathMappings = new HashMap<>();
14+
private final List<HelperResource> resources = new ArrayList<>();
1515

1616
@Override
1717
public void register(String resourcePath) {
18-
resourcePathMappings.put(resourcePath, resourcePath);
18+
resources.add(HelperResource.create(resourcePath, resourcePath));
1919
}
2020

2121
@Override
2222
public void register(String applicationResourcePath, String agentResourcePath) {
23-
resourcePathMappings.put(applicationResourcePath, agentResourcePath);
23+
resources.add(HelperResource.create(applicationResourcePath, agentResourcePath));
2424
}
2525

26-
/**
27-
* Returns the registered mappings, where the keys are the paths in the user's class loader at
28-
* which to inject the resource ({@code applicationResourcePath}) and the values are the paths in
29-
* the agent class loader from which to get the content for the resource ({@code
30-
* agentResourcePath}).
31-
*/
32-
public Map<String, String> getResourcePathMappings() {
33-
return resourcePathMappings;
26+
public List<HelperResource> getResources() {
27+
return resources;
3428
}
3529
}

muzzle/src/main/java/io/opentelemetry/javaagent/tooling/muzzle/ReferenceCollector.java

+17-3
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,28 @@ public ReferenceCollector(
7474
*
7575
* @param resource path to the resource file, same as in {@link ClassLoader#getResource(String)}
7676
* @see InstrumentationClassPredicate
77+
* @deprecated Use {@link #collectReferencesFromResource(HelperResource)} instead.
7778
*/
79+
@Deprecated
7880
public void collectReferencesFromResource(String resource) {
79-
if (!isSpiFile(resource)) {
81+
collectReferencesFromResource(HelperResource.create(resource, resource));
82+
}
83+
84+
/**
85+
* If passed {@code resource} path points to an SPI file (either Java {@link
86+
* java.util.ServiceLoader} or AWS SDK {@code ExecutionInterceptor}) reads the file and adds every
87+
* implementation as a reference, traversing the graph of classes until a non-instrumentation
88+
* (external) class is encountered.
89+
*
90+
* @see InstrumentationClassPredicate
91+
*/
92+
public void collectReferencesFromResource(HelperResource helperResource) {
93+
if (!isSpiFile(helperResource.getApplicationPath())) {
8094
return;
8195
}
8296

8397
List<String> spiImplementations = new ArrayList<>();
84-
try (InputStream stream = getResourceStream(resource)) {
98+
try (InputStream stream = getResourceStream(helperResource.getAgentPath())) {
8599
BufferedReader reader = new BufferedReader(new InputStreamReader(stream, UTF_8));
86100
while (reader.ready()) {
87101
String line = reader.readLine();
@@ -90,7 +104,7 @@ public void collectReferencesFromResource(String resource) {
90104
}
91105
}
92106
} catch (IOException e) {
93-
throw new IllegalStateException("Error reading resource " + resource, e);
107+
throw new IllegalStateException("Error reading resource " + helperResource.getAgentPath(), e);
94108
}
95109

96110
visitClassesAndCollectReferences(spiImplementations, /* startsFromAdviceClass= */ false);

0 commit comments

Comments
 (0)