Merge "Log caller for debug logs when reading external ID notes map"
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java b/java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java
index eef2156..2c72f56 100644
--- a/java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java
+++ b/java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java
@@ -36,10 +36,13 @@
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.server.account.AccountCache;
+import com.google.gerrit.server.account.AccountsUpdate;
 import com.google.gerrit.server.config.AllUsersName;
 import com.google.gerrit.server.git.meta.MetaDataUpdate;
 import com.google.gerrit.server.git.meta.VersionedMetaData;
 import com.google.gerrit.server.index.account.AccountIndexer;
+import com.google.gerrit.server.logging.CallerFinder;
+import com.google.gerrit.server.update.RetryHelper;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
@@ -265,6 +268,7 @@
   private final AllUsersName allUsersName;
   private final Counter0 updateCount;
   private final Repository repo;
+  private final CallerFinder callerFinder;
 
   private NoteMap noteMap;
   private ObjectId oldRev;
@@ -294,6 +298,19 @@
             new Description("Total number of external ID updates.").setRate().setUnit("updates"));
     this.allUsersName = requireNonNull(allUsersName, "allUsersRepo");
     this.repo = requireNonNull(allUsersRepo, "allUsersRepo");
+    this.callerFinder =
+        CallerFinder.builder()
+            // 1. callers that come through ExternalIds
+            .addTarget(ExternalIds.class)
+
+            // 2. callers that come through AccountsUpdate
+            .addTarget(AccountsUpdate.class)
+            .addIgnoredPackage("com.github.rholder.retry")
+            .addIgnoredClass(RetryHelper.class)
+
+            // 3. direct callers
+            .addTarget(ExternalIdNotes.class)
+            .build();
   }
 
   public ExternalIdNotes setAfterReadRevision(Runnable afterReadRevision) {
@@ -658,7 +675,7 @@
   @Override
   protected void onLoad() throws IOException, ConfigInvalidException {
     if (revision != null) {
-      logger.atFine().log("Reading external ID note map");
+      logger.atFine().log("Reading external ID note map (caller: %s)", callerFinder.findCaller());
       noteMap = NoteMap.read(reader, revision);
     } else {
       noteMap = NoteMap.newEmptyMap();
diff --git a/java/com/google/gerrit/server/logging/CallerFinder.java b/java/com/google/gerrit/server/logging/CallerFinder.java
index c27dbbb..73ffeb5 100644
--- a/java/com/google/gerrit/server/logging/CallerFinder.java
+++ b/java/com/google/gerrit/server/logging/CallerFinder.java
@@ -149,6 +149,20 @@
    */
   public abstract int skip();
 
+  /**
+   * Packages that should be ignored and not be considered as caller once a target has been found.
+   *
+   * @return the ignored packages
+   */
+  public abstract ImmutableList<String> ignoredPackages();
+
+  /**
+   * Classes that should be ignored and not be considered as caller once a target has been found.
+   *
+   * @return the qualified names of the ignored classes
+   */
+  public abstract ImmutableList<String> ignoredClasses();
+
   @AutoValue.Builder
   public abstract static class Builder {
     abstract ImmutableList.Builder<Class<?>> targetsBuilder();
@@ -164,6 +178,20 @@
 
     public abstract Builder skip(int skip);
 
+    abstract ImmutableList.Builder<String> ignoredPackagesBuilder();
+
+    public Builder addIgnoredPackage(String ignoredPackage) {
+      ignoredPackagesBuilder().add(ignoredPackage);
+      return this;
+    }
+
+    abstract ImmutableList.Builder<String> ignoredClassesBuilder();
+
+    public Builder addIgnoredClass(Class<?> ignoredClass) {
+      ignoredClassesBuilder().add(ignoredClass.getName());
+      return this;
+    }
+
     public abstract CallerFinder build();
   }
 
@@ -194,7 +222,9 @@
         StackTraceElement element = stack[index];
         if (isCaller(target, element.getClassName(), matchSubClasses())) {
           foundCaller = true;
-        } else if (foundCaller) {
+        } else if (foundCaller
+            && !ignoredPackages().contains(getPackageName(element))
+            && !ignoredClasses().contains(element.getClassName())) {
           return Optional.of(element.toString());
         }
       }
@@ -206,6 +236,11 @@
     }
   }
 
+  private static String getPackageName(StackTraceElement element) {
+    String className = element.getClassName();
+    return className.substring(0, className.lastIndexOf("."));
+  }
+
   private boolean isCaller(Class<?> target, String className, boolean matchSubClasses)
       throws ClassNotFoundException {
     if (matchSubClasses) {