diff --git a/src/main/java/com/google/devtools/build/lib/worker/ErrorMessage.java b/src/main/java/com/google/devtools/build/lib/worker/ErrorMessage.java index d02d3f36c84a4d..46d32985cb45bd 100644 --- a/src/main/java/com/google/devtools/build/lib/worker/ErrorMessage.java +++ b/src/main/java/com/google/devtools/build/lib/worker/ErrorMessage.java @@ -42,6 +42,7 @@ public static final class Builder { private Path logFile; private String logText = ""; private int logSizeLimit = Integer.MAX_VALUE; + private Exception exception; private Builder() {} @@ -90,9 +91,22 @@ public Builder logSizeLimit(int logSizeLimit) { return this; } + /** Lets the error message contain the details of an exception. */ + public Builder exception(Exception e) { + this.exception = e; + return this; + } + /** Builds and returns the formatted error message. */ public ErrorMessage build() { StringBuilder sb = new StringBuilder(message); + + if (exception != null) { + sb.append("\n\n---8<---8<--- Exception details ---8<---8<---\n"); + sb.append(Throwables.getStackTraceAsString(exception).trim()); + sb.append("\n---8<---8<--- End of exception details ---8<---8<---"); + } + if (!logText.isEmpty()) { sb.append("\n\n---8<---8<--- Start of log"); if (logText.length() > logSizeLimit) { diff --git a/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnStrategy.java b/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnStrategy.java index a912d1e56fc522..9a681ab5ea83fa 100644 --- a/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnStrategy.java +++ b/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnStrategy.java @@ -193,7 +193,8 @@ private void actuallyExec( String message = CommandFailureUtils.describeCommandFailure( verboseFailures, spawn.getArguments(), env, execRoot.getPathString()); - throw new UserExecException(ErrorMessage.builder().message(message).build().toString()); + throw new UserExecException( + ErrorMessage.builder().message(message).exception(e).build().toString()); } } @@ -296,6 +297,7 @@ private WorkResponse execInWorker( throw new UserExecException( ErrorMessage.builder() .message("IOException while borrowing a worker from the pool:") + .exception(e) .build() .toString()); } @@ -307,6 +309,7 @@ private WorkResponse execInWorker( ErrorMessage.builder() .message("IOException while preparing the execution environment of a worker:") .logFile(worker.getLogFile()) + .exception(e) .build() .toString()); } @@ -321,6 +324,7 @@ private WorkResponse execInWorker( "Worker process quit or closed its stdin stream when we tried to send a" + " WorkRequest:") .logFile(worker.getLogFile()) + .exception(e) .build() .toString()); } @@ -340,6 +344,7 @@ private WorkResponse execInWorker( ErrorMessage.builder() .message("Worker process returned an unparseable WorkResponse:") .logText(recordingStream.getRecordedDataAsString()) + .exception(e) .build() .toString()); } @@ -365,6 +370,7 @@ private WorkResponse execInWorker( throw new UserExecException( ErrorMessage.builder() .message("IOException while finishing worker execution:") + .exception(e) .build() .toString()); } diff --git a/src/main/java/com/google/devtools/build/lib/worker/WorkerTestStrategy.java b/src/main/java/com/google/devtools/build/lib/worker/WorkerTestStrategy.java index 114f491b7f4288..040f543a303b67 100644 --- a/src/main/java/com/google/devtools/build/lib/worker/WorkerTestStrategy.java +++ b/src/main/java/com/google/devtools/build/lib/worker/WorkerTestStrategy.java @@ -164,6 +164,7 @@ private TestResultData execInWorker( ErrorMessage errorMessage = ErrorMessage.builder() .message("Worker process returned an unparseable WorkResponse:") + .exception(e) .logText(data) .build(); executor.getEventHandler().handle(Event.warn(errorMessage.toString())); @@ -173,15 +174,15 @@ private TestResultData execInWorker( worker.finishExecution(key); if (response == null) { - ErrorMessage errorMessage = + throw new UserExecException( ErrorMessage.builder() .message( "Worker process did not return a WorkResponse. This is usually caused by a bug" + " in the worker, thus dumping its log file for debugging purposes:") .logFile(worker.getLogFile()) .logSizeLimit(4096) - .build(); - throw new UserExecException(errorMessage.toString()); + .build() + .toString()); } actionExecutionContext.getFileOutErr().getErrorStream().write( diff --git a/src/test/java/com/google/devtools/build/lib/worker/ErrorMessageTest.java b/src/test/java/com/google/devtools/build/lib/worker/ErrorMessageTest.java index f0140f492041de..181e43881e6e9d 100644 --- a/src/test/java/com/google/devtools/build/lib/worker/ErrorMessageTest.java +++ b/src/test/java/com/google/devtools/build/lib/worker/ErrorMessageTest.java @@ -112,4 +112,18 @@ public void testErrorMessageWithUnreadableLogFile() { + "java.io.FileNotFoundException: /nope.txt (No such file or directory)\n"); assertThat(errorMessage.toString()).endsWith("---8<---8<--- End of log ---8<---8<---"); } + + @Test + public void testErrorMessageWithException() { + ErrorMessage errorMessage = + ErrorMessage.builder() + .message("An exception occurred.") + .exception(new IllegalStateException("Hello World")) + .build(); + assertThat(errorMessage.toString()) + .startsWith( + "An exception occurred.\n\n" + + "---8<---8<--- Exception details ---8<---8<---\n" + + "java.lang.IllegalStateException: Hello World"); + } }