Jacoco Java Agent在CRON中实践练习(offiline)

1, 下载Jacoco核心包. (https://www.jacoco.org/jacoco/), 此处使用jacoco-0.8.1.

aea3548eded3c08ca98327214d20e749ae5.jpg

2, Instrument需要测试的class文件或者jar包,当运行代码的JVM关闭后,生成好的class文件或者jar包会被放入./.tmp文件夹中

::Off-line instrumentation of Java class files and JAR files.
set path=D:\Java\jdk1.6.0_34\bin
::set path=D:\Java\jdk1.8.0_131\bin
java -jar {Your path}\jacococli.jar instrument lib/rds-sub-expire-alert.jar --dest ./.tmp
pause

3, 添加jacocoagent.jar到ClassPath.

对于jar包,可以在目标jar包中的META-INF/MANIFEST.MF中的Class-Path:部分中加入jacocoagent.jar,并把jacocoagent.jar包放到对应的目录中。

自动化修改META-INF/MANIFEST.MF示例:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class ModifyZipFileUtil {

    public static void modifyFileInZip(String zipedFile, String targetZipFile, String modifyFileInZip, ModifyFileCallback callback) {
        File zip = new File(zipedFile);
        if (!zip.exists() || !zip.isFile()) {
            throw new RuntimeException("Invalid file for:" + zipedFile);
        }
        File targetZip = new File(targetZipFile);
        if (!targetZip.exists()) {
            throw new RuntimeException("Invalid file or path for:" + targetZipFile);
        }

        String fileNameString = zip.getName();
        if (targetZip.isDirectory()) {
            targetZip = new File(targetZipFile, fileNameString);
            //targetZip = new File(targetZipFile, "copy3_" + fileNameString);
            System.out.println(targetZip);
        }
        ZipInputStream zipInputStream = null;
        ZipFile zipFile = null;
        ZipOutputStream zipOutputStream = null;
        try {
            zipInputStream = new ZipInputStream(new FileInputStream(zip));
            zipFile = new ZipFile(zip);
            zipOutputStream = new ZipOutputStream(new FileOutputStream(targetZip));
            ZipEntry zipEntry = null;
            String fileName = null;
            while (null != (zipEntry = zipInputStream.getNextEntry())) {
                fileName = zipEntry.getName();
                System.out.println(fileName);
                if (fileName.equals(modifyFileInZip)) {
                    ZipEntry zipEntryNew = new ZipEntry(fileName);
                    zipOutputStream.putNextEntry(zipEntryNew);
                    callback.doAction(zipFile.getInputStream(zipEntry), zipOutputStream);
                } else {
                    zipOutputStream.putNextEntry(zipEntry);
                    if (!zipEntry.isDirectory()) {
                        copy(zipFile.getInputStream(zipEntry), zipOutputStream);
                    }
                }
                zipOutputStream.closeEntry();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeInputStream(zipInputStream);
            closeOutputStream(zipOutputStream);
        }
    }

    private static void copy(InputStream inputStream, OutputStream outputStream) throws IOException {
        byte[] buff = new byte[9086];
        int len = -1;
        while (true) {
            len = inputStream.read(buff);
            if (-1 == len) {
                break;
            }
            outputStream.write(buff, 0, len);
        }
        outputStream.flush();
    }

    private static void closeInputStream(InputStream inputStream) {
        if (null != inputStream) {
            try {
                inputStream.close();
            } catch (Exception e) {
            }
        }
    }

    private static void closeOutputStream(OutputStream outputStream) {
        if (null != outputStream) {
            try {
                outputStream.close();
            } catch (Exception e) {
            }
        }
    }

    public static void main(String[] args) {
        String zipedFile = "C:\\Users\\jervalj\\Downloads\\9999temp\\rds-sub-expire-alert\\.tmp\\rds-sub-expire-alert.jar";
        String targetZipFile = "C:\\Users\\jervalj\\Downloads\\9999temp\\rds-sub-expire-alert";
        String modifyFileInZip = "META-INF/MANIFEST.MF";
        final String addLibInClassPath = "./../../jacocoagent.jar";
        ModifyFileCallback callback = new ModifyFileCallback() {

            @Override
            public void doAction(InputStream inputStream, OutputStream outputStream) throws Exception {
                String charsetName = "UTF-8";
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, charsetName));
                String line = null;
                byte[] buff = null;
                while (null != (line = bufferedReader.readLine())) {
                    if (line.startsWith("Class-Path:")) {
                        StringBuilder stringBuilder = new StringBuilder();
                        stringBuilder.append("Class-Path: ").append(addLibInClassPath).append(line.substring(line.indexOf(":") + 1));
                        System.out.println(stringBuilder);
                        buff = stringBuilder.toString().getBytes(charsetName);
                        outputStream.write(buff, 0, buff.length);
                    } else {
                        buff = line.getBytes(charsetName);
                        outputStream.write(buff, 0, buff.length);
                    }
                    outputStream.write(System.getProperty("line.separator").getBytes(charsetName));
                }

                bufferedReader.close();
                closeInputStream(inputStream);
                outputStream.flush();
            }
        };
        modifyFileInZip(zipedFile, targetZipFile, modifyFileInZip, callback);
    }
}

