From 83bc2b1fde4b800cfdfa798220fdf040b25e3b54 Mon Sep 17 00:00:00 2001 From: "baranov.e.g" Date: Fri, 30 Oct 2026 11:38:30 +0300 Subject: [PATCH 1/5] IGNITE-29229 Add AssertionErrorCount monitoring metric to detect AssertionError occurrences in the JVM --- .../_docs/monitoring-metrics/new-metrics.adoc | 1 + .../processors/metric/GridMetricManager.java | 43 +++++++++++++++++++ .../testsuites/IgniteKernalSelfTestSuite.java | 2 + 3 files changed, 46 insertions(+) diff --git a/docs/_docs/monitoring-metrics/new-metrics.adoc b/docs/_docs/monitoring-metrics/new-metrics.adoc index 7482933ed43fd..be2052495c2d0 100644 --- a/docs/_docs/monitoring-metrics/new-metrics.adoc +++ b/docs/_docs/monitoring-metrics/new-metrics.adoc @@ -25,6 +25,7 @@ Register name: `sys` [cols="2,1,3",opts="header"] |=== |Name | Type | Description +|AssertionErrorCount | long | Number of AssertionErrors thrown in this JVM. |CpuLoad | double | CPU load. |CurrentThreadCpuTime | long | CPU time of the thread that reads the metric, in nanoseconds. |CurrentThreadUserTime | long | User-mode CPU time of the thread that reads the metric, in nanoseconds. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/GridMetricManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/GridMetricManager.java index c116f17a70f43..1229913431f4d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/GridMetricManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/GridMetricManager.java @@ -32,6 +32,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Consumer; import java.util.function.Supplier; +import jdk.jfr.consumer.RecordingStream; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteException; import org.apache.ignite.internal.GridKernalContext; @@ -45,6 +46,7 @@ import org.apache.ignite.internal.processors.metric.impl.AtomicLongMetric; import org.apache.ignite.internal.processors.metric.impl.DoubleMetricImpl; import org.apache.ignite.internal.processors.metric.impl.HitRateMetric; +import org.apache.ignite.internal.processors.metric.impl.LongAdderMetric; import org.apache.ignite.internal.processors.metric.impl.MaxValueMetric; import org.apache.ignite.internal.processors.metric.impl.MetricUtils; import org.apache.ignite.internal.processors.timeout.GridTimeoutProcessor; @@ -142,6 +144,9 @@ public class GridMetricManager extends GridManagerAdapter imp /** Custom metrics registry name. */ public static final String CUSTOM_METRICS = "custom"; + /** Metric name for the count of AssertionErrors thrown in the JVM. */ + public static final String ASSERTION_ERROR_CNT = "AssertionErrorCount"; + /** JVM interface to memory consumption info */ private static final MemoryMXBean mem = ManagementFactory.getMemoryMXBean(); @@ -202,6 +207,12 @@ public class GridMetricManager extends GridManagerAdapter imp /** */ private final IgniteMetrics customMetrics; + /** AssertionError counter. */ + private final LongAdderMetric assertionErrorCnt; + + /** JFR stream for capturing thrown Errors. */ + private volatile RecordingStream jfrStream; + /** * @param ctx Kernal context. */ @@ -247,6 +258,8 @@ public GridMetricManager(GridKernalContext ctx) { "CPU time of the thread that reads the metric, in nanoseconds."); sysreg.register("CurrentThreadUserTime", threads::getCurrentThreadUserTime, "User-mode CPU time of the thread that reads the metric, in nanoseconds."); + assertionErrorCnt = sysreg.longAdderMetric(ASSERTION_ERROR_CNT, + "Number of AssertionErrors thrown in this JVM."); MetricRegistryImpl pmeReg = registry(PME_METRICS); @@ -273,6 +286,8 @@ public GridMetricManager(GridKernalContext ctx) { startSpi(); + startJfrErrorStream(); + // In case standalone kernal start. if (ctx.internalSubscriptionProcessor() == null) return; @@ -323,6 +338,34 @@ public GridMetricManager(GridKernalContext ctx) { // Stop discovery worker and metrics updater. U.closeQuiet(metricsUpdateTask); + U.closeQuiet(jfrStream); + jfrStream = null; + } + + /** + * Starts a JFR RecordingStream to capture thrown Error events and increment the + * {@link #assertionErrorCnt} metric when an AssertionError is detected. + */ + private void startJfrErrorStream() { + try { + RecordingStream stream = new RecordingStream(); + stream.enable("jdk.JavaErrorThrow"); + stream.onEvent("jdk.JavaErrorThrow", event -> { + try { + jdk.jfr.consumer.RecordedClass cls = event.getClass("thrownClass"); + if (cls != null && "java.lang.AssertionError".equals(cls.getName())) + assertionErrorCnt.increment(); + } + catch (RuntimeException ignored) { + // Ignore — must not disrupt the JFR consumer thread. + } + }); + stream.startAsync(); + jfrStream = stream; + } + catch (RuntimeException cause) { + U.warn(log, "Failed to start JFR error stream: ", cause); + } } /** diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java index dd6dd06042cb6..fb07331ea60a7 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java @@ -20,6 +20,7 @@ import org.apache.ignite.cache.NodeWithFilterRestartTest; import org.apache.ignite.internal.ClusterMetricsSelfTest; import org.apache.ignite.internal.GridCommunicationSelfTest; +import org.apache.ignite.internal.processors.metric.GridMetricManagerAssertionMetricTest; import org.apache.ignite.internal.GridDiscoveryEventSelfTest; import org.apache.ignite.internal.GridDiscoverySelfTest; import org.apache.ignite.internal.GridFailedInputParametersSelfTest; @@ -113,6 +114,7 @@ IgniteConnectionConcurrentReserveAndRemoveTest.class, LongJVMPauseDetectorTest.class, ClusterMetricsSelfTest.class, + GridMetricManagerAssertionMetricTest.class, DeploymentRequestOfUnknownClassProcessingTest.class, ThreadNameValidationTest.class, NodeWithFilterRestartTest.class, From c2a214a151f7d3a83d6961439e775c334dd0b1bc Mon Sep 17 00:00:00 2001 From: "baranov.e.g" Date: Fri, 30 Oct 2026 11:45:11 +0300 Subject: [PATCH 2/5] IGNITE-29229 Add AssertionErrorCount monitoring metric to detect AssertionError occurrences in the JVM --- .../ignite/internal/processors/metric/GridMetricManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/GridMetricManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/GridMetricManager.java index 1229913431f4d..d542ffeacc3c1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/GridMetricManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/GridMetricManager.java @@ -32,6 +32,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Consumer; import java.util.function.Supplier; +import jdk.jfr.consumer.RecordedClass; import jdk.jfr.consumer.RecordingStream; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteException; @@ -352,7 +353,7 @@ private void startJfrErrorStream() { stream.enable("jdk.JavaErrorThrow"); stream.onEvent("jdk.JavaErrorThrow", event -> { try { - jdk.jfr.consumer.RecordedClass cls = event.getClass("thrownClass"); + RecordedClass cls = event.getClass("thrownClass"); if (cls != null && "java.lang.AssertionError".equals(cls.getName())) assertionErrorCnt.increment(); } From d788edd0219fff33b07adb24179ecf5d9b8211a5 Mon Sep 17 00:00:00 2001 From: "baranov.e.g" Date: Fri, 30 Oct 2026 13:37:06 +0300 Subject: [PATCH 3/5] IGNITE-29229 Add test for AssertionErrorCount metric Co-authored-by: GigaCode Assistant --- .../GridMetricManagerAssertionMetricTest.java | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/metric/GridMetricManagerAssertionMetricTest.java diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/metric/GridMetricManagerAssertionMetricTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/metric/GridMetricManagerAssertionMetricTest.java new file mode 100644 index 0000000000000..759859d64f321 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/metric/GridMetricManagerAssertionMetricTest.java @@ -0,0 +1,98 @@ +/* + * 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.ignite.internal.processors.metric; + +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.metric.MetricRegistry; +import org.apache.ignite.spi.metric.LongMetric; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.junit.Test; + +import static org.apache.ignite.internal.processors.metric.GridMetricManager.ASSERTION_ERROR_CNT; +import static org.apache.ignite.internal.processors.metric.GridMetricManager.SYS_METRICS; +import static org.apache.ignite.testframework.GridTestUtils.waitForCondition; + +/** + * Tests the ASSERTION_ERROR_CNT metric in the sys metrics registry. + */ +public class GridMetricManagerAssertionMetricTest extends GridCommonAbstractTest { + + /** + * Verifies that the ASSERTION_ERROR_CNT counter increments + * when an AssertionError is thrown. + * + * @throws Exception If fails. + */ + @Test + public void testAssertionErrorMetric() throws Exception { + try { + IgniteEx grid = startGrid(0); + + MetricRegistry sysReg = grid.context().metric().registry(SYS_METRICS); + + assertNotNull(sysReg); + + LongMetric ctr = sysReg.findMetric(ASSERTION_ERROR_CNT); + + assertNotNull("Metric " + ASSERTION_ERROR_CNT + " not found", ctr); + + long initial = ctr.value(); + + // Throw an AssertionError. + try { + throw new AssertionError("test assertion"); + } + catch (AssertionError e) { + // Expected. + } + + // Metric should increment (JFR events are delivered asynchronously). + assertTrue( + "Metric should increment after AssertionError", + waitForCondition(() -> ctr.value() >= initial + 1, getTestTimeout())); + } + finally { + stopAllGrids(); + } + } + + /** + * Verifies that the ASSERTION_ERROR_CNT metric exposes proper name and description. + * + * @throws Exception If fails. + */ + @Test + public void testMetricMetadata() throws Exception { + try { + IgniteEx grid = startGrid(0); + + MetricRegistry sysReg = grid.context().metric().registry(SYS_METRICS); + + LongMetric ctr = sysReg.findMetric(ASSERTION_ERROR_CNT); + + assertNotNull(ctr); + + assertEquals(SYS_METRICS + "." + ASSERTION_ERROR_CNT, ctr.name()); + + assertEquals("Number of AssertionErrors thrown in this JVM.", ctr.description()); + } + finally { + stopAllGrids(); + } + } +} From 205fe7f9c1e643d685cf2093532713e341d6616f Mon Sep 17 00:00:00 2001 From: "baranov.e.g" Date: Fri, 30 Oct 2026 15:05:52 +0300 Subject: [PATCH 4/5] IGNITE-29229 Add AssertionErrorCount monitoring metric to detect AssertionError occurrences in the JVM --- .../internal/processors/metric/GridMetricManager.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/GridMetricManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/GridMetricManager.java index d542ffeacc3c1..6d2195779f3b8 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/GridMetricManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/GridMetricManager.java @@ -28,6 +28,7 @@ import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Consumer; @@ -354,11 +355,12 @@ private void startJfrErrorStream() { stream.onEvent("jdk.JavaErrorThrow", event -> { try { RecordedClass cls = event.getClass("thrownClass"); - if (cls != null && "java.lang.AssertionError".equals(cls.getName())) + Objects.requireNonNull(cls, "Java error occurs. Unable to get thrown class"); + if ("java.lang.AssertionError".equals(cls.getName())) assertionErrorCnt.increment(); } - catch (RuntimeException ignored) { - // Ignore — must not disrupt the JFR consumer thread. + catch (RuntimeException cause) { + log.warning("Failed to monitor Java error event.", cause); } }); stream.startAsync(); From 81dfc692fbb6c762fc2d3d824c7778da2d0a7f47 Mon Sep 17 00:00:00 2001 From: "baranov.e.g" Date: Fri, 30 Oct 2026 15:35:06 +0300 Subject: [PATCH 5/5] IGNITE-29229 Add AssertionErrorCount monitoring metric to detect AssertionError occurrences in the JVM --- .../metric/GridMetricManagerAssertionMetricTest.java | 4 ++-- .../apache/ignite/testsuites/IgniteKernalSelfTestSuite.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/metric/GridMetricManagerAssertionMetricTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/metric/GridMetricManagerAssertionMetricTest.java index 759859d64f321..93da51c86fbe3 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/metric/GridMetricManagerAssertionMetricTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/metric/GridMetricManagerAssertionMetricTest.java @@ -51,7 +51,7 @@ public void testAssertionErrorMetric() throws Exception { assertNotNull("Metric " + ASSERTION_ERROR_CNT + " not found", ctr); - long initial = ctr.value(); + long init = ctr.value(); // Throw an AssertionError. try { @@ -64,7 +64,7 @@ public void testAssertionErrorMetric() throws Exception { // Metric should increment (JFR events are delivered asynchronously). assertTrue( "Metric should increment after AssertionError", - waitForCondition(() -> ctr.value() >= initial + 1, getTestTimeout())); + waitForCondition(() -> ctr.value() >= init + 1, getTestTimeout())); } finally { stopAllGrids(); diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java index fb07331ea60a7..77d78e4e2e4fb 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java @@ -20,7 +20,6 @@ import org.apache.ignite.cache.NodeWithFilterRestartTest; import org.apache.ignite.internal.ClusterMetricsSelfTest; import org.apache.ignite.internal.GridCommunicationSelfTest; -import org.apache.ignite.internal.processors.metric.GridMetricManagerAssertionMetricTest; import org.apache.ignite.internal.GridDiscoveryEventSelfTest; import org.apache.ignite.internal.GridDiscoverySelfTest; import org.apache.ignite.internal.GridFailedInputParametersSelfTest; @@ -61,6 +60,7 @@ import org.apache.ignite.internal.processors.cluster.ClusterStateChangeOnNodeJoinTest; import org.apache.ignite.internal.processors.cluster.GridAddressResolverSelfTest; import org.apache.ignite.internal.processors.cluster.GridUpdateNotifierSelfTest; +import org.apache.ignite.internal.processors.metric.GridMetricManagerAssertionMetricTest; import org.apache.ignite.internal.processors.port.GridPortProcessorSelfTest; import org.apache.ignite.internal.util.GridMutableLongTest; import org.apache.ignite.internal.util.GridStartupWithUndefinedIgniteHomeSelfTest;