Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
10 changes: 10 additions & 0 deletions changelog/unreleased/fix-jvm-cpu-utilization-metric-name.yml
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
Comment thread
janhoy marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ protected double calculateLiveCPUUsage() {
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)
Expand Down
48 changes: 48 additions & 0 deletions solr/core/src/test/org/apache/solr/util/TestCircuitBreakers.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@

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;
Expand All @@ -30,6 +32,7 @@
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;
Expand All @@ -43,6 +46,7 @@
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;
Expand Down Expand Up @@ -271,6 +275,39 @@ public void testFakeLoadAverageCircuitBreaker() {
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
*
Expand Down Expand Up @@ -441,6 +478,17 @@ protected double calculateLiveCPUUsage() {
}
}

/** 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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,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.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public Object extractFromPrometheus(List<String> prometheusLines) {
.sum();
}
},
SYSLOADAVG("sysLoadAvg", "jvm_system_cpu_utilization_ratio");
SYSLOADAVG("sysLoadAvg", "jvm_system_cpu_utilization");

public final String tagName;
public final String metricName;
Expand Down
Loading