Просмотр исходного кода

Allow specifying a comma separated list of extensions (#6137)

* Allow specifying a comma separated list of extensions

* update doc

* typo

* Update examples/extension/README.md

Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>

Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>
Lauri Tulmin 2 лет назад
Родитель
Сommit
091197a128

+ 2 - 1
examples/extension/README.md

@@ -20,7 +20,8 @@ To add the extension to the instrumentation agent:
           -Dotel.javaagent.extensions=build/libs/opentelemetry-java-instrumentation-extension-demo-1.0-all.jar
           -jar myapp.jar
      ```
-Note: to load multiple extensions, you can specify a directory path for the `otel.javaagent.extensions` value.
+Note: to load multiple extensions, you can specify a comma-separated list of extension jars or directories (that
+contain extension jars) for the `otel.javaagent.extensions` value.
 
 ## Embed extensions in the OpenTelemetry Agent
 

+ 19 - 7
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ExtensionClassLoader.java

@@ -16,6 +16,7 @@ import java.nio.channels.Channels;
 import java.nio.channels.ReadableByteChannel;
 import java.nio.file.Files;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Enumeration;
 import java.util.List;
 import java.util.jar.JarEntry;
@@ -114,27 +115,38 @@ public class ExtensionClassLoader extends URLClassLoader {
     return new ExtensionClassLoader(new URL[] {extensionUrl}, parent);
   }
 
-  private static List<URL> parseLocation(String locationName, File javaagentFile) {
+  // visible for testing
+  static List<URL> parseLocation(String locationName, File javaagentFile) {
+    if (locationName == null) {
+      return Collections.emptyList();
+    }
+
     List<URL> result = new ArrayList<>();
+    for (String location : locationName.split(",")) {
+      parseLocation(location, javaagentFile, result);
+    }
 
-    if (locationName == null) {
-      return result;
+    return result;
+  }
+
+  private static void parseLocation(String locationName, File javaagentFile, List<URL> locations) {
+    if (locationName.isEmpty()) {
+      return;
     }
 
     File location = new File(locationName);
     if (isJar(location)) {
-      addFileUrl(result, location);
+      addFileUrl(locations, location);
     } else if (location.isDirectory()) {
       File[] files = location.listFiles(ExtensionClassLoader::isJar);
       if (files != null) {
         for (File file : files) {
-          if (!file.getAbsolutePath().equals(javaagentFile.getAbsolutePath())) {
-            addFileUrl(result, file);
+          if (isJar(file) && !file.getAbsolutePath().equals(javaagentFile.getAbsolutePath())) {
+            addFileUrl(locations, file);
           }
         }
       }
     }
-    return result;
   }
 
   private static boolean isJar(File f) {

+ 80 - 0
javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/ExtensionClassLoaderTest.java

@@ -0,0 +1,80 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.tooling;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.io.File;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.jar.Attributes;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+public class ExtensionClassLoaderTest {
+  private static final File AGENT_FILE = new File("/agent.jar");
+
+  @Test
+  void testParseLocation(@TempDir Path outputDir) throws Exception {
+    String jarPath1 = createJar("test-1.jar", outputDir);
+    String jarPath2 = createJar("test-2.jar", outputDir);
+    // test that non-jar file is skipped
+    Files.createFile(outputDir.resolve("test.txt"));
+    {
+      List<URL> result = ExtensionClassLoader.parseLocation(jarPath1, AGENT_FILE);
+      assertEquals(1, result.size());
+    }
+    {
+      // empty paths are ignored
+      List<URL> result = ExtensionClassLoader.parseLocation("," + jarPath1 + ",,,", AGENT_FILE);
+      assertEquals(1, result.size());
+    }
+    {
+      List<URL> result = ExtensionClassLoader.parseLocation(jarPath1 + "," + jarPath2, AGENT_FILE);
+      assertEquals(2, result.size());
+    }
+    {
+      List<URL> result = ExtensionClassLoader.parseLocation(outputDir.toString(), AGENT_FILE);
+      assertEquals(2, result.size());
+    }
+    {
+      List<URL> result =
+          ExtensionClassLoader.parseLocation(
+              outputDir + "," + jarPath1 + "," + jarPath2, AGENT_FILE);
+      assertEquals(4, result.size());
+    }
+    {
+      List<URL> result = ExtensionClassLoader.parseLocation("/anydir", AGENT_FILE);
+      assertEquals(0, result.size());
+    }
+    {
+      List<URL> result = ExtensionClassLoader.parseLocation("/anyfile.jar", AGENT_FILE);
+      assertEquals(0, result.size());
+    }
+    {
+      List<URL> result = ExtensionClassLoader.parseLocation(jarPath1 + ",/anyfile.jar", AGENT_FILE);
+      assertEquals(1, result.size());
+    }
+  }
+
+  private static String createJar(String name, Path directory) throws Exception {
+    Path jarPath = directory.resolve(name);
+    createJar(jarPath);
+    return jarPath.toAbsolutePath().toString();
+  }
+
+  private static void createJar(Path path) throws Exception {
+    Manifest manifest = new Manifest();
+    manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
+    try (JarOutputStream jar = new JarOutputStream(Files.newOutputStream(path), manifest)) {
+      // empty jar
+    }
+  }
+}