From 2a25f0a32ee5be57a51067b2a1f81512f9123e23 Mon Sep 17 00:00:00 2001 From: Miroslav Gatsanoga Date: Fri, 10 Jan 2025 15:13:35 +0200 Subject: [PATCH 1/2] feat: initial BlockStreamBucketUploaderMetrics implementation Signed-off-by: Miroslav Gatsanoga --- .../BlockStreamBucketUploaderMetrics.java | 61 ++++++++++++++++ .../node/app/info/InfoInjectionModule.java | 8 ++- .../BlockStreamBucketUploaderMetricsTest.java | 72 +++++++++++++++++++ 3 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 hedera-node/hedera-app/src/main/java/com/hedera/node/app/blocks/BlockStreamBucketUploaderMetrics.java create mode 100644 hedera-node/hedera-app/src/test/java/com/hedera/node/app/blocks/BlockStreamBucketUploaderMetricsTest.java diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/blocks/BlockStreamBucketUploaderMetrics.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/blocks/BlockStreamBucketUploaderMetrics.java new file mode 100644 index 000000000000..d6c70cf068e8 --- /dev/null +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/blocks/BlockStreamBucketUploaderMetrics.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2024-2025 Hedera Hashgraph, LLC + * + * Licensed 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 com.hedera.node.app.blocks; + +import com.hedera.node.app.annotations.NodeSelfId; +import com.swirlds.metrics.api.LongGauge; +import com.swirlds.metrics.api.Metrics; +import edu.umd.cs.findbugs.annotations.NonNull; +import javax.inject.Inject; +import javax.inject.Singleton; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +@Singleton +public class BlockStreamBucketUploaderMetrics { + private static final Logger log = LogManager.getLogger(BlockStreamBucketUploaderMetrics.class); + public static final String PER_NODE_METRIC_PREFIX = "hedera.blocks.bucket.%s"; + public static final String PER_PROVIDER_PER_NODE_METRIC_PREFIX = "hedera.blocks.bucket.%s.%s"; + private final LongGauge blocksRetained; + private static final String BLOCKS_RETAINED = "blocks.retained"; + private static final String BLOCKS_RETAINED_DESC = "Current number of blocks retained on disk for the node"; + + /** + * Constructor for the BlockStreamBucketMetrics. + * + * @param metrics the {@link Metrics} object where all metrics will be registered + */ + @Inject + public BlockStreamBucketUploaderMetrics(@NonNull final Metrics metrics, @NodeSelfId final long selfNodeId) { + blocksRetained = metrics.getOrCreate( + new LongGauge.Config(String.format(PER_NODE_METRIC_PREFIX, selfNodeId), BLOCKS_RETAINED) + .withDescription(BLOCKS_RETAINED_DESC)); + } + + /** + * Current number of blocks retained on disk. + * + * @param blocksRetainedCount current number of blocks retained on disk + */ + public void updateBlocksRetainedCount(final long blocksRetainedCount) { + if (blocksRetainedCount < 0) { + log.warn("Received number of retained blocks: {}", blocksRetainedCount); + } else { + blocksRetained.set(blocksRetainedCount); + } + } +} diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/info/InfoInjectionModule.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/info/InfoInjectionModule.java index b7b3853bf806..6cf23228ce74 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/info/InfoInjectionModule.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/info/InfoInjectionModule.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023-2024 Hedera Hashgraph, LLC + * Copyright (C) 2023-2025 Hedera Hashgraph, LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,4 +31,10 @@ public abstract class InfoInjectionModule { static AccountID selfAccountID(@NonNull final NodeInfo info) { return info.accountId(); } + + @Provides + @NodeSelfId + static long selfNodeId(@NonNull final NodeInfo info) { + return info.nodeId(); + } } diff --git a/hedera-node/hedera-app/src/test/java/com/hedera/node/app/blocks/BlockStreamBucketUploaderMetricsTest.java b/hedera-node/hedera-app/src/test/java/com/hedera/node/app/blocks/BlockStreamBucketUploaderMetricsTest.java new file mode 100644 index 000000000000..d1fc4ad3f6b6 --- /dev/null +++ b/hedera-node/hedera-app/src/test/java/com/hedera/node/app/blocks/BlockStreamBucketUploaderMetricsTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2025 Hedera Hashgraph, LLC + * + * Licensed 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 com.hedera.node.app.blocks; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.hedera.node.app.spi.fixtures.util.LogCaptor; +import com.hedera.node.app.spi.fixtures.util.LogCaptureExtension; +import com.hedera.node.app.spi.fixtures.util.LoggingSubject; +import com.hedera.node.app.spi.fixtures.util.LoggingTarget; +import com.swirlds.metrics.api.LongGauge; +import com.swirlds.metrics.api.Metrics; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith({MockitoExtension.class, LogCaptureExtension.class}) +class BlockStreamBucketUploaderMetricsTest { + @Mock + private Metrics metrics; + + @Mock + private LongGauge longGauge; + + @LoggingSubject + private BlockStreamBucketUploaderMetrics blockStreamBucketUploaderMetrics; + + @LoggingTarget + private LogCaptor logCaptor; + + @BeforeEach + void setUp() { + when(metrics.getOrCreate(any(LongGauge.Config.class))).thenReturn(longGauge); + long selfNodeId = 1L; + blockStreamBucketUploaderMetrics = new BlockStreamBucketUploaderMetrics(metrics, selfNodeId); + } + + @Test + void testUpdateBlocksRetainedCount() { + blockStreamBucketUploaderMetrics.updateBlocksRetainedCount(10L); + verify(longGauge).set(10L); + } + + @Test + void testUpdateBlocksRetainedCountWithNegativeValue() { + blockStreamBucketUploaderMetrics.updateBlocksRetainedCount(-1L); + + assertThat(logCaptor.warnLogs()).contains("Received number of retained blocks: -1"); + verify(longGauge, never()).set(anyLong()); + } +} From 3cdeadbf9daabd8af8b5f581a786cadba25235ef Mon Sep 17 00:00:00 2001 From: Miroslav Gatsanoga Date: Fri, 10 Jan 2025 16:09:10 +0200 Subject: [PATCH 2/2] feat: add gauges for blocks count in uploaded and hashmismatch directories Signed-off-by: Miroslav Gatsanoga --- .../BlockStreamBucketUploaderMetrics.java | 48 +++++++++++++++++-- .../BlockStreamBucketUploaderMetricsTest.java | 28 +++++++++++ 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/blocks/BlockStreamBucketUploaderMetrics.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/blocks/BlockStreamBucketUploaderMetrics.java index d6c70cf068e8..d60c71ff2f2a 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/blocks/BlockStreamBucketUploaderMetrics.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/blocks/BlockStreamBucketUploaderMetrics.java @@ -30,9 +30,19 @@ public class BlockStreamBucketUploaderMetrics { private static final Logger log = LogManager.getLogger(BlockStreamBucketUploaderMetrics.class); public static final String PER_NODE_METRIC_PREFIX = "hedera.blocks.bucket.%s"; public static final String PER_PROVIDER_PER_NODE_METRIC_PREFIX = "hedera.blocks.bucket.%s.%s"; - private final LongGauge blocksRetained; private static final String BLOCKS_RETAINED = "blocks.retained"; - private static final String BLOCKS_RETAINED_DESC = "Current number of blocks retained on disk for the node"; + private static final String BLOCKS_RETAINED_DESC = + "Current number of blocks retained in root block file directory on disk for the node"; + private static final String BLOCKS_UPLOADED = "blocks.uploaded"; + private static final String BLOCKS_UPLOADED_DESC = + "Current number of blocks in uploaded directory on disk for the node"; + private static final String BLOCKS_HASH_MISMATCH = "blocks.hashmismatch"; + private static final String BLOCKS_HASH_MISMATCH_DESC = + "Current number of blocks in hashmismatch directory on disk for the node"; + + private final LongGauge blocksRetained; + private final LongGauge blocksUploaded; + private final LongGauge blocksHashMismatch; /** * Constructor for the BlockStreamBucketMetrics. @@ -44,10 +54,16 @@ public BlockStreamBucketUploaderMetrics(@NonNull final Metrics metrics, @NodeSel blocksRetained = metrics.getOrCreate( new LongGauge.Config(String.format(PER_NODE_METRIC_PREFIX, selfNodeId), BLOCKS_RETAINED) .withDescription(BLOCKS_RETAINED_DESC)); + blocksUploaded = metrics.getOrCreate( + new LongGauge.Config(String.format(PER_NODE_METRIC_PREFIX, selfNodeId), BLOCKS_UPLOADED) + .withDescription(BLOCKS_UPLOADED_DESC)); + blocksHashMismatch = metrics.getOrCreate( + new LongGauge.Config(String.format(PER_NODE_METRIC_PREFIX, selfNodeId), BLOCKS_HASH_MISMATCH) + .withDescription(BLOCKS_HASH_MISMATCH_DESC)); } /** - * Current number of blocks retained on disk. + * Update the metric for the current number of blocks retained in root block file directory. * * @param blocksRetainedCount current number of blocks retained on disk */ @@ -58,4 +74,30 @@ public void updateBlocksRetainedCount(final long blocksRetainedCount) { blocksRetained.set(blocksRetainedCount); } } + + /** + * Update the metric for the current number of blocks in uploaded directory. + * + * @param blocksUploadedCount current number of uploaded blocks on disk + */ + public void updateBlocksUploadedCount(final long blocksUploadedCount) { + if (blocksUploadedCount < 0) { + log.warn("Received number of uploaded blocks: {}", blocksUploadedCount); + } else { + blocksUploaded.set(blocksUploadedCount); + } + } + + /** + * Update the metric for the current number of blocks in hashmismatch directory. + * + * @param blocksHashMismatchCount current number of blocks with hash mismatch on disk + */ + public void updateBlocksHashMismatchCount(final long blocksHashMismatchCount) { + if (blocksHashMismatchCount < 0) { + log.warn("Received number of hash mismatched blocks: {}", blocksHashMismatchCount); + } else { + blocksHashMismatch.set(blocksHashMismatchCount); + } + } } diff --git a/hedera-node/hedera-app/src/test/java/com/hedera/node/app/blocks/BlockStreamBucketUploaderMetricsTest.java b/hedera-node/hedera-app/src/test/java/com/hedera/node/app/blocks/BlockStreamBucketUploaderMetricsTest.java index d1fc4ad3f6b6..43492e20ca6a 100644 --- a/hedera-node/hedera-app/src/test/java/com/hedera/node/app/blocks/BlockStreamBucketUploaderMetricsTest.java +++ b/hedera-node/hedera-app/src/test/java/com/hedera/node/app/blocks/BlockStreamBucketUploaderMetricsTest.java @@ -69,4 +69,32 @@ void testUpdateBlocksRetainedCountWithNegativeValue() { assertThat(logCaptor.warnLogs()).contains("Received number of retained blocks: -1"); verify(longGauge, never()).set(anyLong()); } + + @Test + void testUpdateBlocksUploadedCount() { + blockStreamBucketUploaderMetrics.updateBlocksUploadedCount(10L); + verify(longGauge).set(10L); + } + + @Test + void testUpdateBlocksUploadedCountWithNegativeValue() { + blockStreamBucketUploaderMetrics.updateBlocksUploadedCount(-1L); + + assertThat(logCaptor.warnLogs()).contains("Received number of uploaded blocks: -1"); + verify(longGauge, never()).set(anyLong()); + } + + @Test + void testUpdateBlocksHashMismatchCount() { + blockStreamBucketUploaderMetrics.updateBlocksHashMismatchCount(10L); + verify(longGauge).set(10L); + } + + @Test + void testUpdateBlockHashMismatchCountWithNegativeValue() { + blockStreamBucketUploaderMetrics.updateBlocksHashMismatchCount(-1L); + + assertThat(logCaptor.warnLogs()).contains("Received number of hash mismatched blocks: -1"); + verify(longGauge, never()).set(anyLong()); + } }