This is an automated email from the ASF dual-hosted git repository. dsmiley pushed a commit to branch branch_10x in repository https://gitbox.apache.org/repos/asf/solr.git
commit 319b70d24b3b797387be0ee81afd7359648ce1e0 Author: Jan Høydahl <[email protected]> AuthorDate: Fri Aug 7 19:37:45 2026 +0200 Fix consumers of JVM CPU metrics renamed by OTel Prometheus exporter update (#4711) This also fixes the PlacementPluginIntegrationTest.testAttributeFetcherImpl test failures (cherry picked from commit 6f0d0b5b7295611acf7c3d95030530b415a4b965) --- .../fix-jvm-cpu-utilization-metric-name.yml | 10 +++++ .../cluster/placement/impl/NodeMetricImpl.java | 2 +- .../util/circuitbreaker/CPUCircuitBreaker.java | 2 +- .../org/apache/solr/util/TestCircuitBreakers.java | 48 ++++++++++++++++++++++ .../pages/major-changes-in-solr-10.adoc | 3 ++ .../solr/client/solrj/impl/NodeValueFetcher.java | 2 +- 6 files changed, 64 insertions(+), 3 deletions(-) diff --git a/changelog/unreleased/fix-jvm-cpu-utilization-metric-name.yml b/changelog/unreleased/fix-jvm-cpu-utilization-metric-name.yml new file mode 100644 index 00000000000..1c329ff841d --- /dev/null +++ b/changelog/unreleased/fix-jvm-cpu-utilization-metric-name.yml @@ -0,0 +1,10 @@ +title: > + The Prometheus JVM CPU metrics are now named `jvm_system_cpu_utilization` and + `jvm_cpu_recent_utilization` (the `_ratio` suffix was dropped) following the + OpenTelemetry Prometheus exporter update. +type: changed +authors: + - name: Jan Høydahl +links: + - name: PR#4711 + url: https://github.com/apache/solr/pull/4711 diff --git a/solr/core/src/java/org/apache/solr/cluster/placement/impl/NodeMetricImpl.java b/solr/core/src/java/org/apache/solr/cluster/placement/impl/NodeMetricImpl.java index 4f76896a320..96ba2d1b676 100644 --- a/solr/core/src/java/org/apache/solr/cluster/placement/impl/NodeMetricImpl.java +++ b/solr/core/src/java/org/apache/solr/cluster/placement/impl/NodeMetricImpl.java @@ -38,7 +38,7 @@ public class NodeMetricImpl<T> extends MetricImpl<T> implements NodeMetric<T> { /** System load average. */ public static final NodeMetricImpl<Double> SYSLOAD_AVG = - new NodeMetricImpl<>("sysLoadAvg", "jvm_system_cpu_utilization_ratio"); + new NodeMetricImpl<>("sysLoadAvg", "jvm_system_cpu_utilization"); /** Number of available processors. */ public static final NodeMetricImpl<Integer> AVAILABLE_PROCESSORS = diff --git a/solr/core/src/java/org/apache/solr/util/circuitbreaker/CPUCircuitBreaker.java b/solr/core/src/java/org/apache/solr/util/circuitbreaker/CPUCircuitBreaker.java index 09248363bcd..391f88049dc 100644 --- a/solr/core/src/java/org/apache/solr/util/circuitbreaker/CPUCircuitBreaker.java +++ b/solr/core/src/java/org/apache/solr/util/circuitbreaker/CPUCircuitBreaker.java @@ -112,7 +112,7 @@ public class CPUCircuitBreaker extends CircuitBreaker implements SolrCoreAware { return this.cc .getMetricManager() .getPrometheusMetricReader("solr.jvm") - .collect(name -> name.contains("jvm_system_cpu_utilization_ratio")) + .collect(name -> name.contains("jvm_system_cpu_utilization")) .stream() .filter(GaugeSnapshot.class::isInstance) .map(GaugeSnapshot.class::cast) diff --git a/solr/core/src/test/org/apache/solr/util/TestCircuitBreakers.java b/solr/core/src/test/org/apache/solr/util/TestCircuitBreakers.java index 648ac035854..88bdee78087 100644 --- a/solr/core/src/test/org/apache/solr/util/TestCircuitBreakers.java +++ b/solr/core/src/test/org/apache/solr/util/TestCircuitBreakers.java @@ -19,8 +19,10 @@ package org.apache.solr.util; import static org.hamcrest.CoreMatchers.containsString; +import com.sun.management.OperatingSystemMXBean; import java.io.IOException; import java.lang.invoke.MethodHandles; +import java.lang.management.ManagementFactory; import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -30,6 +32,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; +import org.apache.lucene.util.SuppressForbidden; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.common.SolrException; @@ -43,6 +46,7 @@ import org.apache.solr.util.circuitbreaker.CircuitBreakerRegistry; import org.apache.solr.util.circuitbreaker.LoadAverageCircuitBreaker; import org.apache.solr.util.circuitbreaker.MemoryCircuitBreaker; import org.junit.After; +import org.junit.Assume; import org.junit.BeforeClass; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -271,6 +275,39 @@ public class TestCircuitBreakers extends SolrTestCaseJ4 { assertThatHighQueryLoadTrips(circuitBreaker, 5); } + /** + * Reads a real CPU usage value from the metrics, guarding against a regression where a renamed + * JVM metric made {@link CPUCircuitBreaker#calculateLiveCPUUsage()} silently return -1. Gated by + * an independent native-CPU probe so that a name regression fails here rather than being mistaken + * for an unsupported machine (both otherwise yield -1). + */ + public void testCPUCircuitBreakerReadsLiveUsage() { + Assume.assumeTrue("No native CPU measurement on this machine", nativeCpuMeasurementSupported()); + + double usage = new ExposedCPUCircuitBreaker(h.getCoreContainer()).liveCPUUsage(); + assertTrue("Expected CPU usage >= 0 but got " + usage, usage >= 0); + } + + @SuppressForbidden(reason = "Probing com.sun OperatingSystemMXBean for native CPU support") + private static boolean nativeCpuMeasurementSupported() { + if (!(ManagementFactory.getOperatingSystemMXBean() instanceof OperatingSystemMXBean osBean)) { + return false; + } + // getCpuLoad() needs two samples and may return a negative value on the first calls + for (int i = 0; i < 10; i++) { + if (osBean.getCpuLoad() >= 0) { + return true; + } + try { + Thread.sleep(50); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return false; + } + } + return false; + } + /** * Common assert method to be reused in tests * @@ -441,6 +478,17 @@ public class TestCircuitBreakers extends SolrTestCaseJ4 { } } + /** Exposes the real (protected) CPU usage calculation for testing. */ + private static class ExposedCPUCircuitBreaker extends CPUCircuitBreaker { + public ExposedCPUCircuitBreaker(CoreContainer coreContainer) { + super(coreContainer); + } + + double liveCPUUsage() { + return calculateLiveCPUUsage(); + } + } + private static class FakeLoadAverageCircuitBreaker extends LoadAverageCircuitBreaker { @Override protected double calculateLiveLoadAverage() { diff --git a/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-10.adoc b/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-10.adoc index 80acfeae06a..7b4a5e9e452 100644 --- a/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-10.adoc +++ b/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-10.adoc @@ -412,6 +412,9 @@ Users who consume Solr metrics via OTLP and rely on the 10.0 underscore-format n (e.g., `crossdc.consumer.output.total` → `solr.crossdc.consumer.output.total`) * All CrossDC producer metrics have been renamed: `solr.core.crossdc.producer.*` → `solr.crossdc.producer.*` (e.g., `solr.core.crossdc.producer.submitted` → `solr.crossdc.producer.submitted`) +* The Prometheus JVM CPU utilization metrics lost their `_ratio` suffix, as the updated OpenTelemetry + exporter no longer maps the OTel unit `1` to a `_ratio` suffix: `jvm_system_cpu_utilization_ratio` → + `jvm_system_cpu_utilization` and `jvm_cpu_recent_utilization_ratio` → `jvm_cpu_recent_utilization`. Update your dashboards or other metrics consumers accordingly. diff --git a/solr/solrj-zookeeper/src/java/org/apache/solr/client/solrj/impl/NodeValueFetcher.java b/solr/solrj-zookeeper/src/java/org/apache/solr/client/solrj/impl/NodeValueFetcher.java index 3dd91fca5d3..abd31c5d86c 100644 --- a/solr/solrj-zookeeper/src/java/org/apache/solr/client/solrj/impl/NodeValueFetcher.java +++ b/solr/solrj-zookeeper/src/java/org/apache/solr/client/solrj/impl/NodeValueFetcher.java @@ -74,7 +74,7 @@ public class NodeValueFetcher { .sum(); } }, - SYSLOADAVG("sysLoadAvg", "jvm_system_cpu_utilization_ratio"); + SYSLOADAVG("sysLoadAvg", "jvm_system_cpu_utilization"); public final String tagName; public final String metricName;
