This is an automated email from the ASF dual-hosted git repository. mlbiscoc pushed a commit to branch feature/SOLR-17458 in repository https://gitbox.apache.org/repos/asf/solr.git
commit 5cc10d5b7241b1c1195a3088a8709c556e25f0b8 Author: Matthew Biscocho <[email protected]> AuthorDate: Thu Aug 28 13:52:51 2025 -0400 Close OTEL Observable instruments (#3517) * Close observable instruments * List of closeables * Use unmodifiable instead of copy --- .../src/java/org/apache/solr/core/SolrCore.java | 160 +++++++++++---------- .../src/java/org/apache/solr/core/ZkContainer.java | 144 ++++++++++--------- .../apache/solr/update/DirectUpdateHandler2.java | 26 ++-- .../src/java/org/apache/solr/update/UpdateLog.java | 49 ++++--- .../org/apache/solr/BasicFunctionalityTest.java | 32 ++--- .../test/org/apache/solr/core/SolrCoreTest.java | 34 +++-- .../apache/solr/update/SolrIndexMetricsTest.java | 42 +++--- .../java/org/apache/solr/common/util/IOUtils.java | 5 + 8 files changed, 267 insertions(+), 225 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java b/solr/core/src/java/org/apache/solr/core/SolrCore.java index 3a13af1c07b..4d9ddc03c34 100644 --- a/solr/core/src/java/org/apache/solr/core/SolrCore.java +++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java @@ -261,6 +261,7 @@ public class SolrCore implements SolrInfoBean, Closeable { private AttributedLongCounter newSearcherOtherErrorsCounter; private AttributedLongTimer newSearcherTimer; private AttributedLongTimer newSearcherWarmupTimer; + private List<AutoCloseable> toClose; private final String metricTag = SolrMetricProducer.getUniqueMetricTag(this, null); private final SolrMetricsContext solrMetricsContext; @@ -1324,6 +1325,7 @@ public class SolrCore implements SolrInfoBean, Closeable { @Override public void initializeMetrics( SolrMetricsContext parentContext, Attributes attributes, String scope) { + final List<AutoCloseable> observables = new ArrayList<>(); Attributes baseSearcherAttributes = Attributes.builder() @@ -1369,86 +1371,93 @@ public class SolrCore implements SolrInfoBean, Closeable { baseSearcherTimerMetric, Attributes.builder().putAll(baseSearcherAttributes).put(TYPE_ATTR, "warmup").build()); - parentContext.gauge(() -> getOpenCount(), true, "refCount", Category.CORE.toString()); - - parentContext.observableLongGauge( - "solr_core_ref_count", - "The current number of active references to a Solr core", - (observableLongMeasurement -> { - observableLongMeasurement.record(getOpenCount(), baseGaugeCoreAttributes); - })); - - parentContext.observableLongGauge( - "solr_core_disk_space", - "Solr core disk space metrics", - (observableLongMeasurement -> { - - // initialize disk total / free metrics - Path dataDirPath = Path.of(dataDir); - var totalSpaceAttributes = - Attributes.builder() - .putAll(baseGaugeCoreAttributes) - .put(TYPE_ATTR, "total_space") - .build(); - var usableSpaceAttributes = - Attributes.builder() - .putAll(baseGaugeCoreAttributes) - .put(TYPE_ATTR, "usable_space") - .build(); - try { - observableLongMeasurement.record( - Files.getFileStore(dataDirPath).getTotalSpace(), totalSpaceAttributes); - } catch (IOException e) { - observableLongMeasurement.record(0L, totalSpaceAttributes); - } - try { - observableLongMeasurement.record( - Files.getFileStore(dataDirPath).getUsableSpace(), usableSpaceAttributes); - } catch (IOException e) { - observableLongMeasurement.record(0L, usableSpaceAttributes); - } - }), - OtelUnit.BYTES); - - parentContext.observableLongGauge( - "solr_core_index_size", - "Index size for a Solr core", - (observableLongMeasurement -> { - if (!isClosed()) - observableLongMeasurement.record(getIndexSize(), baseGaugeCoreAttributes); - }), - OtelUnit.BYTES); - - parentContext.observableLongGauge( - "solr_core_segment_count", - "Number of segments in a Solr core", - (observableLongMeasurement -> { - if (isReady()) - observableLongMeasurement.record(getSegmentCount(), baseGaugeCoreAttributes); - })); + observables.add( + parentContext.observableLongGauge( + "solr_core_ref_count", + "The current number of active references to a Solr core", + (observableLongMeasurement -> { + observableLongMeasurement.record(getOpenCount(), baseGaugeCoreAttributes); + }))); + + observables.add( + parentContext.observableLongGauge( + "solr_core_disk_space", + "Solr core disk space metrics", + (observableLongMeasurement -> { + + // initialize disk total / free metrics + Path dataDirPath = Path.of(dataDir); + var totalSpaceAttributes = + Attributes.builder() + .putAll(baseGaugeCoreAttributes) + .put(TYPE_ATTR, "total_space") + .build(); + var usableSpaceAttributes = + Attributes.builder() + .putAll(baseGaugeCoreAttributes) + .put(TYPE_ATTR, "usable_space") + .build(); + try { + observableLongMeasurement.record( + Files.getFileStore(dataDirPath).getTotalSpace(), totalSpaceAttributes); + } catch (IOException e) { + observableLongMeasurement.record(0L, totalSpaceAttributes); + } + try { + observableLongMeasurement.record( + Files.getFileStore(dataDirPath).getUsableSpace(), usableSpaceAttributes); + } catch (IOException e) { + observableLongMeasurement.record(0L, usableSpaceAttributes); + } + }), + OtelUnit.BYTES)); + + observables.add( + parentContext.observableLongGauge( + "solr_core_index_size", + "Index size for a Solr core", + (observableLongMeasurement -> { + if (!isClosed()) + observableLongMeasurement.record(getIndexSize(), baseGaugeCoreAttributes); + }), + OtelUnit.BYTES)); + + observables.add( + parentContext.observableLongGauge( + "solr_core_segment_count", + "Number of segments in a Solr core", + (observableLongMeasurement -> { + if (isReady()) + observableLongMeasurement.record(getSegmentCount(), baseGaugeCoreAttributes); + }))); // NOCOMMIT: Do we need these start_time metrics? I think at minimum it should be optional // otherwise we fall into metric bloat for something people may not care about. - parentContext.observableLongGauge( - "solr_core_start_time", - "Start time of a Solr core", - (observableLongMeasurement -> { - observableLongMeasurement.record( - startTime.getTime(), - Attributes.builder() - .putAll(baseGaugeCoreAttributes) - .put(TYPE_ATTR, "start_time") - .build()); - })); + observables.add( + parentContext.observableLongGauge( + "solr_core_start_time", + "Start time of a Solr core", + (observableLongMeasurement -> { + observableLongMeasurement.record( + startTime.getTime(), + Attributes.builder() + .putAll(baseGaugeCoreAttributes) + .put(TYPE_ATTR, "start_time") + .build()); + }))); if (coreContainer.isZooKeeperAware()) - parentContext.observableLongGauge( - "solr_core_is_leader", - "Indicates whether this Solr core is currently the leader", - (observableLongMeasurement -> { - observableLongMeasurement.record( - (coreDescriptor.getCloudDescriptor().isLeader()) ? 1 : 0, baseGaugeCoreAttributes); - })); + observables.add( + parentContext.observableLongGauge( + "solr_core_is_leader", + "Indicates whether this Solr core is currently the leader", + (observableLongMeasurement -> { + observableLongMeasurement.record( + (coreDescriptor.getCloudDescriptor().isLeader()) ? 1 : 0, + baseGaugeCoreAttributes); + }))); + + this.toClose = Collections.unmodifiableList(observables); // NOCOMMIT: Temporary to see metrics newSearcherCounter.inc(); @@ -1804,6 +1813,7 @@ public class SolrCore implements SolrInfoBean, Closeable { assert false : "Too many closes on SolrCore"; } else if (count == 0) { doClose(); + IOUtils.closeQuietly(toClose); } } finally { MDCLoggingContext.clear(); // balance out from SolrCore open with close diff --git a/solr/core/src/java/org/apache/solr/core/ZkContainer.java b/solr/core/src/java/org/apache/solr/core/ZkContainer.java index 1de6b0e45fd..a3540593204 100644 --- a/solr/core/src/java/org/apache/solr/core/ZkContainer.java +++ b/solr/core/src/java/org/apache/solr/core/ZkContainer.java @@ -23,6 +23,9 @@ import io.opentelemetry.api.common.Attributes; import java.io.IOException; import java.lang.invoke.MethodHandles; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeoutException; import java.util.function.Predicate; @@ -35,6 +38,7 @@ import org.apache.solr.common.cloud.Replica; import org.apache.solr.common.cloud.ZkStateReader; import org.apache.solr.common.cloud.ZooKeeperException; import org.apache.solr.common.util.ExecutorUtil; +import org.apache.solr.common.util.IOUtils; import org.apache.solr.common.util.SolrNamedThreadFactory; import org.apache.solr.common.util.StrUtils; import org.apache.solr.logging.MDCLoggingContext; @@ -68,6 +72,8 @@ public class ZkContainer { private SolrMetricProducer metricProducer; + private List<AutoCloseable> toClose; + public ZkContainer() {} public void initZooKeeper(final CoreContainer cc, CloudConfig config) { @@ -149,74 +155,83 @@ public class ZkContainer { @Override public void initializeMetrics( SolrMetricsContext parentContext, Attributes attributes, String scope) { + final List<AutoCloseable> observables = new ArrayList<>(); ctx = parentContext.getChildContext(this); var metricsListener = zkController.getZkClient().getMetrics(); - ctx.observableLongCounter( - "solr_zk_ops", - "Total number of ZooKeeper operations", - measurement -> { - measurement.record( - metricsListener.getReads(), - attributes.toBuilder().put(OPERATION_ATTR, "read").build()); - measurement.record( - metricsListener.getDeletes(), - attributes.toBuilder().put(OPERATION_ATTR, "delete").build()); - measurement.record( - metricsListener.getWrites(), - attributes.toBuilder().put(OPERATION_ATTR, "write").build()); - measurement.record( - metricsListener.getMultiOps(), - attributes.toBuilder().put(OPERATION_ATTR, "multi").build()); - measurement.record( - metricsListener.getExistsChecks(), - attributes.toBuilder().put(OPERATION_ATTR, "exists").build()); - }); - - ctx.observableLongCounter( - "solr_zk_read", - "Total bytes read from ZooKeeper", - measurement -> { - measurement.record(metricsListener.getBytesRead(), attributes); - }, - OtelUnit.BYTES); - - ctx.observableLongCounter( - "solr_zk_watches_fired", - "Total number of ZooKeeper watches fired", - measurement -> { - measurement.record(metricsListener.getWatchesFired(), attributes); - }); - - ctx.observableLongCounter( - "solr_zk_written", - "Total bytes written to ZooKeeper", - measurement -> { - measurement.record(metricsListener.getBytesWritten()); - }, - OtelUnit.BYTES); - - ctx.observableLongCounter( - "solr_zk_cumulative_multi_ops_total", - "Total cumulative multi-operations count", - measurement -> { - measurement.record(metricsListener.getCumulativeMultiOps()); - }); - - ctx.observableLongCounter( - "solr_zk_child_fetches", - "Total number of ZooKeeper child node fetches", - measurement -> { - measurement.record(metricsListener.getChildFetches()); - }); - - ctx.observableLongCounter( - "solr_zk_cumulative_children_fetched", - "Total cumulative children fetched count", - measurement -> { - measurement.record(metricsListener.getCumulativeChildrenFetched()); - }); + observables.add( + ctx.observableLongCounter( + "solr_zk_ops", + "Total number of ZooKeeper operations", + measurement -> { + measurement.record( + metricsListener.getReads(), + attributes.toBuilder().put(OPERATION_ATTR, "read").build()); + measurement.record( + metricsListener.getDeletes(), + attributes.toBuilder().put(OPERATION_ATTR, "delete").build()); + measurement.record( + metricsListener.getWrites(), + attributes.toBuilder().put(OPERATION_ATTR, "write").build()); + measurement.record( + metricsListener.getMultiOps(), + attributes.toBuilder().put(OPERATION_ATTR, "multi").build()); + measurement.record( + metricsListener.getExistsChecks(), + attributes.toBuilder().put(OPERATION_ATTR, "exists").build()); + })); + + observables.add( + ctx.observableLongCounter( + "solr_zk_read", + "Total bytes read from ZooKeeper", + measurement -> { + measurement.record(metricsListener.getBytesRead(), attributes); + }, + OtelUnit.BYTES)); + + observables.add( + ctx.observableLongCounter( + "solr_zk_watches_fired", + "Total number of ZooKeeper watches fired", + measurement -> { + measurement.record(metricsListener.getWatchesFired(), attributes); + })); + + observables.add( + ctx.observableLongCounter( + "solr_zk_written", + "Total bytes written to ZooKeeper", + measurement -> { + measurement.record(metricsListener.getBytesWritten()); + }, + OtelUnit.BYTES)); + + observables.add( + ctx.observableLongCounter( + "solr_zk_cumulative_multi_ops_total", + "Total cumulative multi-operations count", + measurement -> { + measurement.record(metricsListener.getCumulativeMultiOps()); + })); + + observables.add( + ctx.observableLongCounter( + "solr_zk_child_fetches", + "Total number of ZooKeeper child node fetches", + measurement -> { + measurement.record(metricsListener.getChildFetches()); + })); + + observables.add( + ctx.observableLongCounter( + "solr_zk_cumulative_children_fetched", + "Total cumulative children fetched count", + measurement -> { + measurement.record(metricsListener.getCumulativeChildrenFetched()); + })); + toClose = Collections.unmodifiableList(observables); } @Override @@ -315,6 +330,7 @@ public class ZkContainer { zkServer.stop(); } } + IOUtils.closeQuietly(toClose); } } diff --git a/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java b/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java index 90c8bac2285..098c8170fe4 100644 --- a/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java +++ b/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java @@ -18,12 +18,11 @@ package org.apache.solr.update; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.metrics.ObservableLongCounter; -import io.opentelemetry.api.metrics.ObservableLongGauge; import java.io.IOException; import java.lang.invoke.MethodHandles; import java.lang.reflect.Array; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -50,6 +49,7 @@ import org.apache.solr.cloud.ZkController; import org.apache.solr.common.SolrException; import org.apache.solr.common.cloud.Replica; import org.apache.solr.common.params.ModifiableSolrParams; +import org.apache.solr.common.util.IOUtils; import org.apache.solr.common.util.NamedList; import org.apache.solr.core.SolrConfig.UpdateHandlerInfo; import org.apache.solr.core.SolrCore; @@ -120,9 +120,7 @@ public class DirectUpdateHandler2 extends UpdateHandler AttributedLongCounter rollbackCommands; AttributedLongCounter splitCommands; - ObservableLongGauge commitStats; - ObservableLongGauge updateStats; - ObservableLongCounter softAutoCommits; + List<AutoCloseable> toClose; // tracks when auto-commit should occur protected final CommitTracker commitTracker; @@ -239,6 +237,7 @@ public class DirectUpdateHandler2 extends UpdateHandler } else { this.solrMetricsContext = parentContext.getChildContext(this); } + final List<AutoCloseable> observables = new ArrayList<>(); var baseAttributes = attributes.toBuilder() @@ -306,7 +305,7 @@ public class DirectUpdateHandler2 extends UpdateHandler numErrorsCumulative = new AttributedLongCounter(baseErrorsMetric, baseAttributes.toBuilder().build()); - softAutoCommits = + observables.add( solrMetricsContext.observableLongCounter( "solr_core_update_auto_commits", "Current number of auto commits", @@ -317,12 +316,12 @@ public class DirectUpdateHandler2 extends UpdateHandler observableLongMeasurement.record( softCommitTracker.getCommitCount(), baseAttributes.toBuilder().put(TYPE_ATTR, "soft_auto_commits").build()); - })); + }))); // NOCOMMIT: This might not need to be an obseravableLongGauge, but a simple long gauge. Seems // like a waste to constantly call this callback to get the latest value if the upper bounds // rarely change. - commitStats = + observables.add( solrMetricsContext.observableLongGauge( "solr_core_update_commit_stats", "Metrics around commits", @@ -352,9 +351,9 @@ public class DirectUpdateHandler2 extends UpdateHandler softCommitTracker.getTimeUpperBound(), baseAttributes.toBuilder().put(TYPE_ATTR, "soft_auto_commit_max_time").build()); } - })); + }))); - updateStats = + observables.add( solrMetricsContext.observableLongGauge( "solr_core_update_docs_pending_commit", "Current number of documents pending commit. Value is reset to 0 on commit.", @@ -362,7 +361,9 @@ public class DirectUpdateHandler2 extends UpdateHandler observableLongMeasurement.record( numDocsPending.longValue(), baseAttributes.toBuilder().put(OPERATION_ATTR, "docs_pending").build()); - }); + })); + + this.toClose = Collections.unmodifiableList(observables); var baseSubmittedOpsMetric = solrMetricsContext.longCounter( @@ -1014,8 +1015,7 @@ public class DirectUpdateHandler2 extends UpdateHandler commitTracker.close(); softCommitTracker.close(); - commitStats.close(); - + IOUtils.closeQuietly(toClose); numDocsPending.reset(); try { super.close(); diff --git a/solr/core/src/java/org/apache/solr/update/UpdateLog.java b/solr/core/src/java/org/apache/solr/update/UpdateLog.java index d392e992f2c..b79331216a8 100644 --- a/solr/core/src/java/org/apache/solr/update/UpdateLog.java +++ b/solr/core/src/java/org/apache/solr/update/UpdateLog.java @@ -268,6 +268,7 @@ public class UpdateLog implements PluginInfoInitialized, SolrMetricProducer { protected AttributedLongCounter applyingBufferedOpsCounter; protected AttributedLongCounter replayOpsCounter; protected AttributedLongCounter copyOverOldUpdatesCounter; + protected List<AutoCloseable> toClose; protected SolrMetricsContext solrMetricsContext; public static class LogPtr { @@ -630,6 +631,7 @@ public class UpdateLog implements PluginInfoInitialized, SolrMetricProducer { @Override public void initializeMetrics( SolrMetricsContext parentContext, Attributes attributes, String scope) { + final List<AutoCloseable> observables = new ArrayList<>(); solrMetricsContext = parentContext.getChildContext(this); // NOCOMMIT: We do not need a scope attribute @@ -640,26 +642,31 @@ public class UpdateLog implements PluginInfoInitialized, SolrMetricProducer { .put(CATEGORY_ATTR, SolrInfoBean.Category.TLOG.toString()) .build(); - solrMetricsContext.observableLongGauge( - "solr_core_update_log_buffered_ops", - "The current number of buffered operations", - (observableLongMeasurement -> - observableLongMeasurement.record(computeBufferedOps(), baseAttributes))); - - solrMetricsContext.observableLongGauge( - "solr_core_update_log_replay_logs_remaining", - "The current number of tlogs remaining to be replayed", - (observableLongMeasurement -> { - observableLongMeasurement.record(logs.size(), baseAttributes); - })); - - solrMetricsContext.observableLongGauge( - "solr_core_update_log_size_remaining", - "The total size in bytes of all tlogs remaining to be replayed", - (observableLongMeasurement -> { - observableLongMeasurement.record(getTotalLogsSize(), baseAttributes); - }), - OtelUnit.BYTES); + observables.add( + solrMetricsContext.observableLongGauge( + "solr_core_update_log_buffered_ops", + "The current number of buffered operations", + (observableLongMeasurement -> + observableLongMeasurement.record(computeBufferedOps(), baseAttributes)))); + + observables.add( + solrMetricsContext.observableLongGauge( + "solr_core_update_log_replay_logs_remaining", + "The current number of tlogs remaining to be replayed", + (observableLongMeasurement -> { + observableLongMeasurement.record(logs.size(), baseAttributes); + }))); + + observables.add( + solrMetricsContext.observableLongGauge( + "solr_core_update_log_size_remaining", + "The total size in bytes of all tlogs remaining to be replayed", + (observableLongMeasurement -> { + observableLongMeasurement.record(getTotalLogsSize(), baseAttributes); + }), + OtelUnit.BYTES)); + + toClose = Collections.unmodifiableList(observables); // NOCOMMIT: Do we want to keep this? Metric was just state with the numeric enum value. // Without context this doesn't mean anything and can be very confusing. Maybe keep the numeric @@ -1703,6 +1710,8 @@ public class UpdateLog implements PluginInfoInitialized, SolrMetricProducer { } } catch (IOException e) { log.warn("exception releasing tlog dir", e); + } finally { + IOUtils.closeQuietly(toClose); } } diff --git a/solr/core/src/test/org/apache/solr/BasicFunctionalityTest.java b/solr/core/src/test/org/apache/solr/BasicFunctionalityTest.java index a2d31f6ef82..91cbf47f008 100644 --- a/solr/core/src/test/org/apache/solr/BasicFunctionalityTest.java +++ b/solr/core/src/test/org/apache/solr/BasicFunctionalityTest.java @@ -117,23 +117,21 @@ public class BasicFunctionalityTest extends SolrTestCaseJ4 { @Test public void testSomeStuff() { - clearIndex(); - - SolrCore core = h.getCore(); - - // test that we got the expected config, not just hardcoded defaults - assertNotNull(core.getRequestHandler("/mock")); - - // test stats call - var refCount = - SolrMetricTestUtils.getGaugeDatapoint( - core, - "solr_core_ref_count", - SolrMetricTestUtils.newStandaloneLabelsBuilder(core).label("category", "CORE").build()); - assertNotNull(refCount); - - assertTrue(refCount.getValue() > 0); - + try (SolrCore core = h.getCoreContainer().getCore("collection1")) { + // test that we got the expected config, not just hardcoded defaults + assertNotNull(core.getRequestHandler("/mock")); + + // test stats call + var refCount = + SolrMetricTestUtils.getGaugeDatapoint( + core, + "solr_core_ref_count", + SolrMetricTestUtils.newStandaloneLabelsBuilder(core) + .label("category", "CORE") + .build()); + assertNotNull(refCount); + assertTrue(refCount.getValue() > 0); + } assertQ( "test query on empty index", req("qlkciyopsbgzyvkylsjhchghjrdf"), diff --git a/solr/core/src/test/org/apache/solr/core/SolrCoreTest.java b/solr/core/src/test/org/apache/solr/core/SolrCoreTest.java index 5fe145de556..5af9bfe0436 100644 --- a/solr/core/src/test/org/apache/solr/core/SolrCoreTest.java +++ b/solr/core/src/test/org/apache/solr/core/SolrCoreTest.java @@ -16,6 +16,9 @@ */ package org.apache.solr.core; +import io.opentelemetry.exporter.prometheus.PrometheusMetricReader; +import io.prometheus.metrics.model.snapshots.GaugeSnapshot; +import io.prometheus.metrics.model.snapshots.MetricSnapshots; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -33,8 +36,6 @@ import org.apache.solr.handler.ReplicationHandler; import org.apache.solr.handler.RequestHandlerBase; import org.apache.solr.handler.component.QueryComponent; import org.apache.solr.handler.component.SpellCheckComponent; -import org.apache.solr.metrics.SolrMetricManager; -import org.apache.solr.metrics.SolrMetricTestUtils; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.SolrRequestHandler; import org.apache.solr.response.SolrQueryResponse; @@ -340,7 +341,6 @@ public class SolrCoreTest extends SolrTestCaseJ4 { */ @Test public void testCoreInitDeadlockMetrics() throws Exception { - SolrMetricManager metricManager = h.getCoreContainer().getMetricManager(); CoreContainer coreContainer = h.getCoreContainer(); String coreName = "tmpCore"; @@ -353,16 +353,24 @@ public class SolrCoreTest extends SolrTestCaseJ4 { executor.execute( () -> { while (!created.get()) { - var datapoint = - SolrMetricTestUtils.getGaugeDatapoint( - h.getCore(), - "solr_core_index_size_bytes", - SolrMetricTestUtils.newStandaloneLabelsBuilder(h.getCore()) - .label("category", "CORE") - .build()); - - if (datapoint != null && datapoint.getValue() >= 0) { - atLeastOnePoll.set(true); + try { + PrometheusMetricReader reader = + coreContainer + .getMetricManager() + .getPrometheusMetricReader("solr.core." + coreName); + if (reader != null) { + MetricSnapshots snapshots = reader.collect(); + for (var snapshot : snapshots) { + if (snapshot instanceof GaugeSnapshot gaugeSnapshot) { + var dataPoints = gaugeSnapshot.getDataPoints(); + if (!dataPoints.isEmpty()) { + atLeastOnePoll.compareAndSet(false, true); + } + } + } + } + } catch (Exception ignore) { + // Ignore in case the core may not be fully initialized } try { diff --git a/solr/core/src/test/org/apache/solr/update/SolrIndexMetricsTest.java b/solr/core/src/test/org/apache/solr/update/SolrIndexMetricsTest.java index 4644c851d97..09aa0489949 100644 --- a/solr/core/src/test/org/apache/solr/update/SolrIndexMetricsTest.java +++ b/solr/core/src/test/org/apache/solr/update/SolrIndexMetricsTest.java @@ -23,6 +23,7 @@ import com.codahale.metrics.Timer; import java.util.Map; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.common.SolrInputDocument; +import org.apache.solr.core.SolrCore; import org.apache.solr.metrics.SolrMetricTestUtils; import org.apache.solr.request.SolrQueryRequest; import org.junit.After; @@ -89,30 +90,25 @@ public class SolrIndexMetricsTest extends SolrTestCaseJ4 { System.setProperty("solr.tests.metrics.merge", "false"); System.setProperty("solr.tests.metrics.mergeDetails", "false"); initCore("solrconfig-indexmetrics.xml", "schema.xml"); - addDocs(); - - MetricRegistry registry = - h.getCoreContainer() - .getMetricManager() - .registry(h.getCore().getCoreMetricManager().getRegistryName()); - assertNotNull(registry); - var indexSize = - SolrMetricTestUtils.getGaugeDatapoint( - h.getCore(), - "solr_core_index_size_bytes", - SolrMetricTestUtils.newStandaloneLabelsBuilder(h.getCore()) - .label("category", "CORE") - .build()); - var segmentSize = - SolrMetricTestUtils.getGaugeDatapoint( - h.getCore(), - "solr_core_segment_count", - SolrMetricTestUtils.newStandaloneLabelsBuilder(h.getCore()) - .label("category", "CORE") - .build()); - assertNotNull(indexSize); - assertNotNull(segmentSize); + try (SolrCore core = h.getCoreContainer().getCore("collection1")) { + var indexSize = + SolrMetricTestUtils.getGaugeDatapoint( + core, + "solr_core_index_size_bytes", + SolrMetricTestUtils.newStandaloneLabelsBuilder(core) + .label("category", "CORE") + .build()); + var segmentSize = + SolrMetricTestUtils.getGaugeDatapoint( + core, + "solr_core_segment_count", + SolrMetricTestUtils.newStandaloneLabelsBuilder(core) + .label("category", "CORE") + .build()); + assertNotNull(indexSize); + assertNotNull(segmentSize); + } } @Test diff --git a/solr/solrj/src/java/org/apache/solr/common/util/IOUtils.java b/solr/solrj/src/java/org/apache/solr/common/util/IOUtils.java index b91553a1813..93a2c5eb22e 100644 --- a/solr/solrj/src/java/org/apache/solr/common/util/IOUtils.java +++ b/solr/solrj/src/java/org/apache/solr/common/util/IOUtils.java @@ -23,6 +23,11 @@ import org.slf4j.LoggerFactory; public class IOUtils { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + public static void closeQuietly(Iterable<? extends AutoCloseable> closeables) { + if (closeables == null) return; + for (AutoCloseable closeable : closeables) closeQuietly(closeable); + } + public static void closeQuietly(AutoCloseable closeable) { try { if (closeable != null) {
