From 5ffa400b023c4bca05b60e258df92860e064b724 Mon Sep 17 00:00:00 2001 From: Jake Spain Date: Mon, 18 Dec 2023 08:31:38 -0500 Subject: [PATCH 1/2] Add metrics for failure causes on builds --- .../plugins/bfa/BuildFailureScanner.java | 14 ++++++++++- .../jenkins/plugins/bfa/MetricsManager.java | 24 +++++++++++++++++++ .../plugins/bfa/MetricsManagerTest.java | 16 +++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/sonyericsson/jenkins/plugins/bfa/BuildFailureScanner.java b/src/main/java/com/sonyericsson/jenkins/plugins/bfa/BuildFailureScanner.java index 3763a849..639698f6 100644 --- a/src/main/java/com/sonyericsson/jenkins/plugins/bfa/BuildFailureScanner.java +++ b/src/main/java/com/sonyericsson/jenkins/plugins/bfa/BuildFailureScanner.java @@ -25,6 +25,7 @@ package com.sonyericsson.jenkins.plugins.bfa; +import static com.sonyericsson.jenkins.plugins.bfa.MetricsManager.addJobBuildCausesMetric; import static com.sonyericsson.jenkins.plugins.bfa.MetricsManager.incCounters; import static com.sonyericsson.jenkins.plugins.bfa.MetricsManager.UNKNOWNCAUSE; @@ -34,6 +35,7 @@ import com.sonyericsson.jenkins.plugins.bfa.model.FailureCauseMatrixBuildAction; import com.sonyericsson.jenkins.plugins.bfa.model.FailureReader; import com.sonyericsson.jenkins.plugins.bfa.model.FoundFailureCause; +import com.sonyericsson.jenkins.plugins.bfa.model.IFailureCauseMetricData; import com.sonyericsson.jenkins.plugins.bfa.model.ScannerJobProperty; import com.sonyericsson.jenkins.plugins.bfa.model.indication.FoundIndication; import com.sonyericsson.jenkins.plugins.bfa.model.indication.Indication; @@ -219,13 +221,23 @@ public static void scan(Run build, PrintStream scanLog) { } + /* Strip "job/" from beginning and "/build_number/" from end */ + StringBuilder jobName = new StringBuilder(build.getUrl().replaceFirst("^job/", "")); + String jobNameString = jobName.reverse().toString().replaceFirst("^/\\d+/", ""); + jobName = new StringBuilder(jobNameString).reverse(); + if (!foundCauseList.isEmpty()) { incCounters(foundCauseList, PluginImpl.getInstance().isMetricSquashingEnabled()); + addJobBuildCausesMetric(jobName.toString(), build, foundCauseList); } else { + ArrayList unknownCauses = new ArrayList<>( + Collections.singletonList(UNKNOWNCAUSE) + ); incCounters( - new ArrayList<>(Collections.singletonList(UNKNOWNCAUSE)), + unknownCauses, PluginImpl.getInstance().isMetricSquashingEnabled() ); + addJobBuildCausesMetric(jobName.toString(), build, unknownCauses); } FailureCauseBuildAction buildAction = new FailureCauseBuildAction(foundCauseList); diff --git a/src/main/java/com/sonyericsson/jenkins/plugins/bfa/MetricsManager.java b/src/main/java/com/sonyericsson/jenkins/plugins/bfa/MetricsManager.java index dc5234e4..e4a26c28 100644 --- a/src/main/java/com/sonyericsson/jenkins/plugins/bfa/MetricsManager.java +++ b/src/main/java/com/sonyericsson/jenkins/plugins/bfa/MetricsManager.java @@ -3,6 +3,7 @@ import com.codahale.metrics.MetricRegistry; import com.sonyericsson.jenkins.plugins.bfa.model.FailureCause; import com.sonyericsson.jenkins.plugins.bfa.model.IFailureCauseMetricData; +import hudson.model.Run; import jenkins.metrics.api.Metrics; import java.util.HashSet; @@ -72,4 +73,27 @@ public static void incCounters(List causes, b } } } + + /** + * Add and increment counter metric for found failure causes in a build. + * @param job The name of the job where the failed build occurred + * @param build The build where failure causes occurred + * @param causes A list of found causes for a failed job build + * + */ + public static void addJobBuildCausesMetric(String job, Run build, List causes) { + MetricRegistry metricRegistry = Metrics.metricRegistry(); + int buildNumber = build.getNumber(); + for (IFailureCauseMetricData cause : causes) { + String causeName = cause.getName(); + StringBuilder metricName = new StringBuilder(); + metricName.append("jenkins_bfa.job.@") + .append(job) + .append("@.number.@") + .append(buildNumber) + .append("@.cause.@") + .append(causeName); + metricRegistry.counter(metricName.toString()).inc(); + } + } } diff --git a/src/test/java/com/sonyericsson/jenkins/plugins/bfa/MetricsManagerTest.java b/src/test/java/com/sonyericsson/jenkins/plugins/bfa/MetricsManagerTest.java index 8bd1d78f..554ba7bc 100644 --- a/src/test/java/com/sonyericsson/jenkins/plugins/bfa/MetricsManagerTest.java +++ b/src/test/java/com/sonyericsson/jenkins/plugins/bfa/MetricsManagerTest.java @@ -7,6 +7,7 @@ import com.sonyericsson.jenkins.plugins.bfa.model.IFailureCauseMetricData; import com.sonyericsson.jenkins.plugins.bfa.model.indication.BuildLogIndication; import com.sonyericsson.jenkins.plugins.bfa.model.indication.Indication; +import hudson.model.Run; import jenkins.metrics.api.Metrics; import org.junit.After; @@ -22,6 +23,7 @@ import static com.sonyericsson.jenkins.plugins.bfa.MetricsManager.addMetric; import static com.sonyericsson.jenkins.plugins.bfa.MetricsManager.incCounters; +import static com.sonyericsson.jenkins.plugins.bfa.MetricsManager.addJobBuildCausesMetric; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; @@ -37,6 +39,8 @@ public class MetricsManagerTest { private MetricRegistry metricRegistry; private Counter counter; + private String mockedJobDisplayName; + private Run mockedJobBuild; private FailureCause mockedCause; private List mockedCauseList; private MockedStatic metricsMockedStatic; @@ -49,6 +53,8 @@ public void setUp() { metricRegistry = mock(MetricRegistry.class); counter = mock(Counter.class); List indications = new LinkedList<>(); + mockedJobDisplayName = "myJob"; + mockedJobBuild = mock(Run.class); Indication indication = new BuildLogIndication("something"); indications.add(indication); mockedCause = new FailureCause("id", "myFailureCause", "description", "comment", new Date(), @@ -59,6 +65,7 @@ public void setUp() { metricsMockedStatic.when(Metrics::metricRegistry).thenReturn(metricRegistry); when(metricRegistry.counter(anyString())).thenReturn(counter); + when(mockedJobBuild.getNumber()).thenReturn(1); } /** @@ -100,4 +107,13 @@ public void testIncCountersWithSquashingEnabled() { verify(counter, times(mockedCauseList.size())).inc(); } + /** + * Test that a job counter is incremented for found failure causes in a build. + */ + @Test + public void testaddJobBuildCausesMetric() { + addJobBuildCausesMetric(mockedJobDisplayName, mockedJobBuild, mockedCauseList); + + verify(metricRegistry, times(2)).counter("jenkins_bfa.job.@myJob@.number.@1@.cause.@myFailureCause"); + } } From 270b865085ab34a80705b85add3b237cfc93d18c Mon Sep 17 00:00:00 2001 From: Jake Spain Date: Mon, 18 Dec 2023 14:53:59 -0500 Subject: [PATCH 2/2] Update docs for new `jenkins_bfa_job` metric --- docs/metrics.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/docs/metrics.md b/docs/metrics.md index 62e470ba..29caefae 100644 --- a/docs/metrics.md +++ b/docs/metrics.md @@ -4,7 +4,7 @@ This is a guide for the integration with the [Metrics plugin](https://plugins.je ## Metrics -The integration provides counters for each individual cause and category that you create. These counters will reset to zero when jenkins is restarted. The format for the metrics created is `jenkins_bfa_category_` for each category and `jenkins_bfa_cause_` for each cause. The category and cause names will be escaped by the metrics api to replace any spaces with underscores. +The integration provides counters for each individual cause and category that you create, as well as each job build. These counters will reset to zero when jenkins is restarted. The format for the metrics created is `jenkins_bfa_category_` for each category, `jenkins_bfa_cause_` for each cause, and `jenkins_bfa_job____number____cause__` for each job build. The category, cause, and job names will be escaped by the metrics api to replace any spaces with underscores. ## Exporting @@ -23,9 +23,21 @@ metric_relabel_configs: regex: 'jenkins_bfa_cause_(.*)' target_label: 'cause' - source_labels: [__name__] - regex: 'jenkins_bfa_(.*)_(.*)' + regex: 'jenkins_bfa_job__(.*)__number__(.*)__cause__(.*)' + replacement: '$1' + target_label: 'jenkins_job' + - source_labels: [__name__] + regex: 'jenkins_bfa_job__(.*)__number__(.*)__cause__(.*)' + replacement: '$2' + target_label: 'build_number' + - source_labels: [__name__] + regex: 'jenkins_bfa_job__(.*)__number__(.*)__cause__(.*)' + replacement: '$3' + target_label: 'cause' + - source_labels: [__name__] + regex: 'jenkins_bfa_(.*)' replacement: 'jenkins_bfa' - target_label: __name__ + target_label: __name__ ``` This will provide a metric called `jenkins_bfa` with labels for the category and specific cause.