Add a flag, --experimental_verbose_failures_filter, that gives finer control over failure reporting: rather than dump command lines for all failed actions, dump only for actions whose labels match a regular expression filter.

The existing --verbose_failures flag is still available as an equivalent for --experimental_verbose_failures_filter=.*

PiperOrigin-RevId: 312352624
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionContext.java b/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionContext.java
index cc31b9e..d98bb54 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionContext.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionContext.java
@@ -239,11 +239,9 @@
     return pathResolver;
   }
 
-  /**
-   * Returns whether failures should have verbose error messages.
-   */
-  public boolean getVerboseFailures() {
-    return executor.getVerboseFailures();
+  /** Returns whether failures for {@code failedLabel} should have verbose error messages. */
+  public boolean showVerboseFailures(Label failedLabel) {
+    return executor.getVerboseFailuresPredicate().test(failedLabel);
   }
 
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ExecException.java b/src/main/java/com/google/devtools/build/lib/actions/ExecException.java
index a44e925..053ffe7 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ExecException.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ExecException.java
@@ -94,7 +94,8 @@
    * incorporating just the termination status if available.
    *
    * @param messagePrefix describes the action type as noun
-   * @param verboseFailures true if user requested verbose output with flag --verbose_failures
+   * @param verboseFailures true if user requested verbose output with flag --verbose_failures or
+   *     --experimental_verbose_failures_filter
    * @param action failed action
    * @return ActionExecutionException object describing the action failure
    */
diff --git a/src/main/java/com/google/devtools/build/lib/actions/Executor.java b/src/main/java/com/google/devtools/build/lib/actions/Executor.java
index 269e26a..d72c4a4 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/Executor.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/Executor.java
@@ -15,9 +15,11 @@
 
 import com.google.devtools.build.lib.actions.ActionExecutionContext.ShowSubcommands;
 import com.google.devtools.build.lib.clock.Clock;
+import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.vfs.FileSystem;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.common.options.OptionsProvider;
+import java.util.function.Predicate;
 
 /**
  * The Executor provides the context for the execution of actions. It is only valid during the
@@ -53,10 +55,8 @@
    */
   Clock getClock();
 
-  /**
-   * Returns whether failures should have verbose error messages.
-   */
-  boolean getVerboseFailures();
+  /** Predicate for whether an action's failures should have verbose error messages. */
+  Predicate<Label> getVerboseFailuresPredicate();
 
   /**
    * Returns the command line options of the Blaze command being executed.
diff --git a/src/main/java/com/google/devtools/build/lib/actions/SpawnResult.java b/src/main/java/com/google/devtools/build/lib/actions/SpawnResult.java
index 9ddb878..f345f71 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/SpawnResult.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/SpawnResult.java
@@ -374,7 +374,7 @@
       TerminationStatus status = new TerminationStatus(
           exitCode(), status() == Status.TIMEOUT);
       String reason = " (" + status.toShortString() + ")"; // e.g " (Exit 1)"
-      // Include the command line as error message if --verbose_failures is enabled or
+      // Include the command line as error message if verbose_failures are enabled for this spawn or
       // the command line didn't exit normally.
       String explanation = verboseFailures || !status.exited() ? ": " + message : "";
 
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/AbstractFileWriteAction.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/AbstractFileWriteAction.java
index b2f14b9..a16b2bc 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/actions/AbstractFileWriteAction.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/AbstractFileWriteAction.java
@@ -100,9 +100,10 @@
               return this;
             }
           } catch (ExecException e) {
+            Label label = getOwner().getLabel();
             throw e.toActionExecutionException(
-                "Writing file for rule '" + Label.print(getOwner().getLabel()) + "'",
-                actionExecutionContext.getVerboseFailures(),
+                "Writing file for rule '" + Label.print(label) + "'",
+                actionExecutionContext.showVerboseFailures(label),
                 AbstractFileWriteAction.this);
           }
           afterWrite(actionExecutionContext);
@@ -110,9 +111,10 @@
         }
       };
     } catch (ExecException e) {
+      Label label = getOwner().getLabel();
       throw e.toActionExecutionException(
-          "Writing file for rule '" + Label.print(getOwner().getLabel()) + "'",
-          actionExecutionContext.getVerboseFailures(),
+          "Writing file for rule '" + Label.print(label) + "'",
+          actionExecutionContext.showVerboseFailures(label),
           this);
     }
   }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnAction.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnAction.java
index da11379..be48eb2 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnAction.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnAction.java
@@ -65,6 +65,7 @@
 import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.skylark.Args;
+import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.exec.SpawnStrategyResolver;
@@ -313,13 +314,14 @@
   public final ActionContinuationOrResult beginExecution(
       ActionExecutionContext actionExecutionContext)
       throws ActionExecutionException, InterruptedException {
+    Label label = getOwner().getLabel();
     Spawn spawn;
     try {
       beforeExecute(actionExecutionContext);
       spawn = getSpawn(actionExecutionContext);
     } catch (IOException e) {
       throw toActionExecutionException(
-          new EnvironmentalExecException(e), actionExecutionContext.getVerboseFailures());
+          new EnvironmentalExecException(e), actionExecutionContext.showVerboseFailures(label));
     } catch (CommandLineExpansionException e) {
       throw new ActionExecutionException(e, this, /*catastrophe=*/ false);
     }
