Stream blaze JSON profile output via remote uploader with --experimental_stream_log_file_uploads. When enabled, we do not write the profile to disk at all.

RELNOTES: None
PiperOrigin-RevId: 281272627
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/buildevent/ProfilerStartedEvent.java b/src/main/java/com/google/devtools/build/lib/buildtool/buildevent/ProfilerStartedEvent.java
index c3cf5e9..2d1a2a6 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/buildevent/ProfilerStartedEvent.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/buildevent/ProfilerStartedEvent.java
@@ -13,20 +13,34 @@
 // limitations under the License.
 package com.google.devtools.build.lib.buildtool.buildevent;
 
+import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploader.UploadContext;
 import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.vfs.Path;
+import javax.annotation.Nullable;
 
 /**
  * This event is fired when the profiler is started.
  */
 public class ProfilerStartedEvent implements ExtendedEventHandler.Postable {
-  private final Path profilePath;
+  @Nullable private final Path profilePath;
+  @Nullable private final UploadContext streamingContext;
+  @Nullable private final String name;
 
-  public ProfilerStartedEvent(Path profilePath) {
+  public ProfilerStartedEvent(String name, Path profilePath, UploadContext streamingContext) {
     this.profilePath = profilePath;
+    this.streamingContext = streamingContext;
+    this.name = name;
   }
 
   public Path getProfilePath() {
     return profilePath;
   }
+
+  public UploadContext getStreamingContext() {
+    return streamingContext;
+  }
+
+  public String getName() {
+    return name;
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java b/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
index 7e0b9bc..4e41757 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
@@ -27,6 +27,7 @@
 import com.google.devtools.build.lib.analysis.NoBuildEvent;
 import com.google.devtools.build.lib.bugreport.BugReport;
 import com.google.devtools.build.lib.bugreport.BugReporter;
+import com.google.devtools.build.lib.buildeventstream.BuildEventProtocolOptions;
 import com.google.devtools.build.lib.buildtool.buildevent.ProfilerStartedEvent;
 import com.google.devtools.build.lib.clock.BlazeClock;
 import com.google.devtools.build.lib.events.Event;
@@ -312,16 +313,17 @@
     // TODO(ulfjack): Move the profiler initialization as early in the startup sequence as possible.
     // Profiler setup and shutdown must always happen in pairs. Shutdown is currently performed in
     // the afterCommand call in the finally block below.
-    Path profilePath =
+    ProfilerStartedEvent profilerStartedEvent =
         runtime.initProfiler(
             storedEventHandler,
             workspace,
             commonOptions,
-            env.getCommandId(),
+            options.getOptions(BuildEventProtocolOptions.class),
+            env,
             execStartTimeNanos,
             waitTimeInMs);
     if (commonOptions.postProfileStartedEvent) {
-      storedEventHandler.post(new ProfilerStartedEvent(profilePath));
+      storedEventHandler.post(profilerStartedEvent);
     }
 
     BlazeCommandResult result = BlazeCommandResult.exitCode(ExitCode.BLAZE_INTERNAL_ERROR);
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java b/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
index 2bbfd58..2a115ff 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
@@ -35,10 +35,14 @@
 import com.google.devtools.build.lib.analysis.test.CoverageReportActionFactory;
 import com.google.devtools.build.lib.bugreport.BugReport;
 import com.google.devtools.build.lib.bugreport.BugReporter;
+import com.google.devtools.build.lib.buildeventstream.BuildEvent.LocalFile.LocalFileType;
+import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploader;
+import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploader.UploadContext;
+import com.google.devtools.build.lib.buildeventstream.BuildEventProtocolOptions;
+import com.google.devtools.build.lib.buildtool.buildevent.ProfilerStartedEvent;
 import com.google.devtools.build.lib.clock.BlazeClock;
 import com.google.devtools.build.lib.clock.Clock;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.events.OutputFilter;
 import com.google.devtools.build.lib.exec.BinTools;
@@ -278,12 +282,18 @@
     return moduleInvocationPolicy;
   }
 
+  private BuildEventArtifactUploader newUploader(
+      CommandEnvironment env, String buildEventUploadStrategy) {
+    return getBuildEventArtifactUploaderFactoryMap().select(buildEventUploadStrategy).create(env);
+  }
+
   /** Configure profiling based on the provided options. */
-  Path initProfiler(
-      EventHandler eventHandler,
+  ProfilerStartedEvent initProfiler(
+      ExtendedEventHandler eventHandler,
       BlazeWorkspace workspace,
       CommonCommandOptions options,
-      UUID buildID,
+      BuildEventProtocolOptions bepOptions,
+      CommandEnvironment env,
       long execStartTimeNanos,
       long waitTimeInMs) {
     OutputStream out = null;
@@ -291,6 +301,8 @@
     ImmutableSet.Builder<ProfilerTask> profiledTasksBuilder = ImmutableSet.builder();
     Profiler.Format format = Profiler.Format.BINARY_BAZEL_FORMAT;
     Path profilePath = null;
+    String profileName = null;
+    UploadContext streamingContext = null;
     try {
       if (options.enableTracer || (options.removeBinaryProfile && options.profilePath != null)) {
         if (options.enableTracerCompression == TriState.YES
@@ -303,15 +315,23 @@
         }
         if (options.profilePath != null) {
           profilePath = workspace.getWorkspace().getRelative(options.profilePath);
+          out = profilePath.getOutputStream();
         } else {
-          String profileName = "command.profile";
+          profileName = "command.profile";
           if (format == Format.JSON_TRACE_FILE_COMPRESSED_FORMAT) {
             profileName = "command.profile.gz";
           }
-          profilePath = workspace.getOutputBase().getRelative(profileName);
+          if (bepOptions.streamingLogFileUploads) {
+            BuildEventArtifactUploader buildEventArtifactUploader =
+                newUploader(env, bepOptions.buildEventUploadStrategy);
+            streamingContext = buildEventArtifactUploader.startUpload(LocalFileType.LOG);
+            out = streamingContext.getOutputStream();
+          } else {
+            profilePath = workspace.getOutputBase().getRelative(profileName);
+            out = profilePath.getOutputStream();
+          }
         }
-        out = profilePath.getOutputStream();
-        if (options.announceProfilePath) {
+        if (profilePath != null && options.announceProfilePath) {
           eventHandler.handle(Event.info("Writing tracer profile to '" + profilePath + "'"));
         }
         for (ProfilerTask profilerTask : ProfilerTask.values()) {
@@ -354,7 +374,7 @@
             format,
             getProductName(),
             workspace.getOutputBase().toString(),
-            buildID,
+            env.getCommandId(),
             recordFullProfilerData,
             clock,
             execStartTimeNanos,
@@ -399,7 +419,7 @@
     } catch (IOException e) {
       eventHandler.handle(Event.error("Error while creating profile file: " + e.getMessage()));
     }
-    return profilePath;
+    return new ProfilerStartedEvent(profileName, profilePath, streamingContext);
   }
 
   public FileSystem getFileSystem() {