diff --git a/src/main/java/org/jenkinsci/plugins/prometheus/service/DefaultPrometheusMetrics.java b/src/main/java/org/jenkinsci/plugins/prometheus/service/DefaultPrometheusMetrics.java index e0b6f34e6..f4840b414 100644 --- a/src/main/java/org/jenkinsci/plugins/prometheus/service/DefaultPrometheusMetrics.java +++ b/src/main/java/org/jenkinsci/plugins/prometheus/service/DefaultPrometheusMetrics.java @@ -11,7 +11,7 @@ import org.jenkinsci.plugins.prometheus.ExecutorCollector; import org.jenkinsci.plugins.prometheus.JenkinsStatusCollector; import org.jenkinsci.plugins.prometheus.JobCollector; -import org.jenkinsci.plugins.prometheus.util.MetricsFormatter; +import org.jenkinsci.plugins.prometheus.util.JenkinsNodeBuildsSampleBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,7 +30,7 @@ public DefaultPrometheusMetrics() { CollectorRegistry collectorRegistry = CollectorRegistry.defaultRegistry; collectorRegistry.register(new JobCollector()); collectorRegistry.register(new JenkinsStatusCollector()); - collectorRegistry.register(new DropwizardExports(Metrics.metricRegistry())); + collectorRegistry.register(new DropwizardExports(Metrics.metricRegistry(), new JenkinsNodeBuildsSampleBuilder())); collectorRegistry.register(new DiskUsageCollector()); collectorRegistry.register(new ExecutorCollector()); @@ -52,7 +52,7 @@ public String getMetrics() { public void collectMetrics() { try (StringWriter buffer = new StringWriter()) { TextFormat.write004(buffer, collectorRegistry.metricFamilySamples()); - cachedMetrics.set(MetricsFormatter.formatMetrics(buffer.toString())); + cachedMetrics.set(buffer.toString()); } catch (IOException e) { logger.debug("Unable to collect metrics"); } diff --git a/src/main/java/org/jenkinsci/plugins/prometheus/util/JenkinsNodeBuildsSampleBuilder.java b/src/main/java/org/jenkinsci/plugins/prometheus/util/JenkinsNodeBuildsSampleBuilder.java new file mode 100644 index 000000000..43b905eb7 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/prometheus/util/JenkinsNodeBuildsSampleBuilder.java @@ -0,0 +1,45 @@ +package org.jenkinsci.plugins.prometheus.util; + +import io.prometheus.client.Collector; +import io.prometheus.client.dropwizard.samplebuilder.DefaultSampleBuilder; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A class that converts jenkins.node[.].builds to jenkins.node.builds with a label of node= (or master if not set) + * before creating a Sample + */ +public class JenkinsNodeBuildsSampleBuilder extends DefaultSampleBuilder { + // Note that nodes can have '.' in their name + static Pattern PATTERN = Pattern.compile("jenkins\\.node(\\.(?.*))?\\.builds"); + + @Override + public Collector.MetricFamilySamples.Sample createSample(String dropwizardName, String nameSuffix, List additionalLabelNames, List additionalLabelValues, double value) { + Matcher matcher = PATTERN.matcher(dropwizardName); + + if (matcher.matches()) { + String processedDropwizardName = "jenkins.node.builds"; + String node = matcher.group("node"); + + if (node == null) { + node = "master"; + } + + List processedAdditionalLabelNames = new ArrayList(); + List processedAdditionalLabelValues = new ArrayList(); + + processedAdditionalLabelNames.add("node"); + processedAdditionalLabelNames.addAll(additionalLabelNames); + + processedAdditionalLabelValues.add(node); + processedAdditionalLabelValues.addAll(additionalLabelValues); + + return super.createSample(processedDropwizardName, nameSuffix, processedAdditionalLabelNames, processedAdditionalLabelValues, value); + } else { + return super.createSample(dropwizardName, nameSuffix, additionalLabelNames, additionalLabelValues, value); + } + } +} diff --git a/src/main/java/org/jenkinsci/plugins/prometheus/util/MetricsFormatter.java b/src/main/java/org/jenkinsci/plugins/prometheus/util/MetricsFormatter.java deleted file mode 100644 index 5ed0f120d..000000000 --- a/src/main/java/org/jenkinsci/plugins/prometheus/util/MetricsFormatter.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.jenkinsci.plugins.prometheus.util; - -public class MetricsFormatter { - - public static String formatMetrics(String formatString) { - //node specific build counts - formatString = formatString.replaceAll("jenkins_node_builds_count (.*)", "jenkins_node_builds_count{node=\"master\"} $1"); - formatString = formatString.replaceAll("jenkins_node_(.*)_builds_count (.*)", "jenkins_node_builds_count{node=\"$1\"} $2"); - - //node specific histograms - formatString = formatString.replaceAll("jenkins_node_builds\\{(.*)} (.*)", "jenkins_node_builds{node=\"master\", $1} $2"); - formatString = formatString.replaceAll("jenkins_node_(.*)_builds\\{(.*)} (.*)", "jenkins_node_builds{node=\"$1\", $2} $3"); - - return formatString; - } -} diff --git a/src/test/java/org/jenkinsci/plugins/prometheus/util/JenkinsNodeBuildsSampleBuilderTest.java b/src/test/java/org/jenkinsci/plugins/prometheus/util/JenkinsNodeBuildsSampleBuilderTest.java new file mode 100644 index 000000000..5301f21a0 --- /dev/null +++ b/src/test/java/org/jenkinsci/plugins/prometheus/util/JenkinsNodeBuildsSampleBuilderTest.java @@ -0,0 +1,85 @@ +package org.jenkinsci.plugins.prometheus.util; + +import io.prometheus.client.Collector; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; + +public class JenkinsNodeBuildsSampleBuilderTest { + @Test + public void master_node_count_format() { + Assert.assertEquals( + new Collector.MetricFamilySamples.Sample( + "jenkins_node_builds_count", + Arrays.asList("node", "quantile"), + Arrays.asList("master", "0.5"), + 0.091670452 + ), + new JenkinsNodeBuildsSampleBuilder().createSample( + "jenkins.node.builds", + "_count", + Arrays.asList("quantile"), + Arrays.asList("0.5"), + 0.091670452 + ) + ); + } + + @Test + public void master_node_histogram_format() { + Assert.assertEquals( + new Collector.MetricFamilySamples.Sample( + "jenkins_node_builds", + Arrays.asList("node", "quantile"), + Arrays.asList("master", "0.999"), + 0.091670452 + ), + new JenkinsNodeBuildsSampleBuilder().createSample( + "jenkins.node.builds", + "", + Arrays.asList("quantile"), + Arrays.asList("0.999"), + 0.091670452 + ) + ); + } + + @Test + public void named_node_count_format() { + Assert.assertEquals( + new Collector.MetricFamilySamples.Sample( + "jenkins_node_builds_count", + Arrays.asList("node", "quantile"), + Arrays.asList("evil node_name.com", "0.5"), + 0.091670452 + ), + new JenkinsNodeBuildsSampleBuilder().createSample( + "jenkins.node.evil node_name.com.builds", + "_count", + Arrays.asList("quantile"), + Arrays.asList("0.5"), + 0.091670452 + ) + ); + } + + @Test + public void named_node_histogram_format() { + Assert.assertEquals( + new Collector.MetricFamilySamples.Sample( + "jenkins_node_builds", + Arrays.asList("node", "quantile"), + Arrays.asList("evil node_name.com", "0.999"), + 0.091670452 + ), + new JenkinsNodeBuildsSampleBuilder().createSample( + "jenkins.node.evil node_name.com.builds", + "", + Arrays.asList("quantile"), + Arrays.asList("0.999"), + 0.091670452 + ) + ); + } +} diff --git a/src/test/java/org/jenkinsci/plugins/prometheus/util/MetricsFormatterTest.java b/src/test/java/org/jenkinsci/plugins/prometheus/util/MetricsFormatterTest.java deleted file mode 100644 index 86f3d9a06..000000000 --- a/src/test/java/org/jenkinsci/plugins/prometheus/util/MetricsFormatterTest.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.jenkinsci.plugins.prometheus.util; - -import org.junit.Assert; -import org.junit.Test; - -public class MetricsFormatterTest { - - private final String inString = "jenkins_node_builds{quantile=\"0.5\",} 0.091670452\n" + - "jenkins_node_builds{quantile=\"0.75\",} 0.091670452\n" + - "jenkins_node_builds{quantile=\"0.95\",} 0.091670452\n" + - "jenkins_node_builds{quantile=\"0.98\",} 0.091670452\n" + - "jenkins_node_builds{quantile=\"0.99\",} 0.091670452\n" + - "jenkins_node_builds{quantile=\"0.999\",} 0.091670452\n" + - "jenkins_node_my_node_1_builds{quantile=\"0.99\",} 0.091670452\n" + - "jenkins_node_my_node_4_builds{quantile=\"0.999\",} 0.091670452\n" + - "jenkins_node_builds_count 28458.0\n" + - "jenkins_node_my_node_1_builds_count 12345"; - - @Test - public void master_node_count_format() { - String formatString = MetricsFormatter.formatMetrics(inString); - //master node count - Assert.assertFalse(formatString.contains("jenkins_node_builds_count 28458.0\n")); - Assert.assertTrue(formatString.contains("jenkins_node_builds_count{node=\"master\"} 28458.0\n")); - } - - @Test - public void master_node_histogram_format() { - String formatString = MetricsFormatter.formatMetrics(inString); - //master node histogram - Assert.assertFalse(formatString.contains("jenkins_node_builds{quantile=\"0.999\",} 0.091670452\n")); - Assert.assertTrue(formatString.contains("jenkins_node_builds{node=\"master\", quantile=\"0.999\",} 0.091670452\n")); - } - - @Test - public void named_node_count_format() { - String formatString = MetricsFormatter.formatMetrics(inString); - //named node count - Assert.assertFalse(formatString.contains("jenkins_node_my_node_1_builds_count")); - Assert.assertTrue(formatString.contains("jenkins_node_builds_count{node=\"my_node_1\"} 12345")); - } - - @Test - public void named_node_histogram_format() { - String formatString = MetricsFormatter.formatMetrics(inString); - //named node histogram - Assert.assertFalse(formatString.contains("jenkins_node_my_node_4_builds{quantile=\"0.999\",} 0.091670452\n")); - Assert.assertTrue(formatString.contains("jenkins_node_builds{node=\"my_node_4\", quantile=\"0.999\",} 0.091670452\n")); - } -}