@@ -327,7 +329,7 @@
         actionExecutionContext
             .getContext(SpawnStrategyResolver.class)
             .beginExecution(spawn, actionExecutionContext);
-    return new SpawnActionContinuation(actionExecutionContext, spawnContinuation);
+    return new SpawnActionContinuation(actionExecutionContext, spawnContinuation, label);
   }
 
   private ActionExecutionException toActionExecutionException(
@@ -1357,11 +1359,15 @@
   private final class SpawnActionContinuation extends ActionContinuationOrResult {
     private final ActionExecutionContext actionExecutionContext;
     private final SpawnContinuation spawnContinuation;
+    private final Label label;
 
-    public SpawnActionContinuation(
-        ActionExecutionContext actionExecutionContext, SpawnContinuation spawnContinuation) {
+    SpawnActionContinuation(
+        ActionExecutionContext actionExecutionContext,
+        SpawnContinuation spawnContinuation,
+        Label label) {
       this.actionExecutionContext = actionExecutionContext;
       this.spawnContinuation = spawnContinuation;
+      this.label = label;
     }
 
     @Override
@@ -1382,12 +1388,12 @@
           afterExecute(actionExecutionContext, spawnResults);
           return ActionContinuationOrResult.of(ActionResult.create(nextContinuation.get()));
         }
-        return new SpawnActionContinuation(actionExecutionContext, nextContinuation);
+        return new SpawnActionContinuation(actionExecutionContext, nextContinuation, label);
       } catch (IOException e) {
         throw toActionExecutionException(
-            new EnvironmentalExecException(e), actionExecutionContext.getVerboseFailures());
+            new EnvironmentalExecException(e), actionExecutionContext.showVerboseFailures(label));
       } catch (ExecException e) {
-        throw toActionExecutionException(e, actionExecutionContext.getVerboseFailures());
+        throw toActionExecutionException(e, actionExecutionContext.showVerboseFailures(label));
       }
     }
   }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/TemplateExpansionAction.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/TemplateExpansionAction.java
