Track replication started vs replication failed refs

Add metrics to track number of refs for which fetch operation have
started/completed/failed.

New metric names:
* plugins_pull_replication_fetch_refs_started_total
* plugins_pull_replication_fetch_refs_failed_total
* plugins_pull_replication_fetch_refs_completed_total

Bug: Issue 290254822
Change-Id: I20140b25064b034375ae6af19086bdff3717a770
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationQueueMetrics.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationQueueMetrics.java
index b0fa7e9..abb01b7 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationQueueMetrics.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationQueueMetrics.java
@@ -35,6 +35,7 @@
 public class ReplicationQueueMetrics {
   private static final String EVENTS = "events";
   private static final String TASKS = "tasks";
+  private static final String REFS = "refs";
   public static final String REPLICATION_QUEUE_METRICS = "ReplicationQueueMetrics";
 
   private final Counter1<String> tasksScheduled;
@@ -52,6 +53,10 @@
   private final Counter1<String> tasksStarted;
   private final Set<RegistrationHandle> metricsHandles;
 
+  private final Counter1<String> refsFetchStarted;
+  private final Counter1<String> refsFetchCompleted;
+  private final Counter1<String> refsFetchFailed;
+
   public class RunnableWithMetrics implements Runnable {
     private final Source source;
     private final Runnable runnable;
@@ -64,13 +69,17 @@
     @Override
     public void run() {
       incrementTaskStarted(source);
+      incrementFetchRefsStarted(source, runnable);
+
       runnable.run();
       if (runnable instanceof Completable) {
         Completable completedRunnable = (Completable) runnable;
         if (completedRunnable.hasSucceeded()) {
           incrementTaskCompleted(source);
+          incrementFetchRefsCompleted(source, runnable);
         } else {
           incrementTaskFailed(source);
+          incrementFetchRefsFailed(source, runnable);
         }
       }
     }
@@ -170,6 +179,31 @@
                     .setUnit(TASKS),
                 sourceField));
 
+    refsFetchStarted =
+        registerMetric(
+            metricMaker.newCounter(
+                "fetch/refs/started",
+                new Description("Refs for which fetch operation have started")
+                    .setCumulative()
+                    .setUnit(REFS),
+                sourceField));
+    refsFetchCompleted =
+        registerMetric(
+            metricMaker.newCounter(
+                "fetch/refs/completed",
+                new Description("Refs for which fetch operation have completed")
+                    .setCumulative()
+                    .setUnit(REFS),
+                sourceField));
+    refsFetchFailed =
+        registerMetric(
+            metricMaker.newCounter(
+                "fetch/refs/failed",
+                new Description("Refs for which fetch operation have failed")
+                    .setCumulative()
+                    .setUnit(REFS),
+                sourceField));
+
     this.metricMaker = metricMaker;
   }
 
@@ -269,6 +303,25 @@
     tasksStarted.increment(source.getRemoteConfigName());
   }
 
+  public void incrementFetchRefsStarted(Source source, Runnable runnableTask) {
+    incrementFetchRefsCounter(source, runnableTask, refsFetchStarted);
+  }
+
+  public void incrementFetchRefsCompleted(Source source, Runnable runnableTask) {
+    incrementFetchRefsCounter(source, runnableTask, refsFetchCompleted);
+  }
+
+  public void incrementFetchRefsFailed(Source source, Runnable runnableTask) {
+    incrementFetchRefsCounter(source, runnableTask, refsFetchFailed);
+  }
+
+  private void incrementFetchRefsCounter(
+      Source source, Runnable runnableTask, Counter1<String> counter) {
+    if (runnableTask instanceof FetchOne) {
+      counter.incrementBy(source.getRemoteConfigName(), ((FetchOne) runnableTask).getRefs().size());
+    }
+  }
+
   public Runnable runWithMetrics(Source source, Runnable runnableTask) {
     if (runnableTask instanceof RunnableWithMetrics) {
       return runnableTask;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/Source.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/Source.java
index 012a046..74a6be1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/Source.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/Source.java
@@ -678,6 +678,7 @@
                     : RefUpdate.Result.REJECTED_OTHER_REASON;
             postReplicationFailedEvent(fetchOp, trackingRefUpdate);
             queueMetrics.incrementTaskFailed(this);
+            queueMetrics.incrementFetchRefsFailed(this, fetchOp);
 
             if (fetchOp.setToRetry()) {
               postReplicationScheduledEvent(fetchOp);
diff --git a/src/main/resources/Documentation/metrics.md b/src/main/resources/Documentation/metrics.md
index ac1539c..76861d4 100644
--- a/src/main/resources/Documentation/metrics.md
+++ b/src/main/resources/Documentation/metrics.md
@@ -63,6 +63,22 @@
 - `failed_max_retries`: (counter) number of tasks that have reached their maximum
   retry count but never succeeded.
 
+### plugins/@PLUGIN@/fetch/refs/<metric>/<source>
+
+Cumulative number of refs included in the Git fetch operation.
+
+The `<metric>` field can have one of the values described here below,
+while the `<source>` represents the replication source endpoint name.
+
+- `started`: (counter) number of refs for which fetch operation have started.
+
+- `completed`: (counter) number of refs for which fetch operation have completed.
+
+- `failed`: (counter) number of refs for which fetch operation have failed.
+
+> Bear in mind that the fetch with special `..all..` ref spec will be counted
+> as 1 even if the fetch cause multiple refs to be fetched.
+
 ### plugins/@PLUGIN@
 
 - `apply_object_latency`: (timer) execution time statistics for the