-
Notifications
You must be signed in to change notification settings - Fork 152
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/567 metrics to identify stuck jobs #582
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package org.jenkinsci.plugins.prometheus; | ||
|
||
import hudson.model.Computer; | ||
import hudson.model.Executor; | ||
import hudson.model.Node; | ||
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.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.util.Collection; | ||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.stream.Collectors; | ||
|
||
public class NodeCollector extends Collector { | ||
|
||
private static final Logger LOGGER = LoggerFactory.getLogger(NodeCollector.class); | ||
|
||
@Override | ||
public List<MetricFamilySamples> collect() { | ||
LOGGER.debug("Collecting node metrics for prometheus"); | ||
String[] labelNameArray = {"computerName"}; | ||
|
||
CollectorFactory factory = new CollectorFactory(); | ||
|
||
MetricCollector<Executor, ? extends Collector> likelyStuckCollector = factory.createExecutorStatisticsCollector(CollectorType.EXECUTOR_LIKELY_STUCK_GAUGE, labelNameArray); | ||
|
||
List<? extends MetricCollector<Executor, ? extends Collector>> collectors = List.of(likelyStuckCollector); | ||
|
||
List<Computer> computers = Jenkins.get().getNodes().parallelStream() | ||
.map(Node::toComputer) | ||
.filter(Objects::nonNull) | ||
.collect(Collectors.toList()); | ||
|
||
for (Computer computer : computers) { | ||
String computerName = computer.getName(); | ||
List<Executor> executors = computer.getExecutors(); | ||
if (executors != null) { | ||
for (Executor ex : executors) { | ||
likelyStuckCollector.calculateMetric(ex, new String[]{computerName}); | ||
} | ||
} | ||
} | ||
|
||
return collectors.stream() | ||
.map(MetricCollector::collect) | ||
.flatMap(Collection::stream) | ||
.collect(Collectors.toList()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package org.jenkinsci.plugins.prometheus.collectors.jobs; | ||
|
||
import hudson.model.Job; | ||
import io.prometheus.client.Gauge; | ||
import io.prometheus.client.SimpleCollector; | ||
import org.jenkinsci.plugins.prometheus.collectors.CollectorType; | ||
import org.jenkinsci.plugins.prometheus.collectors.builds.BuildsMetricCollector; | ||
|
||
public class LogUpdatedGauge extends BuildsMetricCollector<Job<?, ?>, Gauge> { | ||
|
||
protected LogUpdatedGauge(String[] labelNames, String namespace, String subsystem) { | ||
super(labelNames, namespace, subsystem); | ||
} | ||
|
||
@Override | ||
protected CollectorType getCollectorType() { | ||
return CollectorType.JOB_LOG_UPDATED_GAUGE; | ||
} | ||
|
||
@Override | ||
protected String getHelpText() { | ||
return "Provides a hint if a job is still logging. Maybe not 100% accurate - but a good hint."; | ||
} | ||
|
||
@Override | ||
protected SimpleCollector.Builder<?, Gauge> getCollectorBuilder() { | ||
return Gauge.build(); | ||
} | ||
|
||
@Override | ||
public void calculateMetric(Job<?, ?> jenkinsObject, String[] labelValues) { | ||
|
||
if (jenkinsObject != null) { | ||
boolean logUpdated = jenkinsObject.isLogUpdated(); | ||
this.collector.labels(labelValues).set(logUpdated ? 1.0 : 0.0); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package org.jenkinsci.plugins.prometheus.collectors.nodes; | ||
|
||
import hudson.model.Executor; | ||
import io.prometheus.client.Gauge; | ||
import io.prometheus.client.SimpleCollector; | ||
import org.jenkinsci.plugins.prometheus.collectors.BaseMetricCollector; | ||
import org.jenkinsci.plugins.prometheus.collectors.CollectorType; | ||
|
||
public class ExecutorLikelyStuckGauge extends BaseMetricCollector<Executor, Gauge> { | ||
|
||
protected ExecutorLikelyStuckGauge(String[] labelNames, String namespace, String subsystem) { | ||
super(labelNames, namespace, subsystem); | ||
} | ||
|
||
@Override | ||
protected CollectorType getCollectorType() { | ||
return CollectorType.EXECUTOR_LIKELY_STUCK_GAUGE; | ||
} | ||
|
||
@Override | ||
protected String getHelpText() { | ||
return "Returns an indication if an executor of a node is likely stuck"; | ||
} | ||
|
||
@Override | ||
protected SimpleCollector.Builder<?, Gauge> getCollectorBuilder() { | ||
return Gauge.build(); | ||
} | ||
|
||
@Override | ||
public void calculateMetric(Executor executor, String[] labelValues) { | ||
if (executor == null) { | ||
return; | ||
} | ||
boolean likelyStuck = executor.isLikelyStuck(); | ||
collector.labels(labelValues).set(likelyStuck ? 1.0 : 0.0); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package org.jenkinsci.plugins.prometheus.collectors.nodes; | ||
|
||
import hudson.model.Executor; | ||
import org.jenkinsci.plugins.prometheus.collectors.BaseCollectorFactory; | ||
import org.jenkinsci.plugins.prometheus.collectors.CollectorType; | ||
import org.jenkinsci.plugins.prometheus.collectors.MetricCollector; | ||
import org.jenkinsci.plugins.prometheus.collectors.NoOpMetricCollector; | ||
|
||
import java.util.stream.Collector; | ||
|
||
public class NodeCollectorFactory extends BaseCollectorFactory { | ||
|
||
public NodeCollectorFactory(){super();} | ||
|
||
public MetricCollector<Executor, ? extends Collector> createExecutorCollector(CollectorType type, String[] labelNames) { | ||
switch (type) { | ||
case EXECUTOR_LIKELY_STUCK_GAUGE: | ||
return saveBuildCollector(new ExecutorLikelyStuckGauge(labelNames, namespace, subsystem)); | ||
default: | ||
return new NoOpMetricCollector<>(); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package org.jenkinsci.plugins.prometheus.collectors.jobs; | ||
|
||
import io.prometheus.client.Collector; | ||
import org.junit.Test; | ||
|
||
import java.util.List; | ||
|
||
import static org.mockito.Mockito.when; | ||
|
||
public class LogUpdatedGaugeTest extends JobCollectorTest { | ||
|
||
|
||
@Test | ||
public void testBasicAttributes() { | ||
Check notice Code scanning / Pmd (reported by Codacy) JUnit tests should include assert() or fail() Note test
JUnit tests should include assert() or fail()
|
||
when(job.isLogUpdated()).thenReturn(true); | ||
|
||
LogUpdatedGauge sut = new LogUpdatedGauge(new String[]{"jenkins_job", "repo"}, "default", "jenkins"); | ||
|
||
sut.calculateMetric(job, new String[]{"job1", "NA"}); | ||
List<Collector.MetricFamilySamples> collect = sut.collect(); | ||
|
||
validateMetricFamilySampleListSize(collect, 1); | ||
|
||
Collector.MetricFamilySamples samples = collect.get(0); | ||
validateNames(samples, new String[]{"default_jenkins_builds_job_log_updated"}); | ||
validateMetricFamilySampleSize(samples, 1); | ||
|
||
} | ||
|
||
@Test | ||
public void testLogIsUpdatedReturnsOne() { | ||
Check notice Code scanning / Pmd (reported by Codacy) JUnit tests should include assert() or fail() Note test
JUnit tests should include assert() or fail()
|
||
|
||
when(job.isLogUpdated()).thenReturn(true); | ||
|
||
LogUpdatedGauge sut = new LogUpdatedGauge(new String[]{"jenkins_job", "repo"}, "default", "jenkins"); | ||
|
||
sut.calculateMetric(job, new String[]{"job1", "NA"}); | ||
List<Collector.MetricFamilySamples> collect = sut.collect(); | ||
Collector.MetricFamilySamples samples = collect.get(0); | ||
validateValue(samples.samples.get(0), 1.0); | ||
} | ||
|
||
@Test | ||
public void testLogIsNotUpdatedReturnsZero() { | ||
Check notice Code scanning / Pmd (reported by Codacy) JUnit tests should include assert() or fail() Note test
JUnit tests should include assert() or fail()
|
||
|
||
when(job.isLogUpdated()).thenReturn(false); | ||
|
||
LogUpdatedGauge sut = new LogUpdatedGauge(new String[]{"jenkins_job", "repo"}, "default", "jenkins"); | ||
|
||
sut.calculateMetric(job, new String[]{"job1", "NA"}); | ||
List<Collector.MetricFamilySamples> collect = sut.collect(); | ||
Collector.MetricFamilySamples samples = collect.get(0); | ||
validateValue(samples.samples.get(0), 0.0); | ||
} | ||
} |
Check warning
Code scanning / Pmd (reported by Codacy)
Avoid unnecessary constructors - the compiler will generate these for you Warning