index 3744a60..9b75cf5 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/actions/TemplateExpansionAction.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/TemplateExpansionAction.java
@@ -169,9 +169,10 @@
             return this;
           }
         } catch (ExecException e) {
+          Label label = getOwner().getLabel();
           throw e.toActionExecutionException(
-              "Error expanding template '" + Label.print(getOwner().getLabel()) + "'",
-              actionExecutionContext.getVerboseFailures(),
+              "Error expanding template '" + Label.print(label) + "'",
+              actionExecutionContext.showVerboseFailures(label),
               TemplateExpansionAction.this);
         }
         return ActionContinuationOrResult.of(ActionResult.create(nextContinuation.get()));
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/coverage/CoverageReportActionBuilder.java b/src/main/java/com/google/devtools/build/lib/bazel/coverage/CoverageReportActionBuilder.java
index c154105..cb6c676 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/coverage/CoverageReportActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/coverage/CoverageReportActionBuilder.java
@@ -148,7 +148,7 @@
       } catch (ExecException e) {
         throw e.toActionExecutionException(
             "Coverage report generation failed: ",
-            actionExecutionContext.getVerboseFailures(),
+            actionExecutionContext.showVerboseFailures(getOwner().getLabel()),
             this);
       }
     }
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildResultPrinter.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildResultPrinter.java
index d4a0e89..715f1bd 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildResultPrinter.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildResultPrinter.java
@@ -177,7 +177,8 @@
       }
       success = failed.isEmpty();
     }
-    if (!success && !request.getOptions(ExecutionOptions.class).verboseFailures) {
+    if (!success && !request.getOptions(ExecutionOptions.class).hasSomeVerboseFailures()) {
+      // TODO(janakr): Show better message if --experimental_verbose_failures_filter is on.
       outErr.printErr("Use --verbose_failures to see the command lines of failed build steps.\n");
     }
   }