interface ModifyFileCallback {
    void doAction(InputStream inputStream, OutputStream outputStream) throws Exception;
}

4, 生成Dump文件*.exec到指定目录

这里有两种方式配置生成目录和相关参数。

a, 通过添加在Classpath里的配置文件jacoco-agent.properties:

destfile=D:/test/jacoco.exec

b, 通过Java System Properties:

System.setProperty("jacoco-agent.destfile", "D:/test/jacoco.exec");

但以上代码必须保证在Jacoco Agent启动前执行,如果不能保证这个前提,那在运行时加上如下VM参数就显得更加明智。

-Djacoco-agent.destfile=D:/test/jacoco.exec

9d6b50978c4aefd782601d4650d5256b329.jpg

5, 生成测试报表

pause
java -jar jacococli.jar report *.exec --classfiles lib/rds-sub-expire-alert.jar --html report.html --sourcefiles E:\workspace4.3\rds-sub-expire-alert\src\main\java
pause

 

 

Jacoco Doc Reference (https://www.jacoco.org/jacoco/):

Offline Instrumentation

One of the main benefits of JaCoCo is the Java agent, which instruments classes on-the-fly. This simplifies code coverage analysis a lot as no pre-instrumentation and classpath tweaking is required. However, there can be situations where on-the-fly instrumentation is not suitable, for example:

  • Runtime environments that do not support Java agents.
  • Deployments where it is not possible to configure JVM options.
  • Bytecode needs to be converted for another VM like the Android Dalvik VM.
  • Conflicts with other agents that do dynamic classfile transformation.

For such scenarios class files can be pre-instrumented with JaCoCo, for example with the instrument Ant task. At runtime the pre-instrumented classes needs be on the classpath instead of the original classes. In addition jacocoagent.jar must be put on the classpath.

Configuration

In offline mode the JaCoCo runtime can be configured with the same set of properties which are available for the agent, except for the includes/excludes options as the class files are already instrumented. There are two different ways to provide the configuration:

  • Configuration File: If a file jacoco-agent.properties is supplied on the classpath options are loaded from this file. The file has to be formatted in the Java properties file format.
  • System Properties: Options can also be supplied as Java system properties. In this case the options have to be prefixed with "jacoco-agent.". For example the location of the *.exec file can be configured with the system property "jacoco-agent.destfile".

In both cases configuration values may contain variables in the format ${name} which are resolved with system property values at runtime. For example:

destfile=/home/godin/jacoco.exec

Class Loading and Initialization

Unlike with on-the-fly instrumentation offline instrumented classes get a direct dependency on the JaCoCo runtime. Therefore jacocoagent.jar has to be on the classpath and accessible by the instrumented classes. The proper location for jacocoagent.jar might depend on your deployment scenario. The first instrumented class loaded will trigger the initialization of the JaCoCo runtime. If no instrumented class is loaded the JaCoCo runtime will not get started at all.

Using Pre-Instrumented Classes With the Java Agent

It is possible to also use offline-instrumented classes with the JaCoCo Java agent. In this case the configuration is taken from the agent options. The agent must be configured in a way that pre-instrumented classes are excluded, e.g. with "excludes=*". Otherwise it will result in error messages on the console if the agent instruments such classes again.

Execution Data Collection

If jacocoagent.jar is used on the classpath it will collect execution data the same way as used as a Java agent. Depending on the output configuration execution data can be collected via a remote connection or is written to the file system when the JVM terminates. For the latter it is required that e.g. a java task is executed with fork="true".

Report Generation

Based on the collected *.exec files reports can be created the same way as for execution data collected with the Java agent. Note that for report generation the original class files have to be supplied, not the instrumented copies.

转载于:https://my.oschina.net/jerval/blog/1827635

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值