Add grace period to avoid collecting stats too often
Some stats might be too heavy to compute.
Added a grace period to avoid too frequent collection.
Bug: Issue 15971
Change-Id: I54adfe04e8aec8f7fd1b7d8bf12367422b5e04e1
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCache.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCache.java
index dfabe10..f1d46b2 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCache.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCache.java
@@ -14,42 +14,62 @@
package com.googlesource.gerrit.plugins.gitrepometrics;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Supplier;
import com.google.common.collect.Maps;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.metrics.Description;
import com.google.gerrit.metrics.MetricMaker;
import com.google.inject.Inject;
-import com.google.inject.Singleton;
import com.googlesource.gerrit.plugins.gitrepometrics.collectors.GitRepoMetric;
import com.googlesource.gerrit.plugins.gitrepometrics.collectors.GitStats;
+import java.time.Clock;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-@Singleton
public class GitRepoMetricsCache {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private Map<String, Long> metrics;
private final MetricMaker metricMaker;
private final List<String> projects;
+ private Map<String, Long> collectedAt;
+ private final long gracePeriodMs;
+
+ private final Clock clock;
public static List<GitRepoMetric> metricsNames = new ArrayList<>(GitStats.availableMetrics());
- @Inject
- GitRepoMetricsCache(MetricMaker metricMaker, GitRepoMetricsConfig config) {
+ @VisibleForTesting
+ GitRepoMetricsCache(MetricMaker metricMaker, GitRepoMetricsConfig config, Clock clock) {
this.metricMaker = metricMaker;
this.projects = config.getRepositoryNames();
this.metrics = Maps.newHashMap();
+ this.collectedAt = Maps.newHashMap();
+ this.clock = clock;
+ this.gracePeriodMs = config.getGracePeriodMs();
+ }
+
+ @Inject
+ GitRepoMetricsCache(MetricMaker metricMaker, GitRepoMetricsConfig config) {
+ this(metricMaker, config, Clock.systemDefaultZone());
}
public Map<String, Long> getMetrics() {
return metrics;
}
- public void setMetrics(Map<String, Long> metrics) {
+ public void setMetrics(Map<String, Long> metrics, String projectName) {
+ this.collectedAt.put(projectName, clock.millis());
this.metrics = metrics;
}
+ @VisibleForTesting
+ public Map<String, Long> getCollectedAt() {
+ return collectedAt;
+ }
+
public void initCache() {
metricsNames.forEach(
gitRepoMetric -> {
@@ -84,6 +104,16 @@
}
public boolean shouldCollectStats(String projectName) {
+ long lastCollectionTime = collectedAt.getOrDefault(projectName, 0L);
+ long currentTimeMs = System.currentTimeMillis();
+ boolean doCollectStats = lastCollectionTime + gracePeriodMs <= currentTimeMs;
+ if (!doCollectStats) {
+ logger.atFine().log(
+ "Skip stats collection for %s (grace period: %d, last collection time: %d, current time: %d",
+ projectName, gracePeriodMs, lastCollectionTime, currentTimeMs);
+ return false;
+ }
+
return projects.stream().anyMatch(p -> p.equals(projectName));
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsConfig.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsConfig.java
index a9937cf..a588a73 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsConfig.java
@@ -22,6 +22,7 @@
import com.google.inject.Singleton;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.TimeUnit;
import org.eclipse.jgit.lib.Config;
@Singleton
@@ -38,4 +39,8 @@
public List<String> getRepositoryNames() {
return Arrays.stream(config.getStringList(pluginName, null, "project")).collect(toList());
}
+
+ public Long getGracePeriodMs() {
+ return config.getTimeUnit("git-repo-metrics", null, "gracePeriod", 0L, TimeUnit.MILLISECONDS);
+ }
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoUpdateListener.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoUpdateListener.java
index 1411c61..e9e4d98 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoUpdateListener.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoUpdateListener.java
@@ -23,7 +23,7 @@
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private final ExecutorService executor;
private final UpdateGitMetricsTask.Factory updateGitMetricsTaskFactory;
- private GitRepoMetricsCache gitRepoMetricsCache;
+ private final GitRepoMetricsCache gitRepoMetricsCache;
@Inject
GitRepoUpdateListener(
@@ -40,11 +40,9 @@
String projectName = event.getProjectName();
logger.atFine().log("Got an update for project %s", projectName);
- if (!gitRepoMetricsCache.shouldCollectStats(projectName)) {
- return;
+ if (gitRepoMetricsCache.shouldCollectStats(projectName)) {
+ UpdateGitMetricsTask updateGitMetricsTask = updateGitMetricsTaskFactory.create(projectName);
+ executor.execute(updateGitMetricsTask);
}
-
- UpdateGitMetricsTask updateGitMetricsTask = updateGitMetricsTaskFactory.create(projectName);
- executor.execute(updateGitMetricsTask);
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTask.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTask.java
index 2196a06..ed120e5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTask.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTask.java
@@ -61,7 +61,7 @@
Map<String, Long> newMetrics = gitStats.get();
logger.atInfo().log(
"Here all the metrics for %s - %s", project.getName(), getStringFromMap(newMetrics));
- gitRepoMetricsCache.setMetrics(newMetrics);
+ gitRepoMetricsCache.setMetrics(newMetrics, projectName);
} catch (RepositoryNotFoundException e) {
logger.atSevere().withCause(e).log("Cannot find repository for %s", projectName);
} catch (IOException e) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/GitStats.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/GitStats.java
index 5a32a5b..2eab2f9 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/GitStats.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/GitStats.java
@@ -81,4 +81,8 @@
private void putMetric(Map<String, Long> metrics, String metricName, long value) {
metrics.put(GitRepoMetricsCache.getMetricName(metricName, p.getName()), value);
}
+
+ public String getStatName() {
+ return "git-statistics";
+ }
}
diff --git a/src/resources/Documentation/config.md b/src/resources/Documentation/config.md
index 3ba47a9..26d162e 100644
--- a/src/resources/Documentation/config.md
+++ b/src/resources/Documentation/config.md
@@ -30,4 +30,8 @@
[git-repo-metrics]
project = test-project
project = another-repo
-```
\ No newline at end of file
+ gracePeriod = 5m
+```
+
+_git-repo-metrics.gracePeriod_: Grace period between samples collection. Used to avoid aggressive
+metrics collection. By default, 0.
\ No newline at end of file
diff --git a/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/ConfigSetupUtils.java b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/ConfigSetupUtils.java
index fc74cef..2872ea9 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/ConfigSetupUtils.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/ConfigSetupUtils.java
@@ -27,15 +27,21 @@
import org.eclipse.jgit.lib.Config;
public class ConfigSetupUtils {
- final static String pluginName = "git-repo-metrics";
+ static final String pluginName = "git-repo-metrics";
private final Path basePath;
private final Path gitBasePath;
private final List<String> projects;
+ private final String gracePeriod;
public ConfigSetupUtils(List<String> projects) throws IOException {
+ this(projects, "0");
+ }
+
+ public ConfigSetupUtils(List<String> projects, String gracePeriod) throws IOException {
this.basePath = Files.createTempDirectory("git_repo_metrics_");
this.gitBasePath = new File(basePath.toFile(), "git").toPath();
this.projects = projects;
+ this.gracePeriod = gracePeriod;
}
public GitRepoMetricsConfig getGitRepoMetricsConfig() {
@@ -50,6 +56,7 @@
Config c = new Config();
c.setStringList(pluginName, null, "project", projects);
+ c.setString(pluginName, null, "gracePeriod", gracePeriod);
c.setString("gerrit", null, "basePath", gitBasePath.toString());
return c;
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheTest.java b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheTest.java
index 7a3cf5a..70c2dd9 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheTest.java
@@ -16,17 +16,21 @@
import static com.google.common.truth.Truth.assertThat;
+import com.google.common.collect.ImmutableMap;
import com.google.gerrit.metrics.CallbackMetric0;
import com.google.gerrit.metrics.Description;
import com.google.gerrit.metrics.DisabledMetricMaker;
import com.googlesource.gerrit.plugins.gitrepometrics.collectors.GitStats;
import java.io.IOException;
+import java.time.Clock;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
import java.util.Collections;
import org.junit.Before;
import org.junit.Test;
public class GitRepoMetricsCacheTest {
- GitRepoMetricsCache gitRepoMetricsCacheModule;
+ GitRepoMetricsCache gitRepoMetricsCache;
GitRepoMetricsConfig gitRepoMetricsConfig;
FakeMetricMaker fakeMetricMaker;
private ConfigSetupUtils configSetupUtils;
@@ -41,28 +45,81 @@
public void shouldRegisterMetrics() throws IOException {
gitRepoMetricsConfig = configSetupUtils.getGitRepoMetricsConfig();
fakeMetricMaker = new FakeMetricMaker();
- gitRepoMetricsCacheModule = new GitRepoMetricsCache(fakeMetricMaker, gitRepoMetricsConfig);
- gitRepoMetricsCacheModule.initCache();
+ gitRepoMetricsCache = new GitRepoMetricsCache(fakeMetricMaker, gitRepoMetricsConfig);
+ gitRepoMetricsCache.initCache();
assertThat(fakeMetricMaker.callsCounter).isEqualTo(GitStats.availableMetrics().size());
}
@Test
public void shouldCollectStatsForEnabledRepo() throws IOException {
gitRepoMetricsConfig = configSetupUtils.getGitRepoMetricsConfig();
- gitRepoMetricsCacheModule =
- new GitRepoMetricsCache(new FakeMetricMaker(), gitRepoMetricsConfig);
+ gitRepoMetricsCache = new GitRepoMetricsCache(new FakeMetricMaker(), gitRepoMetricsConfig);
- assertThat(gitRepoMetricsCacheModule.shouldCollectStats(enabledRepo)).isTrue();
+ assertThat(gitRepoMetricsCache.shouldCollectStats(enabledRepo)).isTrue();
}
@Test
public void shouldNotCollectStatsForDisabledRepo() throws IOException {
String disabledRepo = "disabledRepo";
gitRepoMetricsConfig = configSetupUtils.getGitRepoMetricsConfig();
- gitRepoMetricsCacheModule =
- new GitRepoMetricsCache(new FakeMetricMaker(), gitRepoMetricsConfig);
+ gitRepoMetricsCache = new GitRepoMetricsCache(new FakeMetricMaker(), gitRepoMetricsConfig);
- assertThat(gitRepoMetricsCacheModule.shouldCollectStats(disabledRepo)).isFalse();
+ assertThat(gitRepoMetricsCache.shouldCollectStats(disabledRepo)).isFalse();
+ }
+
+ @Test
+ public void shouldCollectStatsWhenGracePeriodNotSet() throws IOException {
+ ConfigSetupUtils configSetupUtils =
+ new ConfigSetupUtils(Collections.singletonList(enabledRepo));
+ gitRepoMetricsConfig = configSetupUtils.getGitRepoMetricsConfig();
+ gitRepoMetricsCache = new GitRepoMetricsCache(new FakeMetricMaker(), gitRepoMetricsConfig);
+
+ gitRepoMetricsCache.setMetrics(ImmutableMap.of("anyMetric", 0L), enabledRepo);
+
+ assertThat(gitRepoMetricsCache.shouldCollectStats(enabledRepo)).isTrue();
+ }
+
+ @Test
+ public void shouldSkipCollectionWhenGracePeriodIsNotExpired() throws IOException {
+ ConfigSetupUtils configSetupUtils =
+ new ConfigSetupUtils(Collections.singletonList(enabledRepo), "5 m");
+ gitRepoMetricsConfig = configSetupUtils.getGitRepoMetricsConfig();
+ gitRepoMetricsCache = new GitRepoMetricsCache(new FakeMetricMaker(), gitRepoMetricsConfig);
+
+ gitRepoMetricsCache.setMetrics(ImmutableMap.of("anyMetric", 0L), enabledRepo);
+
+ assertThat(gitRepoMetricsCache.shouldCollectStats(enabledRepo)).isFalse();
+ }
+
+ @Test
+ public void shouldCollectStatsWhenGracePeriodIsExpired() throws IOException {
+ ConfigSetupUtils configSetupUtils =
+ new ConfigSetupUtils(Collections.singletonList(enabledRepo), "1 s");
+ gitRepoMetricsConfig = configSetupUtils.getGitRepoMetricsConfig();
+ gitRepoMetricsCache =
+ new GitRepoMetricsCache(
+ new FakeMetricMaker(),
+ gitRepoMetricsConfig,
+ Clock.fixed(
+ Instant.now().minus(2, ChronoUnit.SECONDS), Clock.systemDefaultZone().getZone()));
+
+ gitRepoMetricsCache.setMetrics(ImmutableMap.of("anyMetric", 0L), enabledRepo);
+
+ assertThat(gitRepoMetricsCache.shouldCollectStats(enabledRepo)).isTrue();
+ }
+
+ @Test
+ public void shouldSetCollectionTime() throws IOException {
+ ConfigSetupUtils configSetupUtils =
+ new ConfigSetupUtils(Collections.singletonList(enabledRepo));
+ gitRepoMetricsConfig = configSetupUtils.getGitRepoMetricsConfig();
+ gitRepoMetricsCache = new GitRepoMetricsCache(new FakeMetricMaker(), gitRepoMetricsConfig);
+
+ long currentTimeStamp = System.currentTimeMillis();
+
+ gitRepoMetricsCache.setMetrics(ImmutableMap.of("anyMetric", 0L), enabledRepo);
+
+ assertThat(gitRepoMetricsCache.getCollectedAt().get(enabledRepo)).isAtLeast(currentTimeStamp);
}
private class FakeMetricMaker extends DisabledMetricMaker {