Print the path of too-large stdout/stderr and the flag to increase the limit.

PiperOrigin-RevId: 332503242
diff --git a/src/main/java/com/google/devtools/build/lib/events/BUILD b/src/main/java/com/google/devtools/build/lib/events/BUILD
index aad49b2..cfb4d2d 100644
--- a/src/main/java/com/google/devtools/build/lib/events/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/events/BUILD
@@ -14,6 +14,7 @@
     deps = [
         "//src/main/java/com/google/devtools/build/lib/util/io",
         "//src/main/java/com/google/devtools/build/lib/util/io:out-err",
+        "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
         "//src/main/java/net/starlark/java/eval",
         "//src/main/java/net/starlark/java/syntax",
         "//third_party:guava",
diff --git a/src/main/java/com/google/devtools/build/lib/events/Event.java b/src/main/java/com/google/devtools/build/lib/events/Event.java
index f699405..a7f4f94 100644
--- a/src/main/java/com/google/devtools/build/lib/events/Event.java
+++ b/src/main/java/com/google/devtools/build/lib/events/Event.java
@@ -20,6 +20,7 @@
 
 import com.google.common.collect.ImmutableClassToInstanceMap;
 import com.google.devtools.build.lib.util.io.FileOutErr;
+import com.google.devtools.build.lib.vfs.PathFragment;
 import java.io.IOException;
 import java.io.Serializable;
 import java.util.Arrays;
@@ -190,6 +191,16 @@
     return getProperty(FileOutErr.class) != null;
   }
 
+  /**
+   * Gets the path to the stdout associated with this event (which the caller must not access), or
+   * null if there is no such path.
+   */
+  @Nullable
+  public PathFragment getStdOutPathFragment() {
+    FileOutErr outErr = getProperty(FileOutErr.class);
+    return outErr == null ? null : outErr.getOutputPathFragment();
+  }
+
   /** Gets the size of the stdout associated with this event without reading it. */
   public long getStdOutSize() throws IOException {
     FileOutErr outErr = getProperty(FileOutErr.class);
@@ -206,6 +217,16 @@
     return outErr.outAsBytes();
   }
 
+  /**
+   * Gets the path to the stderr associated with this event (which the caller must not access), or
+   * null if there is no such path.
+   */
+  @Nullable
+  public PathFragment getStdErrPathFragment() {
+    FileOutErr outErr = getProperty(FileOutErr.class);
+    return outErr == null ? null : outErr.getErrorPathFragment();
+  }
+
   /** Gets the size of the stderr associated with this event without reading it. */
   public long getStdErrSize() throws IOException {
     FileOutErr outErr = getProperty(FileOutErr.class);
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/UiEventHandler.java b/src/main/java/com/google/devtools/build/lib/runtime/UiEventHandler.java
index 21fd0ba..362515e 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/UiEventHandler.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/UiEventHandler.java
@@ -383,7 +383,8 @@
   }
 
   @Nullable
