remote/caching: improve error messages for remote caching

Only the last commit needs to be reviewed, as it's rebased on https://github.com/bazelbuild/bazel/pull/5101

Closes #5117.

PiperOrigin-RevId: 195649921
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnCache.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnCache.java
index ff83eb7..8a304cf 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnCache.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnCache.java
@@ -13,6 +13,8 @@
 // limitations under the License.
 package com.google.devtools.build.lib.remote;
 
+import static com.google.common.base.Strings.isNullOrEmpty;
+
 import com.google.devtools.build.lib.actions.ActionInput;
 import com.google.devtools.build.lib.actions.ExecException;
 import com.google.devtools.build.lib.actions.ExecutionStrategy;
@@ -41,19 +43,17 @@
 import io.grpc.Context;
 import java.io.IOException;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.NoSuchElementException;
+import java.util.Set;
 import java.util.SortedMap;
-import java.util.concurrent.atomic.AtomicBoolean;
 import javax.annotation.Nullable;
 
-/**
- * A remote {@link SpawnCache} implementation.
- */
+/** A remote {@link SpawnCache} implementation. */
 @ThreadSafe // If the RemoteActionCache implementation is thread-safe.
 @ExecutionStrategy(
-  name = {"remote-cache"},
-  contextType = SpawnCache.class
-)
+    name = {"remote-cache"},
+    contextType = SpawnCache.class)
 final class RemoteSpawnCache implements SpawnCache {
   private final Path execRoot;
   private final RemoteOptions options;
@@ -61,12 +61,10 @@
   private final AbstractRemoteActionCache remoteCache;
   private final String buildRequestId;
   private final String commandId;
-  private final boolean verboseFailures;
 
   @Nullable private final Reporter cmdlineReporter;
 
-  // Used to ensure that a warning is reported only once.
-  private final AtomicBoolean warningReported = new AtomicBoolean();
+  private final Set<String> reportedErrors = new HashSet<>();
 
   private final DigestUtil digestUtil;
 
@@ -76,13 +74,11 @@
       AbstractRemoteActionCache remoteCache,
       String buildRequestId,
       String commandId,
-      boolean verboseFailures,
       @Nullable Reporter cmdlineReporter,
       DigestUtil digestUtil) {
     this.execRoot = execRoot;
     this.options = options;
     this.remoteCache = remoteCache;
-    this.verboseFailures = verboseFailures;
     this.cmdlineReporter = cmdlineReporter;
     this.buildRequestId = buildRequestId;
     this.commandId = commandId;
@@ -142,10 +138,12 @@
       } catch (CacheNotFoundException e) {
         // There's a cache miss. Fall back to local execution.
       } catch (IOException e) {
-        // There's an IO error. Fall back to local execution.
-        reportOnce(
-            Event.warn(
-                "Some artifacts failed to be downloaded from the remote cache: " + e.getMessage()));
+        String errorMsg = e.getMessage();
+        if (isNullOrEmpty(errorMsg)) {
+          errorMsg = e.getClass().getSimpleName();
+        }
+        errorMsg = "Error reading from the remote cache:\n" + errorMsg;
+        report(Event.warn(errorMsg));
       } finally {
         withMetadata.detach(previous);
       }
@@ -188,13 +186,12 @@
           try {
             remoteCache.upload(actionKey, execRoot, files, context.getFileOutErr(), uploadAction);
           } catch (IOException e) {
-            if (verboseFailures) {
-              report(Event.debug("Upload to remote cache failed: " + e.getMessage()));
-            } else {
-              reportOnce(
-                  Event.warn(
-                      "Some artifacts failed be uploaded to the remote cache: " + e.getMessage()));
+            String errorMsg = e.getMessage();
+            if (isNullOrEmpty(errorMsg)) {
+              errorMsg = e.getClass().getSimpleName();
             }
+            errorMsg = "Error writing to the remote cache:\n" + errorMsg;
+            report(Event.warn(errorMsg));
           } finally {
             withMetadata.detach(previous);
           }
@@ -224,14 +221,16 @@
     }
   }
 
-  private void reportOnce(Event evt) {
-    if (warningReported.compareAndSet(false, true)) {
-      report(evt);
-    }
-  }
-
   private void report(Event evt) {
-    if (cmdlineReporter != null) {
+    if (cmdlineReporter == null) {
+      return;
+    }
+
+    synchronized (this) {
+      if (reportedErrors.contains(evt.getMessage())) {
+        return;
+      }
+      reportedErrors.add(evt.getMessage());
       cmdlineReporter.handle(evt);
     }
   }