diff --git a/changelog/unreleased/pr-24035.toml b/changelog/unreleased/pr-24035.toml new file mode 100644 index 0000000000..fc67c55620 --- /dev/null +++ b/changelog/unreleased/pr-24035.toml @@ -0,0 +1,5 @@ +type = "a" +message = "Create metrics supplier for shards." + +pulls = ["24035"] +issues = ["Graylog2/graylog-plugin-enterprise#12221", "Graylog2/graylog-plugin-enterprise#12223"] diff --git a/graylog2-server/src/main/java/org/graylog2/telemetry/TelemetryModule.java b/graylog2-server/src/main/java/org/graylog2/telemetry/TelemetryModule.java index 7e5da3aab4..387a48c180 100644 --- a/graylog2-server/src/main/java/org/graylog2/telemetry/TelemetryModule.java +++ b/graylog2-server/src/main/java/org/graylog2/telemetry/TelemetryModule.java @@ -21,6 +21,7 @@ import org.graylog2.plugin.PluginModule; import org.graylog2.telemetry.scheduler.TelemetrySubmissionPeriodical; import org.graylog2.telemetry.suppliers.InputsMetricsSupplier; import org.graylog2.telemetry.suppliers.OutputsMetricsSupplier; +import org.graylog2.telemetry.suppliers.ShardsMetricsSupplier; public class TelemetryModule extends PluginModule { @Override @@ -33,5 +34,6 @@ public class TelemetryModule extends PluginModule { addTelemetryMetricProvider("Inputs Metrics", InputsMetricsSupplier.class); addTelemetryMetricProvider("Outputs Metrics", OutputsMetricsSupplier.class); + addTelemetryMetricProvider("Shards Metrics", ShardsMetricsSupplier.class); } } diff --git a/graylog2-server/src/main/java/org/graylog2/telemetry/suppliers/ShardsMetricsSupplier.java b/graylog2-server/src/main/java/org/graylog2/telemetry/suppliers/ShardsMetricsSupplier.java new file mode 100644 index 0000000000..978c5ae49e --- /dev/null +++ b/graylog2-server/src/main/java/org/graylog2/telemetry/suppliers/ShardsMetricsSupplier.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2020 Graylog, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * . + */ +package org.graylog2.telemetry.suppliers; + +import jakarta.inject.Inject; +import org.graylog2.configuration.ElasticsearchConfiguration; +import org.graylog2.indexer.cluster.Cluster; +import org.graylog2.rest.models.system.indexer.responses.ClusterHealth; +import org.graylog2.telemetry.scheduler.TelemetryEvent; +import org.graylog2.telemetry.scheduler.TelemetryMetricSupplier; + +import java.util.Map; +import java.util.Optional; + +public class ShardsMetricsSupplier implements TelemetryMetricSupplier { + private final ElasticsearchConfiguration elasticsearchConfiguration; + private final Cluster cluster; + + @Inject + public ShardsMetricsSupplier(ElasticsearchConfiguration elasticsearchConfiguration, Cluster cluster) { + this.elasticsearchConfiguration = elasticsearchConfiguration; + this.cluster = cluster; + } + + @Override + public Optional get() { + Optional shardStatus = cluster.clusterHealthStats().map(ClusterHealth::shards); + + Map metrics = Map.of( + "shard_min_size", elasticsearchConfiguration.getTimeSizeOptimizingRotationMinShardSize().getQuantity(), + "shard_max_size", elasticsearchConfiguration.getTimeSizeOptimizingRotationMaxShardSize().getQuantity(), + "shards_active", shardStatus.map(ClusterHealth.ShardStatus::active).orElse(0), + "shards_initializing", shardStatus.map(ClusterHealth.ShardStatus::initializing).orElse(0), + "shards_relocating", shardStatus.map(ClusterHealth.ShardStatus::relocating).orElse(0), + "shards_unassigned", shardStatus.map(ClusterHealth.ShardStatus::unassigned).orElse(0) + ); + + return Optional.of(TelemetryEvent.of(metrics)); + } +} diff --git a/graylog2-server/src/test/java/org/graylog2/telemetry/suppliers/ShardsMetricsSupplierTest.java b/graylog2-server/src/test/java/org/graylog2/telemetry/suppliers/ShardsMetricsSupplierTest.java new file mode 100644 index 0000000000..678a8c2ba2 --- /dev/null +++ b/graylog2-server/src/test/java/org/graylog2/telemetry/suppliers/ShardsMetricsSupplierTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2020 Graylog, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * . + */ +package org.graylog2.telemetry.suppliers; + +import com.github.joschi.jadconfig.util.Size; +import org.graylog2.configuration.ElasticsearchConfiguration; +import org.graylog2.indexer.cluster.Cluster; +import org.graylog2.rest.models.system.indexer.responses.ClusterHealth; +import org.graylog2.telemetry.scheduler.TelemetryEvent; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Map; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class ShardsMetricsSupplierTest { + @Mock + private ElasticsearchConfiguration elasticsearchConfiguration; + + @Mock + private Cluster cluster; + + @InjectMocks + private ShardsMetricsSupplier shardsMetricsSupplier; + + @Test + public void shouldReturnShardMetrics() { + Size minSize = Size.gigabytes(29L); + Size maxSize = Size.gigabytes(34L); + ClusterHealth.ShardStatus shardStatus = ClusterHealth.ShardStatus.create(5, 4, 2, 1); + + when(elasticsearchConfiguration.getTimeSizeOptimizingRotationMinShardSize()).thenReturn(minSize); + when(elasticsearchConfiguration.getTimeSizeOptimizingRotationMaxShardSize()).thenReturn(maxSize); + when(cluster.clusterHealthStats()).thenReturn(Optional.of( + ClusterHealth.create("yellow", shardStatus) + )); + + Optional event = shardsMetricsSupplier.get(); + + assertThat(event).isPresent(); + assertThat(event.get().metrics()).isEqualTo(Map.of( + "shard_min_size", minSize.getQuantity(), + "shard_max_size", maxSize.getQuantity(), + "shards_active", shardStatus.active(), + "shards_initializing", shardStatus.initializing(), + "shards_relocating", shardStatus.relocating(), + "shards_unassigned", shardStatus.unassigned() + )); + } +}