-  private byte[] getContentIfSmallEnough(String name, long size, Supplier<byte[]> getContent) {
+  private byte[] getContentIfSmallEnough(
+      String name, long size, Supplier<byte[]> getContent, Supplier<PathFragment> getPath) {
     if (size == 0) {
       // Avoid any possible I/O when we know it'll be empty anyway.
       return null;
@@ -392,7 +393,10 @@
     if (size < maxStdoutErrBytes) {
       return getContent.get();
     } else {
-      return (name + " exceeds maximum size of " + maxStdoutErrBytes + " bytes; skipping")
+      return String.format(
+              "%s (%s) exceeds maximum size of --experimental_ui_max_stdouterr_bytes=%d bytes;"
+                  + " skipping\n",
+              name, getPath.get(), maxStdoutErrBytes)
           .getBytes(StandardCharsets.ISO_8859_1);
     }
   }
@@ -408,8 +412,12 @@
       byte[] stdout = null;
       byte[] stderr = null;
       if (event.hasStdoutStderr()) {
-        stdout = getContentIfSmallEnough("stdout", event.getStdOutSize(), event::getStdOut);
-        stderr = getContentIfSmallEnough("stderr", event.getStdErrSize(), event::getStdErr);
+        stdout =
+            getContentIfSmallEnough(
+                "stdout", event.getStdOutSize(), event::getStdOut, event::getStdOutPathFragment);
+        stderr =
+            getContentIfSmallEnough(
+                "stderr", event.getStdErrSize(), event::getStdErr, event::getStdErrPathFragment);
       }
 
       if (debugAllEvents) {
diff --git a/src/main/java/com/google/devtools/build/lib/util/io/FileOutErr.java b/src/main/java/com/google/devtools/build/lib/util/io/FileOutErr.java
index e44f0f7..5a047e5 100644
--- a/src/main/java/com/google/devtools/build/lib/util/io/FileOutErr.java
+++ b/src/main/java/com/google/devtools/build/lib/util/io/FileOutErr.java
@@ -20,6 +20,7 @@
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.lib.vfs.PathFragment;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
@@ -111,7 +112,8 @@
   }
 
   /**
-   * Returns the {@link Path} this OutErr uses to buffer stdout
+   * Returns the path this OutErr uses to buffer stdout, marking the file as "accessed" because the
+   * caller has unrestricted access to the underlying file.
    *
    * <p>The user must ensure that no other process is writing to the files at time of creation.
    *
@@ -121,13 +123,25 @@
     return getFileOutputStream().getFile();
   }
 
+  /**
+   * Returns the path this OutErr uses to buffer stdout without marking the file as "accessed".
+   *
+   * <p>The user must ensure that no other process is writing to the files at time of creation.
+   *
+   * @return the path object with the contents of stdout
+   */
+  public PathFragment getOutputPathFragment() {
+    return getFileOutputStream().getFileUnsafe().asFragment();
+  }
+
   /** Returns the length of the stdout contents. */
   public long outSize() throws IOException {
     return getFileOutputStream().getRecordedOutputSize();
   }
 
   /**
-   * Returns the {@link Path} this OutErr uses to buffer stderr.
+   * Returns the path this OutErr uses to buffer stderr, marking the file as "accessed" because the
+   * caller has unrestricted access to the underlying file.
    *
    * @return the path object with the contents of stderr
    */
@@ -135,6 +149,15 @@
     return getFileErrorStream().getFile();
   }
 
+  /**
+   * Returns the path this OutErr uses to buffer stderr without marking the file as "accessed".
+   *
+   * @return the path object with the contents of stderr
+   */
+  public PathFragment getErrorPathFragment() {
+    return getFileErrorStream().getFileUnsafe().asFragment();
+  }
+
   public byte[] outAsBytes() {
     return getFileOutputStream().getRecordedOutput();
   }
diff --git a/src/test/shell/integration/ui_test.sh b/src/test/shell/integration/ui_test.sh
index c394f40..2f8670e 100755
--- a/src/test/shell/integration/ui_test.sh
+++ b/src/test/shell/integration/ui_test.sh
@@ -563,13 +563,13 @@
       //outs:short-stdout-long-stderr \
       >"${TEST_log}" 2>&1 || fail "build failed"
   expect_log 'abc'
-  expect_log 'stderr exceeds maximum size'
+  expect_log 'stderr .*/actions/stderr-.* exceeds maximum size'
 
   bazel build --experimental_ui_max_stdouterr_bytes=5 \
       //outs:long-stdout-short-stderr \
       >"${TEST_log}" 2>&1 || fail "build failed"
   expect_log 'abc'
-  expect_log 'stdout exceeds maximum size'
+  expect_log 'stdout .*/actions/stdout-.* exceeds maximum size'
 }
 
 function test_max_stdouterr_bytes_is_for_individual_outputs() {