Skip to content
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

Delay initialization of Prometheus Plugin to fix startup issues in certain environments #648

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.jenkinsci.plugins.prometheus.config;

import hudson.Extension;
import hudson.ExtensionList;
import hudson.util.FormValidation;
import jenkins.YesNoMaybe;
import jenkins.model.GlobalConfiguration;
Expand Down Expand Up @@ -76,7 +77,7 @@ public PrometheusConfiguration() {
}

public static PrometheusConfiguration get() {
return (PrometheusConfiguration) Jenkins.get().getDescriptor(PrometheusConfiguration.class);
return ExtensionList.lookupSingleton(PrometheusConfiguration.class);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ public class MetricStatusChecker {
public static boolean isEnabled(String metricName) {

PrometheusConfiguration configuration = PrometheusConfiguration.get();
if (configuration == null) {
LOGGER.warn("Cannot check if metric is enabled. Unable to get PrometheusConfiguration");
return true;
}

DisabledMetricConfig disabledMetricConfig = configuration.getDisabledMetricConfig();
if (disabledMetricConfig == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.jenkinsci.plugins.prometheus.init;

import hudson.ExtensionList;
import hudson.init.InitMilestone;
import hudson.init.Initializer;
import org.jenkinsci.plugins.prometheus.service.PrometheusMetrics;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class Initializers {

Check warning on line 11 in src/main/java/org/jenkinsci/plugins/prometheus/init/Initializers.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 11 is not covered by tests

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

@Initializer(before = InitMilestone.COMPLETED)
public static void initializePrometheusMetrics() {
LOGGER.debug("Initializing Prometheus Plugin");
try {
PrometheusMetrics prometheusMetrics = ExtensionList.lookupSingleton(PrometheusMetrics.class);
prometheusMetrics.initialize();

Check warning on line 20 in src/main/java/org/jenkinsci/plugins/prometheus/init/Initializers.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 19-20 are not covered by tests
} catch (IllegalStateException e) {
LOGGER.error("Unable to load Prometheus Plugin. Collecting Metrics won't work", e);
}

Check warning on line 23 in src/main/java/org/jenkinsci/plugins/prometheus/init/Initializers.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 23 is not covered by tests
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

import hudson.Extension;
import hudson.ExtensionList;
import hudson.init.InitMilestone;
import hudson.init.Initializer;
import io.prometheus.client.Collector;
import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.dropwizard.DropwizardExports;
Expand All @@ -30,34 +28,13 @@

private volatile boolean initialized = false;
private volatile boolean initializing = false;
private final CollectorRegistry collectorRegistry;
private CollectorRegistry collectorRegistry;
private final AtomicReference<String> cachedMetrics;

public DefaultPrometheusMetrics() {
this.collectorRegistry = CollectorRegistry.defaultRegistry;
this.cachedMetrics = new AtomicReference<>("");
}

@Initializer(after = InitMilestone.JOB_LOADED)
public void registerCollectors() {
if (!initialized && !initializing) {
initializing = true;
LOGGER.debug("Initializing...");
collectorRegistry.register(new JobCollector());
collectorRegistry.register(new JenkinsStatusCollector());
collectorRegistry.register(
new DropwizardExports(Metrics.metricRegistry(), new JenkinsNodeBuildsSampleBuilder()));
collectorRegistry.register(new DiskUsageCollector());
collectorRegistry.register(new ExecutorCollector());
collectorRegistry.register(new CodeCoverageCollector());
// other collectors from other plugins
ExtensionList.lookup(Collector.class).forEach(collectorRegistry::register);
DefaultExports.initialize();
initialized = true;
initializing = false;
}
}

@Override
public String getMetrics() {
return cachedMetrics.get();
Expand All @@ -76,4 +53,25 @@
LOGGER.debug("Unable to collect metrics");
}
}

@Override
public void initialize() {
if (!initialized && !initializing) {
this.collectorRegistry = CollectorRegistry.defaultRegistry;
initializing = true;
LOGGER.debug("Initializing...");
collectorRegistry.register(new JobCollector());
collectorRegistry.register(new JenkinsStatusCollector());
collectorRegistry.register(
new DropwizardExports(Metrics.metricRegistry(), new JenkinsNodeBuildsSampleBuilder()));
collectorRegistry.register(new DiskUsageCollector());
collectorRegistry.register(new ExecutorCollector());
collectorRegistry.register(new CodeCoverageCollector());
// other collectors from other plugins
ExtensionList.lookup(Collector.class).forEach(collectorRegistry::register);
DefaultExports.initialize();
initialized = true;
initializing = false;
}
}

Check warning on line 76 in src/main/java/org/jenkinsci/plugins/prometheus/service/DefaultPrometheusMetrics.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 59-76 are not covered by tests
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ public interface PrometheusMetrics extends ExtensionPoint {

void collectMetrics();

void initialize();

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,6 @@

public class MetricStatusCheckerTest {

@Test
void testNoConfigWontFail() {
Jenkins jenkins = mock(Jenkins.class);

PrometheusConfiguration mockedConfig = mock(PrometheusConfiguration.class);
String namespace = "TestNamespace";

when(mockedConfig.getDefaultNamespace()).thenReturn(namespace);
when(mockedConfig.isCollectNodeStatus()).thenReturn(false);

try (MockedStatic<Jenkins> jenkinsStatic = mockStatic(Jenkins.class);
MockedStatic<PrometheusConfiguration> configStatic = mockStatic(PrometheusConfiguration.class)) {
jenkinsStatic.when(Jenkins::get).thenReturn(jenkins);
configStatic.when(PrometheusConfiguration::get).thenReturn(null);

boolean enabled = MetricStatusChecker.isEnabled("some_metric");
Assertions.assertTrue(enabled);
}
}

@Test
void testNoDisabledMetricConfigWontFail() {
Jenkins jenkins = mock(Jenkins.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,22 @@ public class PrometheusActionTest {
@Mock
private PrometheusConfiguration configuration;

private MockedStatic<ExtensionList> extensionListStatic;
private MockedStatic<Jenkins> jenkinsStatic;

@BeforeEach
public void setUp() {
jenkinsStatic = mockStatic(Jenkins.class);
jenkinsStatic.when(Jenkins::get).thenReturn(jenkins);
when(jenkins.getDescriptor(PrometheusConfiguration.class)).thenReturn(configuration);

when(configuration.getAdditionalPath()).thenReturn("prometheus");
extensionListStatic = mockStatic(ExtensionList.class);
extensionListStatic.when(() -> ExtensionList.lookupSingleton(PrometheusConfiguration.class)).thenReturn(configuration);
}

@AfterEach
public void tearDown() {
extensionListStatic.close();
jenkinsStatic.close();
}

Expand Down Expand Up @@ -92,23 +96,23 @@ public void shouldReturnMetrics() throws IOException, ServletException {
PrometheusMetrics prometheusMetrics = mock(PrometheusMetrics.class);
String responseBody = "testMetric";
when(prometheusMetrics.getMetrics()).thenReturn(responseBody);
try (MockedStatic<ExtensionList> extensionListMockedStatic = mockStatic(ExtensionList.class)) {
extensionListMockedStatic.when(() -> ExtensionList.lookupSingleton(PrometheusMetrics.class)).thenReturn(prometheusMetrics);
StaplerRequest request = mock(StaplerRequest.class);
String url = "prometheus";
when(request.getRestOfPath()).thenReturn(url);

// when
HttpResponse actual = action.doDynamic(request);

// then
AssertStaplerResponse.from(actual)
.call()
.assertHttpStatus(HTTP_OK)
.assertContentType(TextFormat.CONTENT_TYPE_004)
.assertHttpHeader("Cache-Control", "must-revalidate,no-cache,no-store")
.assertBody(responseBody);
}

extensionListStatic.when(() -> ExtensionList.lookupSingleton(PrometheusMetrics.class)).thenReturn(prometheusMetrics);
StaplerRequest request = mock(StaplerRequest.class);
String url = "prometheus";
when(request.getRestOfPath()).thenReturn(url);

// when
HttpResponse actual = action.doDynamic(request);

// then
AssertStaplerResponse.from(actual)
.call()
.assertHttpStatus(HTTP_OK)
.assertContentType(TextFormat.CONTENT_TYPE_004)
.assertHttpHeader("Cache-Control", "must-revalidate,no-cache,no-store")
.assertBody(responseBody);


}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,9 @@
cachedMetrics.set(metrics);
}

@Override
public void initialize() {

Check warning

Code scanning / Pmd (reported by Codacy)

Document empty method body Warning test

Document empty method body

}
}
}
Loading