Merge branch 'stable-2.15' into stable-2.16 * stable-2.15: Add option to exclude metrics Change-Id: I54c39fbff22495155aa48daeb4e518c6f817aea8
diff --git a/BUILD b/BUILD index 89cb6c3..ee7c4fb 100644 --- a/BUILD +++ b/BUILD
@@ -5,8 +5,8 @@ srcs = glob(["src/main/java/**/*.java"]), manifest_entries = [ "Gerrit-PluginName: metrics-reporter-prometheus", - "Gerrit-Module: com.googlesource.gerrit.plugins.metricsreporters.GerritPrometheusModule", - "Gerrit-HttpModule: com.googlesource.gerrit.plugins.metricsreporters.GerritPrometheusHttpModule", + "Gerrit-Module: com.googlesource.gerrit.plugins.metricsreporterprometheus.GerritPrometheusModule", + "Gerrit-HttpModule: com.googlesource.gerrit.plugins.metricsreporterprometheus.GerritPrometheusHttpModule", ], resources = glob(["src/main/resources/**/*"]), deps = [
diff --git a/src/main/java/com/googlesource/gerrit/plugins/metricsreporters/CapabilityChecker.java b/src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/CapabilityChecker.java similarity index 94% rename from src/main/java/com/googlesource/gerrit/plugins/metricsreporters/CapabilityChecker.java rename to src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/CapabilityChecker.java index ae7bc93..f1b936e 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/metricsreporters/CapabilityChecker.java +++ b/src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/CapabilityChecker.java
@@ -11,7 +11,7 @@ // 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.googlesource.gerrit.plugins.metricsreporters; +package com.googlesource.gerrit.plugins.metricsreporterprometheus; import com.google.common.collect.ImmutableSet; import com.google.gerrit.extensions.annotations.PluginName; @@ -44,7 +44,7 @@ public boolean canViewMetrics() { try { permissionBackend - .user(userProvider) + .user(userProvider.get()) .checkAny( ImmutableSet.of( GlobalPermission.ADMINISTRATE_SERVER,
diff --git a/src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/FilteredMetricRegistry.java b/src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/FilteredMetricRegistry.java new file mode 100644 index 0000000..87cdcbd --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/FilteredMetricRegistry.java
@@ -0,0 +1,61 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// 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.googlesource.gerrit.plugins.metricsreporterprometheus; + +import com.codahale.metrics.Counter; +import com.codahale.metrics.Gauge; +import com.codahale.metrics.Histogram; +import com.codahale.metrics.Meter; +import com.codahale.metrics.MetricFilter; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Timer; +import java.util.SortedMap; +import java.util.function.Predicate; + +public class FilteredMetricRegistry extends MetricRegistry { + private final MetricRegistry registry; + private final MetricFilter nonExcluded; + + FilteredMetricRegistry(MetricRegistry registry, Predicate<String> exclusionFilter) { + this.registry = registry; + this.nonExcluded = (n, m) -> !exclusionFilter.test(n); + } + + @Override + @SuppressWarnings("rawtypes") + public SortedMap<String, Gauge> getGauges() { + return registry.getGauges(nonExcluded); + } + + @Override + public SortedMap<String, Counter> getCounters() { + return registry.getCounters(nonExcluded); + } + + @Override + public SortedMap<String, Histogram> getHistograms() { + return registry.getHistograms(nonExcluded); + } + + @Override + public SortedMap<String, Timer> getTimers() { + return registry.getTimers(nonExcluded); + } + + @Override + public SortedMap<String, Meter> getMeters() { + return registry.getMeters(nonExcluded); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/GerritBuildInformationMetric.java b/src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/GerritBuildInformationMetric.java new file mode 100644 index 0000000..0f567b5 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/GerritBuildInformationMetric.java
@@ -0,0 +1,65 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// 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.googlesource.gerrit.plugins.metricsreporterprometheus; + +import com.google.gerrit.common.Version; +import io.prometheus.client.Counter; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; + +public class GerritBuildInformationMetric { + static final Counter requests = + Counter.build() + .name("gerrit_build_info") + .help("Gerrit build information.") + .labelNames("javaversion", "version", "revision") + .register(); + + public void compute() { + GerritVersionInfo versionInfo = extractVersionComponents(); + requests.labels(getJavaVersion(), versionInfo.version, versionInfo.revision); + } + + private static String getJavaVersion() { + RuntimeMXBean mxBean = ManagementFactory.getRuntimeMXBean(); + return String.format("%s(%s)", mxBean.getSpecVersion(), mxBean.getVmVersion()); + } + + private static GerritVersionInfo extractVersionComponents() { + GerritVersionInfo versionInfo = new GerritVersionInfo(); + String fullVersion = Version.getVersion(); + + if (fullVersion == null) { + return versionInfo; + } + + String[] versionComponents = fullVersion.split("-"); + + versionInfo.version = versionComponents[0]; + + if (versionComponents.length > 2) { + versionInfo.revision = versionComponents.length > 2 ? versionComponents[2].substring(1) : ""; + } else { + versionInfo.revision = ""; + } + + return versionInfo; + } + + private static class GerritVersionInfo { + String revision = "unknown"; + String version = "unknown"; + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/GerritPrometheusExporter.java b/src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/GerritPrometheusExporter.java new file mode 100644 index 0000000..0dba67a --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/GerritPrometheusExporter.java
@@ -0,0 +1,96 @@ +// Copyright (C) 2018 The Android Open Source Project +// +// 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.googlesource.gerrit.plugins.metricsreporterprometheus; + +import static java.util.stream.Collectors.toList; + +import com.codahale.metrics.MetricRegistry; +import com.google.common.base.Strings; +import com.google.common.net.HttpHeaders; +import com.google.gerrit.extensions.annotations.PluginName; +import com.google.gerrit.server.config.PluginConfigFactory; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import io.prometheus.client.CollectorRegistry; +import io.prometheus.client.dropwizard.DropwizardExports; +import io.prometheus.client.exporter.MetricsServlet; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.regex.Pattern; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@SuppressWarnings("serial") +@Singleton +public class GerritPrometheusExporter extends MetricsServlet { + private static final String PROMETHEUS_BEARER_TOKEN = "prometheusBearerToken"; + private static final String EXCLUDE_KEY = "excludeMetrics"; + + private final GerritBuildInformationMetric gerritBuildInfoMetric; + private final CapabilityChecker capabilityChecker; + private final String prometheusBearerToken; + + @Inject + public GerritPrometheusExporter( + MetricRegistry registry, + CapabilityChecker capabilityChecker, + PluginConfigFactory cfgFactory, + @PluginName String pluginName) { + this.capabilityChecker = capabilityChecker; + this.prometheusBearerToken = + cfgFactory.getFromGerritConfig(pluginName).getString(PROMETHEUS_BEARER_TOKEN); + this.gerritBuildInfoMetric = new GerritBuildInformationMetric(); + + List<Pattern> excludes = + Arrays.stream(cfgFactory.getFromGerritConfig(pluginName).getStringList(EXCLUDE_KEY)) + .map(Pattern::compile) + .collect(toList()); + + FilteredMetricRegistry filteredRegistry = + new FilteredMetricRegistry( + registry, s -> excludes.stream().anyMatch(e -> e.matcher(s).matches())); + + // Hook the Dropwizard registry into the Prometheus registry + // via the DropwizardExports collector. + CollectorRegistry.defaultRegistry.register(new DropwizardExports(filteredRegistry)); + } + + @Override + public void service(ServletRequest req, ServletResponse res) + throws ServletException, IOException { + if (capabilityChecker.canViewMetrics() || canExportUsingPrometheusBearerToken(req)) { + gerritBuildInfoMetric.compute(); + super.service(req, res); + } else { + HttpServletResponse httpResponse = (HttpServletResponse) res; + httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Forbidden access"); + } + } + + private boolean canExportUsingPrometheusBearerToken(ServletRequest req) { + if (Strings.isNullOrEmpty(prometheusBearerToken)) { + return false; + } + + HttpServletRequest httpRequest = (HttpServletRequest) req; + return Optional.ofNullable(httpRequest.getHeader(HttpHeaders.AUTHORIZATION)) + .map(h -> h.equals("Bearer " + prometheusBearerToken)) + .orElse(false); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/metricsreporters/GerritPrometheusHttpModule.java b/src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/GerritPrometheusHttpModule.java similarity index 92% rename from src/main/java/com/googlesource/gerrit/plugins/metricsreporters/GerritPrometheusHttpModule.java rename to src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/GerritPrometheusHttpModule.java index 5764c38..0a2a625 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/metricsreporters/GerritPrometheusHttpModule.java +++ b/src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/GerritPrometheusHttpModule.java
@@ -11,7 +11,7 @@ // 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.googlesource.gerrit.plugins.metricsreporters; +package com.googlesource.gerrit.plugins.metricsreporterprometheus; import com.google.inject.servlet.ServletModule;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/metricsreporters/GerritPrometheusModule.java b/src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/GerritPrometheusModule.java similarity index 93% rename from src/main/java/com/googlesource/gerrit/plugins/metricsreporters/GerritPrometheusModule.java rename to src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/GerritPrometheusModule.java index 36c8663..591e81e 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/metricsreporters/GerritPrometheusModule.java +++ b/src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/GerritPrometheusModule.java
@@ -11,7 +11,7 @@ // 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.googlesource.gerrit.plugins.metricsreporters; +package com.googlesource.gerrit.plugins.metricsreporterprometheus; import com.google.gerrit.extensions.annotations.Exports; import com.google.gerrit.extensions.config.CapabilityDefinition;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/metricsreporters/ViewMetricsCapability.java b/src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/ViewMetricsCapability.java similarity index 92% rename from src/main/java/com/googlesource/gerrit/plugins/metricsreporters/ViewMetricsCapability.java rename to src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/ViewMetricsCapability.java index c3d22e0..8bb5157 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/metricsreporters/ViewMetricsCapability.java +++ b/src/main/java/com/googlesource/gerrit/plugins/metricsreporterprometheus/ViewMetricsCapability.java
@@ -11,7 +11,7 @@ // 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.googlesource.gerrit.plugins.metricsreporters; +package com.googlesource.gerrit.plugins.metricsreporterprometheus; import com.google.gerrit.extensions.config.CapabilityDefinition;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/metricsreporters/GerritPrometheusExporter.java b/src/main/java/com/googlesource/gerrit/plugins/metricsreporters/GerritPrometheusExporter.java deleted file mode 100644 index 217badb..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/metricsreporters/GerritPrometheusExporter.java +++ /dev/null
@@ -1,83 +0,0 @@ -// Copyright (C) 2018 The Android Open Source Project -// -// 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.googlesource.gerrit.plugins.metricsreporters; - -import com.codahale.metrics.Metric; -import com.codahale.metrics.MetricFilter; -import com.codahale.metrics.MetricRegistry; -import com.google.gerrit.extensions.annotations.PluginName; -import com.google.gerrit.server.config.PluginConfigFactory; -import com.google.inject.Inject; -import com.google.inject.Singleton; -import io.prometheus.client.CollectorRegistry; -import io.prometheus.client.dropwizard.DropwizardExports; -import io.prometheus.client.exporter.MetricsServlet; -import java.io.IOException; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletResponse; - -@SuppressWarnings("serial") -@Singleton -public class GerritPrometheusExporter extends MetricsServlet { - CapabilityChecker capabilityChecker; - private static final String EXCLUDE_KEY = "excludeMetrics"; - - @Inject - public GerritPrometheusExporter( - MetricRegistry registry, - CapabilityChecker capabilityChecker, - PluginConfigFactory cfgFactory, - @PluginName String pluginName) { - this.capabilityChecker = capabilityChecker; - - /* Copy the registry to avoid filtering the global one */ - MetricRegistry filteredRegistry = new MetricRegistry(); - filteredRegistry.registerAll(registry); - - Set<String> excludedMetrics = new HashSet<>(); - excludedMetrics.addAll( - Arrays.asList(cfgFactory.getFromGerritConfig(pluginName).getStringList(EXCLUDE_KEY))); - - excludedMetrics.forEach( - exclude -> { - filteredRegistry.removeMatching( - new MetricFilter() { - @Override - public boolean matches(String name, Metric metric) { - return name.matches(exclude); - } - }); - }); - - // Hook the Dropwizard registry into the Prometheus registry - // via the DropwizardExports collector. - CollectorRegistry.defaultRegistry.register(new DropwizardExports(filteredRegistry)); - } - - @Override - public void service(ServletRequest req, ServletResponse res) - throws ServletException, IOException { - if (capabilityChecker.canViewMetrics()) { - super.service(req, res); - } else { - HttpServletResponse httpResponse = (HttpServletResponse) res; - httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Forbidden access"); - } - } -};
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md index 0092de0..96f347e 100644 --- a/src/main/resources/Documentation/about.md +++ b/src/main/resources/Documentation/about.md
@@ -4,4 +4,5 @@ To access the monitoring URL, a user must be a member of a group that is granted the ‘View Metrics’ capability (provided by this plugin) or the ‘Administrate -Server’ capability. \ No newline at end of file +Server’ capability. Alternatively, authentication using prometheus bearer token +is also supported.
diff --git a/src/main/resources/Documentation/build.md b/src/main/resources/Documentation/build.md index df13ebc..3550c50 100644 --- a/src/main/resources/Documentation/build.md +++ b/src/main/resources/Documentation/build.md
@@ -26,7 +26,7 @@ The output is created in ``` - bazel-genfiles/plugins/@PLUGIN@/@PLUGIN@.jar + bazel-bin/plugins/@PLUGIN@/@PLUGIN@.jar ``` This project can be imported into the Eclipse IDE.
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md index 265a6c7..070151f 100644 --- a/src/main/resources/Documentation/config.md +++ b/src/main/resources/Documentation/config.md
@@ -1,9 +1,13 @@ Configuration ============= +The configuration of the @PLUGIN@ plugin is done in the `gerrit.config` +file. + To access the monitoring URL, a user must be a member of a group that is granted the ‘View Metrics’ capability (provided by this plugin) or the ‘Administrate -Server’ capability.This plugin requires no configuration. +Server’ capability. Alternatively, authentication using prometheus bearer token +is also supported. This capability can be configured in the 'Global Capabilities' section of the ['All-Projects'](@URL@#/admin/projects/All-Projects,access) access right. @@ -11,12 +15,22 @@ It is possible to allow anonymous access to the metrics by giving the capability to the 'Anonymous Users' group. +plugin.@PLUGIN@.prometheusBearerToken +: Bearer token for allowing Prometheus to query Gerrit metrics through its scraper. + Defaults to undefine. + +When defined, access to the plugins/@PLUGIN@/metrics URL does not require any +authentication and do not check any ACL related to the ‘View Metrics’ global capability. +See [Prometheus documentation](https://prometheus.io/docs/prometheus/latest/configuration/configuration) +for how to configure the integration with Prometheus. + plugin.@PLUGIN@.excludeMetrics -: String used to exclude metrics from the report. It can be specified multiple times. - Parsed as regular expression. Note, ^ and $ are automatically added around the string. +: Regex pattern used to exclude metrics from the report. It can be specified multiple times. + Note that pattern matching is done on the whole metric name, not only on a part of it. By default no metric is excluded. For example, to exclude all cache metrics, use: `excludeMetrics = cache.*` + [Back to @PLUGIN@ documentation index][index] -[index]: index.html \ No newline at end of file +[index]: index.html