فهرست منبع

Tests: improve logging for vagrant to emit entire output on failure

This change makes the vagrant tasks extend LoggedExec, so that the
entire vagrant output can be dumped on failure (and completely logged
when using --info). It should help for debugging issues like #18122.
Ryan Ernst 9 سال پیش
والد
کامیت
8fc51380de

+ 6 - 3
buildSrc/src/main/groovy/org/elasticsearch/gradle/LoggedExec.groovy

@@ -26,14 +26,17 @@ import org.gradle.api.tasks.Exec
  * A wrapper around gradle's Exec task to capture output and log on error.
  */
 class LoggedExec extends Exec {
+
+    protected ByteArrayOutputStream output = new ByteArrayOutputStream()
+
     LoggedExec() {
         if (logger.isInfoEnabled() == false) {
-            standardOutput = new ByteArrayOutputStream()
-            errorOutput = standardOutput
+            standardOutput = output
+            errorOutput = output
             ignoreExitValue = true
             doLast {
                 if (execResult.exitValue != 0) {
-                    standardOutput.toString('UTF-8').eachLine { line -> logger.error(line) }
+                    output.toString('UTF-8').eachLine { line -> logger.error(line) }
                     throw new GradleException("Process '${executable} ${args.join(' ')}' finished with non-zero exit value ${execResult.exitValue}")
                 }
             }

+ 19 - 37
buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/BatsOverVagrantTask.groovy

@@ -19,6 +19,7 @@
 package org.elasticsearch.gradle.vagrant
 
 import org.gradle.api.DefaultTask
+import org.gradle.api.tasks.Input
 import org.gradle.api.tasks.TaskAction
 import org.gradle.logging.ProgressLoggerFactory
 import org.gradle.process.internal.ExecAction
@@ -30,41 +31,22 @@ import javax.inject.Inject
  * Runs bats over vagrant. Pretty much like running it using Exec but with a
  * nicer output formatter.
  */
-class BatsOverVagrantTask extends DefaultTask {
-  String command
-  String boxName
-  ExecAction execAction
-
-  BatsOverVagrantTask() {
-    execAction = getExecActionFactory().newExecAction()
-  }
-
-  @Inject
-  ProgressLoggerFactory getProgressLoggerFactory() {
-    throw new UnsupportedOperationException();
-  }
-
-  @Inject
-  ExecActionFactory getExecActionFactory() {
-    throw new UnsupportedOperationException();
-  }
-
-  void boxName(String boxName) {
-    this.boxName = boxName
-  }
-
-  void command(String command) {
-    this.command = command
-  }
-
-  @TaskAction
-  void exec() {
-    // It'd be nice if --machine-readable were, well, nice
-    execAction.commandLine(['vagrant', 'ssh', boxName, '--command', command])
-    execAction.setStandardOutput(new TapLoggerOutputStream(
-      command: command,
-      factory: getProgressLoggerFactory(),
-      logger: logger))
-    execAction.execute();
-  }
+public class BatsOverVagrantTask extends VagrantCommandTask {
+
+    @Input
+    String command
+
+    BatsOverVagrantTask() {
+        project.afterEvaluate {
+            args 'ssh', boxName, '--command', command
+        }
+    }
+
+    @Override
+    protected OutputStream createLoggerOutputStream() {
+        return new TapLoggerOutputStream(
+                command: commandLine.join(' '),
+                factory: getProgressLoggerFactory(),
+                logger: logger)
+    }
 }

+ 2 - 2
buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/TapLoggerOutputStream.groovy

@@ -47,9 +47,9 @@ class TapLoggerOutputStream extends LoggingOutputStream {
   TapLoggerOutputStream(Map args) {
     logger = args.logger
     progressLogger = args.factory.newOperation(VagrantLoggerOutputStream)
-    progressLogger.setDescription("TAP output for $args.command")
+    progressLogger.setDescription("TAP output for `$args.command`")
     progressLogger.started()
-    progressLogger.progress("Starting $args.command...")
+    progressLogger.progress("Starting `$args.command`...")
   }
 
   void flush() {

+ 29 - 43
buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/VagrantCommandTask.groovy

@@ -18,11 +18,10 @@
  */
 package org.elasticsearch.gradle.vagrant
 
-import org.gradle.api.DefaultTask
-import org.gradle.api.tasks.TaskAction
+import org.apache.commons.io.output.TeeOutputStream
+import org.elasticsearch.gradle.LoggedExec
+import org.gradle.api.tasks.Input
 import org.gradle.logging.ProgressLoggerFactory
-import org.gradle.process.internal.ExecAction
-import org.gradle.process.internal.ExecActionFactory
 
 import javax.inject.Inject
 
@@ -30,43 +29,30 @@ import javax.inject.Inject
  * Runs a vagrant command. Pretty much like Exec task but with a nicer output
  * formatter and defaults to `vagrant` as first part of commandLine.
  */
-class VagrantCommandTask extends DefaultTask {
-  List<Object> commandLine
-  String boxName
-  ExecAction execAction
-
-  VagrantCommandTask() {
-    execAction = getExecActionFactory().newExecAction()
-  }
-
-  @Inject
-  ProgressLoggerFactory getProgressLoggerFactory() {
-    throw new UnsupportedOperationException();
-  }
-
-  @Inject
-  ExecActionFactory getExecActionFactory() {
-    throw new UnsupportedOperationException();
-  }
-
-  void boxName(String boxName) {
-    this.boxName = boxName
-  }
-
-  void commandLine(Object... commandLine) {
-    this.commandLine = commandLine
-  }
-
-  @TaskAction
-  void exec() {
-    // It'd be nice if --machine-readable were, well, nice
-    execAction.commandLine(['vagrant'] + commandLine)
-    execAction.setStandardOutput(new VagrantLoggerOutputStream(
-      command: commandLine.join(' '),
-      factory: getProgressLoggerFactory(),
-      /* Vagrant tends to output a lot of stuff, but most of the important
-        stuff starts with ==> $box */
-      squashedPrefix: "==> $boxName: "))
-    execAction.execute();
-  }
+public class VagrantCommandTask extends LoggedExec {
+
+    @Input
+    String boxName
+
+    public VagrantCommandTask() {
+        executable = 'vagrant'
+        project.afterEvaluate {
+            // It'd be nice if --machine-readable were, well, nice
+            standardOutput = new TeeOutputStream(standardOutput, createLoggerOutputStream())
+        }
+    }
+
+    protected OutputStream createLoggerOutputStream() {
+        return new VagrantLoggerOutputStream(
+            command: commandLine.join(' '),
+            factory: getProgressLoggerFactory(),
+            /* Vagrant tends to output a lot of stuff, but most of the important
+              stuff starts with ==> $box */
+            squashedPrefix: "==> $boxName: ")
+    }
+
+    @Inject
+    ProgressLoggerFactory getProgressLoggerFactory() {
+        throw new UnsupportedOperationException();
+    }
 }

+ 70 - 66
buildSrc/src/main/groovy/org/elasticsearch/gradle/vagrant/VagrantLoggerOutputStream.groovy

@@ -20,6 +20,7 @@ package org.elasticsearch.gradle.vagrant
 
 import com.carrotsearch.gradle.junit4.LoggingOutputStream
 import org.gradle.logging.ProgressLogger
+import org.gradle.logging.ProgressLoggerFactory
 
 /**
  * Adapts an OutputStream being written to by vagrant into a ProcessLogger. It
@@ -42,79 +43,82 @@ import org.gradle.logging.ProgressLogger
  * to catch so it can render the output like
  * "Heading text > stdout from the provisioner".
  */
-class VagrantLoggerOutputStream extends LoggingOutputStream {
-  static final String HEADING_PREFIX = '==> '
+public class VagrantLoggerOutputStream extends LoggingOutputStream {
+    private static final String HEADING_PREFIX = '==> '
 
-  ProgressLogger progressLogger
-  String squashedPrefix
-  String lastLine = ''
-  boolean inProgressReport = false
-  String heading = ''
+    ProgressLoggerFactory progressLoggerFactory
 
-  VagrantLoggerOutputStream(Map args) {
-    progressLogger = args.factory.newOperation(VagrantLoggerOutputStream)
-    progressLogger.setDescription("Vagrant $args.command")
-    progressLogger.started()
-    progressLogger.progress("Starting vagrant $args.command...")
-    squashedPrefix = args.squashedPrefix
-  }
 
-  void flush() {
-    if (end == start) return
-    line(new String(buffer, start, end - start))
-    start = end
-  }
+    private ProgressLogger progressLogger
+    String squashedPrefix
+    String lastLine = ''
+    boolean inProgressReport = false
+    String heading = ''
 
-  void line(String line) {
-    // debugPrintLine(line) // Uncomment me to log every incoming line
-    if (line.startsWith('\r\u001b')) {
-      /* We don't want to try to be a full terminal emulator but we want to
-        keep the escape sequences from leaking and catch _some_ of the
-        meaning. */
-      line = line.substring(2)
-      if ('[K' == line) {
-        inProgressReport = true
-      }
-      return
+    VagrantLoggerOutputStream(Map args) {
+        progressLogger = args.factory.newOperation(VagrantLoggerOutputStream)
+        progressLogger.setDescription("Vagrant output for `$args.command`")
+        progressLogger.started()
+        progressLogger.progress("Starting `$args.command`...")
+        squashedPrefix = args.squashedPrefix
     }
-    if (line.startsWith(squashedPrefix)) {
-      line = line.substring(squashedPrefix.length())
-      inProgressReport = false
-      lastLine = line
-      if (line.startsWith(HEADING_PREFIX)) {
-        line = line.substring(HEADING_PREFIX.length())
-        heading = line + ' > '
-      } else {
-        line = heading + line
-      }
-    } else if (inProgressReport) {
-      inProgressReport = false
-      line = lastLine + line
-    } else {
-      return
+
+    void flush() {
+        if (end == start) return
+        line(new String(buffer, start, end - start))
+        start = end
+    }
+
+    void line(String line) {
+        // debugPrintLine(line) // Uncomment me to log every incoming line
+        if (line.startsWith('\r\u001b')) {
+            /* We don't want to try to be a full terminal emulator but we want to
+              keep the escape sequences from leaking and catch _some_ of the
+              meaning. */
+            line = line.substring(2)
+            if ('[K' == line) {
+                inProgressReport = true
+            }
+            return
+        }
+        if (line.startsWith(squashedPrefix)) {
+            line = line.substring(squashedPrefix.length())
+            inProgressReport = false
+            lastLine = line
+            if (line.startsWith(HEADING_PREFIX)) {
+                line = line.substring(HEADING_PREFIX.length())
+                heading = line + ' > '
+            } else {
+                line = heading + line
+            }
+        } else if (inProgressReport) {
+            inProgressReport = false
+            line = lastLine + line
+        } else {
+            return
+        }
+        // debugLogLine(line) // Uncomment me to log every line we add to the logger
+        progressLogger.progress(line)
     }
-    // debugLogLine(line) // Uncomment me to log every line we add to the logger
-    progressLogger.progress(line)
-  }
 
-  void debugPrintLine(line) {
-    System.out.print '----------> '
-    for (int i = start; i < end; i++) {
-      switch (buffer[i] as char) {
-      case ' '..'~':
-        System.out.print buffer[i] as char
-        break
-      default:
-        System.out.print '%'
-        System.out.print Integer.toHexString(buffer[i])
-      }
+    void debugPrintLine(line) {
+        System.out.print '----------> '
+        for (int i = start; i < end; i++) {
+            switch (buffer[i] as char) {
+                case ' '..'~':
+                    System.out.print buffer[i] as char
+                    break
+                default:
+                    System.out.print '%'
+                    System.out.print Integer.toHexString(buffer[i])
+            }
+        }
+        System.out.print '\n'
     }
-    System.out.print '\n'
-  }
 
-  void debugLogLine(line) {
-    System.out.print '>>>>>>>>>>> '
-    System.out.print line
-    System.out.print '\n'
-  }
+    void debugLogLine(line) {
+        System.out.print '>>>>>>>>>>> '
+        System.out.print line
+        System.out.print '\n'
+    }
 }

+ 2 - 2
qa/vagrant/build.gradle

@@ -156,7 +156,7 @@ for (String box : availableBoxes) {
   // always add a halt task for all boxes, so clean makes sure they are all shutdown
   Task halt = tasks.create("vagrant${boxTask}#halt", VagrantCommandTask) {
     boxName box
-    commandLine 'halt', box
+    args 'halt', box
   }
   stop.dependsOn(halt)
   if (boxes.contains(box) == false) {
@@ -176,7 +176,7 @@ for (String box : availableBoxes) {
       vagrant's default but its possible to change that default and folks do.
       But the boxes that we use are unlikely to work properly with other
       virtualization providers. Thus the lock. */
-    commandLine 'up', box, '--provision', '--provider', 'virtualbox'
+    args 'up', box, '--provision', '--provider', 'virtualbox'
     /* It'd be possible to check if the box is already up here and output
       SKIPPED but that would require running vagrant status which is slow! */
     dependsOn checkVagrantVersion