This is an automated email from the ASF dual-hosted git repository.
janhoy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/main by this push:
new e34067ae647 SOLR-18400: Plugins screen 500s when metrics are disabled
(#4803)
e34067ae647 is described below
commit e34067ae6471af9b37f3da07409b0ab62c44f7bf
Author: Jan Høydahl <[email protected]>
AuthorDate: Thu Oct 8 08:33:22 2026 +0200
SOLR-18400: Plugins screen 500s when metrics are disabled (#4803)
---
.../SOLR-18400-plugins-metrics-disabled.yml | 11 ++++
.../apache/solr/handler/admin/MetricsHandler.java | 4 +-
.../solr/handler/admin/MetricsDisabledTest.java | 65 +++++++++++++++++++
.../deployment-guide/pages/metrics-reporting.adoc | 3 +
.../AdminUiMetricsDisabledStandaloneTest.java | 74 ++++++++++++++++++++++
solr/webapp/web/js/angular/app.js | 5 +-
solr/webapp/web/js/angular/controllers/plugins.js | 7 ++
solr/webapp/web/partials/plugins.html | 3 +
8 files changed, 169 insertions(+), 3 deletions(-)
diff --git a/changelog/unreleased/SOLR-18400-plugins-metrics-disabled.yml
b/changelog/unreleased/SOLR-18400-plugins-metrics-disabled.yml
new file mode 100644
index 00000000000..812f62b29f8
--- /dev/null
+++ b/changelog/unreleased/SOLR-18400-plugins-metrics-disabled.yml
@@ -0,0 +1,11 @@
+title: >
+ The metrics endpoints now answer HTTP 510 when metrics collection is
disabled in solr.xml,
+ on both the v1 and v2 API. The v1 API used to return HTTP 500, which made
the Admin UI
+ Plugins / Stats screen render blank. It now explains that metrics are
disabled.
+type: fixed
+authors:
+ - name: Jan Høydahl
+ - name: Eric Pugh
+links:
+ - name: SOLR-18400
+ url: https://issues.apache.org/jira/browse/SOLR-18400
diff --git
a/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java
b/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java
index 784676656ae..d8063bfe988 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java
@@ -124,8 +124,8 @@ public class MetricsHandler extends RequestHandlerBase
implements PermissionName
public void handleRequest(SolrParams params, BiConsumer<String, Object>
consumer) {
if (!enabled) {
- consumer.accept("error", "metrics collection is disabled");
- return;
+ throw new SolrException(
+ SolrException.ErrorCode.INVALID_STATE, "Metrics collection is
disabled");
}
Set<String> metricNames = MetricUtils.readParamsAsSet(params,
MetricUtils.METRIC_NAME_PARAM);
diff --git
a/solr/core/src/test/org/apache/solr/handler/admin/MetricsDisabledTest.java
b/solr/core/src/test/org/apache/solr/handler/admin/MetricsDisabledTest.java
new file mode 100644
index 00000000000..5f70377c444
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/handler/admin/MetricsDisabledTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.handler.admin;
+
+import org.apache.solr.client.solrj.request.MetricsRequest;
+import org.apache.solr.client.solrj.response.InputStreamResponseParser;
+import org.apache.solr.cloud.SolrCloudTestCase;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.NamedList;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Both the v1 {@code /admin/metrics} and the v2 {@code /api/metrics} endpoint
answer HTTP 510 when
+ * metrics collection is switched off in solr.xml.
+ */
+public class MetricsDisabledTest extends SolrCloudTestCase {
+
+ private static final String METRICS_V2_PATH = "/metrics";
+
+ @BeforeClass
+ public static void setupCluster() throws Exception {
+ // MiniSolrCloudCluster's default solr.xml has <metrics enabled="false">
+ configureCluster(1).configure();
+ }
+
+ @Test
+ public void testV1MetricsDisabled() throws Exception {
+ assertMetricsDisabled(CommonParams.METRICS_PATH);
+ }
+
+ @Test
+ public void testV2MetricsDisabled() throws Exception {
+ assertMetricsDisabled(METRICS_V2_PATH);
+ }
+
+ private static void assertMetricsDisabled(String path) throws Exception {
+ var req = new MetricsRequest(path, SolrParams.of(CommonParams.WT,
"prometheus"));
+
+ NamedList<Object> resp = cluster.getSolrClient().request(req);
+ String body = InputStreamResponseParser.consumeResponseToString(resp);
+
+ assertEquals(
+ "Expected HTTP 510 from " + path,
+ SolrException.ErrorCode.INVALID_STATE.code,
+ (int) (Integer) resp.get(InputStreamResponseParser.HTTP_STATUS_KEY));
+ assertTrue(body, body.contains("Metrics collection is disabled"));
+ }
+}
diff --git
a/solr/solr-ref-guide/modules/deployment-guide/pages/metrics-reporting.adoc
b/solr/solr-ref-guide/modules/deployment-guide/pages/metrics-reporting.adoc
index 1be5df0b61b..880359491fd 100644
--- a/solr/solr-ref-guide/modules/deployment-guide/pages/metrics-reporting.adoc
+++ b/solr/solr-ref-guide/modules/deployment-guide/pages/metrics-reporting.adoc
@@ -171,6 +171,9 @@ The V2 `/metrics` endpoint is equivalent to the V1
`/admin/metrics` endpoint.
Examples on this page show only the V2 endpoint.
====
+Metrics collection can be switched off for a node with `<metrics
enabled="false"/>` in `solr.xml`.
+Both endpoints then respond with `HTTP 510` and the message `Metrics
collection is disabled`, which a Prometheus scraper reports as a target that is
down.
+
=== Prometheus
See https://prometheus.io/docs/concepts/data_model/[Prometheus Data Model]
documentation for more information on its data model.
diff --git
a/solr/webapp/src/test/org/apache/solr/webapp/AdminUiMetricsDisabledStandaloneTest.java
b/solr/webapp/src/test/org/apache/solr/webapp/AdminUiMetricsDisabledStandaloneTest.java
new file mode 100644
index 00000000000..7a97de4c6be
--- /dev/null
+++
b/solr/webapp/src/test/org/apache/solr/webapp/AdminUiMetricsDisabledStandaloneTest.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.webapp;
+
+import java.nio.file.Path;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openqa.selenium.By;
+
+/**
+ * SOLR-18400: the Plugins screen on a node with metrics collection switched
off in solr.xml. The
+ * metrics endpoint answers HTTP 510 there, which the screen must turn into an
explanation rather
+ * than a blank page or the global error banner.
+ */
+public class AdminUiMetricsDisabledStandaloneTest extends
AdminUiStandaloneTestBase {
+
+ private static final String CORE = "collection1";
+
+ @BeforeClass
+ public static void startStandaloneNode() throws Exception {
+ // the base class turned metrics on for the UI screens; this suite is
about them being off.
+ // Must come before the node starts, and is restored after the class with
the other properties
+ System.setProperty("metricsEnabled", "false");
+ Path home = buildStandaloneHome(CORE);
+ standaloneJetty = startStandaloneJetty(home);
+ baseUrl = standaloneJetty.getBaseUrl().toString();
+ assertFalse(
+ "fixture node should have metrics disabled",
+
standaloneJetty.getCoreContainer().getConfig().getMetricsConfig().isEnabled());
+ }
+
+ @AfterClass
+ public static void stopStandaloneNode() throws Exception {
+ if (standaloneJetty != null) {
+ standaloneJetty.stop();
+ standaloneJetty = null;
+ }
+ }
+
+ @Test
+ public void testPluginsScreenExplainsDisabledMetrics() {
+ openPage(CORE + "/plugins", By.id("plugins"));
+
+ String message = waitForText(By.cssSelector("#plugins .message-container
.message"));
+ assertTrue(message, message.contains("Metrics collection is disabled"));
+
+ // no plugin categories or entries, as there is no metrics data to build
them from
+ assertTrue(driver.findElements(By.cssSelector("#plugins #navigation
a[rel]")).isEmpty());
+ assertTrue(driver.findElements(By.cssSelector("#plugins #frame
li.entry")).isEmpty());
+
+ // the 510 is handled by the screen itself; the global error banner must
stay away
+ assertTrue(
+ "global error banner should not show for a disabled feature",
+ driver.findElements(By.id("http-exception")).isEmpty());
+
+ // Chrome reports the failed XHR itself at SEVERE level; everything else
must be clean
+ assertNoSevereConsoleErrors("510");
+ }
+}
diff --git a/solr/webapp/web/js/angular/app.js
b/solr/webapp/web/js/angular/app.js
index 1558918d09e..aba91049975 100644
--- a/solr/webapp/web/js/angular/app.js
+++ b/solr/webapp/web/js/angular/app.js
@@ -429,6 +429,9 @@ solrAdminApp.config([
// Schema Designer and Security panels handle errors internally to provide
a better user experience than the global error handler
var isHandledBySchemaDesigner = rejection.config.url &&
rejection.config.url.startsWith("/api/schema-designer/");
var isHandledBySecurity = rejection.config.url &&
rejection.config.url.startsWith("/api/cluster/security/");
+ // HTTP 510 means a feature is switched off in solr.xml, e.g. metrics
collection. The screen
+ // asking for that data explains it in place, so skip the global error
banner.
+ var isDisabledFeature = rejection.status === 510 && rejection.config.url
&& rejection.config.url.endsWith("admin/metrics");
if (rejection.status === 0) {
$rootScope.$broadcast('connectionStatusActive');
if (!$rootScope.retryCount) $rootScope.retryCount=0;
@@ -463,7 +466,7 @@ solrAdminApp.config([
} else if (isHandledBySecurity) {
// Let the security panel surface the detailed error in its own dialog
$rootScope.$broadcast('securityApiError', rejection);
- } else {
+ } else if (!isDisabledFeature) {
// schema designer prefers to handle errors itself
if (!isHandledBySchemaDesigner) {
$rootScope.exceptions[rejection.config.url] = rejection.data.error;
diff --git a/solr/webapp/web/js/angular/controllers/plugins.js
b/solr/webapp/web/js/angular/controllers/plugins.js
index bf0dd9bcac7..157639980f0 100644
--- a/solr/webapp/web/js/angular/controllers/plugins.js
+++ b/solr/webapp/web/js/angular/controllers/plugins.js
@@ -35,6 +35,7 @@ solrAdminApp.controller('PluginsController',
var type = $location.search().type;
Metrics.raw(params, function (response) {
+ $scope.metricsDisabled = false;
$scope.types = getPluginTypesFromMetrics(response.data, type);
$scope.type = getSelectedType($scope.types, type);
@@ -44,6 +45,12 @@ solrAdminApp.controller('PluginsController',
} else {
$scope.plugins = [];
}
+ }, function (response) {
+ // Solr answers HTTP 510 when metrics collection is turned off
in solr.xml
+ $scope.metricsDisabled = response.status === 510;
+ $scope.types = [];
+ $scope.type = null;
+ $scope.plugins = [];
});
};
diff --git a/solr/webapp/web/partials/plugins.html
b/solr/webapp/web/partials/plugins.html
index 1e80b6f9b6e..f858f4ce6dd 100644
--- a/solr/webapp/web/partials/plugins.html
+++ b/solr/webapp/web/partials/plugins.html
@@ -17,6 +17,9 @@ limitations under the License.
<div id="plugins" class="clearfix">
<div id="frame">
+ <div class="message-container" ng-show="metricsDisabled">
+ <div class="message">Metrics collection is disabled in this node's
solr.xml (<metrics enabled="false">), so no plugin information is
available.</div>
+ </div>
<ul>
<li class="entry" ng-class="{changed: plugin.changed}" ng-repeat="plugin
in type.plugins">
<a ng-click="selectPlugin(plugin)">