Introduce basic metrics for the owners plugin
The following metrics groups were introduced:
1. configuration load:
* plugins/owners/count_configuration_loads: config loads counter
* plugins/owners/load_configuration_latency: latency for config load
2. owners submit rule execution (note that it is referenced from both
Gerrit internals and from the submit requirements predicate):
* plugins/owners/count_submit_rule_runs: rule evaluation counter
* plugins/owners/run_submit_rule_latency: rule evaluation latency
Bug: Issue 15556
Change-Id: Ibffd10b79affbe5280a63384e713074e9c9d34ca
diff --git a/owners/src/main/java/com/googlesource/gerrit/owners/OwnersMetrics.java b/owners/src/main/java/com/googlesource/gerrit/owners/OwnersMetrics.java
new file mode 100644
index 0000000..5cc8e19
--- /dev/null
+++ b/owners/src/main/java/com/googlesource/gerrit/owners/OwnersMetrics.java
@@ -0,0 +1,60 @@
+// Copyright (C) 2023 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.owners;
+
+import com.google.gerrit.metrics.Counter0;
+import com.google.gerrit.metrics.Description;
+import com.google.gerrit.metrics.Description.Units;
+import com.google.gerrit.metrics.MetricMaker;
+import com.google.gerrit.metrics.Timer0;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+@Singleton
+class OwnersMetrics {
+ final Counter0 countConfigLoads;
+ final Timer0 loadConfig;
+
+ final Counter0 countSubmitRuleRuns;
+ final Timer0 runSubmitRule;
+
+ @Inject
+ OwnersMetrics(MetricMaker metricMaker) {
+ this.countConfigLoads =
+ createCounter(
+ metricMaker, "count_configuration_loads", "Total number of owners configuration loads");
+ this.loadConfig =
+ createTimer(
+ metricMaker,
+ "load_configuration_latency",
+ "Latency for loading owners configuration for a change");
+
+ this.countSubmitRuleRuns =
+ createCounter(
+ metricMaker, "count_submit_rule_runs", "Total number of owners submit rule runs");
+ this.runSubmitRule =
+ createTimer(
+ metricMaker, "run_submit_rule_latency", "Latency for running the owners submit rule");
+ }
+
+ private static Counter0 createCounter(MetricMaker metricMaker, String name, String description) {
+ return metricMaker.newCounter(name, new Description(description).setRate());
+ }
+
+ private static Timer0 createTimer(MetricMaker metricMaker, String name, String description) {
+ return metricMaker.newTimer(
+ name, new Description(description).setCumulative().setUnit(Units.MILLISECONDS));
+ }
+}
diff --git a/owners/src/main/java/com/googlesource/gerrit/owners/OwnersSubmitRequirement.java b/owners/src/main/java/com/googlesource/gerrit/owners/OwnersSubmitRequirement.java
index cfa4064..c6af4c8 100644
--- a/owners/src/main/java/com/googlesource/gerrit/owners/OwnersSubmitRequirement.java
+++ b/owners/src/main/java/com/googlesource/gerrit/owners/OwnersSubmitRequirement.java
@@ -31,6 +31,7 @@
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.SubmitRecord;
import com.google.gerrit.extensions.annotations.Exports;
+import com.google.gerrit.metrics.Timer0;
import com.google.gerrit.server.approval.ApprovalsUtil;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.notedb.ChangeNotes;
@@ -75,6 +76,7 @@
private static final LegacySubmitRequirement SUBMIT_REQUIREMENT =
LegacySubmitRequirement.builder().setFallbackText("Owners").setType("owners").build();
+ private final OwnersMetrics metrics;
private final PluginSettings pluginSettings;
private final ProjectCache projectCache;
private final Accounts accounts;
@@ -84,12 +86,14 @@
@Inject
OwnersSubmitRequirement(
+ OwnersMetrics metrics,
PluginSettings pluginSettings,
ProjectCache projectCache,
Accounts accounts,
GitRepositoryManager repoManager,
DiffOperations diffOperations,
ApprovalsUtil approvalsUtil) {
+ this.metrics = metrics;
this.pluginSettings = pluginSettings;
this.projectCache = projectCache;
this.accounts = accounts;
@@ -112,7 +116,8 @@
return Optional.empty();
}
- try {
+ metrics.countSubmitRuleRuns.increment();
+ try (Timer0.Context ctx = metrics.runSubmitRule.start()) {
ProjectState projectState = getProjectState(project);
PathOwners pathOwners = getPathOwners(cd, projectState);
Map<String, Set<Account.Id>> fileOwners = pathOwners.getFileOwners();
@@ -187,26 +192,29 @@
private PathOwners getPathOwners(ChangeData cd, ProjectState projectState)
throws IOException, DiffNotAvailableException {
- String branch = cd.change().getDest().branch();
+ metrics.countConfigLoads.increment();
+ try (Timer0.Context ctx = metrics.loadConfig.start()) {
+ String branch = cd.change().getDest().branch();
- List<Project.NameKey> parents =
- Optional.<Project.NameKey>ofNullable(projectState.getProject().getParent())
- .map(Arrays::asList)
- .orElse(Collections.emptyList());
+ List<Project.NameKey> parents =
+ Optional.<Project.NameKey>ofNullable(projectState.getProject().getParent())
+ .map(Arrays::asList)
+ .orElse(Collections.emptyList());
- Project.NameKey nameKey = projectState.getNameKey();
- try (Repository repo = repoManager.openRepository(nameKey)) {
- PathOwners pathOwners =
- new PathOwners(
- accounts,
- repoManager,
- repo,
- parents,
- pluginSettings.isBranchDisabled(branch) ? Optional.empty() : Optional.of(branch),
- getDiff(nameKey, cd.currentPatchSet().commitId()),
- pluginSettings.expandGroups());
+ Project.NameKey nameKey = projectState.getNameKey();
+ try (Repository repo = repoManager.openRepository(nameKey)) {
+ PathOwners pathOwners =
+ new PathOwners(
+ accounts,
+ repoManager,
+ repo,
+ parents,
+ pluginSettings.isBranchDisabled(branch) ? Optional.empty() : Optional.of(branch),
+ getDiff(nameKey, cd.currentPatchSet().commitId()),
+ pluginSettings.expandGroups());
- return pathOwners;
+ return pathOwners;
+ }
}
}
diff --git a/owners/src/main/resources/Documentation/metrcis.md b/owners/src/main/resources/Documentation/metrcis.md
new file mode 100644
index 0000000..c1927b7
--- /dev/null
+++ b/owners/src/main/resources/Documentation/metrcis.md
@@ -0,0 +1,17 @@
+Metrics
+=============
+
+The following metrics are emitted when submit requirements are enabled
+(`owners.enableSubmitRequirement = true`):
+
+* plugins/owners/count_configuration_loads
+ : the total number of owners configuration loads.
+
+* plugins/owners/load_configuration_latency
+ : the latency for loading owners configuration for a change.
+
+* plugins/owners/count_submit_rule_runs
+ : the total number of owners submit rule runs.
+
+* plugins/owners/run_submit_rule_latency
+ : the latency for running the owners submit rule.
diff --git a/owners/src/test/java/com/googlesource/gerrit/owners/OwnersMetricsIT.java b/owners/src/test/java/com/googlesource/gerrit/owners/OwnersMetricsIT.java
new file mode 100644
index 0000000..b241b66
--- /dev/null
+++ b/owners/src/test/java/com/googlesource/gerrit/owners/OwnersMetricsIT.java
@@ -0,0 +1,68 @@
+// Copyright (C) 2023 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.owners;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import com.codahale.metrics.MetricRegistry;
+import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
+import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.acceptance.TestPlugin;
+import com.google.gerrit.acceptance.UseLocalDisk;
+import com.google.gerrit.acceptance.config.GlobalPluginConfig;
+import com.google.inject.Inject;
+import org.junit.Test;
+
+@TestPlugin(name = "owners", sysModule = "com.googlesource.gerrit.owners.OwnersModule")
+@UseLocalDisk
+public class OwnersMetricsIT extends LightweightPluginDaemonTest {
+ @Inject MetricRegistry metricRegistry;
+
+ @Test
+ @GlobalPluginConfig(
+ pluginName = "owners",
+ name = "owners.enableSubmitRequirement",
+ value = "true")
+ public void shouldOwnersMetricsBeAvailable() throws Exception {
+ // one needs to at least create the OWNERS file to have metrics emitted
+ TestAccount admin2 = accountCreator.admin2();
+ addOwnerFileToRoot(true, admin2);
+
+ assertMetricExists("plugins/owners/count_configuration_loads");
+ assertMetricExists("plugins/owners/load_configuration_latency");
+ assertMetricExists("plugins/owners/count_submit_rule_runs");
+ assertMetricExists("plugins/owners/run_submit_rule_latency");
+ }
+
+ private void assertMetricExists(String name) {
+ assertWithMessage(name).that(metricRegistry.getMetrics().get(name)).isNotNull();
+ }
+
+ private void addOwnerFileToRoot(boolean inherit, TestAccount u) throws Exception {
+ // Add OWNERS file to root:
+ //
+ // inherited: true
+ // owners:
+ // - u.email()
+ merge(
+ createChange(
+ testRepo,
+ "master",
+ "Add OWNER file",
+ "OWNERS",
+ String.format("inherited: %s\nowners:\n- %s\n", inherit, u.email()),
+ ""));
+ }
+}