forked from lsjostro/prometheus-plugin
-
Notifications
You must be signed in to change notification settings - Fork 151
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding metrics for code coverage (#545)
* Base implementation * Need to update to latest LTS because of new dependency * Implementing CodeCoverageCollector * Fixing calculation of coverage metrics * Adding Tests * Removing unnecessary constructor call
- Loading branch information
Waschndolos
authored
Sep 3, 2023
1 parent
8b5f2ed
commit 607db93
Showing
36 changed files
with
1,600 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
src/main/java/org/jenkinsci/plugins/prometheus/BaseCollector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package org.jenkinsci.plugins.prometheus; | ||
|
||
import io.prometheus.client.Collector; | ||
import io.prometheus.client.Gauge; | ||
import org.jenkinsci.plugins.prometheus.util.ConfigurationUtils; | ||
|
||
public abstract class BaseCollector extends Collector { | ||
|
||
|
||
protected static Gauge.Builder newGaugeBuilder(String... labels) { | ||
return newGaugeBuilder().labelNames(labels); | ||
} | ||
|
||
protected static Gauge.Builder newGaugeBuilder() { | ||
return Gauge.build() | ||
.namespace(ConfigurationUtils.getNamespace()) | ||
.subsystem(ConfigurationUtils.getSubSystem()); | ||
} | ||
} |
94 changes: 94 additions & 0 deletions
94
src/main/java/org/jenkinsci/plugins/prometheus/CodeCoverageCollector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package org.jenkinsci.plugins.prometheus; | ||
|
||
import hudson.model.Job; | ||
import hudson.model.Run; | ||
import io.jenkins.plugins.coverage.metrics.steps.CoverageBuildAction; | ||
import io.prometheus.client.Collector; | ||
import jenkins.model.Jenkins; | ||
import org.apache.commons.collections.CollectionUtils; | ||
import org.jenkinsci.plugins.prometheus.collectors.CollectorFactory; | ||
import org.jenkinsci.plugins.prometheus.collectors.CollectorType; | ||
import org.jenkinsci.plugins.prometheus.collectors.MetricCollector; | ||
import org.jenkinsci.plugins.prometheus.config.PrometheusConfiguration; | ||
import org.jenkinsci.plugins.prometheus.util.Jobs; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
public class CodeCoverageCollector extends BaseCollector { | ||
|
||
private static final Logger LOGGER = LoggerFactory.getLogger(CodeCoverageCollector.class); | ||
|
||
@Override | ||
public List<MetricFamilySamples> collect() { | ||
|
||
if (!isCodeCoverageAPIPluginLoaded()) { | ||
LOGGER.warn("Cannot collect code coverage data because plugin Code Coverage API (shortname: 'code-coverage-api') is not loaded."); | ||
return Collections.emptyList(); | ||
} | ||
|
||
if (!isCodeCoverageCollectionConfigured()) { | ||
return Collections.emptyList(); | ||
} | ||
|
||
List<List<MetricFamilySamples>> samples = new ArrayList<>(); | ||
Jobs.forEachJob(job -> CollectionUtils.addIgnoreNull(samples, collectCoverageMetricForJob(job))); | ||
|
||
|
||
return samples.stream().flatMap(Collection::stream).collect(Collectors.toList()); | ||
} | ||
|
||
private List<MetricFamilySamples> collectCoverageMetricForJob(Job<?,?> job) { | ||
if (job == null) { | ||
return Collections.emptyList(); | ||
} | ||
|
||
Run<?,?> lastBuild = job.getLastBuild(); | ||
if (lastBuild == null || lastBuild.isBuilding()) { | ||
return Collections.emptyList(); | ||
} | ||
|
||
CoverageBuildAction coverageBuildAction = lastBuild.getAction(CoverageBuildAction.class); | ||
if (coverageBuildAction == null) { | ||
return Collections.emptyList(); | ||
} | ||
|
||
CollectorFactory factory = new CollectorFactory(); | ||
List<MetricCollector<Run<?,?>, ? extends Collector>> collectors = new ArrayList<>(); | ||
|
||
collectors.add(factory.createCoverageRunCollector(CollectorType.COVERAGE_CLASS_COVERED, new String[]{"job_name"})); | ||
collectors.add(factory.createCoverageRunCollector(CollectorType.COVERAGE_CLASS_MISSED, new String[]{"job_name"})); | ||
collectors.add(factory.createCoverageRunCollector(CollectorType.COVERAGE_CLASS_TOTAL, new String[]{"job_name"})); | ||
|
||
collectors.add(factory.createCoverageRunCollector(CollectorType.COVERAGE_BRANCH_COVERED, new String[]{"job_name"})); | ||
collectors.add(factory.createCoverageRunCollector(CollectorType.COVERAGE_BRANCH_MISSED, new String[]{"job_name"})); | ||
collectors.add(factory.createCoverageRunCollector(CollectorType.COVERAGE_BRANCH_TOTAL, new String[]{"job_name"})); | ||
|
||
collectors.add(factory.createCoverageRunCollector(CollectorType.COVERAGE_INSTRUCTION_COVERED, new String[]{"job_name"})); | ||
collectors.add(factory.createCoverageRunCollector(CollectorType.COVERAGE_INSTRUCTION_MISSED, new String[]{"job_name"})); | ||
collectors.add(factory.createCoverageRunCollector(CollectorType.COVERAGE_INSTRUCTION_TOTAL, new String[]{"job_name"})); | ||
|
||
collectors.add(factory.createCoverageRunCollector(CollectorType.COVERAGE_FILE_COVERED, new String[]{"job_name"})); | ||
collectors.add(factory.createCoverageRunCollector(CollectorType.COVERAGE_FILE_MISSED, new String[]{"job_name"})); | ||
collectors.add(factory.createCoverageRunCollector(CollectorType.COVERAGE_FILE_TOTAL, new String[]{"job_name"})); | ||
|
||
collectors.forEach(c -> c.calculateMetric(lastBuild, new String[]{job.getName()})); | ||
|
||
return collectors.stream() | ||
.map(MetricCollector::collect) | ||
.flatMap(Collection::stream) | ||
.collect(Collectors.toList()); | ||
} | ||
private boolean isCodeCoverageAPIPluginLoaded() { | ||
return Jenkins.get().getPlugin("code-coverage-api") != null; | ||
} | ||
|
||
private boolean isCodeCoverageCollectionConfigured() { | ||
return PrometheusConfiguration.get().isCollectCodeCoverage(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
...java/org/jenkinsci/plugins/prometheus/collectors/coverage/CoverageBranchCoveredGauge.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package org.jenkinsci.plugins.prometheus.collectors.coverage; | ||
|
||
import edu.hm.hafner.coverage.Coverage; | ||
import edu.hm.hafner.coverage.Metric; | ||
import hudson.model.Run; | ||
import io.jenkins.plugins.coverage.metrics.model.Baseline; | ||
import io.prometheus.client.Gauge; | ||
import io.prometheus.client.SimpleCollector; | ||
import org.jenkinsci.plugins.prometheus.collectors.CollectorType; | ||
|
||
import java.util.Optional; | ||
|
||
public class CoverageBranchCoveredGauge extends CoverageMetricsCollector<Run<?, ?>, Gauge> { | ||
|
||
protected CoverageBranchCoveredGauge(String[] labelNames, String namespace, String subsystem) { | ||
super(labelNames, namespace, subsystem); | ||
} | ||
|
||
@Override | ||
protected CollectorType getCollectorType() { | ||
return CollectorType.COVERAGE_BRANCH_COVERED; | ||
} | ||
|
||
@Override | ||
protected String getHelpText() { | ||
return "Returns the number of branches covered"; | ||
} | ||
|
||
@Override | ||
protected SimpleCollector.Builder<?, Gauge> getCollectorBuilder() { | ||
return Gauge.build(); | ||
} | ||
|
||
@Override | ||
public void calculateMetric(Run<?, ?> jenkinsObject, String[] labelValues) { | ||
|
||
Optional<Coverage> optional = getCoverage(jenkinsObject, Metric.BRANCH, Baseline.PROJECT); | ||
if (optional.isEmpty()) { | ||
return; | ||
} | ||
|
||
Coverage coverage = optional.get(); | ||
collector.labels(labelValues).set(coverage.getCovered()); | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
.../java/org/jenkinsci/plugins/prometheus/collectors/coverage/CoverageBranchMissedGauge.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package org.jenkinsci.plugins.prometheus.collectors.coverage; | ||
|
||
import edu.hm.hafner.coverage.Coverage; | ||
import edu.hm.hafner.coverage.Metric; | ||
import hudson.model.Run; | ||
import io.jenkins.plugins.coverage.metrics.model.Baseline; | ||
import io.prometheus.client.Gauge; | ||
import io.prometheus.client.SimpleCollector; | ||
import org.jenkinsci.plugins.prometheus.collectors.CollectorType; | ||
|
||
import java.util.Optional; | ||
|
||
public class CoverageBranchMissedGauge extends CoverageMetricsCollector<Run<?, ?>, Gauge> { | ||
|
||
protected CoverageBranchMissedGauge(String[] labelNames, String namespace, String subsystem) { | ||
super(labelNames, namespace, subsystem); | ||
} | ||
|
||
@Override | ||
protected CollectorType getCollectorType() { | ||
return CollectorType.COVERAGE_BRANCH_MISSED; | ||
} | ||
|
||
@Override | ||
protected String getHelpText() { | ||
return "Returns the number of branches missed"; | ||
} | ||
|
||
@Override | ||
protected SimpleCollector.Builder<?, Gauge> getCollectorBuilder() { | ||
return Gauge.build(); | ||
} | ||
|
||
@Override | ||
public void calculateMetric(Run<?, ?> jenkinsObject, String[] labelValues) { | ||
|
||
Optional<Coverage> optional = getCoverage(jenkinsObject, Metric.BRANCH, Baseline.PROJECT); | ||
if (optional.isEmpty()) { | ||
return; | ||
} | ||
|
||
Coverage coverage = optional.get(); | ||
collector.labels(labelValues).set(coverage.getMissed()); | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
...n/java/org/jenkinsci/plugins/prometheus/collectors/coverage/CoverageBranchTotalGauge.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package org.jenkinsci.plugins.prometheus.collectors.coverage; | ||
|
||
import edu.hm.hafner.coverage.Coverage; | ||
import edu.hm.hafner.coverage.Metric; | ||
import hudson.model.Run; | ||
import io.jenkins.plugins.coverage.metrics.model.Baseline; | ||
import io.prometheus.client.Gauge; | ||
import io.prometheus.client.SimpleCollector; | ||
import org.jenkinsci.plugins.prometheus.collectors.CollectorType; | ||
|
||
import java.util.Optional; | ||
|
||
public class CoverageBranchTotalGauge extends CoverageMetricsCollector<Run<?, ?>, Gauge> { | ||
|
||
protected CoverageBranchTotalGauge(String[] labelNames, String namespace, String subsystem) { | ||
super(labelNames, namespace, subsystem); | ||
} | ||
|
||
@Override | ||
protected CollectorType getCollectorType() { | ||
return CollectorType.COVERAGE_BRANCH_TOTAL; | ||
} | ||
|
||
@Override | ||
protected String getHelpText() { | ||
return "Returns the number of branches total"; | ||
} | ||
|
||
@Override | ||
protected SimpleCollector.Builder<?, Gauge> getCollectorBuilder() { | ||
return Gauge.build(); | ||
} | ||
|
||
@Override | ||
public void calculateMetric(Run<?, ?> jenkinsObject, String[] labelValues) { | ||
|
||
Optional<Coverage> optional = getCoverage(jenkinsObject, Metric.BRANCH, Baseline.PROJECT); | ||
if (optional.isEmpty()) { | ||
return; | ||
} | ||
|
||
Coverage coverage = optional.get(); | ||
collector.labels(labelValues).set(coverage.getTotal()); | ||
} | ||
} |
Oops, something went wrong.