You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@dubbo.apache.org by al...@apache.org on 2022/04/25 06:00:04 UTC

[dubbo-samples] branch master updated: Add jacoco agent inject support (#441)

This is an automated email from the ASF dual-hosted git repository.

albumenj pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/dubbo-samples.git


The following commit(s) were added to refs/heads/master by this push:
     new 63013d29 Add jacoco agent inject support (#441)
63013d29 is described below

commit 63013d29ef393fe9294e5d93e456d3ed2a3f7763
Author: Albumen Kevin <jh...@gmail.com>
AuthorDate: Mon Apr 25 13:59:56 2022 +0800

    Add jacoco agent inject support (#441)
    
    * Add jacoco collector
    
    * add asf header
---
 test/dubbo-scenario-builder/pom.xml                |   6 +
 .../dubbo/scenario/builder/ConfigurationImpl.java  |  22 ++-
 .../dubbo/scenario/builder/IConfiguration.java     |   2 +
 .../dubbo/scenario/builder/JacocoDownloader.java   | 181 +++++++++++++++++++++
 .../scenario/builder/ScenarioBuilderMain.java      |   1 +
 5 files changed, 208 insertions(+), 4 deletions(-)

diff --git a/test/dubbo-scenario-builder/pom.xml b/test/dubbo-scenario-builder/pom.xml
index eaf7c870..c51b3ba2 100644
--- a/test/dubbo-scenario-builder/pom.xml
+++ b/test/dubbo-scenario-builder/pom.xml
@@ -36,6 +36,12 @@
             <version>2.3.28</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.asynchttpclient</groupId>
+            <artifactId>async-http-client</artifactId>
+            <version>2.12.1</version>
+        </dependency>
+
         <dependency>
             <groupId>org.yaml</groupId>
             <artifactId>snakeyaml</artifactId>
diff --git a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ConfigurationImpl.java b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ConfigurationImpl.java
index 1c9894d8..140698e1 100644
--- a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ConfigurationImpl.java
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ConfigurationImpl.java
@@ -17,11 +17,12 @@
 
 package org.apache.dubbo.scenario.builder;
 
-import org.apache.commons.lang3.StringUtils;
 import org.apache.dubbo.scenario.builder.exception.ConfigureFileNotFoundException;
 import org.apache.dubbo.scenario.builder.vo.CaseConfiguration;
 import org.apache.dubbo.scenario.builder.vo.DockerService;
 import org.apache.dubbo.scenario.builder.vo.ServiceComponent;
+
+import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.yaml.snakeyaml.Yaml;
@@ -72,6 +73,7 @@ public class ConfigurationImpl implements IConfiguration {
     private String configBasedir;
     private String scenarioName;
     private final String scenarioLogDir;
+    private final boolean jacocoEnable = Boolean.parseBoolean(System.getProperty("jacoco.enable"));
     private int scenarioTimeout = 200;
     private int javaDebugPort = 20660;
     private int debugTimeout = 36000;
@@ -241,12 +243,13 @@ public class ConfigurationImpl implements IConfiguration {
 
     private void fillupServices(CaseConfiguration caseConfiguration) throws IOException {
         List<String> caseSystemProps = caseConfiguration.getSystemProps();
+        int index = 0;
         for (Map.Entry<String, ServiceComponent> entry : caseConfiguration.getServices().entrySet()) {
             String serviceName = entry.getKey();
             ServiceComponent service = entry.getValue();
             String type = service.getType();
             if (isAppOrTestService(type)) {
-                service.setImage(SAMPLE_TEST_IMAGE+":"+testImageVersion);
+                service.setImage(SAMPLE_TEST_IMAGE + ":" + testImageVersion);
                 service.setBasedir(toAbsolutePath(service.getBasedir()));
                 if (service.getVolumes() == null) {
                     service.setVolumes(new ArrayList<>());
@@ -272,7 +275,7 @@ public class ConfigurationImpl implements IConfiguration {
 
                 //set run delay
                 if (service.getRunDelay() > 0) {
-                    setEnv(service, ENV_RUN_DELAY, service.getRunDelay()+"");
+                    setEnv(service, ENV_RUN_DELAY, service.getRunDelay() + "");
                 }
 
                 //set check timeout
@@ -286,7 +289,7 @@ public class ConfigurationImpl implements IConfiguration {
                         String debugOpts;
                         if (isJdk9OrLater) {
                             debugOpts = String.format("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:%s", debugPort);
-                        }else {
+                        } else {
                             debugOpts = String.format("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=%s", debugPort);
                         }
                         appendEnv(service, ENV_DEBUG_OPTS, debugOpts);
@@ -377,6 +380,12 @@ public class ConfigurationImpl implements IConfiguration {
                 appendEnv(service, ENV_JAVA_OPTS, str);
             }
 
+            if (jacocoEnable) {
+                //set jacoco agent
+                String jacoco = "-javaagent:/usr/local/dubbo/app/jacocoagent.jar=destfile=/usr/local/dubbo/app/jacoco/" + index++ + "-jacoco.exec";
+                appendEnv(service, ENV_JAVA_OPTS, jacoco);
+            }
+
             if (service.getHealthcheck() != null) {
                 healthcheckServices.add(serviceName);
             }
@@ -530,6 +539,11 @@ public class ConfigurationImpl implements IConfiguration {
         return System.getProperty("jacoco.home");
     }
 
+    @Override
+    public boolean enableJacoco() {
+        return jacocoEnable;
+    }
+
     @Override
     public String debugMode() {
         return isDebug() ? "1" : "0";
diff --git a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/IConfiguration.java b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/IConfiguration.java
index abebb5d2..acc8cf97 100644
--- a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/IConfiguration.java
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/IConfiguration.java
@@ -44,6 +44,8 @@ public interface IConfiguration {
 
     String jacocoHome();
 
+    boolean enableJacoco();
+
     String debugMode();
 
     Map<String, Object> toMap();
diff --git a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/JacocoDownloader.java b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/JacocoDownloader.java
new file mode 100644
index 00000000..d0660665
--- /dev/null
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/JacocoDownloader.java
@@ -0,0 +1,181 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.scenario.builder;
+
+import org.asynchttpclient.AsyncCompletionHandler;
+import org.asynchttpclient.AsyncHttpClient;
+import org.asynchttpclient.DefaultAsyncHttpClient;
+import org.asynchttpclient.DefaultAsyncHttpClientConfig;
+import org.asynchttpclient.Response;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.invoke.MethodHandles;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public class JacocoDownloader {
+    private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+    /**
+     * The jacoco agent version
+     */
+    private static final String JACOCO_VERSION = "0.8.8";
+
+    /**
+     * The jacoco binary file name
+     */
+    private static final String JACOCO_BINARY_FILE_NAME = "org.jacoco.agent-" + JACOCO_VERSION + "-runtime.jar";
+
+    /**
+     * The url format for jacoco binary file.
+     */
+    private static final String JACOCO_BINARY_URL_FORMAT = "https://repo1.maven.org/maven2/org/jacoco/org.jacoco.agent/" + JACOCO_VERSION + "/org.jacoco.agent-" + JACOCO_VERSION + "-runtime.jar";
+
+    /**
+     * The temporary directory.
+     */
+    private static final String TEMPORARY_DIRECTORY = "jacoco";
+
+    /**
+     * The timeout when download jacoco binary archive file.
+     */
+    private static final int REQUEST_TIMEOUT = 30 * 1000;
+
+    /**
+     * The timeout when connect the download url.
+     */
+    private static final int CONNECT_TIMEOUT = 10 * 1000;
+
+    /**
+     * Returns {@code true} if the file exists with the given file path, otherwise {@code false}.
+     *
+     * @param filePath the file path to check.
+     */
+    private static boolean checkFile(Path filePath) {
+        return Files.exists(filePath) && filePath.toFile().isFile();
+    }
+
+    public static void initialize(IConfiguration configuration) {
+        if (!configuration.enableJacoco()) {
+            return;
+        }
+
+        Path expectedFile = new File(configuration.outputDir() + File.separator + "jacocoagent.jar").toPath();
+        // checks the jacoco binary file exists or not
+        if (checkFile(expectedFile)) {
+            return;
+        }
+        Path temporaryFilePath;
+        try {
+            temporaryFilePath = Paths.get(Files.createTempDirectory("").getParent().toString(),
+                    TEMPORARY_DIRECTORY,
+                    JACOCO_BINARY_FILE_NAME);
+        } catch (IOException e) {
+            throw new RuntimeException(String.format("Cannot create the temporary directory, file path: %s", TEMPORARY_DIRECTORY), e);
+        }
+
+        // create the temporary directory path.
+        try {
+            Files.createDirectories(temporaryFilePath.getParent());
+        } catch (IOException e) {
+            throw new RuntimeException(String.format("Failed to create the temporary directory to save jacoco binary file, file path:%s", temporaryFilePath.getParent()), e);
+        }
+
+        // download jacoco binary file in temporary directory.
+        try {
+            LOGGER.info("It is beginning to download the jacoco binary archive, it will take several minutes..." +
+                    "\nThe jacoco binary archive file will be download from " + JACOCO_BINARY_URL_FORMAT + "," +
+                    "\nwhich will be saved in " + temporaryFilePath.toString() + "," +
+                    "\nalso it will be renamed to '" + JACOCO_BINARY_FILE_NAME + "' and moved into " + expectedFile + ".\n");
+            download(temporaryFilePath);
+        } catch (Exception e) {
+            throw new RuntimeException(String.format("Download jacoco binary archive failed, download url:%s, file path:%s." +
+                            "\nOr you can do something to avoid this problem as below:" +
+                            "\n1. Download jacoco binary archive manually regardless of the version" +
+                            "\n2. Rename the downloaded file named 'org.jacoco.agent-{version}-runtime.jar' to 'jacocoagent.jar'" +
+                            "\n3. Put the renamed file in %s, you maybe need to create the directory if necessary.\n",
+                    JACOCO_BINARY_URL_FORMAT, temporaryFilePath, expectedFile), e);
+        }
+
+        // check downloaded jacoco binary file in temporary directory.
+        if (!checkFile(temporaryFilePath)) {
+            throw new IllegalArgumentException(String.format("There are some unknown problem occurred when downloaded the jacoco binary archive file, file path:%s", temporaryFilePath));
+        }
+
+        // create target directory if necessary
+        if (!Files.exists(expectedFile)) {
+            try {
+                Files.createDirectories(expectedFile.getParent());
+            } catch (IOException e) {
+                throw new IllegalArgumentException(String.format("Failed to create target directory, the directory path: %s", expectedFile.getParent()), e);
+            }
+        }
+
+        // copy the downloaded jacoco binary file into the target file path
+        try {
+            Files.copy(temporaryFilePath, expectedFile, StandardCopyOption.REPLACE_EXISTING);
+        } catch (IOException e) {
+            throw new IllegalArgumentException(String.format("Failed to copy file, the source file path: %s, the target file path: %s", temporaryFilePath, expectedFile), e);
+        }
+
+        // checks the jacoco binary file exists or not again
+        if (!checkFile(expectedFile)) {
+            throw new IllegalArgumentException(String.format("The jacoco binary archive file doesn't exist, file path:%s", expectedFile));
+        }
+
+    }
+
+    /**
+     * Download the file with the given url.
+     *
+     * @param targetPath the target path to save the downloaded file.
+     */
+    private static void download(Path targetPath) throws ExecutionException, InterruptedException, IOException, TimeoutException {
+        AsyncHttpClient asyncHttpClient = new DefaultAsyncHttpClient(
+                new DefaultAsyncHttpClientConfig.Builder()
+                        .setConnectTimeout(CONNECT_TIMEOUT)
+                        .setRequestTimeout(REQUEST_TIMEOUT)
+                        .setMaxRequestRetry(1)
+                        .build());
+        Future<Response> responseFuture = asyncHttpClient.prepareGet(JacocoDownloader.JACOCO_BINARY_URL_FORMAT).execute(new AsyncCompletionHandler<Response>() {
+            @Override
+            public Response onCompleted(Response response) {
+                LOGGER.info("Download jacoco binary archive file successfully! download url: " + JacocoDownloader.JACOCO_BINARY_URL_FORMAT);
+                return response;
+            }
+
+            @Override
+            public void onThrowable(Throwable t) {
+                LOGGER.warn("Failed to download the file, download url: " + JacocoDownloader.JACOCO_BINARY_URL_FORMAT);
+                super.onThrowable(t);
+            }
+        });
+        // Future timeout should 2 times as equal as REQUEST_TIMEOUT, because it will retry 1 time.
+        Response response = responseFuture.get(REQUEST_TIMEOUT * 2, TimeUnit.MILLISECONDS);
+        Files.copy(response.getResponseBodyAsStream(), targetPath, StandardCopyOption.REPLACE_EXISTING);
+    }
+
+}
diff --git a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ScenarioBuilderMain.java b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ScenarioBuilderMain.java
index 62be59b6..8f9e7263 100644
--- a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ScenarioBuilderMain.java
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ScenarioBuilderMain.java
@@ -22,6 +22,7 @@ public class ScenarioBuilderMain {
     public static void main(String[] args) throws Exception {
         IConfiguration configuration = new ConfigurationImpl();
         configuration.scenarioGenerator().generate(configuration);
+        JacocoDownloader.initialize(configuration);
         System.out.println("outputDir: " + configuration.outputDir());
         System.exit(0);
     }


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org