diff --git a/src/main/java/com/google/devtools/build/lib/exec/AbstractSpawnStrategy.java b/src/main/java/com/google/devtools/build/lib/exec/AbstractSpawnStrategy.java
index c8c7a7c..9656851 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/AbstractSpawnStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/AbstractSpawnStrategy.java
@@ -168,7 +168,8 @@
           !Strings.isNullOrEmpty(resultMessage)
               ? resultMessage
               : CommandFailureUtils.describeCommandFailure(
-                  actionExecutionContext.getVerboseFailures(),
+                  actionExecutionContext.showVerboseFailures(
+                      spawn.getResourceOwner().getOwner().getLabel()),
                   spawn.getArguments(),
                   spawn.getEnvironment(),
                   cwd,
diff --git a/src/main/java/com/google/devtools/build/lib/exec/BUILD b/src/main/java/com/google/devtools/build/lib/exec/BUILD
index b9df475..e25903d 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/exec/BUILD
@@ -59,6 +59,7 @@
         ":spawn_strategy_registry",
         "//src/main/java/com/google/devtools/build/lib/actions",
         "//src/main/java/com/google/devtools/build/lib/clock",
+        "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/concurrent",
         "//src/main/java/com/google/devtools/build/lib/events",
         "//src/main/java/com/google/devtools/build/lib/vfs",
@@ -87,6 +88,7 @@
         "//src/main/java/com/google/devtools/build/lib/actions",
         "//src/main/java/com/google/devtools/build/lib/actions:localhost_capacity",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/per_label_options",
+        "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/util",
         "//src/main/java/com/google/devtools/build/lib/util:resource_converter",
         "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
diff --git a/src/main/java/com/google/devtools/build/lib/exec/BlazeExecutor.java b/src/main/java/com/google/devtools/build/lib/exec/BlazeExecutor.java
index 96bba6f..584cd77 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/BlazeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/BlazeExecutor.java
@@ -17,11 +17,13 @@
 import com.google.devtools.build.lib.actions.ActionExecutionContext.ShowSubcommands;
 import com.google.devtools.build.lib.actions.Executor;
 import com.google.devtools.build.lib.clock.Clock;
+import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
 import com.google.devtools.build.lib.events.Reporter;
 import com.google.devtools.build.lib.vfs.FileSystem;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.common.options.OptionsProvider;
+import java.util.function.Predicate;
 import javax.annotation.Nullable;
 
 /**
@@ -34,8 +36,7 @@
  */
 @ThreadSafe
 public final class BlazeExecutor implements Executor {
-
-  private final boolean verboseFailures;
+  private final Predicate<Label> verboseFailures;
   private final ShowSubcommands showSubcommands;
   private final FileSystem fileSystem;
   private final Path execRoot;
@@ -63,7 +64,7 @@
       ModuleActionContextRegistry actionContextRegistry,
       SpawnStrategyRegistry spawnStrategyRegistry) {
     ExecutionOptions executionOptions = options.getOptions(ExecutionOptions.class);
-    this.verboseFailures = executionOptions.verboseFailures;
+    this.verboseFailures = executionOptions.getVerboseFailuresPredicate();
     this.showSubcommands = executionOptions.showSubcommands;
     this.fileSystem = fileSystem;
     this.execRoot = execRoot;
@@ -106,9 +107,8 @@
     return actionContextRegistry.getContext(type);
   }
 
-  /** Returns true iff the --verbose_failures option was enabled. */
   @Override
-  public boolean getVerboseFailures() {
+  public Predicate<Label> getVerboseFailuresPredicate() {
     return verboseFailures;
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/exec/ExecutionOptions.java b/src/main/java/com/google/devtools/build/lib/exec/ExecutionOptions.java
index 8b589bf..28464e8 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/ExecutionOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/ExecutionOptions.java
@@ -20,6 +20,7 @@
 import com.google.devtools.build.lib.actions.LocalHostCapacity;
 import com.google.devtools.build.lib.actions.ResourceSet;
 import com.google.devtools.build.lib.analysis.config.PerLabelOptions;
+import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.util.OptionsUtils;
 import com.google.devtools.build.lib.util.RegexFilter;
 import com.google.devtools.build.lib.util.ResourceConverter;
@@ -38,6 +39,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Predicate;
 
 /**
  * Options affecting the execution phase of a build.
@@ -126,9 +128,9 @@
       documentationCategory = OptionDocumentationCategory.LOGGING,
       effectTags = {OptionEffectTag.EXECUTION},
       help =
-          "Writes intermediate parameter files to output tree even when using "
-              + "remote action execution. Useful when debugging actions. "
-              + "This is implied by --subcommands and --verbose_failures.")
+          "Writes intermediate parameter files to output tree even when using remote action"
+              + " execution. Useful when debugging actions. This is implied by --subcommands,"
+              + " --verbose_failures, and --experimental_verbose_failures_filter.")
   public boolean materializeParamFiles;
 
   @Option(
@@ -140,10 +142,13 @@
   public boolean materializeParamFilesDirectly;
 
   public boolean shouldMaterializeParamFiles() {
-    // Implied by --subcommands and --verbose_failures
+    // Implied by --subcommands and verbose_failures
     return materializeParamFiles
         || showSubcommands != ActionExecutionContext.ShowSubcommands.FALSE
-        || verboseFailures;
+        // Conservatively materialize params files if any failures may be verbose.
+        // TODO(janakr): Could try to thread action label through to here and only materialize for
+        //  those actions, but seems pretty gnarly.
+        || hasSomeVerboseFailures();
   }
 
   @Option(
@@ -151,10 +156,33 @@
       defaultValue = "false",
       documentationCategory = OptionDocumentationCategory.LOGGING,
       effectTags = {OptionEffectTag.TERMINAL_OUTPUT},
-      help = "If a command fails, print out the full command line.")
+      help = "If any command fails, print out the full command line.")
   public boolean verboseFailures;
 
   @Option(
+      name = "experimental_verbose_failures_filter",
+      defaultValue = "null",
+      converter = RegexFilter.RegexFilterConverter.class,
+      documentationCategory = OptionDocumentationCategory.LOGGING,
+      effectTags = {OptionEffectTag.TERMINAL_OUTPUT},
+      help =
+          "If a command fails, print out the full command line if its label matches the given"
+              + " regex filter.")
+  public RegexFilter verboseFailuresFilter;
+
+  public boolean hasSomeVerboseFailures() {
+    return verboseFailures || verboseFailuresFilter != null;
+  }
+
+  public Predicate<Label> getVerboseFailuresPredicate() {
+    return verboseFailures
+        ? l -> true
+        : verboseFailuresFilter == null
+            ? l -> false
+            : l -> l == null || verboseFailuresFilter.isIncluded(l.getCanonicalForm());
+  }
+
+  @Option(
       name = "subcommands",
       abbrev = 's',
       defaultValue = "false",
diff --git a/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeStrategy.java b/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeStrategy.java
index e9c3cd7..63ffb8d 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeStrategy.java
@@ -125,7 +125,9 @@
         }
       } catch (ExecException e) {
         throw e.toActionExecutionException(
-            action.getProgressMessage(), actionExecutionContext.getVerboseFailures(), action);
+            action.getProgressMessage(),
+            actionExecutionContext.showVerboseFailures(action.getOwner().getLabel()),
+            action);
       }
     }
   }
diff --git a/src/main/java/com/google/devtools/build/lib/remote/BUILD b/src/main/java/com/google/devtools/build/lib/remote/BUILD
index 6bf532e..87c4505 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/remote/BUILD
@@ -51,6 +51,7 @@
         "//src/main/java/com/google/devtools/build/lib/authandtls",
         "//src/main/java/com/google/devtools/build/lib/bazel/repository/downloader",
         "//src/main/java/com/google/devtools/build/lib/buildeventstream",
+        "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/collect",
         "//src/main/java/com/google/devtools/build/lib/collect/nestedset",
         "//src/main/java/com/google/devtools/build/lib/concurrent",
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteActionContextProvider.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteActionContextProvider.java
index 53aa101..8b0f2e3 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteActionContextProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteActionContextProvider.java
@@ -96,7 +96,8 @@
             env.getExecRoot(),
             checkNotNull(env.getOptions().getOptions(RemoteOptions.class)),
             env.getOptions().getOptions(ExecutionOptions.class),
-            checkNotNull(env.getOptions().getOptions(ExecutionOptions.class)).verboseFailures,
+            checkNotNull(env.getOptions().getOptions(ExecutionOptions.class))
+                .getVerboseFailuresPredicate(),
             env.getReporter(),
             env.getBuildRequestId(),
             env.getCommandId().toString(),
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnRunner.java
index bd0e378..124ed94 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnRunner.java
@@ -54,6 +54,7 @@
 import com.google.devtools.build.lib.actions.Spawns;
 import com.google.devtools.build.lib.actions.cache.VirtualActionInput;
 import com.google.devtools.build.lib.analysis.platform.PlatformUtils;
+import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.Reporter;
@@ -100,6 +101,7 @@
 import java.util.SortedMap;
 import java.util.TreeSet;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Predicate;
 import java.util.function.Supplier;
 import javax.annotation.Nullable;
 
@@ -143,7 +145,7 @@
   private final Path execRoot;
   private final RemoteOptions remoteOptions;
   private final ExecutionOptions executionOptions;
-  private final boolean verboseFailures;
+  private final Predicate<Label> verboseFailures;
 
   @Nullable private final Reporter cmdlineReporter;
   private final RemoteExecutionCache remoteCache;
@@ -167,7 +169,7 @@
       Path execRoot,
       RemoteOptions remoteOptions,
       ExecutionOptions executionOptions,
-      boolean verboseFailures,
+      Predicate<Label> verboseFailures,
       @Nullable Reporter cmdlineReporter,
       String buildRequestId,
       String commandId,
@@ -337,7 +339,8 @@
               spawnMetricsAccounting(spawnMetrics, actionResult.getExecutionMetadata());
 
               try (SilentCloseable c = prof.profile(REMOTE_DOWNLOAD, "download server logs")) {
-                maybeDownloadServerLogs(reply, actionKey);
+                maybeDownloadServerLogs(
+                    reply, actionKey, spawn.getResourceOwner().getOwner().getLabel());
               }
 
               try {
@@ -500,7 +503,7 @@
     }
   }
 
-  private void maybeDownloadServerLogs(ExecuteResponse resp, ActionKey actionKey)
+  private void maybeDownloadServerLogs(ExecuteResponse resp, ActionKey actionKey, Label label)
       throws InterruptedException {
     ActionResult result = resp.getResult();
     if (resp.getServerLogsCount() > 0
@@ -515,11 +518,13 @@
           try {
             getFromFuture(remoteCache.downloadFile(logPath, e.getValue().getDigest()));
           } catch (IOException ex) {
-            reportOnce(Event.warn("Failed downloading server logs from the remote cache."));
+            reportOnce(
+                Event.warn(
+                    "Failed downloading server logs for " + label + " from the remote cache."));
           }
         }
       }
-      if (logCount > 0 && verboseFailures) {
+      if (logCount > 0 && verboseFailures.test(label)) {
         report(
             Event.info("Server logs of failing action:\n   " + (logCount > 1 ? parent : logPath)));
       }
@@ -558,11 +563,20 @@
       return execLocallyAndUpload(
           spawn, context, inputMap, actionKey, action, command, uploadLocalResults);
     }
-    return handleError(cause, context.getFileOutErr(), actionKey, context);
+    return handleError(
+        cause,
+        context.getFileOutErr(),
+        actionKey,
+        context,
+        spawn.getResourceOwner().getOwner().getLabel());
   }
 
   private SpawnResult handleError(
-      IOException exception, FileOutErr outErr, ActionKey actionKey, SpawnExecutionContext context)
+      IOException exception,
+      FileOutErr outErr,
+      ActionKey actionKey,
+      SpawnExecutionContext context,
+      Label label)
       throws ExecException, InterruptedException, IOException {
     boolean remoteCacheFailed = false;
     if (exception instanceof BulkTransferException) {
@@ -573,7 +587,7 @@
       ExecutionStatusException e = (ExecutionStatusException) exception.getCause();
       if (e.getResponse() != null) {
         ExecuteResponse resp = e.getResponse();
-        maybeDownloadServerLogs(resp, actionKey);
+        maybeDownloadServerLogs(resp, actionKey, label);
         if (resp.hasResult()) {
           try {
             // We try to download all (partial) results even on server error, for debuggability.
@@ -601,10 +615,10 @@
     }
 
     final String errorMessage;
-    if (!verboseFailures) {
+    if (!verboseFailures.test(label)) {
       errorMessage = Utils.grpcAwareErrorMessage(exception);
     } else {
-      // On --verbose_failures print the whole stack trace
+      // With verbose_failures print the whole stack trace
       errorMessage = Throwables.getStackTraceAsString(exception);
     }
 
@@ -720,7 +734,7 @@
       remoteCache.upload(
           actionKey, action, command, execRoot, outputFiles, context.getFileOutErr());
     } catch (IOException e) {
-      if (verboseFailures) {
+      if (verboseFailures.test(spawn.getResourceOwner().getOwner().getLabel())) {
         report(Event.debug("Upload to remote cache failed: " + e.getMessage()));
       } else {
         reportOnce(Event.warn("Some artifacts failed be uploaded to the remote cache."));
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java
index 08e93a9..b55046d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java
@@ -57,6 +57,7 @@
 import com.google.devtools.build.lib.actions.extra.ExtraActionInfo;
 import com.google.devtools.build.lib.analysis.skylark.Args;
 import com.google.devtools.build.lib.bugreport.BugReport;
+import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.LabelConstants;
 import com.google.devtools.build.lib.collect.CollectionUtils;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
@@ -434,9 +435,10 @@
         throw new IllegalStateException(e.getCause());
       }
     } catch (ExecException e) {
+      Label label = getOwner().getLabel();
       throw e.toActionExecutionException(
-          "Include scanning of rule '" + getOwner().getLabel() + "'",
-          actionExecutionContext.getVerboseFailures(),
+          "Include scanning of rule '" + label + "'",
+          actionExecutionContext.showVerboseFailures(label),
           this);
     }
   }
@@ -1811,9 +1813,10 @@
         dotDContents = getDotDContents(spawnResults.get(0));
       } catch (ExecException e) {
         copyTempOutErrToActionOutErr();
+        Label label = getOwner().getLabel();
         throw e.toActionExecutionException(
-            "C++ compilation of rule '" + getOwner().getLabel() + "'",
-            actionExecutionContext.getVerboseFailures(),
+            "C++ compilation of rule '" + label + "'",
+            actionExecutionContext.showVerboseFailures(label),
             CppCompileAction.this);
       } catch (InterruptedException e) {
         copyTempOutErrToActionOutErr();
@@ -1904,7 +1907,7 @@
           throw new EnvironmentalExecException(e)
               .toActionExecutionException(
                   getRawProgressMessage(),
-                  actionExecutionContext.getVerboseFailures(),
+                  actionExecutionContext.showVerboseFailures(getOwner().getLabel()),
                   CppCompileAction.this);
         }
       }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkAction.java
index 3ae5e3d..47918a8 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkAction.java
@@ -48,6 +48,7 @@
 import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.skylark.Args;
+import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.RepositoryName;
 import com.google.devtools.build.lib.collect.CollectionUtils;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
@@ -567,9 +568,10 @@
         }
         return ActionContinuationOrResult.of(ActionResult.create(nextContinuation.get()));
       } catch (ExecException e) {
+        Label label = getOwner().getLabel();
         throw e.toActionExecutionException(
-            "Linking of rule '" + getOwner().getLabel() + "'",
-            actionExecutionContext.getVerboseFailures(),
+            "Linking of rule '" + label + "'",
+            actionExecutionContext.showVerboseFailures(label),
             CppLinkAction.this);
       }
     }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/FakeCppCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/FakeCppCompileAction.java
index cd236be..88ba5a1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/FakeCppCompileAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/FakeCppCompileAction.java
@@ -33,6 +33,7 @@
 import com.google.devtools.build.lib.actions.ResourceSet;
 import com.google.devtools.build.lib.actions.Spawn;
 import com.google.devtools.build.lib.actions.SpawnResult;
+import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible;
@@ -143,9 +144,10 @@
       // The SpawnActionContext guarantees that the first list entry is the successful one.
       dotDContents = getDotDContents(spawnResults.get(0));
     } catch (ExecException e) {
+      Label label = getOwner().getLabel();
       throw e.toActionExecutionException(
-          "C++ compilation of rule '" + getOwner().getLabel() + "'",
-          actionExecutionContext.getVerboseFailures(),
+          "C++ compilation of rule '" + label + "'",
+          actionExecutionContext.showVerboseFailures(label),
           this);
     } finally {
       clearAdditionalInputs();
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java
index eb88793..4aaa692 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java
@@ -544,7 +544,8 @@
       return Deps.Dependencies.parseFrom(input);
     } catch (IOException e) {
       throw toActionExecutionException(
-          new EnvironmentalExecException(e), actionExecutionContext.getVerboseFailures());
+          new EnvironmentalExecException(e),
+          actionExecutionContext.showVerboseFailures(getOwner().getLabel()));
     }
   }
 
@@ -610,9 +611,11 @@
             actionExecutionContext, results, fallbackContinuation);
       } catch (IOException e) {
         throw toActionExecutionException(
-            new EnvironmentalExecException(e), actionExecutionContext.getVerboseFailures());
+            new EnvironmentalExecException(e),
+            actionExecutionContext.showVerboseFailures(getOwner().getLabel()));
       } catch (ExecException e) {
-        throw toActionExecutionException(e, actionExecutionContext.getVerboseFailures());
+        throw toActionExecutionException(
+            e, actionExecutionContext.showVerboseFailures(getOwner().getLabel()));
       }
     }
   }
@@ -656,7 +659,8 @@
             ActionResult.create(
                 ImmutableList.copyOf(Iterables.concat(primaryResults, fallbackResults))));
       } catch (ExecException e) {
-        throw toActionExecutionException(e, actionExecutionContext.getVerboseFailures());
+        throw toActionExecutionException(
+            e, actionExecutionContext.showVerboseFailures(getOwner().getLabel()));
       }
     }
   }
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/AbstractSandboxSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/AbstractSandboxSpawnRunner.java
index 8a23059..4a667a4 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/AbstractSandboxSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/AbstractSandboxSpawnRunner.java
@@ -28,6 +28,7 @@
 import com.google.devtools.build.lib.actions.SpawnResult.Status;
 import com.google.devtools.build.lib.actions.Spawns;
 import com.google.devtools.build.lib.actions.UserExecException;
+import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.exec.BinTools;
 import com.google.devtools.build.lib.exec.ExecutionOptions;
 import com.google.devtools.build.lib.exec.SpawnRunner;
@@ -47,6 +48,7 @@
 import java.io.IOException;
 import java.time.Duration;
 import java.util.Map;
+import java.util.function.Predicate;
 
 /** Abstract common ancestor for sandbox spawn runners implementing the common parts. */
 abstract class AbstractSandboxSpawnRunner implements SpawnRunner {
@@ -56,7 +58,7 @@
       "\n\nUse --sandbox_debug to see verbose messages from the sandbox";
 
   private final SandboxOptions sandboxOptions;
-  private final boolean verboseFailures;
+  private final Predicate<Label> verboseFailures;
   private final ImmutableSet<Path> inaccessiblePaths;
   protected final BinTools binTools;
   private final Path execRoot;
@@ -64,7 +66,8 @@
 
   public AbstractSandboxSpawnRunner(CommandEnvironment cmdEnv) {
     this.sandboxOptions = cmdEnv.getOptions().getOptions(SandboxOptions.class);
-    this.verboseFailures = cmdEnv.getOptions().getOptions(ExecutionOptions.class).verboseFailures;
+    this.verboseFailures =
+        cmdEnv.getOptions().getOptions(ExecutionOptions.class).getVerboseFailuresPredicate();
     this.inaccessiblePaths =
         sandboxOptions.getInaccessiblePaths(cmdEnv.getRuntime().getFileSystem());
     this.binTools = cmdEnv.getBlazeWorkspace().getBinTools();
@@ -144,7 +147,7 @@
           null);
     } else {
       return CommandFailureUtils.describeCommandFailure(
-              verboseFailures,
+              verboseFailures.test(originalSpawn.getResourceOwner().getOwner().getLabel()),
               originalSpawn.getArguments(),
               originalSpawn.getEnvironment(),
               sandbox.getSandboxExecRoot().getPathString(),
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/BUILD b/src/main/java/com/google/devtools/build/lib/sandbox/BUILD
index fd70d08..6745eac 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/BUILD
@@ -21,6 +21,7 @@
         "//src/main/java/com/google/devtools/build/lib/analysis:blaze_directories",
         "//src/main/java/com/google/devtools/build/lib/analysis:test/test_configuration",
         "//src/main/java/com/google/devtools/build/lib/analysis/platform:platform_utils",
+        "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/events",
         "//src/main/java/com/google/devtools/build/lib/exec:abstract_spawn_strategy",
         "//src/main/java/com/google/devtools/build/lib/exec:bin_tools",