使用jacoco动态获取目标服务的覆盖率

一般而言,jacoco的覆盖率文件是在maven build时生成exec,再调用jacoco-tool生成html-report,整个过程都可以交给maven做完,但是最近碰到这种需求,要求目标服务正常运行,jacoco动态的获取目标service的覆盖率信息。

客户端:

需要让目标服务配置javaagent,该agent的配置在jacoco官方文档中给出过案例如下:

(https://www.eclemma.org/jacoco/trunk/doc)

-javaagent:E:\jacocoagent.jar=includes=*,append=true,output=tcpserver,port=8494,address=127.0.0.1

可以看到我依赖了一个jacocoagent.jar的包,其次需要暴露自己的port和address供远程访问。

服务端:

我查看了jacoco的官方文档,发现它提供maven的插件:

(https://www.eclemma.org/jacoco/trunk/doc/maven.html)


            org.jacoco
            jacoco-maven-plugin
            0.7.8

使用jacoco动态获取目标服务的覆盖率_第1张图片

里面提供了大量的jacoco 下载,合并等方法。

由于jacoco原理的插桩,即探针(Probe)插入,每次生成覆盖率都依赖探针。所以我们可以利用jacoco-maven-tool的reset方法来清除探针,再生成覆盖率文件。这样就可以满足每次去生成的jacoco覆盖率文件都是最近的覆盖率文件。如果需要得到所有的覆盖率文件,则使用merge方法可以实现。

好了,有了上面的这些认识,我便把jacoco官方的tool进行封装,得到我想要的一个覆盖率工具类,如下:



import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.jacoco.core.tools.ExecDumpClient;
import org.jacoco.core.tools.ExecFileLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class ExecDumpClientGenericService implements ExecDumpClientService {

    private static final Logger LOG = LoggerFactory.getLogger(ExecDumpClientGenericService.class);
    private String host;
    private int port;
    private int retryCount;
    private File dumpDestExecFile;
    private File mergeDestExecFile;

    private ExecDumpClientGenericService() {
        this.retryCount = 2;
    }

    /**
     * ExecDumpClientGenericService
     *
     * @param host host
     * @param port port
     * @return ExecDumpClientGenericService
     */
    public static ExecDumpClientGenericService build(String host, int port) {
        return new ExecDumpClientGenericService().setHost(host).setPort(port);
    }

    /**
     * ExecDumpClientGenericService
     *
     * @param dumpJacocoExecConfigBo dumpJacocoExecConfigBo
     * @return ExecDumpClientGenericService
     */
    public static ExecDumpClientGenericService build(DumpJacocoExecConfigBo dumpJacocoExecConfigBo) {
        return new ExecDumpClientGenericService().setHost(dumpJacocoExecConfigBo.getHost()).setPort(dumpJacocoExecConfigBo.getPort());
    }

    @Override
    public void dump(boolean reset) throws IOException {
        dump(reset, true);
    }

    @Override
    public void dump(boolean reset, boolean append) throws IOException {
        ExecDumpClient dumpClient = new ExecDumpClient() {
            @Override
            protected void onConnecting(InetAddress address, int port) {
                LOG.info("Connecting to {}:{}", address, port);
            }

            @Override
            protected void onConnectionFailure(IOException exception) {
                LOG.info(exception.getMessage());
            }
        };
        dumpClient.setReset(reset);
        dumpClient.setRetryCount(retryCount);

        final ExecFileLoader dump = dumpClient.dump(host, port);
        dump.save(dumpDestExecFile, append);
        LOG.info(CommonUtil.info("Dump successful! Create dumped file: {}", dumpDestExecFile.getAbsolutePath()));
    }

    @Override
    public void merge(List requireMergedFiles) throws IOException {
        merge(requireMergedFiles, true);
    }

    @Override
    public void merge(List requireMergedFiles, boolean append) throws IOException {
        if (CollectionUtils.isEmpty(requireMergedFiles)) {
            LOG.warn("The require merged files must NOT be empty!");
            return;
        }
        LOG.info("Execute merge: ");
        final ExecFileLoader loader = new ExecFileLoader();
        for (File file : requireMergedFiles) {
            loader.load(file);
            LOG.info(file.getAbsolutePath());
        }
        loader.save(mergeDestExecFile, append);
        LOG.info(CommonUtil.info("Merge successful! Create merged file: {}", mergeDestExecFile.getAbsolutePath()));
    }

    /**
     * setHost
     *
     * @param host host
     * @return ExecDumpClientGenericService
     */
    public ExecDumpClientGenericService setHost(String host) {
        this.host = host;
        return this;
    }

    /**
     * setPort
     *
     * @param port port
     * @return ExecDumpClientGenericService
     */
    public ExecDumpClientGenericService setPort(int port) {
        this.port = port;
        return this;
    }

    /**
     * setDumpDestExecFile
     *
     * @param dumpDestExecFile dumpDestExecFile
     * @return ExecDumpClientGenericService
     */
    public ExecDumpClientGenericService setDumpDestExecFile(File dumpDestExecFile) {
        this.dumpDestExecFile = dumpDestExecFile;
        return this;
    }

    /**
     * setMergeDestExecFile
     *
     * @param mergeDestExecFile mergeDestExecFile
     * @return ExecDumpClientGenericService
     */
    public ExecDumpClientGenericService setMergeDestExecFile(File mergeDestExecFile) {
        this.mergeDestExecFile = mergeDestExecFile;
        return this;
    }

    /**
     * setRetryCount
     *
     * @param retryCount try to reconnection count, and default is 3
     * @return ExecDumpClientGenericService
     */
    public ExecDumpClientGenericService setRetryCount(int retryCount) {
        this.retryCount = retryCount;
        return this;
    }
}

你可能感兴趣的:(DevOps)