From 3812b43f8459bb8c48c249149c3b483323c7dd9e Mon Sep 17 00:00:00 2001 From: Madhusoodan P Date: Sat, 30 May 2020 22:22:31 +0530 Subject: [PATCH 1/6] HBASE-20904 Prometheus /metrics http endpoint for monitoring Co-authored-by: Luca Kovacs --- .../src/main/resources/hbase-default.xml | 8 ++ .../metrics2/impl/MetricsExportHelper.java | 41 +++++++++ .../metrics/TestMetricsExportHelper.java | 75 ++++++++++++++++ hbase-http/pom.xml | 13 +++ .../apache/hadoop/hbase/http/HttpServer.java | 33 ++++--- .../hadoop/hbase/http/ServletConfig.java | 48 +++++++++++ .../prometheus/PrometheusHadoop2Servlet.java | 86 +++++++++++++++++++ .../prometheus/TestPrometheus2Servlet.java | 84 ++++++++++++++++++ src/main/asciidoc/_chapters/ops_mgt.adoc | 9 ++ 9 files changed, 386 insertions(+), 11 deletions(-) create mode 100644 hbase-hadoop-compat/src/main/java/org/apache/hadoop/metrics2/impl/MetricsExportHelper.java create mode 100644 hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/metrics/TestMetricsExportHelper.java create mode 100644 hbase-http/src/main/java/org/apache/hadoop/hbase/http/ServletConfig.java create mode 100644 hbase-http/src/main/java/org/apache/hadoop/hbase/http/prometheus/PrometheusHadoop2Servlet.java create mode 100644 hbase-http/src/test/java/org/apache/hadoop/hbase/http/prometheus/TestPrometheus2Servlet.java diff --git a/hbase-common/src/main/resources/hbase-default.xml b/hbase-common/src/main/resources/hbase-default.xml index dc94a6d3e683..4388a55a773d 100644 --- a/hbase-common/src/main/resources/hbase-default.xml +++ b/hbase-common/src/main/resources/hbase-default.xml @@ -1786,6 +1786,14 @@ possible configurations would overwhelm and obscure the important. ThreadPool. + + hbase.http.metrics.servlets + jmx,prometheus + + Comma separated list of servlet names to enable for metrics collection. Supported + servlets are jmx, metrics, prometheus + + hbase.replication.rpc.codec org.apache.hadoop.hbase.codec.KeyValueCodecWithTags diff --git a/hbase-hadoop-compat/src/main/java/org/apache/hadoop/metrics2/impl/MetricsExportHelper.java b/hbase-hadoop-compat/src/main/java/org/apache/hadoop/metrics2/impl/MetricsExportHelper.java new file mode 100644 index 000000000000..e0e846bcf6d7 --- /dev/null +++ b/hbase-hadoop-compat/src/main/java/org/apache/hadoop/metrics2/impl/MetricsExportHelper.java @@ -0,0 +1,41 @@ +/* + * 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.metrics2.impl; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import org.apache.hadoop.metrics2.MetricsRecord; +import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; +import org.apache.yetus.audience.InterfaceAudience; + +@InterfaceAudience.Private +public class MetricsExportHelper { + + public static Collection export() { + MetricsSystemImpl instance = (MetricsSystemImpl) DefaultMetricsSystem.instance(); + MetricsBuffer metricsBuffer = instance.sampleMetrics(); + List metrics = new LinkedList<>(); + for (MetricsBuffer.Entry entry : metricsBuffer) { + entry.records().forEach(metrics::add); + } + return metrics; + } + +} diff --git a/hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/metrics/TestMetricsExportHelper.java b/hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/metrics/TestMetricsExportHelper.java new file mode 100644 index 000000000000..7649d9959aa1 --- /dev/null +++ b/hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/metrics/TestMetricsExportHelper.java @@ -0,0 +1,75 @@ +/* + * 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.hbase.metrics; + +import java.util.Collection; +import org.apache.hadoop.hbase.HBaseClassTestRule; +import org.apache.hadoop.hbase.testclassification.MetricsTests; +import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.apache.hadoop.metrics2.AbstractMetric; +import org.apache.hadoop.metrics2.MetricsRecord; +import org.apache.hadoop.metrics2.impl.MetricsExportHelper; +import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category({ MetricsTests.class, SmallTests.class}) +public class TestMetricsExportHelper { + + @ClassRule + public static final HBaseClassTestRule CLASS_RULE = + HBaseClassTestRule.forClass(TestMetricsExportHelper.class); + + @Test + public void testExportHelper() { + DefaultMetricsSystem.initialize("exportHelperTestSystem"); + DefaultMetricsSystem.instance().start(); + + String metricsName = "exportMetricsTestGrp"; + String gaugeName = "exportMetricsTestGauge"; + String counterName = "exportMetricsTestCounter"; + + BaseSourceImpl baseSource = new BaseSourceImpl(metricsName, "", metricsName, metricsName); + + baseSource.setGauge(gaugeName, 0); + baseSource.incCounters(counterName, 1); + + Collection metrics = MetricsExportHelper.export(); + DefaultMetricsSystem.instance().stop(); + + Assert.assertTrue(metrics.stream().anyMatch(mr -> mr.name().equals(metricsName))); + Assert.assertTrue(gaugeName + " is missing in the export", contains(metrics, metricsName, gaugeName)); + Assert.assertTrue(counterName + " is missing in the export", contains(metrics, metricsName, counterName)); + } + + private boolean contains(Collection metrics, String metricsName, String metricName) { + return metrics + .stream() + .filter(mr -> mr.name().equals(metricsName)) + .anyMatch(mr -> { + for (AbstractMetric metric : mr.metrics()) { + if(metric.name().equals(metricName)) + return true; + } + return false; + } + ); + } +} diff --git a/hbase-http/pom.xml b/hbase-http/pom.xml index 3da0b9a15d99..acaea79ca00f 100644 --- a/hbase-http/pom.xml +++ b/hbase-http/pom.xml @@ -57,6 +57,19 @@ test-jar test + + org.apache.hbase + hbase-metrics-api + + + org.apache.hbase + hbase-metrics + test + + + hbase-hadoop-compat + org.apache.hbase + org.apache.hbase diff --git a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java index 8c45d4f8aca2..3b01c3c3d5a9 100644 --- a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java +++ b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java @@ -53,7 +53,6 @@ import org.apache.hadoop.fs.CommonConfigurationKeys; import org.apache.hadoop.hbase.HBaseInterfaceAudience; import org.apache.hadoop.hbase.http.conf.ConfServlet; -import org.apache.hadoop.hbase.http.jmx.JMXJsonServlet; import org.apache.hadoop.hbase.http.log.LogLevel; import org.apache.hadoop.hbase.util.ReflectionUtils; import org.apache.hadoop.hbase.util.Threads; @@ -154,6 +153,14 @@ public class HttpServer implements FilterContainer { public static final String NO_CACHE_FILTER = "NoCacheFilter"; public static final String APP_DIR = "webapps"; + public static final String METRIC_SERVLETS_CONF_KEY = "hbase.http.metrics.servlets"; + public static final String METRICS_SERVLETS_DEFAULT[] = {"jmx,prometheus"}; + private static final Map METRIC_SERVLETS = new HashMap() {{ + put("jmx", new ServletConfig("jmx", "/jmx", "org.apache.hadoop.hbase.http.jmx.JMXJsonServlet")); + put("metrics", new ServletConfig("metrics", "/metrics", "org.apache.hadoop.metrics.MetricsServlet")); + put("prometheus", new ServletConfig("prometheus", "/prometheus", "org.apache.hadoop.hbase.http.prometheus.PrometheusHadoop2Servlet")); + }}; + private final AccessControlList adminsAcl; protected final Server webServer; @@ -751,16 +758,7 @@ protected void addDefaultServlets(ContextHandlerCollection contexts, Configurati // set up default servlets addPrivilegedServlet("stacks", "/stacks", StackServlet.class); addPrivilegedServlet("logLevel", "/logLevel", LogLevel.Servlet.class); - // Hadoop3 has moved completely to metrics2, and dropped support for Metrics v1's - // MetricsServlet (see HADOOP-12504). We'll using reflection to load if against hadoop2. - // Remove when we drop support for hbase on hadoop2.x. - try { - Class clz = Class.forName("org.apache.hadoop.metrics.MetricsServlet"); - addPrivilegedServlet("metrics", "/metrics", clz.asSubclass(HttpServlet.class)); - } catch (Exception e) { - // do nothing - } - addPrivilegedServlet("jmx", "/jmx", JMXJsonServlet.class); + // While we don't expect users to have sensitive information in their configuration, they // might. Give them an option to not expose the service configuration to all users. if (conf.getBoolean(HTTP_PRIVILEGED_CONF_KEY, HTTP_PRIVILEGED_CONF_DEFAULT)) { @@ -784,6 +782,19 @@ protected void addDefaultServlets(ContextHandlerCollection contexts, Configurati LOG.info("ASYNC_PROFILER_HOME environment variable and async.profiler.home system property " + "not specified. Disabling /prof endpoint."); } + + /* register metrics servlets */ + String enabledServlets[] = conf.getStrings(METRIC_SERVLETS_CONF_KEY, METRICS_SERVLETS_DEFAULT); + for (String enabledServlet : enabledServlets) { + try { + ServletConfig servletConfig = METRIC_SERVLETS.get(enabledServlet); + Class clz = Class.forName(servletConfig.getClazz()); + addPrivilegedServlet(servletConfig.getName(), servletConfig.getPathSpec(), clz.asSubclass(HttpServlet.class)); + } catch (Exception e) { + /* shouldn't be fatal, so warn the user about it */ + LOG.warn("Couldn't register the servlet " + enabledServlet, e); + } + } } /** diff --git a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/ServletConfig.java b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/ServletConfig.java new file mode 100644 index 000000000000..776bc1af70f4 --- /dev/null +++ b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/ServletConfig.java @@ -0,0 +1,48 @@ +/* + * 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.hbase.http; + +import org.apache.yetus.audience.InterfaceAudience; + +/* pojo to hold the servlet info */ + +@InterfaceAudience.Private +class ServletConfig { + private String name; + private String pathSpec; + private String clazz; + + public ServletConfig(String name, String pathSpec, String clazz) { + this.name = name; + this.pathSpec = pathSpec; + this.clazz = clazz; + } + + public String getName() { + return name; + } + + public String getPathSpec() { + return pathSpec; + } + + public String getClazz() { + return clazz; + } +} diff --git a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/prometheus/PrometheusHadoop2Servlet.java b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/prometheus/PrometheusHadoop2Servlet.java new file mode 100644 index 000000000000..2f2679643e02 --- /dev/null +++ b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/prometheus/PrometheusHadoop2Servlet.java @@ -0,0 +1,86 @@ +/* + * 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.hbase.http.prometheus; + +import java.io.IOException; +import java.io.Writer; +import java.util.Collection; +import java.util.regex.Pattern; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import com.google.errorprone.annotations.RestrictedApi; +import org.apache.commons.lang3.StringUtils; +import org.apache.hadoop.metrics2.AbstractMetric; +import org.apache.hadoop.metrics2.MetricType; +import org.apache.hadoop.metrics2.MetricsRecord; +import org.apache.hadoop.metrics2.MetricsTag; +import org.apache.hadoop.metrics2.impl.MetricsExportHelper; +import org.apache.yetus.audience.InterfaceAudience; + +@InterfaceAudience.Private +public class PrometheusHadoop2Servlet extends HttpServlet { + + private static final Pattern SPLIT_PATTERN = + Pattern.compile("(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=([A-Z][a-z]))|\\W|(_)+"); + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws IOException { + writeMetrics(resp.getWriter()); + } + + static String toPrometheusName(String metricRecordName, String metricName) { + String baseName = metricRecordName + StringUtils.capitalize(metricName); + String[] parts = SPLIT_PATTERN.split(baseName); + return String + .join("_", parts) + .toLowerCase(); + } + + @RestrictedApi(explanation = "Should only be called in tests", link = "", + allowedOnPath = ".*/src/test/.*") + void writeMetrics(Writer writer) throws IOException { + Collection metricRecords = MetricsExportHelper.export(); + for (MetricsRecord metricsRecord : metricRecords) { + for (AbstractMetric metrics : metricsRecord.metrics()) { + if (metrics.type() == MetricType.COUNTER || metrics.type() == MetricType.GAUGE) { + + String key = toPrometheusName(metricsRecord.name(), metrics.name()); + writer.append("# TYPE ").append(key).append(" ") + .append(metrics.type().toString().toLowerCase()).append("\n") + .append(key).append("{"); + + /* add tags */ + String sep = ""; + for (MetricsTag tag : metricsRecord.tags()) { + String tagName = tag.name().toLowerCase(); + writer.append(sep).append(tagName) + .append("=\"") + .append(tag.value()).append("\""); + sep = ","; + } + writer.append("} "); + writer.append(metrics.value().toString()).append('\n'); + } + } + } + writer.flush(); + } +} diff --git a/hbase-http/src/test/java/org/apache/hadoop/hbase/http/prometheus/TestPrometheus2Servlet.java b/hbase-http/src/test/java/org/apache/hadoop/hbase/http/prometheus/TestPrometheus2Servlet.java new file mode 100644 index 000000000000..3c4886534313 --- /dev/null +++ b/hbase-http/src/test/java/org/apache/hadoop/hbase/http/prometheus/TestPrometheus2Servlet.java @@ -0,0 +1,84 @@ +/* + * 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.hbase.http.prometheus; + +import static java.nio.charset.StandardCharsets.UTF_8; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import org.apache.hadoop.hbase.HBaseClassTestRule; +import org.apache.hadoop.hbase.testclassification.MiscTests; +import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.apache.hadoop.metrics2.MetricsSystem; +import org.apache.hadoop.metrics2.annotation.Metric; +import org.apache.hadoop.metrics2.annotation.Metrics; +import org.apache.hadoop.metrics2.impl.MetricsExportHelper; +import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; +import org.apache.hadoop.metrics2.lib.MutableCounterLong; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +/** + * Test prometheus Sink. + */ +@Category({ SmallTests.class, MiscTests.class }) +public class TestPrometheus2Servlet { + + @ClassRule + public static final HBaseClassTestRule CLASS_TEST_RULE = + HBaseClassTestRule.forClass(TestPrometheus2Servlet.class); + + @Test + public void testPublish() throws IOException { + //GIVEN + MetricsSystem metrics = DefaultMetricsSystem.instance(); + metrics.init("test"); + TestMetrics testMetrics = metrics.register("TestMetrics", "Testing metrics", new TestMetrics()); + metrics.start(); + + testMetrics.numBucketCreateFails.incr(); + metrics.publishMetricsNow(); + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + OutputStreamWriter writer = new OutputStreamWriter(stream, UTF_8); + + //WHEN + PrometheusHadoop2Servlet prom2Servlet = new PrometheusHadoop2Servlet(); + prom2Servlet.writeMetrics(writer); + + //THEN + String writtenMetrics = stream.toString(UTF_8.name()); + System.out.println(writtenMetrics); + Assert.assertTrue("The expected metric line is missing from prometheus metrics output", + writtenMetrics.contains("test_metrics_num_bucket_create_fails{context=\"dfs\"")); + + metrics.stop(); + metrics.shutdown(); + } + + /** + * Example metric pojo. + */ + @Metrics(about = "Test Metrics", context = "dfs") + private static class TestMetrics { + + @Metric + private MutableCounterLong numBucketCreateFails; + } +} diff --git a/src/main/asciidoc/_chapters/ops_mgt.adoc b/src/main/asciidoc/_chapters/ops_mgt.adoc index 13e67c498890..ef85a1c5576c 100644 --- a/src/main/asciidoc/_chapters/ops_mgt.adoc +++ b/src/main/asciidoc/_chapters/ops_mgt.adoc @@ -1610,6 +1610,15 @@ See link:https://hadoop.apache.org/docs/current/api/org/apache/hadoop/metrics2/p To disable metrics for a region server, edit the _conf/hadoop-metrics2-hbase.properties_ file and comment out any uncommented lines. Restart the region server for the changes to take effect. +[[enabling.metrics.servlets]] +=== Enabling Metrics Servlets + +HBase exposes the metrics in many formats such as JSON, prometheus-format through different servlets (`/jmx`, `/metrics`, `/prometheus`, `/prometheus-hadoop2`). Any of these servlets can be enabled or disabled by the configuration property `hbase.http.metrics.servlets`. The value for the property should be a comma separated list of the servlet aliases which are `{jmx, metrics, prometheus, prometheus-hadoop2}`. `/jmx` and `/metrics` are enabled by default. To get metrics using these servlets access the URL `http://SERVER_HOSTNAME:SERVER_WEB_UI_PORT/endpoint`. Where endpoint is one of {`/jmx`, `/metrics`, `/prometheus`, `/prometheus-hadoop2`}. Eg. `http://my.rs.xyz.com:16030/prometheus-hadoop2` + +[[prometheus.format.metrics]] +=== Prometheus servlets +HBase exposes the metrics in prometheus friendly format through two different servlets `/prometheus` and `/prometheus-hadoop2`. Currently `/prometheus-hadoop2` exposes all the available metrics. `/prometheus` is based on the HBase native metrics API and is incomplete till all the metric sources start using this native metrics API. + [[discovering.available.metrics]] === Discovering Available Metrics From a9a01d1af783217149e9231732f28491470c4a77 Mon Sep 17 00:00:00 2001 From: Luca Kovacs Date: Thu, 11 Aug 2022 13:29:51 +0200 Subject: [PATCH 2/6] Fix spotless errors --- .../metrics2/impl/MetricsExportHelper.java | 1 - .../metrics/TestMetricsExportHelper.java | 28 +++++++++---------- hbase-http/pom.xml | 2 +- .../apache/hadoop/hbase/http/HttpServer.java | 21 +++++++++----- .../hadoop/hbase/http/ServletConfig.java | 1 - .../prometheus/PrometheusHadoop2Servlet.java | 19 ++++--------- .../prometheus/TestPrometheus2Servlet.java | 8 +++--- 7 files changed, 38 insertions(+), 42 deletions(-) diff --git a/hbase-hadoop-compat/src/main/java/org/apache/hadoop/metrics2/impl/MetricsExportHelper.java b/hbase-hadoop-compat/src/main/java/org/apache/hadoop/metrics2/impl/MetricsExportHelper.java index e0e846bcf6d7..91ed05ae7c31 100644 --- a/hbase-hadoop-compat/src/main/java/org/apache/hadoop/metrics2/impl/MetricsExportHelper.java +++ b/hbase-hadoop-compat/src/main/java/org/apache/hadoop/metrics2/impl/MetricsExportHelper.java @@ -15,7 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.apache.hadoop.metrics2.impl; import java.util.Collection; diff --git a/hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/metrics/TestMetricsExportHelper.java b/hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/metrics/TestMetricsExportHelper.java index 7649d9959aa1..8cae2fdcae51 100644 --- a/hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/metrics/TestMetricsExportHelper.java +++ b/hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/metrics/TestMetricsExportHelper.java @@ -30,7 +30,7 @@ import org.junit.Test; import org.junit.experimental.categories.Category; -@Category({ MetricsTests.class, SmallTests.class}) +@Category({ MetricsTests.class, SmallTests.class }) public class TestMetricsExportHelper { @ClassRule @@ -55,21 +55,19 @@ public void testExportHelper() { DefaultMetricsSystem.instance().stop(); Assert.assertTrue(metrics.stream().anyMatch(mr -> mr.name().equals(metricsName))); - Assert.assertTrue(gaugeName + " is missing in the export", contains(metrics, metricsName, gaugeName)); - Assert.assertTrue(counterName + " is missing in the export", contains(metrics, metricsName, counterName)); + Assert.assertTrue(gaugeName + " is missing in the export", + contains(metrics, metricsName, gaugeName)); + Assert.assertTrue(counterName + " is missing in the export", + contains(metrics, metricsName, counterName)); } - private boolean contains(Collection metrics, String metricsName, String metricName) { - return metrics - .stream() - .filter(mr -> mr.name().equals(metricsName)) - .anyMatch(mr -> { - for (AbstractMetric metric : mr.metrics()) { - if(metric.name().equals(metricName)) - return true; - } - return false; - } - ); + private boolean contains(Collection metrics, String metricsName, + String metricName) { + return metrics.stream().filter(mr -> mr.name().equals(metricsName)).anyMatch(mr -> { + for (AbstractMetric metric : mr.metrics()) { + if (metric.name().equals(metricName)) return true; + } + return false; + }); } } diff --git a/hbase-http/pom.xml b/hbase-http/pom.xml index acaea79ca00f..3c8ba421fa18 100644 --- a/hbase-http/pom.xml +++ b/hbase-http/pom.xml @@ -67,8 +67,8 @@ test - hbase-hadoop-compat org.apache.hbase + hbase-hadoop-compat diff --git a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java index 3b01c3c3d5a9..1833ebb3cbb2 100644 --- a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java +++ b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java @@ -154,12 +154,18 @@ public class HttpServer implements FilterContainer { public static final String APP_DIR = "webapps"; public static final String METRIC_SERVLETS_CONF_KEY = "hbase.http.metrics.servlets"; - public static final String METRICS_SERVLETS_DEFAULT[] = {"jmx,prometheus"}; - private static final Map METRIC_SERVLETS = new HashMap() {{ - put("jmx", new ServletConfig("jmx", "/jmx", "org.apache.hadoop.hbase.http.jmx.JMXJsonServlet")); - put("metrics", new ServletConfig("metrics", "/metrics", "org.apache.hadoop.metrics.MetricsServlet")); - put("prometheus", new ServletConfig("prometheus", "/prometheus", "org.apache.hadoop.hbase.http.prometheus.PrometheusHadoop2Servlet")); - }}; + public static final String METRICS_SERVLETS_DEFAULT[] = { "jmx,prometheus" }; + private static final Map METRIC_SERVLETS = + new HashMap() { + { + put("jmx", + new ServletConfig("jmx", "/jmx", "org.apache.hadoop.hbase.http.jmx.JMXJsonServlet")); + put("metrics", + new ServletConfig("metrics", "/metrics", "org.apache.hadoop.metrics.MetricsServlet")); + put("prometheus", new ServletConfig("prometheus", "/prometheus", + "org.apache.hadoop.hbase.http.prometheus.PrometheusHadoop2Servlet")); + } + }; private final AccessControlList adminsAcl; @@ -789,7 +795,8 @@ protected void addDefaultServlets(ContextHandlerCollection contexts, Configurati try { ServletConfig servletConfig = METRIC_SERVLETS.get(enabledServlet); Class clz = Class.forName(servletConfig.getClazz()); - addPrivilegedServlet(servletConfig.getName(), servletConfig.getPathSpec(), clz.asSubclass(HttpServlet.class)); + addPrivilegedServlet(servletConfig.getName(), servletConfig.getPathSpec(), + clz.asSubclass(HttpServlet.class)); } catch (Exception e) { /* shouldn't be fatal, so warn the user about it */ LOG.warn("Couldn't register the servlet " + enabledServlet, e); diff --git a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/ServletConfig.java b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/ServletConfig.java index 776bc1af70f4..befe60957605 100644 --- a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/ServletConfig.java +++ b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/ServletConfig.java @@ -15,7 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.apache.hadoop.hbase.http; import org.apache.yetus.audience.InterfaceAudience; diff --git a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/prometheus/PrometheusHadoop2Servlet.java b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/prometheus/PrometheusHadoop2Servlet.java index 2f2679643e02..d09adae751e1 100644 --- a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/prometheus/PrometheusHadoop2Servlet.java +++ b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/prometheus/PrometheusHadoop2Servlet.java @@ -15,9 +15,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.apache.hadoop.hbase.http.prometheus; +import com.google.errorprone.annotations.RestrictedApi; import java.io.IOException; import java.io.Writer; import java.util.Collection; @@ -25,7 +25,6 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import com.google.errorprone.annotations.RestrictedApi; import org.apache.commons.lang3.StringUtils; import org.apache.hadoop.metrics2.AbstractMetric; import org.apache.hadoop.metrics2.MetricType; @@ -41,21 +40,18 @@ public class PrometheusHadoop2Servlet extends HttpServlet { Pattern.compile("(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=([A-Z][a-z]))|\\W|(_)+"); @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) - throws IOException { + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { writeMetrics(resp.getWriter()); } static String toPrometheusName(String metricRecordName, String metricName) { String baseName = metricRecordName + StringUtils.capitalize(metricName); String[] parts = SPLIT_PATTERN.split(baseName); - return String - .join("_", parts) - .toLowerCase(); + return String.join("_", parts).toLowerCase(); } @RestrictedApi(explanation = "Should only be called in tests", link = "", - allowedOnPath = ".*/src/test/.*") + allowedOnPath = ".*/src/test/.*") void writeMetrics(Writer writer) throws IOException { Collection metricRecords = MetricsExportHelper.export(); for (MetricsRecord metricsRecord : metricRecords) { @@ -64,16 +60,13 @@ void writeMetrics(Writer writer) throws IOException { String key = toPrometheusName(metricsRecord.name(), metrics.name()); writer.append("# TYPE ").append(key).append(" ") - .append(metrics.type().toString().toLowerCase()).append("\n") - .append(key).append("{"); + .append(metrics.type().toString().toLowerCase()).append("\n").append(key).append("{"); /* add tags */ String sep = ""; for (MetricsTag tag : metricsRecord.tags()) { String tagName = tag.name().toLowerCase(); - writer.append(sep).append(tagName) - .append("=\"") - .append(tag.value()).append("\""); + writer.append(sep).append(tagName).append("=\"").append(tag.value()).append("\""); sep = ","; } writer.append("} "); diff --git a/hbase-http/src/test/java/org/apache/hadoop/hbase/http/prometheus/TestPrometheus2Servlet.java b/hbase-http/src/test/java/org/apache/hadoop/hbase/http/prometheus/TestPrometheus2Servlet.java index 3c4886534313..f08ab52de314 100644 --- a/hbase-http/src/test/java/org/apache/hadoop/hbase/http/prometheus/TestPrometheus2Servlet.java +++ b/hbase-http/src/test/java/org/apache/hadoop/hbase/http/prometheus/TestPrometheus2Servlet.java @@ -18,6 +18,7 @@ package org.apache.hadoop.hbase.http.prometheus; import static java.nio.charset.StandardCharsets.UTF_8; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; @@ -27,7 +28,6 @@ import org.apache.hadoop.metrics2.MetricsSystem; import org.apache.hadoop.metrics2.annotation.Metric; import org.apache.hadoop.metrics2.annotation.Metrics; -import org.apache.hadoop.metrics2.impl.MetricsExportHelper; import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; import org.apache.hadoop.metrics2.lib.MutableCounterLong; import org.junit.Assert; @@ -47,7 +47,7 @@ public class TestPrometheus2Servlet { @Test public void testPublish() throws IOException { - //GIVEN + // GIVEN MetricsSystem metrics = DefaultMetricsSystem.instance(); metrics.init("test"); TestMetrics testMetrics = metrics.register("TestMetrics", "Testing metrics", new TestMetrics()); @@ -58,11 +58,11 @@ public void testPublish() throws IOException { ByteArrayOutputStream stream = new ByteArrayOutputStream(); OutputStreamWriter writer = new OutputStreamWriter(stream, UTF_8); - //WHEN + // WHEN PrometheusHadoop2Servlet prom2Servlet = new PrometheusHadoop2Servlet(); prom2Servlet.writeMetrics(writer); - //THEN + // THEN String writtenMetrics = stream.toString(UTF_8.name()); System.out.println(writtenMetrics); Assert.assertTrue("The expected metric line is missing from prometheus metrics output", From 65a8fe37fc13c38ab82807cd75244d420eddaaae Mon Sep 17 00:00:00 2001 From: Luca Kovacs Date: Mon, 15 Aug 2022 13:53:50 +0200 Subject: [PATCH 3/6] Fixed errors, renamed classes Notes: - Fixed error that caused test fails - Renamed PrometheusHadoop2Servlet to PrometheusHadoopServlet (same in the test files) - Added comments, change in the documenatation --- .../main/java/org/apache/hadoop/hbase/http/HttpServer.java | 2 +- ...eusHadoop2Servlet.java => PrometheusHadoopServlet.java} | 7 ++++++- ...tPrometheus2Servlet.java => TestPrometheusServlet.java} | 6 +++--- src/main/asciidoc/_chapters/ops_mgt.adoc | 4 ++-- 4 files changed, 12 insertions(+), 7 deletions(-) rename hbase-http/src/main/java/org/apache/hadoop/hbase/http/prometheus/{PrometheusHadoop2Servlet.java => PrometheusHadoopServlet.java} (90%) rename hbase-http/src/test/java/org/apache/hadoop/hbase/http/prometheus/{TestPrometheus2Servlet.java => TestPrometheusServlet.java} (94%) diff --git a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java index 1833ebb3cbb2..9638010d05ea 100644 --- a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java +++ b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java @@ -154,7 +154,7 @@ public class HttpServer implements FilterContainer { public static final String APP_DIR = "webapps"; public static final String METRIC_SERVLETS_CONF_KEY = "hbase.http.metrics.servlets"; - public static final String METRICS_SERVLETS_DEFAULT[] = { "jmx,prometheus" }; + public static final String METRICS_SERVLETS_DEFAULT[] = { "jmx" }; private static final Map METRIC_SERVLETS = new HashMap() { { diff --git a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/prometheus/PrometheusHadoop2Servlet.java b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/prometheus/PrometheusHadoopServlet.java similarity index 90% rename from hbase-http/src/main/java/org/apache/hadoop/hbase/http/prometheus/PrometheusHadoop2Servlet.java rename to hbase-http/src/main/java/org/apache/hadoop/hbase/http/prometheus/PrometheusHadoopServlet.java index d09adae751e1..f5049da57b86 100644 --- a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/prometheus/PrometheusHadoop2Servlet.java +++ b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/prometheus/PrometheusHadoopServlet.java @@ -34,7 +34,7 @@ import org.apache.yetus.audience.InterfaceAudience; @InterfaceAudience.Private -public class PrometheusHadoop2Servlet extends HttpServlet { +public class PrometheusHadoopServlet extends HttpServlet { private static final Pattern SPLIT_PATTERN = Pattern.compile("(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=([A-Z][a-z]))|\\W|(_)+"); @@ -50,6 +50,11 @@ static String toPrometheusName(String metricRecordName, String metricName) { return String.join("_", parts).toLowerCase(); } + /* + * SimpleClient for Prometheus is not used, because the format is very easy to implement and this + * solution doesn't add any dependencies to the project. You can check the Prometheus format here: + * https://prometheus.io/docs/instrumenting/exposition_formats/ + */ @RestrictedApi(explanation = "Should only be called in tests", link = "", allowedOnPath = ".*/src/test/.*") void writeMetrics(Writer writer) throws IOException { diff --git a/hbase-http/src/test/java/org/apache/hadoop/hbase/http/prometheus/TestPrometheus2Servlet.java b/hbase-http/src/test/java/org/apache/hadoop/hbase/http/prometheus/TestPrometheusServlet.java similarity index 94% rename from hbase-http/src/test/java/org/apache/hadoop/hbase/http/prometheus/TestPrometheus2Servlet.java rename to hbase-http/src/test/java/org/apache/hadoop/hbase/http/prometheus/TestPrometheusServlet.java index f08ab52de314..fcfde82ad41c 100644 --- a/hbase-http/src/test/java/org/apache/hadoop/hbase/http/prometheus/TestPrometheus2Servlet.java +++ b/hbase-http/src/test/java/org/apache/hadoop/hbase/http/prometheus/TestPrometheusServlet.java @@ -39,11 +39,11 @@ * Test prometheus Sink. */ @Category({ SmallTests.class, MiscTests.class }) -public class TestPrometheus2Servlet { +public class TestPrometheusServlet { @ClassRule public static final HBaseClassTestRule CLASS_TEST_RULE = - HBaseClassTestRule.forClass(TestPrometheus2Servlet.class); + HBaseClassTestRule.forClass(TestPrometheusServlet.class); @Test public void testPublish() throws IOException { @@ -59,7 +59,7 @@ public void testPublish() throws IOException { OutputStreamWriter writer = new OutputStreamWriter(stream, UTF_8); // WHEN - PrometheusHadoop2Servlet prom2Servlet = new PrometheusHadoop2Servlet(); + PrometheusHadoopServlet prom2Servlet = new PrometheusHadoopServlet(); prom2Servlet.writeMetrics(writer); // THEN diff --git a/src/main/asciidoc/_chapters/ops_mgt.adoc b/src/main/asciidoc/_chapters/ops_mgt.adoc index ef85a1c5576c..8af14758ba8d 100644 --- a/src/main/asciidoc/_chapters/ops_mgt.adoc +++ b/src/main/asciidoc/_chapters/ops_mgt.adoc @@ -1613,11 +1613,11 @@ Restart the region server for the changes to take effect. [[enabling.metrics.servlets]] === Enabling Metrics Servlets -HBase exposes the metrics in many formats such as JSON, prometheus-format through different servlets (`/jmx`, `/metrics`, `/prometheus`, `/prometheus-hadoop2`). Any of these servlets can be enabled or disabled by the configuration property `hbase.http.metrics.servlets`. The value for the property should be a comma separated list of the servlet aliases which are `{jmx, metrics, prometheus, prometheus-hadoop2}`. `/jmx` and `/metrics` are enabled by default. To get metrics using these servlets access the URL `http://SERVER_HOSTNAME:SERVER_WEB_UI_PORT/endpoint`. Where endpoint is one of {`/jmx`, `/metrics`, `/prometheus`, `/prometheus-hadoop2`}. Eg. `http://my.rs.xyz.com:16030/prometheus-hadoop2` +HBase exposes the metrics in many formats such as JSON, prometheus-format through different servlets (`/jmx`, `/metrics`, `/prometheus`). Any of these servlets can be enabled or disabled by the configuration property `hbase.http.metrics.servlets`. The value for the property should be a comma separated list of the servlet aliases which are `{jmx, metrics, prometheus}`. `/jmx` is enabled by default. To get metrics using these servlets access the URL `http://SERVER_HOSTNAME:SERVER_WEB_UI_PORT/endpoint`. Where endpoint is one of {`/jmx`, `/metrics`, `/prometheus`}. Eg. `http://my.rs.xyz.com:16030/prometheus` [[prometheus.format.metrics]] === Prometheus servlets -HBase exposes the metrics in prometheus friendly format through two different servlets `/prometheus` and `/prometheus-hadoop2`. Currently `/prometheus-hadoop2` exposes all the available metrics. `/prometheus` is based on the HBase native metrics API and is incomplete till all the metric sources start using this native metrics API. +HBase exposes the metrics in prometheus friendly format through a servlet, `/prometheus`. Currently `/prometheus` exposes all the available metrics. [[discovering.available.metrics]] === Discovering Available Metrics From 8b8775b7689f3651b221f74c7ef0b409fbce0c2c Mon Sep 17 00:00:00 2001 From: Luca Kovacs Date: Tue, 16 Aug 2022 19:26:39 +0200 Subject: [PATCH 4/6] Fixed RestrictedAPI annotation, change in default servlet Notes: - Fixed RestrictedAPI annontation - Added '/metrics' endpoint to defaults --- hbase-common/src/main/resources/hbase-default.xml | 2 +- .../main/java/org/apache/hadoop/hbase/http/HttpServer.java | 4 ++-- .../hadoop/hbase/http/prometheus/PrometheusHadoopServlet.java | 4 ++-- src/main/asciidoc/_chapters/ops_mgt.adoc | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hbase-common/src/main/resources/hbase-default.xml b/hbase-common/src/main/resources/hbase-default.xml index 4388a55a773d..42ba70a7ac6d 100644 --- a/hbase-common/src/main/resources/hbase-default.xml +++ b/hbase-common/src/main/resources/hbase-default.xml @@ -1788,7 +1788,7 @@ possible configurations would overwhelm and obscure the important. hbase.http.metrics.servlets - jmx,prometheus + jmx,metrics,prometheus Comma separated list of servlet names to enable for metrics collection. Supported servlets are jmx, metrics, prometheus diff --git a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java index 9638010d05ea..70f8cf4481f5 100644 --- a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java +++ b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java @@ -154,7 +154,7 @@ public class HttpServer implements FilterContainer { public static final String APP_DIR = "webapps"; public static final String METRIC_SERVLETS_CONF_KEY = "hbase.http.metrics.servlets"; - public static final String METRICS_SERVLETS_DEFAULT[] = { "jmx" }; + public static final String METRICS_SERVLETS_DEFAULT[] = { "jmx", "metrics", "prometheus" }; private static final Map METRIC_SERVLETS = new HashMap() { { @@ -163,7 +163,7 @@ public class HttpServer implements FilterContainer { put("metrics", new ServletConfig("metrics", "/metrics", "org.apache.hadoop.metrics.MetricsServlet")); put("prometheus", new ServletConfig("prometheus", "/prometheus", - "org.apache.hadoop.hbase.http.prometheus.PrometheusHadoop2Servlet")); + "org.apache.hadoop.hbase.http.prometheus.PrometheusHadoopServlet")); } }; diff --git a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/prometheus/PrometheusHadoopServlet.java b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/prometheus/PrometheusHadoopServlet.java index f5049da57b86..c6e13b37c66d 100644 --- a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/prometheus/PrometheusHadoopServlet.java +++ b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/prometheus/PrometheusHadoopServlet.java @@ -55,8 +55,8 @@ static String toPrometheusName(String metricRecordName, String metricName) { * solution doesn't add any dependencies to the project. You can check the Prometheus format here: * https://prometheus.io/docs/instrumenting/exposition_formats/ */ - @RestrictedApi(explanation = "Should only be called in tests", link = "", - allowedOnPath = ".*/src/test/.*") + @RestrictedApi(explanation = "Should only be called in tests or self", link = "", + allowedOnPath = ".*/src/test/.*|.*/PrometheusHadoopServlet\\.java") void writeMetrics(Writer writer) throws IOException { Collection metricRecords = MetricsExportHelper.export(); for (MetricsRecord metricsRecord : metricRecords) { diff --git a/src/main/asciidoc/_chapters/ops_mgt.adoc b/src/main/asciidoc/_chapters/ops_mgt.adoc index 8af14758ba8d..1889b1b3b1c8 100644 --- a/src/main/asciidoc/_chapters/ops_mgt.adoc +++ b/src/main/asciidoc/_chapters/ops_mgt.adoc @@ -1613,7 +1613,7 @@ Restart the region server for the changes to take effect. [[enabling.metrics.servlets]] === Enabling Metrics Servlets -HBase exposes the metrics in many formats such as JSON, prometheus-format through different servlets (`/jmx`, `/metrics`, `/prometheus`). Any of these servlets can be enabled or disabled by the configuration property `hbase.http.metrics.servlets`. The value for the property should be a comma separated list of the servlet aliases which are `{jmx, metrics, prometheus}`. `/jmx` is enabled by default. To get metrics using these servlets access the URL `http://SERVER_HOSTNAME:SERVER_WEB_UI_PORT/endpoint`. Where endpoint is one of {`/jmx`, `/metrics`, `/prometheus`}. Eg. `http://my.rs.xyz.com:16030/prometheus` +HBase exposes the metrics in many formats such as JSON, prometheus-format through different servlets (`/jmx`, `/metrics`, `/prometheus`). Any of these servlets can be enabled or disabled by the configuration property `hbase.http.metrics.servlets`. The value for the property should be a comma separated list of the servlet aliases which are `{jmx, metrics, prometheus}`. `/jmx`, `/metrics`, `/prometheus` are enabled by default. To get metrics using these servlets access the URL `http://SERVER_HOSTNAME:SERVER_WEB_UI_PORT/endpoint`. Where endpoint is one of {`/jmx`, `/metrics`, `/prometheus`}. Eg. `http://my.rs.xyz.com:16030/prometheus` [[prometheus.format.metrics]] === Prometheus servlets From f7507b01a133bd7aeaff6a4827dac4e9471bd507 Mon Sep 17 00:00:00 2001 From: Luca Kovacs Date: Wed, 17 Aug 2022 23:10:23 +0200 Subject: [PATCH 5/6] Changes in coding style to prevent error prone or checktyle warnings --- .../metrics2/impl/MetricsExportHelper.java | 8 +++--- .../metrics/TestMetricsExportHelper.java | 4 ++- .../apache/hadoop/hbase/http/HttpServer.java | 25 +++++++++---------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/hbase-hadoop-compat/src/main/java/org/apache/hadoop/metrics2/impl/MetricsExportHelper.java b/hbase-hadoop-compat/src/main/java/org/apache/hadoop/metrics2/impl/MetricsExportHelper.java index 91ed05ae7c31..9232bcc17657 100644 --- a/hbase-hadoop-compat/src/main/java/org/apache/hadoop/metrics2/impl/MetricsExportHelper.java +++ b/hbase-hadoop-compat/src/main/java/org/apache/hadoop/metrics2/impl/MetricsExportHelper.java @@ -17,20 +17,22 @@ */ package org.apache.hadoop.metrics2.impl; +import java.util.ArrayList; import java.util.Collection; -import java.util.LinkedList; import java.util.List; import org.apache.hadoop.metrics2.MetricsRecord; import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; import org.apache.yetus.audience.InterfaceAudience; @InterfaceAudience.Private -public class MetricsExportHelper { +public final class MetricsExportHelper { + private MetricsExportHelper() { + } public static Collection export() { MetricsSystemImpl instance = (MetricsSystemImpl) DefaultMetricsSystem.instance(); MetricsBuffer metricsBuffer = instance.sampleMetrics(); - List metrics = new LinkedList<>(); + List metrics = new ArrayList<>(); for (MetricsBuffer.Entry entry : metricsBuffer) { entry.records().forEach(metrics::add); } diff --git a/hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/metrics/TestMetricsExportHelper.java b/hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/metrics/TestMetricsExportHelper.java index 8cae2fdcae51..3a86dd049663 100644 --- a/hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/metrics/TestMetricsExportHelper.java +++ b/hbase-hadoop-compat/src/test/java/org/apache/hadoop/hbase/metrics/TestMetricsExportHelper.java @@ -65,7 +65,9 @@ private boolean contains(Collection metrics, String metricsName, String metricName) { return metrics.stream().filter(mr -> mr.name().equals(metricsName)).anyMatch(mr -> { for (AbstractMetric metric : mr.metrics()) { - if (metric.name().equals(metricName)) return true; + if (metric.name().equals(metricName)) { + return true; + } } return false; }); diff --git a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java index 70f8cf4481f5..64fc02287981 100644 --- a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java +++ b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java @@ -69,6 +69,7 @@ import org.slf4j.LoggerFactory; import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; +import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableMap; import org.apache.hbase.thirdparty.com.google.common.collect.Lists; import org.apache.hbase.thirdparty.org.eclipse.jetty.http.HttpVersion; import org.apache.hbase.thirdparty.org.eclipse.jetty.server.Handler; @@ -154,18 +155,16 @@ public class HttpServer implements FilterContainer { public static final String APP_DIR = "webapps"; public static final String METRIC_SERVLETS_CONF_KEY = "hbase.http.metrics.servlets"; - public static final String METRICS_SERVLETS_DEFAULT[] = { "jmx", "metrics", "prometheus" }; - private static final Map METRIC_SERVLETS = - new HashMap() { - { - put("jmx", - new ServletConfig("jmx", "/jmx", "org.apache.hadoop.hbase.http.jmx.JMXJsonServlet")); - put("metrics", - new ServletConfig("metrics", "/metrics", "org.apache.hadoop.metrics.MetricsServlet")); - put("prometheus", new ServletConfig("prometheus", "/prometheus", - "org.apache.hadoop.hbase.http.prometheus.PrometheusHadoopServlet")); - } - }; + public static final String[] METRICS_SERVLETS_DEFAULT = { "jmx", "metrics", "prometheus" }; + private static final ImmutableMap METRIC_SERVLETS = new ImmutableMap.Builder() + .put("jmx", + new ServletConfig("jmx", "/jmx", "org.apache.hadoop.hbase.http.jmx.JMXJsonServlet")) + .put("metrics", + new ServletConfig("metrics", "/metrics", "org.apache.hadoop.metrics.MetricsServlet")) + .put("prometheus", new ServletConfig("prometheus", "/prometheus", + "org.apache.hadoop.hbase.http.prometheus.PrometheusHadoopServlet")) + .build(); private final AccessControlList adminsAcl; @@ -790,7 +789,7 @@ protected void addDefaultServlets(ContextHandlerCollection contexts, Configurati } /* register metrics servlets */ - String enabledServlets[] = conf.getStrings(METRIC_SERVLETS_CONF_KEY, METRICS_SERVLETS_DEFAULT); + String[] enabledServlets = conf.getStrings(METRIC_SERVLETS_CONF_KEY, METRICS_SERVLETS_DEFAULT); for (String enabledServlet : enabledServlets) { try { ServletConfig servletConfig = METRIC_SERVLETS.get(enabledServlet); From b1f645c2f84dff6fed9d085d42af0b5ea4aeb066 Mon Sep 17 00:00:00 2001 From: Luca Kovacs Date: Tue, 23 Aug 2022 09:52:12 +0200 Subject: [PATCH 6/6] Fixed FindBugs issue in HttpServer.java --- .../java/org/apache/hadoop/hbase/http/HttpServer.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java index 64fc02287981..50cefc4c39af 100644 --- a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java +++ b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java @@ -793,9 +793,11 @@ protected void addDefaultServlets(ContextHandlerCollection contexts, Configurati for (String enabledServlet : enabledServlets) { try { ServletConfig servletConfig = METRIC_SERVLETS.get(enabledServlet); - Class clz = Class.forName(servletConfig.getClazz()); - addPrivilegedServlet(servletConfig.getName(), servletConfig.getPathSpec(), - clz.asSubclass(HttpServlet.class)); + if (servletConfig != null) { + Class clz = Class.forName(servletConfig.getClazz()); + addPrivilegedServlet(servletConfig.getName(), servletConfig.getPathSpec(), + clz.asSubclass(HttpServlet.class)); + } } catch (Exception e) { /* shouldn't be fatal, so warn the user about it */ LOG.warn("Couldn't register the servlet " + enabledServlet, e);