Add filesystem metrics
Collect metrics from filesystem:
- number of keep files
- number of directories
- number of empty directories
- number of total files
Bug: Issue 16223
Change-Id: I37a142a166c9beb164e72c6ac9e57e70b677a39a
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/Module.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/Module.java
index 1ffb65c..f612533 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/Module.java
@@ -18,6 +18,7 @@
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.inject.Scopes;
+import com.googlesource.gerrit.plugins.gitrepometrics.collectors.FSMetricsCollector;
import com.googlesource.gerrit.plugins.gitrepometrics.collectors.GitStatsMetricsCollector;
import com.googlesource.gerrit.plugins.gitrepometrics.collectors.MetricsCollector;
import java.util.concurrent.ExecutorService;
@@ -34,6 +35,7 @@
DynamicSet.bind(binder(), GitReferenceUpdatedListener.class).to(GitRepoUpdateListener.class);
DynamicSet.setOf(binder(), MetricsCollector.class);
DynamicSet.bind(binder(), MetricsCollector.class).to(GitStatsMetricsCollector.class);
+ DynamicSet.bind(binder(), MetricsCollector.class).to(FSMetricsCollector.class);
listener().to(PluginStartup.class);
install(new UpdateGitMetricsTaskModule());
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/FSMetricsCollector.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/FSMetricsCollector.java
new file mode 100644
index 0000000..87e2b0e
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/FSMetricsCollector.java
@@ -0,0 +1,109 @@
+// Copyright (C) 2022 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.gitrepometrics.collectors;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.flogger.FluentLogger;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.HashMap;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.eclipse.jgit.internal.storage.file.FileRepository;
+
+public class FSMetricsCollector implements MetricsCollector {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ public static String numberOfKeepFiles = "numberOfKeepFiles";
+ public static String numberOfEmptyDirectories = "numberOfEmptyDirectories";
+ public static String numberOfDirectories = "numberOfDirectories";
+ public static String numberOfFiles = "numberOfFiles";
+
+ @Override
+ public HashMap<String, Long> collect(FileRepository repository, String projectName) {
+ HashMap<String, Long> metrics = new HashMap<>();
+
+ HashMap<String, AtomicInteger> partialMetrics =
+ filesAndDirectoriesCount(repository, projectName);
+ putMetric(
+ projectName,
+ metrics,
+ numberOfEmptyDirectories,
+ partialMetrics.get(numberOfEmptyDirectories).longValue());
+ putMetric(
+ projectName,
+ metrics,
+ numberOfDirectories,
+ partialMetrics.get(numberOfDirectories).longValue());
+ putMetric(projectName, metrics, numberOfFiles, partialMetrics.get(numberOfFiles).longValue());
+ putMetric(
+ projectName, metrics, numberOfKeepFiles, partialMetrics.get(numberOfKeepFiles).longValue());
+
+ return metrics;
+ }
+
+ private HashMap<String, AtomicInteger> filesAndDirectoriesCount(
+ FileRepository repository, String projectName) {
+ HashMap<String, AtomicInteger> counter =
+ new HashMap<String, AtomicInteger>() {
+ {
+ put(numberOfFiles, new AtomicInteger(0));
+ put(numberOfDirectories, new AtomicInteger(0));
+ put(numberOfEmptyDirectories, new AtomicInteger(0));
+ put(numberOfKeepFiles, new AtomicInteger(0));
+ }
+ };
+ try {
+ Files.walk(repository.getObjectsDirectory().toPath())
+ .parallel()
+ .forEach(
+ path -> {
+ if (path.toFile().isFile()) {
+ counter.get(numberOfFiles).updateAndGet(metricCounter -> metricCounter + 1);
+ if (path.toFile().getName().endsWith(".keep")) {
+ counter.get(numberOfKeepFiles).updateAndGet(metricCounter -> metricCounter + 1);
+ }
+ }
+ if (path.toFile().isDirectory()) {
+ counter.get(numberOfDirectories).updateAndGet(metricCounter -> metricCounter + 1);
+ if (Objects.requireNonNull(path.toFile().listFiles()).length == 0) {
+ counter
+ .get(numberOfEmptyDirectories)
+ .updateAndGet(metricCounter -> metricCounter + 1);
+ }
+ }
+ });
+ } catch (IOException e) {
+ logger.atSevere().withCause(e).log("Can't open object directory for project " + projectName);
+ }
+
+ return counter;
+ }
+
+ @Override
+ public String getMetricsCollectorName() {
+ return "filesystem-statistics";
+ }
+
+ @Override
+ public ImmutableList<GitRepoMetric> availableMetrics() {
+ return ImmutableList.of(
+ new GitRepoMetric(numberOfKeepFiles, "Number of keep files on filesystem", "Count"),
+ new GitRepoMetric(
+ numberOfEmptyDirectories, "Number of empty directories on filesystem", "Count"),
+ new GitRepoMetric(numberOfDirectories, "Number of directories on filesystem", "Count"),
+ new GitRepoMetric(numberOfFiles, "Number of directories on filesystem", "Count"));
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/GitStatsMetricsCollector.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/GitStatsMetricsCollector.java
index 00182e4..aa01d1a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/GitStatsMetricsCollector.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/GitStatsMetricsCollector.java
@@ -16,7 +16,6 @@
import com.google.common.collect.ImmutableList;
import com.google.common.flogger.FluentLogger;
-import com.googlesource.gerrit.plugins.gitrepometrics.GitRepoMetricsCache;
import java.io.IOException;
import java.util.HashMap;
import org.eclipse.jgit.internal.storage.file.FileRepository;
@@ -69,11 +68,6 @@
new GitRepoMetric(numberOfBitmaps, "Number of bitmaps", "Count"));
}
- private void putMetric(
- String projectName, HashMap<String, Long> metrics, String metricName, long value) {
- metrics.put(GitRepoMetricsCache.getMetricName(metricName, projectName), value);
- }
-
@Override
public String getMetricsCollectorName() {
return "git-statistics";
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/MetricsCollector.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/MetricsCollector.java
index 311a707..bfe06f4 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/MetricsCollector.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/MetricsCollector.java
@@ -14,6 +14,8 @@
package com.googlesource.gerrit.plugins.gitrepometrics.collectors;
+import static com.googlesource.gerrit.plugins.gitrepometrics.GitRepoMetricsCache.getMetricName;
+
import com.google.common.collect.ImmutableList;
import java.util.HashMap;
import org.eclipse.jgit.internal.storage.file.FileRepository;
@@ -45,4 +47,9 @@
* metric collector implementation.
*/
ImmutableList<GitRepoMetric> availableMetrics();
+
+ default void putMetric(
+ String projectName, HashMap<String, Long> metrics, String metricName, long value) {
+ metrics.put(getMetricName(metricName, projectName), value);
+ }
}
diff --git a/src/resources/Documentation/config.md b/src/resources/Documentation/config.md
index 26d162e..963f413 100644
--- a/src/resources/Documentation/config.md
+++ b/src/resources/Documentation/config.md
@@ -15,6 +15,10 @@
plugins_git_repo_metrics_numberofpackfiles_<repo_name>
plugins_git_repo_metrics_sizeoflooseobjects_<repo_name>
plugins_git_repo_metrics_sizeofpackedobjects_<repo_name>
+plugins_git_repo_metrics_numberofkeepfiles_<repo_name>
+plugins_git_repo_metrics_numberoffiles_<repo_name>
+plugins_git_repo_metrics_numberofdirectories_<repo_name>
+plugins_git_repo_metrics_numberofemptydirectories_<repo_name>
```
Settings
diff --git a/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheIT.java b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheIT.java
index 97031c3..f9693ac 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheIT.java
@@ -22,6 +22,7 @@
import com.google.gerrit.acceptance.UseLocalDisk;
import com.google.gerrit.acceptance.config.GlobalPluginConfig;
import com.google.inject.Inject;
+import com.googlesource.gerrit.plugins.gitrepometrics.collectors.FSMetricsCollector;
import com.googlesource.gerrit.plugins.gitrepometrics.collectors.GitStatsMetricsCollector;
import java.util.Arrays;
import java.util.List;
@@ -48,7 +49,10 @@
.filter(metricName -> metricName.contains("git-repo-metrics"))
.collect(Collectors.toList());
- int expectedMetricsCount = new GitStatsMetricsCollector().availableMetrics().size();
+ int expectedMetricsCount =
+ new GitStatsMetricsCollector().availableMetrics().size()
+ + new FSMetricsCollector().availableMetrics().size();
+
assertThat(repoMetricsCount.size()).isEqualTo(availableProjects.size() * expectedMetricsCount);
}
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/FSMetricsCollectorTest.java b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/FSMetricsCollectorTest.java
new file mode 100644
index 0000000..f330af3
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/FSMetricsCollectorTest.java
@@ -0,0 +1,65 @@
+// Copyright (C) 2022 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.gitrepometrics.collectors;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.HashMap;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.internal.storage.file.FileRepository;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+public class FSMetricsCollectorTest {
+
+ @Rule public TemporaryFolder dir = new TemporaryFolder();
+
+ private FileRepository repository;
+
+ @Before
+ public void setUp() throws Exception {
+ repository = createRepository("someRepo.git");
+ }
+
+ @Test
+ public void testCorrectMetricsCollection() throws IOException {
+ File objectDirectory = repository.getObjectsDirectory();
+ Files.createFile(new File(objectDirectory, "pack/keep1.keep").toPath());
+
+ HashMap<String, Long> metrics = new FSMetricsCollector().collect(repository, "testRepo");
+
+ // This is the FS structure, from the "objects" directory, metrics are collected from:
+ // .
+ // ├── info
+ // └── pack
+ // └── keep1.keep
+ assertThat(metrics.get("numberofkeepfiles_testrepo")).isEqualTo(1); // keep1.keep
+ assertThat(metrics.get("numberoffiles_testrepo")).isEqualTo(1); // keep1.keep
+ assertThat(metrics.get("numberofdirectories_testrepo")).isEqualTo(3); // info, pack and .
+ assertThat(metrics.get("numberofemptydirectories_testrepo")).isEqualTo(1); // info
+ }
+
+ private FileRepository createRepository(String repoName) throws Exception {
+ File repo = dir.newFolder(repoName);
+ try (Git git = Git.init().setDirectory(repo).call()) {
+ return (FileRepository) git.getRepository();
+ }
+ }
+}