Skip to content

Commit

Permalink
Feature/516 add ignored metrics regexp option to ignore specific metr…
Browse files Browse the repository at this point in the history
…ics based on regexp (#542)

* Adding configuration page for disabling certain metrics
* Make disable work
* Adding documentation
  • Loading branch information
Waschndolos authored Aug 26, 2023
1 parent 3586406 commit 8b5f2ed
Show file tree
Hide file tree
Showing 69 changed files with 1,043 additions and 381 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Please note that the documentation is a WIP.
- Metrics from [Metrics-plugin](https://github.com/jenkinsci/metrics-plugin)
- Metrics from this plugin. Refer [Prometheus-plugin](docs/metrics/index.md)

## Configuring the plugin
You can find some examples in this documentation [Configuring Plugin](docs/configuration/configuration.md)

## Environment variables

Expand Down
18 changes: 18 additions & 0 deletions docs/configuration/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Plugin configuration

This page is under construction.

## Disable Metrics (since v2.3.0)
Sometimes you don't need all metrics in your prometheus endpoint which this plugin provides.
You can disable certain metrics. These metrics are not being collected by the plugin and therefore not added in the
prometheus endpoint.
A
![img.png](img/disabled_metrics.png)

### Regex Entry
A Regex entry can be used to disable a group of metrics. E.g. if you want to disable everything with
default_jenkins_disk.*

### Fully qualified Name Entry
If you want to disable certain individual entries you can do it with this entry. The value should be the same
as you can see it in the prometheus endpoint. It's case-insensitive.
Binary file added docs/configuration/img/disabled_metrics.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,12 @@

import com.cloudbees.simplediskusage.DiskItem;
import com.cloudbees.simplediskusage.JobDiskItem;
import hudson.model.LoadStatistics;
import io.prometheus.client.Collector;
import jenkins.model.Jenkins;
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.collectors.disk.DiskUsageBytesGauge;
import org.jenkinsci.plugins.prometheus.collectors.disk.FileStoreAvailableGauge;
import org.jenkinsci.plugins.prometheus.collectors.disk.FileStoreCapacityGauge;
import org.jenkinsci.plugins.prometheus.collectors.disk.JobUsageBytesGauge;
import org.jenkinsci.plugins.prometheus.config.PrometheusConfiguration;
import org.jenkinsci.plugins.prometheus.util.ConfigurationUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -79,8 +73,8 @@ private static List<MetricFamilySamples> collectDiskUsage() throws IOException {
});

List<MetricCollector<FileStore, ? extends Collector>> fileStoreCollectors = new ArrayList<>();
fileStoreCollectors.add(factory.createFileStoreCollector(CollectorType.FILE_STORE_CAPACITY_GAUGE,new String[]{"file_store"} ));
fileStoreCollectors.add(factory.createFileStoreCollector(CollectorType.FILE_STORE_AVAILABLE_GAUGE ,new String[]{"file_store"} ));
fileStoreCollectors.add(factory.createFileStoreCollector(CollectorType.FILE_STORE_CAPACITY_GAUGE, new String[]{"file_store"}));
fileStoreCollectors.add(factory.createFileStoreCollector(CollectorType.FILE_STORE_AVAILABLE_GAUGE, new String[]{"file_store"}));

usedFileStores.forEach(store -> {
final String labelValue = toLabelValue(Optional.of(store));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
public class ExecutorCollector extends Collector {

private static final Logger LOGGER = LoggerFactory.getLogger(ExecutorCollector.class);

@Override
public List<MetricFamilySamples> collect() {
LOGGER.debug("Collecting executor metrics for prometheus");
Expand All @@ -41,7 +42,7 @@ public List<MetricFamilySamples> collect() {

Label[] labels = Jenkins.get().getLabels().toArray(new Label[0]);
for (Label l : labels) {
collectors.forEach(c -> c.calculateMetric(l.loadStatistics.computeSnapshot(), new String[] {l.getDisplayName()}));
collectors.forEach(c -> c.calculateMetric(l.loadStatistics.computeSnapshot(), new String[]{l.getDisplayName()}));
}

return collectors.stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
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 java.util.ArrayList;
import java.util.Collection;
Expand All @@ -23,7 +22,7 @@ public List<MetricFamilySamples> collect() {
collectors.add(factory.createJenkinsCollector(CollectorType.JENKINS_VERSION_INFO_GAUGE, new String[]{}));
collectors.add(factory.createJenkinsCollector(CollectorType.JENKINS_UP_GAUGE, new String[]{}));
collectors.add(factory.createJenkinsCollector(CollectorType.JENKINS_UPTIME_GAUGE, new String[]{}));
collectors.add(factory.createJenkinsCollector(CollectorType.NODES_ONLINE_GAUGE, new String[]{}));
collectors.add(factory.createJenkinsCollector(CollectorType.NODES_ONLINE_GAUGE, new String[]{"node"}));

collectors.forEach(c -> c.calculateMetric(Jenkins.get(), new String[]{}));

Expand Down
52 changes: 25 additions & 27 deletions src/main/java/org/jenkinsci/plugins/prometheus/JobCollector.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
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.collectors.builds.BuildCollectorFactory;
import org.jenkinsci.plugins.prometheus.collectors.jobs.JobCollectorFactory;
import org.jenkinsci.plugins.prometheus.config.PrometheusConfiguration;
import org.jenkinsci.plugins.prometheus.util.Jobs;
import org.jenkinsci.plugins.prometheus.util.Runs;
Expand All @@ -27,24 +25,24 @@ public class JobCollector extends Collector {
private static final String NOT_AVAILABLE = "NA";
private static final String UNDEFINED = "UNDEFINED";

private MetricCollector<Run, ? extends Collector> summary;
private MetricCollector<Run, ? extends Collector> jobSuccessCount;
private MetricCollector<Run, ? extends Collector> jobFailedCount;
private MetricCollector<Job, ? extends Collector> jobHealthScoreGauge;
private MetricCollector<Job, ? extends Collector> nbBuildsGauge;
private MetricCollector<Job, ? extends Collector> buildDiscardGauge;
private MetricCollector<Job, ? extends Collector> currentRunDurationGauge;
private MetricCollector<Run<?, ?>, ? extends Collector> summary;
private MetricCollector<Run<?, ?>, ? extends Collector> jobSuccessCount;
private MetricCollector<Run<?, ?>, ? extends Collector> jobFailedCount;
private MetricCollector<Job<?, ?>, ? extends Collector> jobHealthScoreGauge;
private MetricCollector<Job<?, ?>, ? extends Collector> nbBuildsGauge;
private MetricCollector<Job<?, ?>, ? extends Collector> buildDiscardGauge;
private MetricCollector<Job<?, ?>, ? extends Collector> currentRunDurationGauge;

private static class BuildMetrics {

public MetricCollector<Run, ? extends Collector> jobBuildResultOrdinal;
public MetricCollector<Run, ? extends Collector> jobBuildResult;
public MetricCollector<Run, ? extends Collector> jobBuildStartMillis;
public MetricCollector<Run, ? extends Collector> jobBuildDuration;
public MetricCollector<Run, ? extends Collector> stageSummary;
public MetricCollector<Run, ? extends Collector> jobBuildTestsTotal;
public MetricCollector<Run, ? extends Collector> jobBuildTestsSkipped;
public MetricCollector<Run, ? extends Collector> jobBuildTestsFailing;
public MetricCollector<Run<?, ?>, ? extends Collector> jobBuildResultOrdinal;
public MetricCollector<Run<?, ?>, ? extends Collector> jobBuildResult;
public MetricCollector<Run<?, ?>, ? extends Collector> jobBuildStartMillis;
public MetricCollector<Run<?, ?>, ? extends Collector> jobBuildDuration;
public MetricCollector<Run<?, ?>, ? extends Collector> stageSummary;
public MetricCollector<Run<?, ?>, ? extends Collector> jobBuildTestsTotal;
public MetricCollector<Run<?, ?>, ? extends Collector> jobBuildTestsSkipped;
public MetricCollector<Run<?, ?>, ? extends Collector> jobBuildTestsFailing;

private final String buildPrefix;

Expand Down Expand Up @@ -176,12 +174,12 @@ public List<MetricFamilySamples> collect() {

private void addSamples(List<MetricFamilySamples> allSamples, List<MetricFamilySamples> newSamples, String logMessage) {
for (MetricFamilySamples metricFamilySample : newSamples) {
int sampleCount = metricFamilySample.samples.size();
if (sampleCount > 0) {
logger.debug(logMessage, sampleCount, metricFamilySample.name);
allSamples.addAll(newSamples);
}
int sampleCount = metricFamilySample.samples.size();
if (sampleCount > 0) {
logger.debug(logMessage, sampleCount, metricFamilySample.name);
allSamples.addAll(newSamples);
}
}
}

private void addSamples(List<MetricFamilySamples> allSamples, BuildMetrics buildMetrics) {
Expand All @@ -195,7 +193,7 @@ private void addSamples(List<MetricFamilySamples> allSamples, BuildMetrics build
addSamples(allSamples, buildMetrics.stageSummary.collect(), "Adding [{}] samples from summary ({})");
}

protected void appendJobMetrics(Job job) {
protected void appendJobMetrics(Job<?, ?> job) {
boolean isAppendParamLabel = PrometheusConfiguration.get().isAppendParamLabel();
boolean isAppendStatusLabel = PrometheusConfiguration.get().isAppendStatusLabel();
boolean isPerBuildMetrics = PrometheusConfiguration.get().isPerBuildMetrics();
Expand All @@ -208,7 +206,7 @@ protected void appendJobMetrics(Job job) {
}
String[] baseLabelValueArray = {job.getFullName(), repoName, String.valueOf(job.isBuildable())};

Run lastBuild = job.getLastBuild();
Run<?, ?> lastBuild = job.getLastBuild();

Check warning on line 209 in src/main/java/org/jenkinsci/plugins/prometheus/JobCollector.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 209 is not covered by tests
// Never built
if (null == lastBuild) {
logger.debug("job [{}] never built", job.getFullName());
Expand All @@ -221,7 +219,7 @@ protected void appendJobMetrics(Job job) {
currentRunDurationGauge.calculateMetric(job, baseLabelValueArray);
processRun(job, lastBuild, baseLabelValueArray, lastBuildMetrics);

Run run = lastBuild;
Run<?, ?> run = lastBuild;

Check warning on line 222 in src/main/java/org/jenkinsci/plugins/prometheus/JobCollector.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 222 is not covered by tests
while (run != null) {
logger.debug("getting metrics for run [{}] from job [{}], include per run metrics [{}]", run.getNumber(), job.getName(), isPerBuildMetrics);
if (Runs.includeBuildInMetrics(run)) {
Expand All @@ -231,7 +229,7 @@ protected void appendJobMetrics(Job job) {
String[] labelValueArray = baseLabelValueArray;

if (isAppendParamLabel) {
String params = Runs.getBuildParameters(run).entrySet().stream().map(e -> "" + e.getKey() + "=" + e.getValue()).collect(Collectors.joining(";"));
String params = Runs.getBuildParameters(run).entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining(";"));

Check warning on line 232 in src/main/java/org/jenkinsci/plugins/prometheus/JobCollector.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 232 is not covered by tests
labelValueArray = Arrays.copyOf(labelValueArray, labelValueArray.length + 1);
labelValueArray[labelValueArray.length - 1] = params;
}
Expand Down Expand Up @@ -269,7 +267,7 @@ protected void appendJobMetrics(Job job) {
}
}

private void processRun(Job job, Run run, String[] buildLabelValueArray, BuildMetrics buildMetrics) {
private void processRun(Job<?, ?> job, Run<?, ?> run, String[] buildLabelValueArray, BuildMetrics buildMetrics) {
logger.debug("Processing run [{}] from job [{}]", run.getNumber(), job.getName());
buildMetrics.jobBuildResultOrdinal.calculateMetric(run, buildLabelValueArray);
buildMetrics.jobBuildResult.calculateMetric(run, buildLabelValueArray);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.jenkinsci.plugins.prometheus.collectors;

import org.jenkinsci.plugins.prometheus.config.disabledmetrics.MetricStatusChecker;
import org.jenkinsci.plugins.prometheus.util.ConfigurationUtils;

public abstract class BaseCollectorFactory {
Expand All @@ -12,8 +13,12 @@ public BaseCollectorFactory() {
subsystem = ConfigurationUtils.getSubSystem();
}

protected boolean isEnabledViaConfig(CollectorType type) {
// prepare for disable via config
return true;

protected MetricCollector saveBuildCollector(MetricCollector collector) {
String fullName = namespace + "_" + subsystem + "_" + collector.calculateName();
if (MetricStatusChecker.isEnabled(fullName)) {

Check warning on line 19 in src/main/java/org/jenkinsci/plugins/prometheus/collectors/BaseCollectorFactory.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 19 is only partially covered, one branch is missing
return collector;
}
return new NoOpMetricCollector<>();

Check warning on line 22 in src/main/java/org/jenkinsci/plugins/prometheus/collectors/BaseCollectorFactory.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 22 is not covered by tests
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
package org.jenkinsci.plugins.prometheus.collectors;

import io.prometheus.client.Collector;
import io.prometheus.client.SimpleCollector;

import java.util.List;

public abstract class BaseMetricCollector<T, I extends Collector> implements MetricCollector<T, I> {
public abstract class BaseMetricCollector<T, I extends SimpleCollector<?>> implements MetricCollector<T, I> {

protected final static String SEPARATOR = "_";

protected final String[] labelNames;
protected final String namespace;
protected final String subsystem;
protected final String namePrefix;

protected I collector;

protected BaseMetricCollector(String[] labelNames, String namespace, String subsystem, String namePrefix) {
Expand All @@ -31,14 +31,38 @@ protected BaseMetricCollector(String[] labelNames, String namespace, String subs
collector = initCollector();
}

protected abstract I initCollector();
/**
* @return - the name of the collector without subsystem, namespace, prefix
*/
protected abstract CollectorType getCollectorType();

/**
* @return - the help text which should be displayed
*/
protected abstract String getHelpText();

/**
* @return - builder object of the type of collector
*/
protected abstract SimpleCollector.Builder<?, I> getCollectorBuilder();

protected I initCollector() {
return getCollectorBuilder()
.name(calculateName())
.subsystem(subsystem)
.namespace(namespace)
.labelNames(labelNames)
.help(getHelpText())
.create();
}

@Override
public List<Collector.MetricFamilySamples> collect() {
return collector.collect();
}

protected String calculateName(String name) {
public String calculateName() {
String name = getCollectorType().getName();
StringBuilder sb = new StringBuilder();
if (isBaseNameSet()) {
sb.append(getBaseName()).append(SEPARATOR);
Expand All @@ -62,4 +86,5 @@ protected String getBaseName() {
return "";
}

public abstract void calculateMetric(T jenkinsObject, String[] labelValues);
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ public CollectorFactory() {
diskCollectorFactory = new DiskCollectorFactory();
}

public MetricCollector<Run, ? extends Collector> createRunCollector(CollectorType type, String[] labelNames, String prefix) {
public MetricCollector<Run<?, ?>, ? extends Collector> createRunCollector(CollectorType type, String[] labelNames, String prefix) {
return buildCollectorFactory.createCollector(type, labelNames, prefix);
}

public MetricCollector<Job, ? extends Collector> createJobCollector(CollectorType type, String[] labelNames) {
public MetricCollector<Job<?, ?>, ? extends Collector> createJobCollector(CollectorType type, String[] labelNames) {
return jobCollectorFactory.createCollector(type, labelNames);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,27 @@
/**
* Implementations of this interface shall be able to construct and calculate any subclass of
* {@link io.prometheus.client.SimpleCollector}
*
* @param <T> - any subclass of {@link io.prometheus.client.SimpleCollector}
*/
public interface MetricCollector<T, I extends Collector> {

/**
* This method contains the logic to calculate a metric value based on the given Jenkins object (e.g. Job, Run,...)
*
* @param jenkinsObject - Examples: {@link hudson.model.Job}, {@link hudson.model.Run}
* @param labelValues - The label values for the calculation
* @param labelValues - The label values for the calculation
*/
void calculateMetric(T jenkinsObject, String[] labelValues);

/**
* Calling this method basically calls I.collect()
*/
List<I.MetricFamilySamples> collect();

/**
* Calling this method will return the resulting name of the metric with base name and prefix
* @return the full name of the collector
*/
String calculateName();
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

public class NoOpMetricCollector<T, I extends Collector> implements MetricCollector<T, I> {
@Override
public void calculateMetric(Object jenkinsObject, String[] labelValues) {
public void calculateMetric(T jenkinsObject, String[] labelValues) {
// do nothing
}

Expand All @@ -16,4 +16,9 @@ public List<Collector.MetricFamilySamples> collect() {
// do nothing
return new ArrayList<>();
}

@Override
public String calculateName() {
return "";

Check warning on line 22 in src/main/java/org/jenkinsci/plugins/prometheus/collectors/NoOpMetricCollector.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 22 is not covered by tests
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

import hudson.model.Run;
import hudson.tasks.test.AbstractTestResultAction;
import io.prometheus.client.Collector;
import io.prometheus.client.SimpleCollector;
import org.jenkinsci.plugins.prometheus.collectors.builds.BuildsMetricCollector;
import org.jenkinsci.plugins.prometheus.config.PrometheusConfiguration;

public abstract class TestBasedMetricCollector<T, I extends Collector> extends BuildsMetricCollector<T, I> {
public abstract class TestBasedMetricCollector<T, I extends SimpleCollector<?>> extends BuildsMetricCollector<T, I> {

public TestBasedMetricCollector(String[] labelNames, String namespace, String subsystem, String namePrefix) {
super(labelNames, namespace, subsystem, namePrefix);
Expand Down
Loading

0 comments on commit 8b5f2ed

Please sign in to comment.