diff --git a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/volume/TestVolumeIOStatsWithPrometheusSink.java b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/volume/TestVolumeIOStatsWithPrometheusSink.java index 8600de542430..875f8ce63644 100644 --- a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/volume/TestVolumeIOStatsWithPrometheusSink.java +++ b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/volume/TestVolumeIOStatsWithPrometheusSink.java @@ -42,7 +42,7 @@ public class TestVolumeIOStatsWithPrometheusSink { public void init() { metrics = DefaultMetricsSystem.instance(); metrics.init("test"); - sink = new PrometheusMetricsSink(); + sink = new PrometheusMetricsSink("random"); metrics.register("Prometheus", "Prometheus", sink); } diff --git a/hadoop-hdds/framework/dev-support/findbugsExcludeFile.xml b/hadoop-hdds/framework/dev-support/findbugsExcludeFile.xml index 6251188ecc17..a111802321e3 100644 --- a/hadoop-hdds/framework/dev-support/findbugsExcludeFile.xml +++ b/hadoop-hdds/framework/dev-support/findbugsExcludeFile.xml @@ -21,10 +21,6 @@ - - - - diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/http/BaseHttpServer.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/http/BaseHttpServer.java index 4315dcdd54d2..144cec862099 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/http/BaseHttpServer.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/http/BaseHttpServer.java @@ -148,7 +148,7 @@ public BaseHttpServer(MutableConfigurationSource conf, String name) conf.getBoolean(HddsConfigKeys.HDDS_PROFILER_ENABLED, false); if (prometheusSupport) { - prometheusMetricsSink = new PrometheusMetricsSink(); + prometheusMetricsSink = new PrometheusMetricsSink(name); httpServer.getWebAppContext().getServletContext() .setAttribute(PROMETHEUS_SINK, prometheusMetricsSink); HddsPrometheusConfig prometheusConfig = diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/http/PrometheusMetricsSink.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/http/PrometheusMetricsSink.java index 320f92efc79e..a0bec87ea9e9 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/http/PrometheusMetricsSink.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/http/PrometheusMetricsSink.java @@ -17,18 +17,14 @@ */ package org.apache.hadoop.hdds.server.http; -import static org.apache.hadoop.hdds.utils.RocksDBStoreMBean.ROCKSDB_CONTEXT_PREFIX; - import java.io.IOException; import java.io.Writer; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.TreeMap; -import java.util.List; -import java.util.regex.Pattern; import org.apache.commons.configuration2.SubsetConfiguration; -import org.apache.commons.lang3.StringUtils; -import org.apache.hadoop.hdds.utils.DecayRpcSchedulerUtil; +import org.apache.hadoop.hdds.utils.PrometheusMetricsSinkUtil; import org.apache.hadoop.metrics2.AbstractMetric; import org.apache.hadoop.metrics2.MetricType; import org.apache.hadoop.metrics2.MetricsRecord; @@ -49,14 +45,10 @@ public class PrometheusMetricsSink implements MetricsSink { Collections.synchronizedSortedMap(new TreeMap<>()); private Map> nextMetricLines = Collections.synchronizedSortedMap(new TreeMap<>()); + private final String servername; - private static final Pattern SPLIT_PATTERN = - Pattern.compile("(? metricTagList = DecayRpcSchedulerUtil - .tagListWithUsernameIfNeeded(metricsRecord, username); + List metricsTags = + PrometheusMetricsSinkUtil.addTags(key, username, servername, + metricsRecord.tags()); //add tags - for (MetricsTag tag : metricTagList) { + for (MetricsTag tag : metricsTags) { String tagName = tag.name().toLowerCase(); //ignore specific tag which includes sub-hierarchy - if (!tagName.equals("numopenconnectionsperuser")) { - prometheusMetricKey.append(sep) - .append(tagName) - .append("=\"") - .append(tag.value()) - .append("\""); - sep = ","; + if (tagName.equals("numopenconnectionsperuser")) { + continue; } + + prometheusMetricKey.append(sep) + .append(tagName) + .append("=\"") + .append(tag.value()) + .append("\""); + sep = ","; } prometheusMetricKey.append("}"); return prometheusMetricKey.toString(); } - /** - * Convert CamelCase based names to lower-case names where the separator - * is the underscore, to follow prometheus naming conventions. - */ - public String prometheusName(String recordName, - String metricName) { - - // RocksDB metric names already have underscores as delimiters, - // but record name is from DB file name and '.' (as in 'om.db') is invalid - if (StringUtils.isNotEmpty(recordName) && - recordName.startsWith(ROCKSDB_CONTEXT_PREFIX)) { - return normalizeName(recordName) + "_" + metricName.toLowerCase(); - } - - String baseName = StringUtils.capitalize(recordName) - + StringUtils.capitalize(metricName); - return normalizeName(baseName); - } - - public static String normalizeName(String baseName) { - String[] parts = SPLIT_PATTERN.split(baseName); - String result = String.join("_", parts).toLowerCase(); - return REPLACE_PATTERN.matcher(result).replaceAll("_"); - } - @Override public void flush() { synchronized (this) { diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/DecayRpcSchedulerUtil.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/DecayRpcSchedulerUtil.java index e0fe8be8a8cd..cfdf704016ce 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/DecayRpcSchedulerUtil.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/DecayRpcSchedulerUtil.java @@ -18,13 +18,10 @@ package org.apache.hadoop.hdds.utils; import com.google.common.base.Strings; +import java.util.Optional; import org.apache.hadoop.metrics2.MetricsInfo; -import org.apache.hadoop.metrics2.MetricsRecord; import org.apache.hadoop.metrics2.MetricsTag; -import java.util.ArrayList; -import java.util.List; - /** * Helper functions for DecayRpcScheduler * metrics for Prometheus. @@ -34,25 +31,13 @@ public final class DecayRpcSchedulerUtil { private DecayRpcSchedulerUtil() { } - private static final MetricsInfo USERNAME_INFO = new MetricsInfo() { - @Override - public String name() { - return "username"; - } - - @Override - public String description() { - return "caller username"; - } - }; - /** * For Decay_Rpc_Scheduler, the metric name is in format * "Caller().Volume" * or * "Caller().Priority" * Split it and return the metric. - * + *

* If the recordName doesn't belong to Decay_Rpc_Scheduler, * then return the metricName as it is without making * any changes to it. @@ -78,6 +63,7 @@ public static String splitMetricNameIfNeeded(String recordName, * For Decay_Rpc_Scheduler, split the metric name * and then get the part that is in the format "Caller()" * and split it to return the username. + * * @param recordName * @param metricName * @return caller username or null if not present @@ -102,20 +88,33 @@ public static String checkMetricNameForUsername(String recordName, return null; } + /** - * MetricRecord.tags() is an unmodifiable collection of tags. - * Store it in a list, to modify it and add a username tag. - * @param metricsRecord - * @return the new list with the metric tags and the username tag + * Create a username metrics tag. + * @param username caller username + * @return empty optional if no metrics tag was created, otherwise + * optional of metrics tag. */ - public static List tagListWithUsernameIfNeeded( - MetricsRecord metricsRecord, String username) { - List list = new ArrayList<>(metricsRecord.tags()); - - if (!Strings.isNullOrEmpty(username)) { - MetricsTag tag = new MetricsTag(USERNAME_INFO, username); - list.add(tag); + public static Optional createUsernameTag(String username) { + if (Strings.isNullOrEmpty(username)) { + return Optional.empty(); } - return list; + + final String name = "username"; + final String description = "caller username"; + final MetricsInfo metricsInfo = new MetricsInfo() { + @Override + public String name() { + return name; + } + + @Override + public String description() { + return description; + } + }; + MetricsTag metricsTag = new MetricsTag(metricsInfo, username); + return Optional.of(metricsTag); } + } diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/PrometheusMetricsSinkUtil.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/PrometheusMetricsSinkUtil.java new file mode 100644 index 000000000000..44ccb5397be3 --- /dev/null +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/PrometheusMetricsSinkUtil.java @@ -0,0 +1,116 @@ +/** + * 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.hadoop.hdds.utils; + +import static org.apache.hadoop.hdds.utils.RocksDBStoreMBean.ROCKSDB_CONTEXT_PREFIX; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; +import org.apache.hadoop.metrics2.MetricsTag; + +/** + * Util class for + * {@link org.apache.hadoop.hdds.server.http.PrometheusMetricsSink}. + */ +public final class PrometheusMetricsSinkUtil { + private static final Pattern SPLIT_PATTERN = + Pattern.compile("(? addTags(String key, String username, + String servername, Collection unmodifiableTags) { + List metricTags = new ArrayList<>(unmodifiableTags); + + Stream.of(DecayRpcSchedulerUtil.createUsernameTag(username), + UgiMetricsUtil.createServernameTag(key, servername)) + .forEach( + metricsTag -> metricsTag.ifPresent(mt -> addTag(mt, metricTags))); + + return metricTags; + } + + /** + * Adds metric tag to a metrics tags. + * @param metricsTag metrics tag to be added + * @param metricsTags metrics tags where metrics tag needs to be added + */ + private static void addTag(MetricsTag metricsTag, + List metricsTags) { + metricsTags.add(metricsTag); + } + + /** + * Convert CamelCase based names to lower-case names where the separator + * is the underscore, to follow prometheus naming conventions. + */ + public static String prometheusName(String recordName, + String metricName) { + + // RocksDB metric names already have underscores as delimiters, + // but record name is from DB file name and '.' (as in 'om.db') is invalid + if (StringUtils.isNotEmpty(recordName) && + recordName.startsWith(ROCKSDB_CONTEXT_PREFIX)) { + return normalizeName(recordName) + "_" + metricName.toLowerCase(); + } + + String baseName = StringUtils.capitalize(recordName) + + StringUtils.capitalize(metricName); + return normalizeName(baseName); + } + + /** + * Normalizes metrics tag key name. + * @param baseName + * @return normalized name. + */ + private static String normalizeName(String baseName) { + String[] parts = SPLIT_PATTERN.split(baseName); + String result = String.join("_", parts).toLowerCase(); + return REPLACE_PATTERN.matcher(result).replaceAll("_"); + } + + public static String getMetricName(String recordName, String metricName) { + return DecayRpcSchedulerUtil.splitMetricNameIfNeeded(recordName, + metricName); + } + + public static String getUsername(String recordName, String metricName) { + return DecayRpcSchedulerUtil.checkMetricNameForUsername(recordName, + metricName); + } +} diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/UgiMetricsUtil.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/UgiMetricsUtil.java new file mode 100644 index 000000000000..60edf3c982cd --- /dev/null +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/UgiMetricsUtil.java @@ -0,0 +1,68 @@ +/** + * 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.hadoop.hdds.utils; + +import java.util.Optional; +import org.apache.hadoop.metrics2.MetricsInfo; +import org.apache.hadoop.metrics2.MetricsTag; + +/** + * Util class for UGI metrics. + */ +public final class UgiMetricsUtil { + + private static final String UGI_METRICS = "ugi_metrics"; + + /** + * Never constructed. + */ + private UgiMetricsUtil() { + } + + /** + * Creates servername metrics tag. + * + * @param key metrics entry key + * @param servername server name + * @return empty optional if no metrics tag was created, otherwise + * optional of metrics tag. + */ + public static Optional createServernameTag(String key, + String servername) { + if (!key.contains(UGI_METRICS)) { + return Optional.empty(); + } + + final String name = "servername"; + final String description = "name of the server"; + final MetricsInfo metricsInfo = new MetricsInfo() { + @Override + public String name() { + return name; + } + + @Override + public String description() { + return description; + } + }; + MetricsTag metricsTag = new MetricsTag(metricsInfo, servername); + return Optional.of(metricsTag); + } + +} diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/http/TestPrometheusMetricsIntegration.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/http/TestPrometheusMetricsIntegration.java index bc2ccef57dad..5243dfda51d9 100644 --- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/http/TestPrometheusMetricsIntegration.java +++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/http/TestPrometheusMetricsIntegration.java @@ -79,7 +79,7 @@ public void init() { metrics = DefaultMetricsSystem.instance(); metrics.init("test"); - sink = new PrometheusMetricsSink(); + sink = new PrometheusMetricsSink("random"); metrics.register("Prometheus", "Prometheus", sink); } diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/http/TestPrometheusMetricsSink.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/http/TestPrometheusMetricsSink.java deleted file mode 100644 index dc15d805d670..000000000000 --- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/http/TestPrometheusMetricsSink.java +++ /dev/null @@ -1,83 +0,0 @@ -/** - * 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.hadoop.hdds.server.http; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -/** - * Test prometheus Sink. - */ -public class TestPrometheusMetricsSink { - - private static PrometheusMetricsSink sink; - - @BeforeAll - public static void setUp() { - sink = new PrometheusMetricsSink(); - } - - @Test - public void testNamingCamelCase() { - //THEN - Assertions.assertEquals("rpc_time_some_metrics", - sink.prometheusName("RpcTime", "SomeMetrics")); - - Assertions.assertEquals("om_rpc_time_om_info_keys", - sink.prometheusName("OMRpcTime", "OMInfoKeys")); - - Assertions.assertEquals("rpc_time_small", - sink.prometheusName("RpcTime", "small")); - } - - @Test - public void testNamingRocksDB() { - //RocksDB metrics are handled differently. - // THEN - Assertions.assertEquals("rocksdb_om_db_num_open_connections", - sink.prometheusName("Rocksdb_om.db", "num_open_connections")); - } - - @Test - public void testNamingPipeline() { - // GIVEN - String recordName = "SCMPipelineMetrics"; - String metricName = "NumBlocksAllocated-" - + "RATIS-THREE-47659e3d-40c9-43b3-9792-4982fc279aba"; - - // THEN - Assertions.assertEquals( - "scm_pipeline_metrics_" - + "num_blocks_allocated_" - + "ratis_three_47659e3d_40c9_43b3_9792_4982fc279aba", - sink.prometheusName(recordName, metricName)); - } - - @Test - public void testNamingSpaces() { - //GIVEN - String recordName = "JvmMetrics"; - String metricName = "GcTimeMillisG1 Young Generation"; - - // THEN - Assertions.assertEquals( - "jvm_metrics_gc_time_millis_g1_young_generation", - sink.prometheusName(recordName, metricName)); - } -} diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/utils/TestDecayRpcSchedulerUtil.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/utils/TestDecayRpcSchedulerUtil.java index b3ccbafca625..f84e6ce06872 100644 --- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/utils/TestDecayRpcSchedulerUtil.java +++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/utils/TestDecayRpcSchedulerUtil.java @@ -19,6 +19,9 @@ package org.apache.hadoop.hdds.utils; +import java.util.Optional; +import org.apache.hadoop.metrics2.MetricsTag; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -41,7 +44,7 @@ public class TestDecayRpcSchedulerUtil { private static final String RANDOM_METRIC_NAME = "ThreadsNew"; @Test - public void testSplitMetricNameIfNeeded() { + void testSplitMetricNameIfNeeded() { // Split the metric name and return only the // name of the metric type. String splitName = DecayRpcSchedulerUtil @@ -57,7 +60,7 @@ public void testSplitMetricNameIfNeeded() { } @Test - public void testCheckMetricNameForUsername() { + void testCheckMetricNameForUsername() { // Get the username from the metric name. String decayRpcSchedulerUsername = DecayRpcSchedulerUtil .checkMetricNameForUsername(RECORD_NAME, METRIC_NAME); @@ -72,4 +75,34 @@ public void testCheckMetricNameForUsername() { assertNull(nullUsername); } + + @Test + void testCreateUsernameTagWithNullUsername() { + // GIVEN + final String username = null; + + // WHEN + Optional optionalMetricsTag = + DecayRpcSchedulerUtil.createUsernameTag(username); + + // THEN + Assertions.assertFalse(optionalMetricsTag.isPresent()); + } + + @Test + void testCreateUsernameTagWithNotNullUsername() { + // GIVEN + final String username = "username"; + + // WHEN + Optional optionalMetricsTag = + DecayRpcSchedulerUtil.createUsernameTag(username); + + // THEN + Assertions.assertTrue(optionalMetricsTag.isPresent()); + Assertions.assertEquals(username, optionalMetricsTag.get().value()); + Assertions.assertEquals(username, optionalMetricsTag.get().name()); + Assertions.assertEquals("caller username", + optionalMetricsTag.get().description()); + } } diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/utils/TestPrometheusMetricsSinkUtil.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/utils/TestPrometheusMetricsSinkUtil.java new file mode 100644 index 000000000000..ef64bbb6e8e1 --- /dev/null +++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/utils/TestPrometheusMetricsSinkUtil.java @@ -0,0 +1,229 @@ +/** + * 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.hadoop.hdds.utils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import org.apache.hadoop.metrics2.MetricsTag; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * Class for unit tests for {@link PrometheusMetricsSinkUtil}. + */ +class TestPrometheusMetricsSinkUtil { + + private static final String USERNAME_TAG_NAME = "username"; + private static final String USERNAME_TAG_DESCRIPTION = "caller username"; + private static final String SERVERNAME_TAG_NAME = "servername"; + private static final String SERVERNAME_TAG_DESCRIPTION = "name of the server"; + + @Test + void testAddTagsAddUsernameTagWithNullUsername() { + // GIVEN + final String key = "key"; + final String username = null; + final String servername = null; + Collection unmodifiableMetricTags = + Collections.unmodifiableList(new ArrayList<>()); + + // WHEN + List metricsTags = PrometheusMetricsSinkUtil.addTags(key, + username, servername, unmodifiableMetricTags); + + // THEN + Assertions.assertFalse(metricsTags.stream() + .anyMatch(metricsTag -> metricsTag.name().equals(USERNAME_TAG_NAME) || + metricsTag.description().equals(USERNAME_TAG_DESCRIPTION))); + } + + @Test + void testAddTagsAddUsernameTagWithEmptyUsername() { + // GIVEN + final String key = "key"; + final String username = ""; + final String servername = null; + Collection unmodifiableMetricTags = + Collections.unmodifiableList(new ArrayList<>()); + + // WHEN + List metricsTags = PrometheusMetricsSinkUtil.addTags(key, + username, servername, unmodifiableMetricTags); + + // THEN + Assertions.assertFalse(metricsTags.stream() + .anyMatch(metricsTag -> metricsTag.name().equals(USERNAME_TAG_NAME) || + metricsTag.description().equals(USERNAME_TAG_DESCRIPTION))); + } + + @Test + void testAddTagsAddUsernameTagWithUsername() { + // GIVEN + final String key = "key"; + final String username = "username"; + final String servername = null; + Collection unmodifiableMetricTags = + Collections.unmodifiableList(new ArrayList<>()); + + // WHEN + List metricsTags = PrometheusMetricsSinkUtil.addTags(key, + username, servername, unmodifiableMetricTags); + + // THEN + Assertions.assertTrue(metricsTags.stream() + .anyMatch(metricsTag -> metricsTag.name().equals(USERNAME_TAG_NAME) && + metricsTag.description().equals(USERNAME_TAG_DESCRIPTION))); + } + + @Test + void testAddTagsAddServernameTagWithNoUgiMetricsKey() { + // GIVEN + final String key = "key"; + final String username = null; + final String servername = "SERVERNAME"; + Collection unmodifiableMetricTags = + Collections.unmodifiableList(new ArrayList<>()); + + // WHEN + List metricsTags = PrometheusMetricsSinkUtil.addTags(key, + username, servername, unmodifiableMetricTags); + + // THEN + Assertions.assertFalse(metricsTags.stream() + .anyMatch(metricsTag -> metricsTag.name().equals(SERVERNAME_TAG_NAME) || + metricsTag.description().equals(SERVERNAME_TAG_DESCRIPTION))); + } + + @Test + void testAddTagsAddServernameTagWithUgiMetricsKey() { + // GIVEN + final String key = "ugi_metrics"; + final String username = null; + final String servername = "SERVERNAME"; + Collection unmodifiableMetricTags = + Collections.unmodifiableList(new ArrayList<>()); + + // WHEN + List metricsTags = PrometheusMetricsSinkUtil.addTags(key, + username, servername, unmodifiableMetricTags); + + // THEN + Assertions.assertTrue(metricsTags.stream() + .anyMatch(metricsTag -> metricsTag.name().equals(SERVERNAME_TAG_NAME) && + metricsTag.description().equals(SERVERNAME_TAG_DESCRIPTION))); + } + + @Test + void testAddTags() { + // GIVEN + final String key = "ugi_metrics"; + final String username = "username"; + final String servername = "SERVERNAME"; + Collection unmodifiableMetricTags = + Collections.unmodifiableList(new ArrayList<>()); + + // WHEN + List metricsTags = PrometheusMetricsSinkUtil.addTags(key, + username, servername, unmodifiableMetricTags); + + // THEN + Assertions.assertTrue(metricsTags.stream() + .anyMatch(metricsTag -> metricsTag.name().equals(USERNAME_TAG_NAME))); + Assertions.assertTrue(metricsTags.stream() + .anyMatch(metricsTag -> metricsTag.name().equals(SERVERNAME_TAG_NAME))); + } + + @Test + void testNamingCamelCase() { + //THEN + Assertions.assertEquals("rpc_time_some_metrics", + PrometheusMetricsSinkUtil.prometheusName("RpcTime", "SomeMetrics")); + + Assertions.assertEquals("om_rpc_time_om_info_keys", + PrometheusMetricsSinkUtil.prometheusName("OMRpcTime", "OMInfoKeys")); + + Assertions.assertEquals("rpc_time_small", + PrometheusMetricsSinkUtil.prometheusName("RpcTime", "small")); + } + + @Test + void testNamingRocksDB() { + //RocksDB metrics are handled differently. + // THEN + Assertions.assertEquals("rocksdb_om_db_num_open_connections", + PrometheusMetricsSinkUtil.prometheusName("Rocksdb_om.db", + "num_open_connections")); + } + + @Test + void testNamingPipeline() { + // GIVEN + String recordName = "SCMPipelineMetrics"; + String metricName = "NumBlocksAllocated-" + + "RATIS-THREE-47659e3d-40c9-43b3-9792-4982fc279aba"; + + // THEN + Assertions.assertEquals( + "scm_pipeline_metrics_" + "num_blocks_allocated_" + + "ratis_three_47659e3d_40c9_43b3_9792_4982fc279aba", + PrometheusMetricsSinkUtil.prometheusName(recordName, metricName)); + } + + @Test + void testNamingSpaces() { + //GIVEN + String recordName = "JvmMetrics"; + String metricName = "GcTimeMillisG1 Young Generation"; + + // THEN + Assertions.assertEquals( + "jvm_metrics_gc_time_millis_g1_young_generation", + PrometheusMetricsSinkUtil.prometheusName(recordName, metricName)); + } + + @Test + void testGetMetricName() { + // GIVEN + final String recordName = "record_name"; + final String metricName = "metric_name"; + + // WHEN + String newMetricName = PrometheusMetricsSinkUtil.getMetricName(recordName, + metricName); + + // THEN + Assertions.assertEquals(metricName, newMetricName); + } + + @Test + void testGetUsername() { + // GIVEN + final String recordName = "record_name"; + final String metricName = "metric_name"; + + // WHEN + String username = PrometheusMetricsSinkUtil.getUsername(recordName, + metricName); + + // THEN + Assertions.assertNull(username); + } + +} \ No newline at end of file diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/utils/TestUgiMetricsUtil.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/utils/TestUgiMetricsUtil.java new file mode 100644 index 000000000000..75ee8cd69463 --- /dev/null +++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/utils/TestUgiMetricsUtil.java @@ -0,0 +1,63 @@ +/** + * 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.hadoop.hdds.utils; + +import java.util.Optional; +import org.apache.hadoop.metrics2.MetricsTag; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * Class for unit tests for {@link UgiMetricsUtil}. + */ +class TestUgiMetricsUtil { + + @Test + void testCreateServernameTagWithNonCompatibleKey() { + // GIVEN + final String key = "non_ugi"; + final String servername = "servername"; + + // WHEN + Optional optionalMetricsTag = + UgiMetricsUtil.createServernameTag(key, servername); + + // THEN + Assertions.assertFalse(optionalMetricsTag.isPresent()); + } + + @Test + void testCreateServernameTagWithCompatibleKey() { + // GIVEN + final String key = "ugi_metrics"; + final String servername = "servername"; + + // WHEN + Optional optionalMetricsTag = + UgiMetricsUtil.createServernameTag(key, servername); + + // THEN + Assertions.assertTrue(optionalMetricsTag.isPresent()); + Assertions.assertEquals(servername, optionalMetricsTag.get().value()); + Assertions.assertEquals(servername, optionalMetricsTag.get().name()); + Assertions.assertEquals("name of the server", + optionalMetricsTag.get().description()); + } + +} \ No newline at end of file