Skip to content

Commit

Permalink
Add support for serializing Any types to BEP's JSON transport.
Browse files Browse the repository at this point in the history
Followup from issue bazelbuild#19471 to include details specific to execution strategy
for the select actions included in BEP.

PiperOrigin-RevId: 577279639
Change-Id: I112182134f1ce798c22f8f81998a14040344c191
  • Loading branch information
michaeledgar authored and copybara-github committed Oct 27, 2023
1 parent 2d0d22d commit b940a3a
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ java_library(
),
deps = [
":buildeventservice-options",
"//src/main/java/com/google/devtools/build/lib:build-request-options",
"//src/main/java/com/google/devtools/build/lib:runtime",
"//src/main/java/com/google/devtools/build/lib/analysis:blaze_directories",
"//src/main/java/com/google/devtools/build/lib/analysis:test/test_configuration",
Expand All @@ -62,6 +61,7 @@ java_library(
"//src/main/java/com/google/devtools/build/lib/util/io:out-err",
"//src/main/java/com/google/devtools/common/options",
"//src/main/protobuf:failure_details_java_proto",
"//src/main/protobuf:spawn_java_proto",
"//third_party:auth",
"//third_party:auto_value",
"//third_party:flogger",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.events.Reporter;
import com.google.devtools.build.lib.exec.Protos.SpawnExec;
import com.google.devtools.build.lib.network.ConnectivityStatus;
import com.google.devtools.build.lib.network.ConnectivityStatus.Status;
import com.google.devtools.build.lib.network.ConnectivityStatusProvider;
Expand All @@ -72,6 +73,7 @@
import com.google.devtools.common.options.OptionsBase;
import com.google.devtools.common.options.OptionsParsingException;
import com.google.devtools.common.options.OptionsParsingResult;
import com.google.protobuf.util.JsonFormat.TypeRegistry;
import com.google.protobuf.util.Timestamps;
import java.io.BufferedOutputStream;
import java.io.IOException;
Expand Down Expand Up @@ -748,6 +750,16 @@ private BuildEventServiceTransport createBesTransport(
.build();
}

/**
* Returns the JSON type registry, used to resolve {@code Any} type names at serialization time.
*
* <p>Intended to be overridden by custom build tools with a subclassed {@link
* BuildEventServiceModule} to add additional Any types to be produced.
*/
protected TypeRegistry makeJsonTypeRegistry() {
return TypeRegistry.newBuilder().add(SpawnExec.getDescriptor()).build();
}

private ImmutableSet<BuildEventTransport> createBepTransports(
CommandEnvironment cmdEnv,
ThrowingBuildEventArtifactUploaderSupplier uploaderSupplier,
Expand Down Expand Up @@ -820,7 +832,11 @@ private ImmutableSet<BuildEventTransport> createBepTransports(
: new LocalFilesArtifactUploader();
bepTransportsBuilder.add(
new JsonFormatFileTransport(
bepJsonOutputStream, bepOptions, localFileUploader, artifactGroupNamer));
bepJsonOutputStream,
bepOptions,
localFileUploader,
artifactGroupNamer,
makeJsonTypeRegistry()));
} catch (IOException exception) {
// TODO(b/125216340): Consider making this a warning instead of an error once the
// associated bug has been resolved.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,11 @@ message ActionExecuted {
// End of action execution, after all attempted execution completes.
google.protobuf.Timestamp end_time = 13;

// Additional details about action execution supplied by any/all strategies.
// Additional details about action execution supplied by strategies. Bazel
// options will determine which strategy details are included when multiple
// strategies are involved in a single action's execution.
//
// The default type will be `tools.proto.SpawnExec` found in `spawn.proto`.
repeated google.protobuf.Any strategy_details = 14;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ java_library(
"//src/main/java/com/google/devtools/common/options",
"//src/main/protobuf:failure_details_java_proto",
"//third_party:flogger",
"//third_party:gson",
"//third_party:guava",
"//third_party:jsr305",
"//third_party/protobuf:protobuf_java",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,41 @@

import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.flogger.GoogleLogger;
import com.google.devtools.build.lib.buildeventstream.ArtifactGroupNamer;
import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploader;
import com.google.devtools.build.lib.buildeventstream.BuildEventProtocolOptions;
import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
import com.google.devtools.build.lib.buildeventstream.BuildEventTransport;
import com.google.gson.GsonBuilder;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.util.JsonFormat;
import com.google.protobuf.util.JsonFormat.Printer;
import com.google.protobuf.util.JsonFormat.TypeRegistry;
import java.io.BufferedOutputStream;

/**
* A simple {@link BuildEventTransport} that writes the JSON representation of the protocol-buffer
* representation of the events to a file.
*/
public final class JsonFormatFileTransport extends FileTransport {
private static final GoogleLogger logger = GoogleLogger.forEnclosingClass();

private static final String UNKNOWN_ANY_TYPE_ERROR_EVENT =
new GsonBuilder().create().toJson(new UnknownAnyProtoError());

private final Printer jsonPrinter;

public JsonFormatFileTransport(
BufferedOutputStream outputStream,
BuildEventProtocolOptions options,
BuildEventArtifactUploader uploader,
ArtifactGroupNamer namer) {
ArtifactGroupNamer namer,
TypeRegistry typeRegistry) {
super(outputStream, options, uploader, namer);
jsonPrinter =
JsonFormat.printer().usingTypeRegistry(typeRegistry).omittingInsignificantWhitespace();
}

@Override
Expand All @@ -47,14 +62,24 @@ public String name() {
protected byte[] serializeEvent(BuildEventStreamProtos.BuildEvent buildEvent) {
String protoJsonRepresentation;
try {
protoJsonRepresentation =
JsonFormat.printer().omittingInsignificantWhitespace().print(buildEvent) + "\n";
protoJsonRepresentation = jsonPrinter.print(buildEvent);
} catch (InvalidProtocolBufferException e) {
// We don't expect any unknown Any fields in our protocol buffer. Nevertheless, handle
// the exception gracefully and, at least, return valid JSON with an id field.
protoJsonRepresentation =
"{\"id\" : \"unknown\", \"exception\" : \"InvalidProtocolBufferException\"}\n";
logger.atWarning().withCause(e).log(
"Failed to serialize to JSON due to Any type resolution failure: %s", buildEvent);
protoJsonRepresentation = UNKNOWN_ANY_TYPE_ERROR_EVENT;
}
return protoJsonRepresentation.getBytes(UTF_8);
return (protoJsonRepresentation + "\n").getBytes(UTF_8);
}

/** Error produced when serializing an {@code Any} protobuf whose contained type is unknown. */
@VisibleForTesting
static class UnknownAnyProtoError {
@SuppressWarnings({"FieldCanBeStatic", "unused"}) // Used by Gson formatting; cannot be static
private final String id = "unknown";

@SuppressWarnings({"FieldCanBeStatic", "unused"}) // Used by Gson formatting; cannot be static
private final String exception = "InvalidProtocolBufferException";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ java_test(
"//src/main/java/com/google/devtools/build/lib/buildeventstream/transports",
"//src/main/java/com/google/devtools/build/lib/vfs",
"//src/main/java/com/google/devtools/common/options",
"//src/main/protobuf:spawn_java_proto",
"//third_party:gson",
"//third_party:guava",
"//third_party:junit4",
"//third_party:mockito",
Expand Down
Loading

0 comments on commit b940a3a

Please sign in to comment.