ExceptionHookImpl: Identify exceptions cause by MissingObjectException

Missing Git objects are often the cause of exceptions and we would like
to track in our metrics how often they occur. By returning a unique
string as cause, occurrences of this exception go into a separate metric
bucket.

This also reduces noise in the metrics which allows us to see how many
remaining unknown causes of internal server errors there are.

Signed-off-by: Edwin Kempin <ekempin@google.com>
Change-Id: Ibc636d3da60dbafd81f3fbb7c1ef4f574e7dd82d
diff --git a/java/com/google/gerrit/server/ExceptionHookImpl.java b/java/com/google/gerrit/server/ExceptionHookImpl.java
index 8393451..5a3f077 100644
--- a/java/com/google/gerrit/server/ExceptionHookImpl.java
+++ b/java/com/google/gerrit/server/ExceptionHookImpl.java
@@ -20,6 +20,7 @@
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.git.LockFailureException;
 import java.util.Optional;
+import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.lib.RefUpdate;
 
 /**
@@ -42,6 +43,9 @@
     if (isLockFailure(throwable)) {
       return Optional.of(RefUpdate.Result.LOCK_FAILURE.name());
     }
+    if (isMissingObjectException(throwable)) {
+      return Optional.of("missing_object");
+    }
     return Optional.empty();
   }
 
@@ -65,6 +69,10 @@
     return isMatching(throwable, t -> t instanceof LockFailureException);
   }
 
+  private static boolean isMissingObjectException(Throwable throwable) {
+    return isMatching(throwable, t -> t instanceof MissingObjectException);
+  }
+
   /**
    * Check whether the given exception or any of its causes matches the given predicate.
    *